如何在没有泵送WM_PAINT的情况下在STA中输入COM消息?

时间:2017-10-17 18:36:22

标签: c++ winapi com

我需要在等待事件修复死锁时抽取COM消息。为了处理COM调用,尽可能少地输出消息会更好。这个角色的最佳候选者是CoWaitForMultipleHandles,但starting from Vista除了COM消息之外它还支持WM_PAINT。从重新入口的角度来看,抽取WM_PAINT对我来说太危险了,我不想安装自定义填充程序数据库作为解决此问题的方法。

我尝试将手动发送到隐藏的仅消息窗口的COM消息泵出来。

我找到了两种方法来获取隐藏窗口的HWND:

  1. ((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA使用.NET Core中的ntinfo.h。对于未来的变化而言,这似乎没有记录,也不是可靠的解决方案。
  2. this question中的建议查找OleMainThreadWndClass的窗口。问题是CoInitialize没有创建窗口。它是在第一次跨公寓电话后创建的,可能会也可能不会在我的应用程序中发生。每次我需要HWND时运行搜索循环从性能角度来看都很糟糕,但缓存HWND似乎是不可能的,因为我不知道它何时被创建。
  3. 有没有办法确定是否为当前公寓创建了隐藏窗口?我想它会比循环便宜,然后我可以找到并缓存HWND。

    有没有更好的方法在不泵送WM_PAINT的情况下泵送COM消息?

    更新:您可以通过为任何界面调用CoMarshalInterThreadInterfaceInStream来强制创建窗口。然后调用Co­Release­Marshal­Data以释放流指针。这就是我最终在搜索OleMainThreadWndClass时所做的事情。

1 个答案:

答案 0 :(得分:-3)

当消息队列中没有其他消息并执行GetMessage或使用PeekMessage时,会生成

WM_PAINT

WM_PAINT仅在您发送时发送。此外,在窗口再次失效之前,没有新的WM_PAINT消息。

因此,如果您发送WM_PAINT消息,则取决于您。但要注意,还有其他机会可以像WM_TIMER消息那样重入。

有关此内容的详细信息,请参阅WM_PAINT的文档。

从我的角度来看,最好的解决方案是将应用程序设置为等待"等等。模式,甚至可以在这个未定义的等待状态下处理WM_PAINT。你知道什么时候你被重新进入。它总是在WM_PAINT ...或类似的消息之后到达,就像其他输入消息一样。所以我在这里看不到任何问题。 STA有一个线程,您始终处理消息到结尾,直到您执行GetMessage,启动模式对话框或显示MessageBox。当你在一些消息处理中时,什么都不会打扰你。

也许其他解决方案是在第二个线程内等待此事件。此主题可能没有任何窗口,您可以将事件转换为应用程序中需要的任何内容。

所以你的问题可能没有足够的信息,这个死锁是如何真正出现的。所以这个答案可能还不够。

在写完这篇文章后,我倾向于认为这是一个XY问题。