【问题标题】:How to patch TControlCanvas.CreateHandle (FreeDeviceContexts issue)?如何修补 TControlCanvas.CreateHandle(FreeDeviceContexts 问题)?
【发布时间】:2016-12-07 15:45:13
【问题描述】:

这个问题和我之前的问题有关:

access violation at address in module ntdll.dll - RtlEnterCriticalSection with TCanvas.Lock

显然 Delphi 的代码中有一个错误(请参阅QC 64898: Access violation in FreeDeviceContexts)。这个错误一直持续到 D2010,AFAIK。

到目前为止,建议的解决方法运行良好。现在我进退两难了。

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

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

注意:我将只为这个项目使用补丁(Delphi 5)。我不介意硬编码偏移量。 AFAIK,补丁私有总是使用硬编码的偏移量,基于编译器版本。我可能能够自己处理私人事务(没有类助手),但我不知道如何处理 CanvasListFreeDeviceContext(),它们在 Controls 的实现部分中声明单位。

【问题讨论】:

  • 在 D5 中并不容易。您将如何访问私人信息?还是CanvasList?没有帮手破解隐私。并且没有简单的方法可以访问CanvasList。可以通过一些棘手的逆向工程来完成。但毫无意义。使用你自己的Controls 单位就可以了。这没有问题。什么不安全?
  • 虽然 D5 中没有“类助手”,但您仍然可以使用覆盖类(相对)轻松地访问您拥有源 (deltics.co.nz/blog/posts/825) 的任何类的私有成员。在这种情况下,这是否有帮助或者是正确的做法是另一回事。一个固定的(定制的)Controls 单元可能是要走的路。
  • 它不需要重建整个 RTL。因为您只更改了单元的实现,所以不需要重新构建 RTL。 Controls 的接口部分没有改变,链接器只是链接到你的单元而不是 Borland 单元。
  • @DavidHeffernan,我可能会选择按照你的方式去做。我不坚持。我的问题是:Is it possible to patch TControlCanvas.CreateHandle? 我只是好奇它是否可行。就是这样。
  • 如果你改变接口然后编译器对象。它告诉您使用Controls 的单元是针对不同版本的单元编译的。试试看。向TControl 添加一个什么都不做的方法。

标签: delphi patch delphi-5 detours


【解决方案1】:

正如 cmets 中所讨论的,可以访问类的 privateprotected 成员,即使在没有“类助手”的旧版 Delphi 中也是如此。

但是,在这种情况下,问题在于特定方法实现的细节,而不仅仅是能够访问或修改私有成员变量。此外,在所涉及的单元中使用实现变量的特定方法的实现。特别是您记下的 CanvasList 变量。

即使有类助手的好处,也没有简单的方法可以访问该实现变量。

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

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

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

在新开发环境的情况下,仔细的项目配置应该处理好事情(当然,您修改的Controls.pas 单元是您的版本控制项目的一部分)。

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

但我真的想访问 CanvasList 变量

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

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

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

鉴于存在更简单的解决方案(复制和修改单元),我强烈建议尝试实施这样的解决方案是浪费时间和精力。

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

p>

就最终结果而言,它并不比复制单元好,但肯定要困难得多,可靠性也差得多。

【讨论】:

  • “没有简单方法可以访问该实现变量” - 有没有办法?如果是,那么如何?
  • 我扩展了答案以概述“如何”。这不是工作代码的演示(我没有时间),而是您需要采取的方法的概述(以及您真的不想去那里的原因)。坚持使用本机的副本。 :)
  • 最健壮的方法是在运行时反汇编代码以找到地址。但这是一个杯子游戏
猜你喜欢
  • 2015-05-13
  • 1970-01-01
  • 2017-04-29
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多