I got to debug a COM threading issue where we see that when we are communicating between an application (say an MFC application) and a class library (developed using C# and implementing a COM component) the messages between the C++ thread and the C# thread are not being marshaled.
The thread that actually makes the COM call is an STA thread and the call stack shows that it is waiting (the reason for hang) and no cross apartment information is available to this thread. A typical call-stack is shown below.
05f2e758 7705c752 ntdll!NtWaitForMultipleObjects+0xc
05f2e8dc 766d9879 KERNELBASE!WaitForMultipleObjectsEx+0x10b
05f2e934 766d9778 USER32!RealMsgWaitForMultipleObjectsEx+0x16b
05f2e954 76c884d3 USER32!MsgWaitForMultipleObjectsEx+0x3e
05f2e9b4 76c8bbe6 combase!CCliModalLoop::BlockFn+0xff
05f2e9e8 76d3efc5 combase!ClassicSTAThreadDispatchCrossApartmentCall+0x12f
05f2eb04 76c8b7f3 combase!CRpcChannelBuffer::SendReceive2+0x555
05f2ebbc 76cc115d combase!ClassicSTAThreadSendReceive+0x1be
05f2ec18 76d3d39a combase!CCtxComChnl::SendReceive+0x281
05f2ec34 76b2e4a0 combase!NdrExtpProxySendReceive+0x43
05f2ec40 76bab313 RPCRT4!NdrpProxySendReceive+0xe
05f2f05c 76d3c779 RPCRT4!NdrClientCall2+0x20c
05f2f358 73df8242 clr!RCW::CallQueryInterface+0x95
05f2f3b8 73df81ba clr!RCW::GetComIPForMethodTableFromCache+0xba
05f2f3c8 73df892a clr!RCW::GetComIPFromRCW+0x2d
05f2f474 73d9b51b clr!ComObject::SupportsInterface+0xd5
05f2f4b8 73ee1de1 clr!ObjIsInstanceOf+0x9b
05f2f554 02aa0bc0 clr!JITutil_ChkCastAny+0x77
05f2f5ac 72fc2407 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(System.Object)+0x6f
05f2fa64 73e3cf6a clr!ThreadNative::KickOffThread+0x1d2
05f2fb7c 76378543 clr!Thread::intermediateThreadProc+0x4d
05f2fb88 778abf39 KERNEL32!BaseThreadInitThunk+0xe
05f2fbcc 778abf0c ntdll!__RtlUserThreadStart+0x72
As per the COM apartment rules an STA apartment has only one thread. In this issue we are getting a hang as because we are not marshaling between the two different STA threads. The reason behind this being the STA thread is not pumping messages, it just hangs doing nothing. COM STA threads are required to pump messages and the way to do it is by introducing a message pump (example code below).
HWND hWnd = NULL;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
if (bRet == -1)
// handle the error and possibly exit
Going back to the original issue - this means that the STA thread was not pumping messages, it just hangs, doing nothing. After introducing the above message loop everything started working.
Rules for single-threaded apartments are simple, but it is important to follow them carefully:
If the creators apartment is multithreaded and the threading model is BOTH then the object lives in MTA. MTA objects won’t have to go about doing cross apartment calls for communicating with each other. Here is a table that lists where the COM object is supposed to live for an apartment and threading model.
Where Object live