Marshaling: CoUnitialize is blocking thread exit
Env: VC++60, Windows 2000 Professional
app. MFC dialog based, STA
This application has two threads:
in the first (main) I create a smart pointer to a COM component and marshal it with CoMarshalInterThreadInterfaceInStream(). after I create the second thread and pass the IStream pointer as parameter. I perform these actions in OnInitDialog().
in the second thread (worker) I got the pointer and unmarshal it with CoGetInterfaceAndReleaseStream().
the marshaling works perfect, the problem happens after it: I start a while loop that finishes only when I set an event from the main thread (in OnOK() fro example. at this point I wait for a single event that the exiting thread set (WaitForSingleObject())).
After the while {} in the worker thread function I call CoUnitialize() and there seems to be the problem, because it never returns.
If I call CoUnitialize() before the while loop it works fine, but I cannot do it because I use the marshaled pointer inside this loop.
If I remove the call to CoUnitialize somehow the compiler put it, because the bahvior is the same, the finished exit code never comes to GetExitCodeThread() function, even if the thread function returns fine. If I use the thread handle as object for WaitForSingleObject() (my first option) it always returns TIMEOUT, because if I have CoUnitialize() it stay there, if I don't have the function return, but the thread never signal as finished.
Here I put the skeleton of my test application code, my real application reflects has the same behavior:
BOOL CMyDlg::OnInitDialog()
{
// ...
// instantiate the COM comp. and create the smart pointer
spConnector.CreateInstance(__uuidof(cocConnector));
// marshal the interface to be used by the other thread
HRESULT hr = ::CreateStreamOnHGlobal(NULL, true, &pstm);
hr = ::CoMarshalInterThreadInterfaceInStream(IID_intConnector,spConnectorP,&pstm);
DWORD dwThreadId;
hThread = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,&pstm,0,&dwThreadId);
hEvent = CreateEvent(NULL,false,false,NULL);// finish the sec. thread
hEvent2 = CreateEvent(NULL,false,false,NULL);// feedback from sec. thread
}
DWORD WINAPI ThreadProc(IN LPSTREAM *pstm)
{
MSG msg;
intConnectorPtr spConnector2;
CoInitialize(NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(*pstm,IID_intConnector,(LPVOID*) &spConnector2);
while(WaitForSingleObject(hEvent, 10) != WAIT_OBJECT_0)
{
// ... do the job with the smart pointer
// ... check for windows messages (message loop)
}
CoUninitialize(); // --> here it never returns
SetEvent(hEvent2);
return 999;
}
void CMyDlg::OnOK()
{
DWORD dwExitCode = 0;
SetEvent(hEvent);
dwExitCode = WaitForSingleObject(hEvent2, 3000); // the event comes
::GetExitCodeThread(hThread, &dwExitCode); // but thread is always alive
if (dwExitCode == STILL_ACTIVE)
{
::TerminateThread(hThread, 99);
}
}
If I remove the unmarshal function everything works.
I tested in many other ways, with variables instead of events,
waiting for the handle of the thread and so on...
The main problem is that: GetExitCodeThread(hThread, &ret) always return STILL_ACTIVE when Unmarshal+infiniteloop+CoUnitialize are used together, even if I see the worker thread function returning.
any ideas?
thanx,
Aquino

