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

    技术2022-05-11  99

    一说到修改 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 下个版本会引入了新的技术,直接修改声明部分的代码将变的可能


    最新回复(0)