Friday, January 7, 2011

CreateThread Usage Pattern

I don’t really use the old thread pool (Windows 2000 & XP) in favor of the new awesome thread pool introduced in Vista, but sometimes you might inherit old code that does. I just finished fixing a bug related to the old CreateThread. I have some time before my team’s Friday afternoon party, so I thought I would share. I found the error thanks to App Verifier; +1 to App Verifier’s awesomeness.

Basically the usage pattern is:
1. get the module handle (GetModuleHandleEx)
2. create the thread (CreateThread)
3. If COM, CoInitialize a new apartment for the thread
4. Do work
5. If COM, CoUninitialize
6. FreeLibraryAndExitThread with the handle gotten in #1
7. Return

Steps 1-2, The thread creator would do something like this:

if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&Class::ThreadProc , &s_hModule))
hr = HRESULT_FROM_WIN32( GetLastError() );

if (S_OK == hr) {
if (s_hThread)
CloseHandle(s_hThread);
s_hThread = CreateThread(NULL, 0, ThreadProc, this, 0, &s_dwThreadID);
if (!s_hThread) {
hr = HRESULT_FROM_WIN32(::GetLastError());
FreeLibrary( s_hModule );
}
}


In my case, the bug was in the GetModuleHandleEx. Take heed that if you are using the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRES flag, then the second parameter should an address inside of your DLL; I have read that &__ImageBase or the HINSTANCE passed into DllMain should also do the trick. Also the third parameter will be used inside the thread proc.

Steps 3-7:

DWORD WINAPI Class::ThreadProc(void *pv)
{
if (S_OK == CoInitializeEx( NULL, COINIT_MULTITHREADED)) {
//...
// do work here
CoUninitialize();
}

FreeLibraryAndExitThread(s_hModule, 0);
return 0;
}


As always, read the documentation to go deeper in the topic.

No comments:

Post a Comment