为什么不在组件创建或流式传输期间使用句柄?

时间:2009-02-24 17:35:39

标签: delphi custom-controls sdl vcl

我想制作一个自定义VCL控件,它通过SDL_CreateWindowFrom函数包装SDL渲染表面。 SDL_CreateWindowFrom获取现有的HWND句柄并将高性能渲染上下文(它有几个可用的后端,包括DirectX和OpenGL)放在其上。

帮助文件说“在组件创建或流式传输期间不要引用Handle属性”。但它并没有说明原因。它说当你第一次尝试访问Handle属性时,它会调用HandleNeeded来确保存在有效的句柄。

所以我有两个问题。 1:在组件创建期间不应引用Handle属性的原因是什么? 2.如果控件的整个点是要包装需要初始化HWND的渲染表面,那么何时可以安全地执行(理想情况下)应该在创建/流式传输期间进行的初始化?

3 个答案:

答案 0 :(得分:14)

在它的核心,它是一个表现的东西。在流式传输过程中,可能还会发生其他“坏”副作用。事情处于“建设中期”,通常预计会出现的情况可能都没有。

当您引用“Handle”属性时,这将启动句柄创建过程。这是因为读取Handle实际上调用了GetHandle。在流式传输过程中这么做太快,最多可能会导致流速性能降低,更糟糕的是,部分配置的“句柄”。

如果需要在属性设置器中正确引用句柄,则应通过检查HandleAllocated来检查是否已创建句柄,然后才引用它。如果你需要对句柄进行一些标志更改,比如调用SetWindowLong()或其他东西,那么你应该在组件实例中“缓存”该状态,然后覆盖CreateWnd并在那时应用这些设置。另一种选择是在流式传输时推迟所有句柄访问(如果在ComponentState中为csLoading),直到调用Loaded虚方法。

最后,您需要了解可能需要重新创建句柄的情况。如果周围的表单或父组件的句柄经过重新创建过程,则会发生这种情况。直到更新的Windows版本,更改某些窗口标志的唯一方法是销毁句柄并在CreateWindowEx()调用中使用新标志重新创建。有许多组件仍然可以做到这一点。通过检查(控制状态中的csRecreating),您知道是否处于重新创建状态。

因此,要直接回答您的问题,最好的地方是覆盖CreateWnd并在那里完成您的工作。只有在创建句柄时才会调用CreateWnd。正确设计的组件在显示之前应该只对CreateWnd进行一次调用。

答案 1 :(得分:3)

回答第二个问题:假设您的控件是 TCustomControl ,您应该覆盖 CreateWindowHandle()。这样做的好处是,每次为控件创建新的窗口句柄时,都会正确重复所有初始化。这允许更改一些无法重新设置或重置的窗口样式标志,而无需重新创建窗口。它还允许通过在不需要时释放句柄来节省资源,并在以后重新创建它。

答案 2 :(得分:1)

另请参阅此问题whats-the-difference-between-createwnd-and-createwindowhandle,以及更多有关做什么和何时......

的详细答案