I am automating Excel. However I've received user reports that sometimes my application (which is running in a separate process from Excel), sometimes will hang indefinitely while calling Excel using COM interop. I think I've nailed it down to lack of an IMessageFilter registered on the calling thread (an STA thread that I start and have control over) so that I can give the user the option to cancel their call.
The IMessageFilter
seems to be working. I've implemented it and registered it on my calling thread. Now, if I simply jump into VBA and call Application.Wait(Now + TimeValue("0:00:30"))
(i.e. just block for 30 seconds) then my thread gets notified through the IMessageFilter.MessagePending()
, which is what I want. However, I am unable to trigger IMessageFilter.RetryRejectedCall()
. Apparently, Excel's Application.Wait()
does not block its main thread, because I can still call properties and methods while this occurs (but I will get repeated IMessageFilter.MessagePending()
notifications).
My hypothesis has been that if I just block Excel's UI thread completely, then I can get it to reject the call from my application and notify me through IMessageFilter.RetryRejectedCall()
but no dice. I also tried using kernel32
to sleep the thread, but that didn't work either - my app just did a blocking wait until the sleep was over and Excel's main thread got its message pump going again.
How can I trigger IMessageFilter.RetryRejectedCall()
, i.e. how can I put Excel in a state where it will reject interop calls? My purpose is to test my app. I've written tests that simulate it but obviously I would like to see the real thing in action.
Relevant posts:
How can I get a C# timer to execute on the same thread that created it?
C# Excel interop - how to test if interop object is still working and performing a task?