【发布时间】:2018-03-29 13:10:52
【问题描述】:
我需要在等待事件修复死锁时发送 COM 消息。最好只发送尽可能少的消息来处理该 COM 调用。这个角色的最佳人选是CoWaitForMultipleHandles 但starting from Vista 除了COM 消息外,它还泵送WM_PAINT。从重入的角度来看,抽 WM_PAINT 对我来说太危险了,我不想安装自定义 shim 数据库来解决这个问题。
我正在尝试手动泵送发送到隐藏的仅消息窗口的 COM 消息。
我找到了两种获取隐藏窗口HWND的方法:
-
((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA使用来自 .NET Core 的 ntinfo.h。就未来的变化而言,这似乎是未记录且不可靠的解决方案。 - 按照this question 中的建议查找
OleMainThreadWndClass的窗口。问题是CoInitialize没有创建窗口。它稍后在第一次跨公寓调用时创建,这可能会或可能不会在我的应用程序中发生。从性能角度来看,每次需要 HWND 时都运行搜索循环很糟糕,但缓存 HWND 似乎是不可能的,因为我不知道它是什么时候创建的。
有没有办法确定是否为当前公寓创建了隐藏窗口?我想它会比循环便宜,然后我可以找到并缓存 HWND。
有没有更好的方法来泵送 COM 消息而不泵送 WM_PAINT?
更新:您可以通过为任何界面调用CoMarshalInterThreadInterfaceInStream 来强制创建窗口。然后调用CoReleaseMarshalData 释放流指针。这就是我在搜索OleMainThreadWndClass 时最终所做的。
【问题讨论】:
-
如果你想走黑暗路线,你应该能够直接通过内存 PEB 中的 AppCompatFlags 调整:social.msdn.microsoft.com/Forums/sqlserver/en-US/…。我认为你可以禁用 WM_PAINT 泵如果你二进制和当前带有标志的 AppCompatFlags值 0x100000。注意 AppCompatFlags 从 PEB 开始的偏移量与 x64 和 x32 不同。
-
我想不出一个不处理 WM_PAINT 消息的好理由。如果您的 WM_PAINT 处理程序中的某些东西是“危险的”,我猜想您正在 WM_PAINT 中做一些您不应该做的事情。 WM_PAINT 处理程序应该只读取状态(确定要绘制什么所需的任何变量),而不是修改状态。
-
@MichaelGunter,虚拟网格在 WM_PAINT 处理程序中做了很多有趣的事情。