如何在等待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