如何在等待 COM 事件完成时阻止 UI 线程。我订阅了 COM 的更新事件,表明事件已完成。
MyRData.OnUpdate += OnUpdate;
我不拥有 COM 代码,也无法对其进行更改。
我尝试了 AutoResetEvent,但是它阻止了 UI 线程并且我没有收到来自 COM 的更新。
如何在等待 COM 事件完成时阻止 UI 线程。我订阅了 COM 的更新事件,表明事件已完成。
MyRData.OnUpdate += OnUpdate;
我不拥有 COM 代码,也无法对其进行更改。
我尝试了 AutoResetEvent,但是它阻止了 UI 线程并且我没有收到来自 COM 的更新。
我的回答与@EricBrown 的回答非常相似,但有一点不同。
创建嵌套消息循环可能会导致同一线程上MsgWaitForMultipleObjectsEx
的代码重入(通过内部PeekMessage/TranslateMessage/DispatchMessage
模式调度的窗口消息)。在最坏的情况下,您可能会在前一个调用返回之前调用相同的 COM 对象方法。
我会首先尝试将CoWaitForMultipleHandles与COWAIT_DISPATCH_CALLS一起使用(但没有COWAIT_DISPATCH_WINDOW_MESSAGES
)。如果您的 COM 对象是由进程外服务器提供的,这很可能应该有效。否则,您应该考虑进行一些重入检查。
我有一个相关的问题,其中一些代码显示了如何使用 C# 完成它(我必须在COWAIT_DISPATCH_WINDOW_MESSAGES
那里使用,否则我所追求的事件不会被触发)。
[更新]理想情况下,您应该async/await
对类似的事情使用模式并将您的事件包装为一个任务(例如这里是如何)。我理解,有时重构现有代码以使用这种方法是不可行的。但是,如果挂起的操作需要相当长的时间才能完成,则等待其完成事件的更用户友好的方法可能只是显示带有“请稍候...”消息的模态对话框(如评论中所述) . 您只需从事件处理程序中关闭此对话框。事实上,AFAIK,这是 WinForms 应用程序进入嵌套消息循环的唯一认可方式。
[更新]正如 Eric 在评论中指出的那样,COWAIT_DISPATCH_WINDOW_MESSAGES
STA 线程确实需要。显然,COWAIT_DISPATCH_CALLS
它是为新的鲜为人知的ASTA 模型而设计的,在其他公寓类型中没有任何意义。
如果使用进程外 COM 服务器,.NET 事件处理程序将作为自由线程对象回调,而不管等待线程的单元模型如何(根据我的经验,进程外对象所在的 STA 线程绝不是同一个 STA 线程最初创建)。因此,使用WaitHandle.WaitOne等待(不抽水)就足够了。但是,如果事件处理程序访问除 之外的任何状态数据WaitHandle
,则需要适当的同步(使用锁等)。
您很可能希望在等待事件时发送消息。为此,MsgWaitForMultipleObjectsEx是无价的。我有一个答案(针对不同的问题),它展示了MsgWaitForMultipleObjectsEx
.
我终于使用 Application.DoEvents()