4

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

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

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

4

2 回答 2

15

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

当您引用“句柄”属性时,这将启动句柄创建过程。这是因为读取Handle实际上调用了GetHandle。在流式传输过程中过早地执行此操作,您可能最终会得到最好的流式传输性能,更糟糕的是,部分配置的“句柄”。

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

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

所以要直接回答你的问题,最好的地方是覆盖 CreateWnd 并在那里做你的工作。CreateWnd 只会在创建句柄时被调用。一个设计合理的组件在显示之前应该只调用一次 CreateWnd。

于 2009-02-24T17:59:33.080 回答
3

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

于 2009-02-24T17:48:47.880 回答