1

How do I block the UI thread while waiting for COM event to complete. I subscribe to update event of COM which signals the event has completed.

MyRData.OnUpdate += OnUpdate;

I do not own the COM code and cannot make changes to it.

I tried AutoResetEvent however that blocks the UI thread and i dont recieve updates from COM.

Rauld
  • 980
  • 2
  • 10
  • 19

3 Answers3

2

My answer is very similar to @EricBrown's one, but there is one different point.

Creating a nested message loop with MsgWaitForMultipleObjectsEx may lead to code reentrancy on the same thread (via a window message dispatched by the inner PeekMessage/TranslateMessage/DispatchMessage pattern). At worst scenario, you may end up calling the same COM object method before the previous call has returned.

I would first try using CoWaitForMultipleHandles with COWAIT_DISPATCH_CALLS (but without COWAIT_DISPATCH_WINDOW_MESSAGES). In case your COM object is provided by an out-of-proc server, this most likely should work. Otherwise, you should consider putting some reentrancy checks in place.

I have a related question with some code showing how it could be done with C# (I had to use COWAIT_DISPATCH_WINDOW_MESSAGES there, otherwise the event I was after wasn't getting fired).

[UPDATE] Ideally, you should use async/await pattern for things like that and wrap your event as a task (e.g. here's how). I understand, sometimes it is not feasible to re-factor existing code to use this approach. However, if a pending operation takes considerable time to complete, a more user-friendly way to wait for its completion event might be just to show a modal dialog with a nice "please wait..." message (as discussed here in comments). You'd just close this dialog from your event handler. In fact, AFAIK, this is the only endorsed way for a WinForms app to enter a nested message loop.

[UPDATE] As Eric pointed out in comments, COWAIT_DISPATCH_WINDOW_MESSAGES is indeeded required for an STA thread. Apparently, COWAIT_DISPATCH_CALLS is intended for the new little-known ASTA model and has no meaning in other apartment types.

In case with out-of-proc COM servers, .NET event handlers are called back as free-threaded objects regardless of the waiting thread's apartment model (in my experience, it's never the same STA thread on which the out-of-proc object was originally created). Thus, waiting with WaitHandle.WaitOne (no pumping) should be sufficient. However, if the event handler accesses any state data besides the WaitHandle, proper synchronization is required (with locks etc).

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 2
    If the code is in a STA, `COWAIT_DISPATCH_WINDOW_MESSAGES` is required. [Chris Brumme's article](http://blogs.msdn.com/b/cbrumme/archive/2004/02/02/66219.aspx) (referenced in your nested message loop article) emphasizes this. Incoming COM calls arrive via window messages. Overall, I prefer your solution (I just *knew* someone at MSFT had already packaged up the MsgWaitForMultipleObjects code); it's cleaner & simpler; but the odds are @Rauld will have to pump. – Eric Brown Aug 29 '13 at 15:31
  • @EricBrown, a great point, thank you. I did not know `COWAIT_DISPATCH_CALLS` is not enough for STA. The article you mentioned looks a must-read, yet i overlooked it, get to catch-up. – noseratio Aug 29 '13 at 15:51
1

Most likely you want to pump messages while waiting for an event. For this, MsgWaitForMultipleObjectsEx is invaluable. I have an answer (to a different question) that demonstrates a common usage pattern for MsgWaitForMultipleObjectsEx.

Community
  • 1
  • 1
Eric Brown
  • 13,774
  • 7
  • 30
  • 71
  • do you have a C# example ? – Rauld Aug 29 '13 at 11:42
  • @EricBrown, as long as we have to pump messages, using `MsgWaitForMultipleObjectsEx` might actually be more appropriate than `CoWaitForMultipleHandles`, because the former would allow using `Application.DoEvents` instead of native `PeekMessage/TranslateMessage/DispatchMessage`. – noseratio Aug 30 '13 at 06:43
  • @Rauld - I don't really have an example, but [PInvoke.net](http://pinvoke.net) has signatures for all the native functions. – Eric Brown Aug 30 '13 at 17:22
  • @Noseratio - another good point. (I do all my development in C++, and sometimes it shows. :)) – Eric Brown Aug 30 '13 at 17:23
0

I finally ended up using Application.DoEvents()

Rauld
  • 980
  • 2
  • 10
  • 19
  • 1
    You may want to check [this](http://stackoverflow.com/a/19555959/1768303), specifically `WaitWithDoEvents` from there. – noseratio Oct 25 '13 at 02:01