为啥 TForm.Handle 是一个吸气剂而不是一个字段?
Posted
技术标签:
【中文标题】为啥 TForm.Handle 是一个吸气剂而不是一个字段?【英文标题】:Why TForm.Handle is a getter instead of a field?为什么 TForm.Handle 是一个吸气剂而不是一个字段? 【发布时间】:2016-10-03 12:10:29 【问题描述】:我最近在调试一个复杂的错误。这是由访问不存在的Form.Handle
(垃圾指针)引起的。这个错误以一种让我意想不到的方式暴露出来——访问表单Handle
导致调整大小和重绘。
我希望通过垃圾指针访问Form.Handle
只会返回一些垃圾THandle。期望 Handle
在表单创建时创建一次,并且在表单被销毁之前保持不变。
问题
为什么会这样,TForm.Handle
不是在创建表单时被初始化并通过以下方式访问的字段
property Handle: Integer read FHandle;
,但是是一个吸气剂
property Handle: Integer read GetHandle;
在首次访问时创建句柄甚至窗口 (CreateWnd
)?
【问题讨论】:
见Delphi XE2, vcl styles recreating window handle 和PostMessage returns “invalid window handle” in thread。简而言之,windows在某些情况下需要重新创建句柄。 了解 VCL 窗口娱乐 因为更改窗口的某些属性需要销毁并重新创建它(请参阅RecreateWnd
并计算在表单单元中调用它的次数)。 complicated bug 是由于您没有正确理解 Form.Handle 引起的,而不是 TForm 如何使用它的句柄的问题。 :-)
这个问题似乎将属性的结构与窗口 [re]creation 关联/混合。这就是为什么您会在其中一个主题上获得 cmet,而在另一个主题上获得答案。
不是错误,而是严重的误解。你的假设是完全无效的。见***.com/questions/21011780和***.com/questions/582903
【参考方案1】:
即使底层操作系统 window 不存在,表单 object 也可以存在。在那些时候,Handle
字段将为 0,这对于需要有效窗口句柄的代码没有帮助。为确保每次需要时都能获得有效句柄,您需要在引用 Handle
字段之前调用 HandleNeeded
。作为带有getter的属性,该属性可以自动为您调用HandleNeeded
,让Handle
属性的使用更加方便。
【讨论】:
“让它变得更容易”,除了从不同线程访问句柄的时候,现在看来这是一个非常糟糕的主意。 是的。在这些情况下,首先调用HandleAllocated
,以猜测Handle
的后续访问是否有效。您无法知道,因为主线程可能会在检查时间和使用时间之间破坏窗口。最终,关于在其他线程中做 UI 的东西。如果另一个线程需要知道一个窗口句柄,让主线程将句柄提供给另一个线程(而不是另一个线程自己获取句柄),同时让主线程承担责任确保提供的句柄在其他线程需要时保持有效。
@Kromster,如果您想从线程访问表单句柄以发送/发布消息,最好在主线程中分配带有AllocateHwnd()
的句柄,并让线程将消息发布到此句柄。从那里可以将消息转发到 VCL。
我比@LURD 说得更强烈。规则是您从不在主线程之外使用 VCL 窗口句柄,因为它们需要重新创建。因此,您使用的窗口句柄不是,例如来自 AllocateHWnd
的窗口句柄。以上是关于为啥 TForm.Handle 是一个吸气剂而不是一个字段?的主要内容,如果未能解决你的问题,请参考以下文章