如何访问私有成员变量和函数 (修正版)

原创 2007年04月09日 00:49:00
这篇文章介绍一些 Delphi 穿透 OOP 约束的技巧。
访问保护的 (protected) 变量
如果是某个类的保护变量,可以在任何地方,通过如下方法访问:
type
  TSomeClassAccess = 
class(TSomeClass);

begin
  TSomeClassAccess(Object1).protected_Bool := False;
  TSomeClassAccess(Object1).protected_Int  := 
0;
  ...
end;

 
访问私有的 (private) 变量
如果是某个类的私有变量,我们需要计算该变量在 VMT 中的偏移量。同时由于类声明可能在不同的 Delphi 版本中也有所不同,所以最好事先先检查一下源码。例:访问 TMenuItem 的第二个内部成员变量 FHandle
type
  THackMenuItem = 
class(TComponent)
  
protected //<-- change to protected 
    FxxxxCaption: AnsiString;
    FHandle: HMENU;
//<-- the property you want to access
begin
  THackMenuItem(AMenuItem).FHandle := 0;
  ...
end;

 
访问部分私有的 (private) 函数
访问私有函数要相对困难许多。据我所知只有定义时声明为 virtualoverridedynamic message 私有函数才可以被访问或替换。其实现原理和访问私有变量相似:先计算该函数在 VMT/DMT 中的偏移量然后把该内存地址替换成新函数的内存地址。具体做法可以参考 TntControls TntSystem.pas 安装系统补丁或者是 Fastcode 控件包。
友情提醒:(1) 通常私有函数中会涉及到一些访问其它的私有函数/变量。往往为了访问一个私有函数,还需要修改更多个私有函数/变量。相对比较复杂,也不很可靠。(2) 内存地址修改不当会引发于一些软件的冲突,如 AQTime
注:如果变量定义时未设置关键字 strict,同一个单元里面的所有类的内部变量/函数可以直接相互访问。这个是 Delphi 开的一个不大不小的后门。
 
增加私有的 (private) 函数 (a)
我们真的需要吗?有时候要!比如我在写一个 Dunit 单元测试的时候,需要接受 WM_COPYDATA 消息。但是这个消息是发送给 GUITestRunner 的,我必须打入 GUITestRunner 才可以得到相应消息。实现方法和访问私有函数类似,我们计算 VMT/DMT 的长度,在尾端增加一个新的函数指针。我在网上找到一篇文章说的比较详细,请点击这里查看。这个方法有个限制:这个修改不是编译期完成的,你必须在类实例化之后,才进行修改。如果这个类被频繁使用,这个做法显然有些麻烦。如果能把这段修改代码放如类的构析函数中,问题就迎刃而解了。我在假想:我们是否可以使用介绍3中引入的方法,实现这个……

增加私有的 (private) 函数 (b)
还有一种更干净的修改方法,我们定义一个同名的类来欺骗编译器。例:我们创建一个新的单元,名为 GUITestRunnerPatch.pas
type
  THackGUITestRunner = 
class(GUITestRunner.TGUITestRunner)
  
private
    procedure WMCopyData(var Msg: TWMCopyData);
message WM_COPYDATA; //<-- the method you want to append
  end;

在需要使用GUITestRunner 的地方加上新的GUITestRunnerPatch。注意:一定要在其之后,否则编译器不会调用你修改过的这个类,而是调用了原先的那个。
 
总结:
在进入 Delphi 的内部世界时,我们要尽可能的考虑代码的移植性和通用性,要以少量修改换回最佳效果。如果上面介绍的修修补补不能解决你的问题,当然你也可以直接修改 Delphi 的控件源码。修改之后,勾选编译选项里面的 „Use Debug DCUs“,并编译程序,再将编译得到的 dcu 文件保存到编译目录下面。我一般创建2个目录:PatchedVCLs PreCompiled 放修改过的源码,和编译之后的版本。然后把这个2个目录定义到环境变量里面,这样只要在每个项目的路径设置中添加这些变量,就可以使用改动过的代码了。如果本文不正确的地方,欢迎拍砖。
 

修改static中成员变量的值

 class person{     String name;     int age;     static String country;     public person(){}...
  • chenzhonghan8899
  • chenzhonghan8899
  • 2016-06-13 18:55:07
  • 298

被static修饰的成员变量可以被修改吗

被static修饰的变量、常量、方法被称作静态变量、静态常量以及静态方法。 那么被static修饰的成员变量可以被修改吗?可以。只要是变量就可以被修改。被static修饰的成员变量和成员方法独立于该...
  • dengfan666
  • dengfan666
  • 2017-11-23 20:01:08
  • 1558

方法传入参数(来自成员变量),在方法中修改参数,退出方法后,是否会改变参数值呢?

现在列出三种不同的方法传入参数; 1、传入参数为整形变量: public static void main(String[] args){ int a = 10; test(a); System.ou...
  • u010698072
  • u010698072
  • 2016-06-29 20:05:31
  • 4361

关于成员变量和局部变量是否都会被默认初始化的问题

成员变量可以不用初始化,其具有默认值;但是局部变量一定需要初始化,否则编译报错。 public class Demo { int m; public static void main(...
  • rockpk008
  • rockpk008
  • 2016-08-04 23:51:42
  • 3072

static变量可以被修改吗?

静态变量并不是说其就不能改变值,不能改变值的量叫常量。 其拥有的值是可变的 ,而且它会保持最新的值。说其静态,是因为它不会随着函数的调用和退出而发生变化。即上次调用函数的时候,如果我们给静态变量赋予某...
  • qq_16334327
  • qq_16334327
  • 2017-10-11 11:08:26
  • 1366

java不可变类中静态成员变量可以改变吗

java不可变类中静态成员变量可以改变吗  分享| 2014-07-30 15:40齐藤教练 | 浏览 299 次  来自:手机知道 我有更好的答案 按默认排序 | 按时...
  • evilcry2012
  • evilcry2012
  • 2016-01-25 13:15:28
  • 931

成员变量赋值问题【向前引用】

今天,同学问了我一个问题,代码如下 public class Test10 { //这个小程序 为啥不报错,应该是先执行a=10这个程序块,但是我们没有设定a的类型啊 { ...
  • hon_3y
  • hon_3y
  • 2017-01-19 14:42:55
  • 635

springMVC 谨慎使用成员变量

1.springMVC默认是单例的 对于同一个Controller,只会生成一个实例来处理所有的请求,因此bean实例只会实例化一次,并被存放在工厂中,以供其他请求使用。 在不定义成员变量的情...
  • panda_In5
  • panda_In5
  • 2017-11-14 13:03:17
  • 713

如何封装.h和.a静态库使得头文件中不含有暴露内部实现的private成员变量

参考:C++类怎么将一些成员的声明定义都放到cpp文件中 http://bbs.csdn.net/topics/350125990实现:分为四个文件: 最终需要交给别人的只有network....
  • u010286868
  • u010286868
  • 2016-05-29 15:38:52
  • 2543
收藏助手
不良信息举报
您举报文章:如何访问私有成员变量和函数 (修正版)
举报原因:
原因补充:

(最多只允许输入30个字)