1

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

MyRData.OnUpdate += OnUpdate;

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

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

4

3 回答 3

2

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

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

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

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

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

[更新]正如 Eric 在评论中指出的那样,COWAIT_DISPATCH_WINDOW_MESSAGESSTA 线程确实需要。显然,COWAIT_DISPATCH_CALLS它是为新的鲜为人知的ASTA 模型而设计的,在其他公寓类型中没有任何意义

如果使用进程外 COM 服务器,.NET 事件处理程序将作为自由线程对象回调,而不管等待线程的单元模型如何(根据我的经验,进程外对象所在的 STA 线程绝不是同一个 STA 线程最初创建)。因此,使用WaitHandle.WaitOne等待(不抽水)就足够了。但是,如果事件处理程序访问除 之外的任何状态数据WaitHandle,则需要适当的同步(使用等)。

于 2013-08-29T07:04:45.997 回答
1

您很可能希望在等待事件时发送消息。为此,MsgWaitForMultipleObjectsEx是无价的。我有一个答案(针对不同的问题),它展示了MsgWaitForMultipleObjectsEx.

于 2013-08-28T17:33:24.870 回答
0

我终于使用 Application.DoEvents()

于 2013-10-17T09:26:48.137 回答