Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何修补TControlCanvas.CreateHandle(FreeDeviceContext问题)?_Delphi_Patch_Delphi 5_Detours - Fatal编程技术网

Delphi 如何修补TControlCanvas.CreateHandle(FreeDeviceContext问题)?

Delphi 如何修补TControlCanvas.CreateHandle(FreeDeviceContext问题)?,delphi,patch,delphi-5,detours,Delphi,Patch,Delphi 5,Detours,这个问题与我先前的问题有关: 显然Delphi的代码中有一个bug(请参阅)。这个错误一直持续到2010年2月,好吧 到目前为止,建议的解决办法效果良好。现在我左右为难 我不喜欢在我的项目中使用Controls.pas的私有副本,我不确定它是否安全。Controls单元是一个非常低级的单元,考虑到我的大型应用程序运行良好,除了上面提到的问题之外,我真的觉得这是一个激烈的举动。我也不确定是否/如何重建项目中依赖控件的所有组件/单元 是否可以修补使用内部画布列表和私有成员的TControlCanv

这个问题与我先前的问题有关:

显然Delphi的代码中有一个bug(请参阅)。这个错误一直持续到2010年2月,好吧

到目前为止,建议的解决办法效果良好。现在我左右为难

我不喜欢在我的项目中使用
Controls.pas
的私有副本,我不确定它是否安全。
Controls
单元是一个非常低级的单元,考虑到我的大型应用程序运行良好,除了上面提到的问题之外,我真的觉得这是一个激烈的举动。我也不确定是否/如何重建项目中依赖
控件的所有组件/单元

是否可以修补使用内部
画布列表和私有成员的
TControlCanvas.CreateHandle()


注意:我将只为这个项目使用补丁(Delphi 5)。我不介意硬编码偏移量。顺便说一句,根据编译器版本,修补隐私总是使用硬编码偏移量。我可能可以自己处理私人事务(没有类助手),但我不知道如何处理
CanvasList
FreeDeviceContext()
,它们在
控件
单元的实现部分声明。

如评论中所述,可以访问类的
私有
受保护
成员,即使在没有“类助手”的旧版本的Delphi中也是如此

然而,本例中的问题围绕着特定方法实现的细节,而不仅仅是能够访问或修改私有成员变量。此外,使用所涉及单元中的实现变量的特定方法的实现。特别是您注意到的
CanvasList
变量

即使有类助手的帮助,也没有简单的方法来访问该实现变量

您当前的解决方案是最简单和最安全的方法:使用整个单元的副本,并对解决问题所需的特定方法进行修改

请放心,这种做法并不少见。:)

这种方法的唯一问题是,在建立新的开发环境或升级到新版本的IDE时,确保管理依赖于该单元的“私有化”副本这一事实

在新的开发环境中,仔细的项目配置应该能够解决问题(当然,修改后的
控件.pas
单元是版本控制项目的一部分)

在升级到较新的Delphi版本的情况下,您只需记住在每个新版本中重新访问修改的
控件
单元,更新项目中的私有副本,并根据需要重新应用所做的修改。在大多数情况下(如果不是所有的话),这应该是直截了当的

但我确实想访问CanvasList变量 正如我上面所说的,没有简单的方法来访问该单元中使用的实现变量(如果您想在运行时设法“修补”代码,而不是在编译时用修改过的副本替换代码,那么这是必要的)

但这意味着有一个**非**简单的方法。还有

与应用程序中的任何数据一样,该变量驻留在进程中的某个内存地址。只有编译器作用域规则阻止您在源代码中直接寻址它。没有什么能阻止您在运行时找到该位置并通过指针寻址该内存位置,就像您可以访问的任何其他“原始”内存地址一样

我没有一个详细的演示如何做到这一点,强烈建议尝试实现这样的解决方案是浪费时间和精力的,因为存在一个更简单的解决方案(复制和修改单元)

除此之外,根据确定所涉及内存位置的方法的可靠性,直接访问该内存位置不仅可能受到编译器版本差异的影响,甚至可能受到编译器设置引起的更改的影响


就最终结果而言,它并不比复制单元好多少,但肯定更难,更不可靠。

在D5中不容易。你将如何进入私人空间?或
画布列表
?没有帮手来破解私密处。而且在
CanvasList
上找不到简单的方法。这可以通过一些巧妙的逆向工程来实现。但毫无意义。使用您自己的
控制装置
就可以了。这没问题。什么是不安全的?虽然D5中没有“类助手”,但您仍然可以使用覆盖类(相对)轻松地访问任何具有源()的类的私有成员。在这种情况下,这是否有帮助或是正确的做法是另一回事。一个固定的(定制的)控制单元可能是最好的选择。它不需要重建整个RTL。因为您只更改单元的实现,所以不需要重建RTL。
控件的接口部分保持不变,链接器只是链接到您的单元,而不是Borland单元。@DavidHeffernan,我可能会选择您的方式。我不坚持。我的问题是:
是否可以修补TControlCanvas.CreateHandle?
我只是好奇它是否可行。仅此而已。如果更改接口,则编译器对象。它告诉您使用
控件的单元是根据不同版本的单元编译的。试试看。在
t控制中添加一个不做任何事情的方法“没有简单的方法可以访问该实现变量”-有方法吗?如果是,那么怎么做?我扩展了答案,概述了“怎么做”。这不是w的演示