如何在等待COM事件完成时阻止UI线程。我订阅更新事件的COM事件已完成信号。等待COM事件完成
MyRData.OnUpdate += OnUpdate;
我没有自己的COM代码,无法对其进行更改。
我试过AutoResetEvent,但阻止UI线程,我不接受来自COM的更新。
如何在等待COM事件完成时阻止UI线程。我订阅更新事件的COM事件已完成信号。等待COM事件完成
MyRData.OnUpdate += OnUpdate;
我没有自己的COM代码,无法对其进行更改。
我试过AutoResetEvent,但阻止UI线程,我不接受来自COM的更新。
我终于结束了使用 Application.DoEvents()
您可能需要检查[this](http://stackoverflow.com/a/19555959/1768303),特别是'WaitWithDoEvents'。 – Noseratio
很可能你想在等待事件时抽出消息。为此,MsgWaitForMultipleObjectsEx是无价的。我有一个answer(针对不同的问题),演示MsgWaitForMultipleObjectsEx
的常见使用模式。
我的答案与@ EricBrown的非常相似,但有一点不同。
使用MsgWaitForMultipleObjectsEx
创建nested message loop可能会导致代码在相同线程上的重入(通过由内部PeekMessage/TranslateMessage/DispatchMessage
模式分派的窗口消息)。在最糟糕的情况下,您可能最终会在前一个调用返回之前调用相同的COM对象方法之前。
我会先尝试使用CoWaitForMultipleHandles与COWAIT_DISPATCH_CALLS(但没有COWAIT_DISPATCH_WINDOW_MESSAGES
)。如果你的COM对象是由一个out-proc服务器提供的,这很可能应该起作用。否则,你应该考虑进行一些重入检查。我有一个related question与一些代码显示它可以如何完成与C#(我不得不使用COWAIT_DISPATCH_WINDOW_MESSAGES
那里,否则事件我以后没有被解雇)。
[更新]理想情况下,你应该使用这样的事情async/await
图案和包装你的事件作为一个任务(例如here's how)。我明白,有时重新使用现有的代码来使用这种方法是不可行的。但是,如果挂起的操作需要花费相当长的时间才能完成,那么等待其完成事件的更加用户友好的方式可能仅仅是显示一个模型对话框,其中包含一个很好的“请稍候...”消息(如comments中所述) 。您只需从您的事件处理程序关闭此对话框。实际上,AFAIK,这是WinForms应用程序进入嵌套消息循环的唯一支持方式。
[UPDATE]正如Eric在评论中指出的那样,COWAIT_DISPATCH_WINDOW_MESSAGES
对于STA线程是不需要的。显然,COWAIT_DISPATCH_CALLS
旨在用于新的鲜为人知的ASTA model和has no meaning in other apartment types。
如果使用out-proc COM服务器,则无论等待线程的公寓模型如何,都会将.NET事件处理程序作为自由线程对象进行回调(in my experience,它永远不会是同一个STA线程, proc对象最初是创建的)。因此,等待WaitHandle.WaitOne(不抽水)应该就足够了。但是,如果事件处理程序访问除WaitHandle
以外的任何状态数据,则需要进行适当的同步(使用locks等)。
如果代码在STA中,则需要'COWAIT_DISPATCH_WINDOW_MESSAGES'。 [Chris Brumme的文章](http://blogs.msdn.com/b/cbrumme/archive/2004/02/02/66219.aspx)(在嵌套消息循环文章中引用)强调这一点。传入的COM呼叫通过窗口消息到达。总的来说,我更喜欢你的解决方案(我只是*知道*在MSFT的人已经打包了MsgWaitForMultipleObjects代码);它更干净简单;但赔率是@Rauld将不得不泵。 –
@EricBrown,很棒的一点,谢谢。我不知道“COWAIT_DISPATCH_CALLS”对于STA是不够的。你提到的文章看起来是必读的,但我忽略了它,赶上了。 – Noseratio
你怎么知道的COM事件是否已经完成? –
@Jeroen van Langen更新了问题 – Rauld