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).