如何在STA中抽取COM消息而不抽取WM_PAINT?
我需要在等待事件修复死锁时抽取COM消息。尽可能少地输入消息来处理该COM调用会更好。该角色的最佳人选是CoWaitForMultipleHandles,但starting from Vista除了COM消息外,还会泵送WM_PAINT。对于我来说,重新导入WM_PAINT对我来说太危险了,我不想安装一个自定义填充数据库作为这个问题的解决方案。如何在STA中抽取COM消息而不抽取WM_PAINT?
我试图泵送COM消息手动发送到隐藏的消息窗口。
我发现两种方式来获得隐藏窗口的HWND:
-
((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA
使用ntinfo.h从.NET的核心。就未来的变化而言,这似乎没有证据,也不是可靠的解决方案。 - 按照this question中的建议查找
OleMainThreadWndClass
的窗口。问题是CoInitialize
不会创建该窗口。它是在第一次跨公寓呼叫后创建的,可能会或可能不会在我的应用程序中发生。每次我需要HWND时运行搜索循环从性能角度来看是不好的,但是缓存HWND似乎是不可能的,因为我不知道它是什么时候创建的。
有没有办法确定是否为当前公寓创建了隐藏窗口?我想它会比循环更便宜,然后我可以找到并缓存HWND。
有没有更好的方法来泵送COM消息而不抽水WM_PAINT?
更新:您可以通过调用CoMarshalInterThreadInterfaceInStream
来强制窗口创建任何接口。然后调用CoReleaseMarshalData
来释放流指针。这就是我最终在搜索OleMainThreadWndClass
时所做的事情。
WM_PAINT
是在消息队列中没有其他消息并执行GetMessage或使用PeekMessage时生成的。
但WM_PAINT
只发送,如果你调度它。也没有新的WM_PAINT
消息,直到窗口再次失效。
因此,如果您发送WM_PAINT
消息,则取决于您。但请注意,还有其他的再入机会,例如WM_TIMER
消息。
有关详细信息,请参阅WM_PAINT的文档。
从我的角度来看,最好的解决方案是将应用程序设置为“等待”模式,甚至可以在这个未定义的等待状态下处理WM_PAINT。你知道你什么时候重新进入。它总是在WM_PAINT之后...或者像其他输入消息一样到达的类似消息。所以我在这里没有看到任何问题。 STA有一个线程,并且您始终处理消息到结束,直到您执行GetMessage
,启动模态对话框或显示MessageBox。当你在一些消息处理中时,什么都不会打扰你。
也许其他解决方案是在第二个线程内等待此事件。这个线程可能没有任何窗口,您可以将事件转换为您的应用程序中需要的任何内容。
所以你的问题可能没有足够的信息如何真正出现这个死锁。所以这个答案可能不够。
写完后,我倾向于认为这是一个XY问题。
如果你想去黑暗的路线,你应该能够调整AppCompatFlags直接通过内存PEB:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/5a28a9f5-5711-4efa -843e-e98927fa2b92/dcom-in-vista-specific-processing-wmpaint-messages?forum = windowsgeneraldevelopmentissues。我认为你可以禁用WM_PAINT泵,如果你的二进制和当前AppCompatFlags标志值为0x100000。注意从PEB开始的AppCompatFlags偏移量与x64和x32不同。 –
我想不出处理WM_PAINT消息的唯一好理由。如果WM_PAINT处理程序中的某些内容是“危险的”,我会猜测你在WM_PAINT中做了一些你不应该做的事情。 WM_PAINT处理程序应该只读取状态(任何必要的变量来弄清楚画什么),而不是修改状态。 –
@MichaelGunter,虚拟网格在WM_PAINT处理程序中做了很多有趣的事情。 –