如何修补 TControlCanvas.CreateHandle(FreeDeviceContexts 问题)?
How to patch TControlCanvas.CreateHandle (FreeDeviceContexts issue)?
这个问题与我之前的问题有关:
access violation at address in module ntdll.dll - RtlEnterCriticalSection with TCanvas.Lock
显然 Delphi 的代码中存在错误(参见 QC 64898: Access violation in FreeDeviceContexts)。这个错误一直持续到 D2010,AFAIK。
到目前为止,建议的解决方法运行良好。现在我进退两难。
我不喜欢在我的项目中使用 Controls.pas
的私人副本的想法 - 我不确定它是否安全。 Controls
单元是一个非常低级的单元,我真的觉得这是一个过激的举动,考虑到我的大型应用程序运行良好,除了提到的问题。我也不确定 if/how 重建依赖于我项目中 Controls
单元的 all components/units。
是否可以修补使用内部 CanvasList
和私有成员的 TControlCanvas.CreateHandle()
?
注意: 我将只为这个项目使用补丁 (Delphi 5)。我不介意对偏移量进行硬编码。 AFAIK,根据编译器版本,修补 privates 总是使用硬编码的偏移量。我 可能 能够自己处理私人事务(没有 class 助手),但我不知道如何处理 CanvasList
和 FreeDeviceContext()
,这在 Controls
单元的实现部分声明。
正如评论中所讨论的那样, 可以访问 classes 的 private
和 protected
成员,即使在较旧的没有 "class helpers".
的 Delphi 版本
然而,本例中的问题围绕着特定方法实现的细节,而不仅仅是能够访问或修改私有成员变量。此外,在所涉及的单元中使用实现变量的特定方法的实现。特别是您注意到的 CanvasList
变量。
即使有 class 助手的好处,也没有简单的方法来访问该实现变量。
您当前的解决方案是最简单和最安全的方法:使用整个单元的副本,并对解决问题所需的特定方法应用修改。
请放心,这并不罕见。 :)
使用这种方法的唯一问题是,在建立新的开发环境或升级到新版本的 IDE.
对于新的开发环境,仔细的项目配置应该可以解决问题(当然,您修改的 Controls.pas
单元是您的版本控制项目的一部分)。
在升级到较新的 Delphi 版本的情况下,您只需要记住在每个新版本中重新访问修改后的 Controls
单元,更新项目中的私有副本并重新应用您所做的适当修改。在大多数(如果不是全部)情况下,这应该是直截了当的。
但我真的想访问 CanvasList 变量
正如我上面所说,没有简单方法来访问该单元中使用的实现变量(如果你想方设法"patch" 运行时的代码,而不是在编译时用修改后的副本替换它。
但这意味着存在**非**简单的方法。还有。
与应用程序中的任何数据一样,该变量驻留在进程中的某个内存地址。只有编译器作用域规则会阻止您直接在源代码中解决它。没有什么能阻止您弄清楚如何在运行时找到该位置并通过指针寻址该内存位置,就像您可以访问的任何其他 "raw" 内存地址一样。
我没有关于如何做到这一点的详细演示,强烈建议尝试实施这样的解决方案是浪费时间和精力,因为存在更简单的解决方案(复制和修改单元) .
除此之外,取决于用于确定所涉及内存位置的方法的可靠性,直接访问该内存位置可能不仅容易受到编译器版本之间差异的影响,甚至可能会受到编译器设置引起的更改的影响。
就最终结果而言,它并不比复制单元好,但肯定更难,更不可靠。
这个问题与我之前的问题有关:
access violation at address in module ntdll.dll - RtlEnterCriticalSection with TCanvas.Lock
显然 Delphi 的代码中存在错误(参见 QC 64898: Access violation in FreeDeviceContexts)。这个错误一直持续到 D2010,AFAIK。
到目前为止,建议的解决方法运行良好。现在我进退两难。
我不喜欢在我的项目中使用 Controls.pas
的私人副本的想法 - 我不确定它是否安全。 Controls
单元是一个非常低级的单元,我真的觉得这是一个过激的举动,考虑到我的大型应用程序运行良好,除了提到的问题。我也不确定 if/how 重建依赖于我项目中 Controls
单元的 all components/units。
是否可以修补使用内部 CanvasList
和私有成员的 TControlCanvas.CreateHandle()
?
注意: 我将只为这个项目使用补丁 (Delphi 5)。我不介意对偏移量进行硬编码。 AFAIK,根据编译器版本,修补 privates 总是使用硬编码的偏移量。我 可能 能够自己处理私人事务(没有 class 助手),但我不知道如何处理 CanvasList
和 FreeDeviceContext()
,这在 Controls
单元的实现部分声明。
正如评论中所讨论的那样, 可以访问 classes 的 private
和 protected
成员,即使在较旧的没有 "class helpers".
然而,本例中的问题围绕着特定方法实现的细节,而不仅仅是能够访问或修改私有成员变量。此外,在所涉及的单元中使用实现变量的特定方法的实现。特别是您注意到的 CanvasList
变量。
即使有 class 助手的好处,也没有简单的方法来访问该实现变量。
您当前的解决方案是最简单和最安全的方法:使用整个单元的副本,并对解决问题所需的特定方法应用修改。
请放心,这并不罕见。 :)
使用这种方法的唯一问题是,在建立新的开发环境或升级到新版本的 IDE.
对于新的开发环境,仔细的项目配置应该可以解决问题(当然,您修改的 Controls.pas
单元是您的版本控制项目的一部分)。
在升级到较新的 Delphi 版本的情况下,您只需要记住在每个新版本中重新访问修改后的 Controls
单元,更新项目中的私有副本并重新应用您所做的适当修改。在大多数(如果不是全部)情况下,这应该是直截了当的。
但我真的想访问 CanvasList 变量
正如我上面所说,没有简单方法来访问该单元中使用的实现变量(如果你想方设法"patch" 运行时的代码,而不是在编译时用修改后的副本替换它。
但这意味着存在**非**简单的方法。还有。
与应用程序中的任何数据一样,该变量驻留在进程中的某个内存地址。只有编译器作用域规则会阻止您直接在源代码中解决它。没有什么能阻止您弄清楚如何在运行时找到该位置并通过指针寻址该内存位置,就像您可以访问的任何其他 "raw" 内存地址一样。
我没有关于如何做到这一点的详细演示,强烈建议尝试实施这样的解决方案是浪费时间和精力,因为存在更简单的解决方案(复制和修改单元) .
除此之外,取决于用于确定所涉及内存位置的方法的可靠性,直接访问该内存位置可能不仅容易受到编译器版本之间差异的影响,甚至可能会受到编译器设置引起的更改的影响。
就最终结果而言,它并不比复制单元好,但肯定更难,更不可靠。