If you work with COM objects you may accidently attempt to use or create COM object in one thread and accidently use it in another thread. And then unless original thread is free threaded .NET will attempt to switch to original thread.
And from there you will see one of the following outcomes.
- If that thread pump messages, then .NET will attempt to send message to that thread to switch. Sometimes it can lead to deadlock or just long delay if that thread is busy. Main thread usually pumps messages, so usually .NET able to switch to main thread.
- You will get error that Interface is not supported. Sometimes you will get that cryptic message even that interface is clearly supported. You will get this message because .NET don’t know how to marshal to original thread, specially if this is some background thread. In this case .NET is not able to marshal, so it will ask object itself to marshal by requesting few interfaces and one of them is IMarshal. Most objects do not support these interfaces and you will see that error message
- When original thread was terminated, or if that was thread pool thread and it will clean its state on next request. In this case you will get this one from MDA: Managed Debugging Assistant 'DisconnectedContext' : 'Transition into COM context 0xed058 for this RuntimeCallableWrapper failed with the following error: The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)). This is typically because the COM context 0xed058 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0xec968). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.'
Yesterday I asked to help find source of that last problem. When I did run our application in Visual Studio and got error message, there were no call stack. If we “Enable native code debugging“ in Visual Studio I got this call stack:
Not really helpful. Then I try to debug it in WinDbg but by default MDA is not enabled there. To enable it simplest way will be to create environment variable COMPLUS_MDA and assign value managedDebugger. Alternatively you can see values here and assign disconnectedContext to monitor only that problem.
But remember to remove it when you finish. Then you will be able to see MDA messages in WinDbg but it will not stop on these messages. I checked .NET source code and it looks like it should stop but it doesn’t. But anyway you can execute this command:
And MDA will call this function when context is disconnected. Then you can see call stack. Moreover, if you step out from this function you will be able to check parameters in one of the 4 arguments that kv command displays and one of them will be RCW. You can use! DumpRCW and see what interface it is.
And in RCW dump you will be to see original IUnknown interface. Then you can check first 3 pointers on this address using dps command in WinDbg. After that you can see disassemble and it is usually thunk that adjusts pointer to interface to pointer to class (In C++ it is called this). In our situation it was Delphi and it was possible to get class name of object from pointer to class because 3 functions of IUnknown belong to common class for most classes that implements IUnknown methods.
I hope it helps someone