如何访问私有成员变量和函数

一说到修改 Delphi 源码或者访问对象的私有成员函数,很多人马上可以说出种种危害来否定我。这种做法我也提倡,但是有时候如果可以灵活运用,可以解决由于 Delphi 因为封装不正确而带来的问题。我在这里分享一些技巧:

1.     访问私有成员变量
如果是 protected 的变量,可以用如下方法访问:

type
  TSomeClassAccess = 
class(TSomeClass);

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

如果是 private 的变量,那么就要当心了。因为涉及到偏移量。还要考虑不同 Delphi 版本的控件的内部成员可能也有变化。最简单的例子是:访问 TMenuItem 的第二个内部成员变量 FHandle

type
  THackMenuItem = 
class(TComponent)
  
protected //<-- change to protected 
    FxxxxCaption: AnsiString;
    FHandle: HMENU;
//<-- the property you want to access

  end;


begin
  THackMenuItem(AMenuItem).FHandle := 0;
  ...
end;

2.      访问私有成员函数
这个目前普遍的做法是偷梁换柱。就是把自己的函数地址替换成待修改函数的内存地址。不过其中涉及到了内存修改、地址偏移量……,具体做法可以参考 TntControls TntSystem.pas 安装系统补丁,或者是 Fastcode 控件包。当然这个替换是会出现副作用的:例如 AQTime 就无法测试安装过 TntSystem 补丁的程序。

3.      直接修改代码的实现
如果是运行库中的具体实现要修改,可以直接动源码,因为改动是implementation 的部分,不会影响到其它的调用该单元的部分。(注意:interface implementation 的内容不能直接修改,否则无法编译通过。)修改之后,勾选编译选项里面的 „Use Debug DCUs“,并编译程序,再将编译得到的 dcu 文件保存到编译目录下面。我一般创建2个目录:PatchedVCLs PreCompiled 放修改过的源码,和编译之后的版本。然后把这个2个目录定义到环境变量里面,这样只要在每个项目的路径设置中添加这些变量,就可以使用改动过的代码了。

4.      间接修改代码的实现
如果要在修改定义部分怎么办?方法3是肯定行不通了。因为所有引用到这个单元的单元也需要重新编译,但不是所有 Delphi 源码你都可以重新编译的。这种情况就伤脑筋了。我目前只可以修改很小一部分的。基本思路是在自己的程序里面定义需访问对象的扩展类和具体实现。然后释放原先对象实例,并以新扩展类重新创建实例。请参考 打入消息循环的另类方法


总结:
以上四种方法是我在修改 Delphi 库或者第三方控件时候所用到的。在修改源码的时候,尽量要考虑到代码的移植性。要做到最少量的修改,得到最好的效果。并且需要考虑修改的代码是否可以在不 同的 Delphi 版本中使用。我在实际项目中,修改了67个源码。(有时间的话,我会一一列出,有需要的可以问我索取。)同时也欢迎交流更多的修改方法,以及 Delphi 不正确封装的补丁。


题外话:

刚刚来自 CodeGear 的消息,Delphi 下个版本会引入了新的技术,直接修改声明部分的代码将变的可能

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试