PostMessage在线程中返回“无效窗口句柄”

时间:2010-08-13 05:50:10

标签: multithreading delphi delphi-2010 messaging

后台:我正在使用OmniThreadLibrary在后台加载批处理模式ADO存储过程。我打开SP之后通过交换连接做了一些略显狡猾的事情,但这看起来非常可靠。我正在使用PostMessage将消息发送回调用表单,这在我的测试应用程序中有效。 Primoz的comms频道为我工作,我正在使用它们进行线程间通信,但对于我们的主要应用程序,我试图通过使用标准的PostMessage调用来避免这种依赖,就像我们在app中的其他地方一样。

问题:不幸的是,当我把它放到我们的主应用程序中时,PostMessage调用线程开始失败1400:无效的窗口句柄。

我已经自由地添加了额外的PostMessage调用和日志代码来尝试找到问题,但我现在已经没有想法了。代码是样板:

const WM_PW_ADLQUEUEEMPTY = WM_USER + 11;
...
if PostMessage (OwnerHandle, WM_PW_ADLPROGRESS, QueueID, 10) then
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+')     OK for Queue ' + IntToStr (QueueID))
else
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+') failed for Queue ' + IntToStr (QueueID));

但是一系列电话的日志对我来说并不是很有启发性。请注意,时间之后的四个十六进制数字是来自GetCurrentThreadID的线程ID。

15:41:53.221 1614  TpwAsyncDataLoader.RunQueue WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)    OK for Queue -6
15:41:53.265 13B4  TADLQueue.Run WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)     OK for Queue -6
15:41:53.554 13B4  TADLQueueManager.WriteSysErrorMessageToDatabase Postmessage   00A5110C (IsWindow False)  failed with 1400  Invalid window handle

有人可以对此有所了解吗?当我看着窗户把手变得无效时,我很困惑,但这就是我的样子。

我能想到的一件事是我在这里展示的表单不是处理消息而是我看到“消息队列已满”失败而不是看起来像IsWindow(句柄)失败。我该如何测试呢?

2 个答案:

答案 0 :(得分:4)

有些情况下会重新创建句柄,最明显的是当您更改窗口标志时。这可能是您的应用程序中发生的事情。

迄今为止,我发现所有关于重新创建窗口句柄的内容都是来自Allen Bauer的this post,但我肯定会读到Peter Peter写的更详细的内容。不幸的是,我似乎无法找到那个。

  

最后,您需要了解案例   你的手柄可能需要得到的地方   重建。这可能发生在   周围的形式或父母   组件的句柄通过一个   重新创建过程。直到最近   Windows的发布,唯一的方法   改变一些窗口标志是   摧毁手柄并重新创建   CreateWindowEx()中的新标志   呼叫。有许多组件   仍然这样做。你知道,如果你在   通过检查重新创建情况   (cs在ControlState中创建)。

修改

实际上并不是彼得的帖子,但它可能会给你一些新鲜的想法。

  

直到表格才会有句柄   你第一次展示它(除非   形式加载序列中的东西   请求句柄)但句柄是   隐藏表单时不会被破坏   除非你做某事   迫使形式重建   手柄,例如改变它的边界风格   或边框图标,或调用RecreateWnd   你自己把握住了   相同。

  

这可能不太理想但不能   要避免,至少不是这样   德尔福拖拽和停靠目前   实现。停靠拖动时   形成另一种形式它变成了   控件(使用WS_CHILD窗口样式)   这意味着它的窗口句柄   必须被破坏并重新创建   新的风格。并摧毁了   容器控件的窗口句柄   自动销毁手柄   所有的孩子控制。

  

还有表格的事实   窗口句柄被破坏了   分配给它时重新创建   父母财产。这也毁了   并为所有人重新创建句柄   表格上的控件。

答案 1 :(得分:0)

我有一个类似的问题(但在VC ++ 2010中),我没有在任何论坛上找到解决方案,所以我在这里发布,希望这会有所帮助:

问题:

  • 创建一个帖子,
  • 传递HWnd句柄
  • 在线程中,PostMessage 抛出1400错误(无效句柄),虽然指针是相等的 从UI线程看到的句柄(使用GetSafeHWnd())。

解决方案:

  1. 不要传递句柄,而是传递父CDialog(Ex)类
  2. 此类有一个m_hWnd成员,可以完成这项工作
  3. 这是一个(Cpp)示例,对于演员阵容感到抱歉。

    // In the worker thread
    ThreadParam *threadParam = (ThreadParam*)param
    
    // This is ugly because my pointer is a void *, to avoid one more forward declaration
    CCoreGenDlg *dlg = static_cast<CCoreGenDlg *>(threadParam->ptr);
    
    // Post
    bool b = PostMessage(dlg->m_hWnd ,1221,0,(LPARAM)message);
    

    干杯&#39;