【问题标题】:How pump COM messages in STA without pumping WM_PAINT?如何在 STA 中泵送 COM 消息而不泵送 WM_PAINT?
【发布时间】:2018-03-29 13:10:52
【问题描述】:

我需要在等待事件修复死锁时发送 COM 消息。最好只发送尽可能少的消息来处理该 COM 调用。这个角色的最佳人选是CoWaitForMultipleHandlesstarting from Vista 除了COM 消息外,它还泵送WM_PAINT。从重入的角度来看,抽 WM_PAINT 对我来说太危险了,我不想安装自定义 shim 数据库来解决这个问题。

我正在尝试手动泵送发送到隐藏的仅消息窗口的 COM 消息。

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

  1. ((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA 使用来自 .NET Core 的 ntinfo.h。就未来的变化而言,这似乎是未记录且不可靠的解决方案。
  2. 按照this question 中的建议查找OleMainThreadWndClass 的窗口。问题是CoInitialize 没有创建窗口。它稍后在第一次跨公寓调用时创建,这可能会或可能不会在我的应用程序中发生。从性能角度来看,每次需要 HWND 时都运行搜索循环很糟糕,但缓存 HWND 似乎是不可能的,因为我不知道它是什么时候创建的。

有没有办法确定是否为当前公寓创建了隐藏窗口?我想它会比循环便宜,然后我可以找到并缓存 HWND。

有没有更好的方法来泵送 COM 消息而不泵送 WM_PAINT?

更新:您可以通过为任何界面调用CoMarshalInterThreadInterfaceInStream 来强制创建窗口。然后调用Co­Release­Marshal­Data 释放流指针。这就是我在搜索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 处理程序中做了很多有趣的事情。

标签: c++ winapi com


【解决方案1】:

WM_PAINT是在消息队列中没有其他消息并且执行GetMessage或使用PeekMessage时生成的。

WM_PAINT 只有在您发送它时才会发送。在窗口再次失效之前,也没有新的WM_PAINT 消息。

因此,是否发送WM_PAINT 消息取决于您。但请注意,还有其他重新进入的机会,例如 WM_TIMER 消息。

关于此的详细信息在WM_PAINT 的文档中。

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

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

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

写完之后,我倾向于认为这是一个 XY 问题。

【讨论】:

    猜你喜欢
    • 2016-03-29
    • 2014-02-08
    • 2014-03-01
    • 2013-07-18
    • 2010-12-11
    • 2014-03-07
    • 1970-01-01
    • 2010-12-07
    • 2014-07-20
    相关资源
    最近更新 更多