等待COM事件完成

本文关键字:事件 COM 等待 | 更新日期: 2023-09-27 18:29:30

如何在等待COM事件完成时阻止UI线程。我订阅了COM的更新事件,该事件表示事件已完成。

MyRData.OnUpdate += OnUpdate;

我不拥有COM代码,无法对其进行更改。

我尝试了AutoResetEvent,但它阻止了UI线程,并且我没有从COM收到更新。

等待COM事件完成

我的答案与@EricBrown的答案非常相似,但有一点不同。

使用MsgWaitForMultipleObjectsEx创建嵌套消息循环可能会导致代码在同一线程上重新进入(通过内部PeekMessage/TranslateMessage/DispatchMessage模式调度的窗口消息)。在最坏的情况下,您可能会在前一个调用返回之前调用相同的COM对象方法

我会首先尝试将CoWaitForMultipleHandles与COWAIT_DISPATCH_CALLS一起使用(但不使用COWAIT_DISPATCH_WINDOW_MESSAGES)。如果COM对象是由进程外的服务器提供的,那么这很可能会起作用。否则,您应该考虑进行一些可重入性检查。

我有一个相关的问题,其中有一些代码显示了如何使用C#(我必须在那里使用COWAIT_DISPATCH_WINDOW_MESSAGES,否则我所关注的事件不会被解雇)。

[UPDATE]理想情况下,您应该使用async/await模式来处理类似的事情,并将事件包装为任务(例如,以下是如何处理)。我理解,有时重新考虑现有代码来使用这种方法是不可行的。然而,如果一个挂起的操作需要相当长的时间才能完成,那么等待其完成事件的一种更用户友好的方式可能只是显示一个带有"请稍候…"消息的模式对话框(如评论中所述)。您只需要从事件处理程序中关闭此对话框。事实上,AFAIK,这是WinForms应用程序进入嵌套消息循环的唯一认可方式。

[UPDATE]正如Eric在评论中指出的,COWAIT_DISPATCH_WINDOW_MESSAGES是STA线程所必需的。显然,COWAIT_DISPATCH_CALLS适用于鲜为人知的ASTA新模式,在其他公寓类型中没有任何意义

在进程外COM服务器的情况下,无论等待线程的单元模型如何,.NET事件处理程序都会作为自由线程对象被调用(根据我的经验,它从来不是最初创建进程外对象的STA线程)。因此,使用WaitHandle.WaitOne(无泵送)等待就足够了。但是,如果事件处理程序访问WaitHandle之外的任何状态数据,则需要正确的同步(使用锁等)。

您很可能希望在等待事件时发送消息。为此,MsgWaitForMultipleObjectsEx是非常宝贵的。我有一个答案(针对另一个问题),它展示了MsgWaitForMultipleObjectsEx的常见使用模式。

我最终使用Application.DoEvents()