我試圖使用CoRegisterClassObject來定製我加載的DLL的COM對象在他們的方式。我正在嘗試一些解決當線程的公寓類型與com對象不匹配時遇到的問題。基本思想是,由於使用coregisterclassobject在創建com對象時會忽略註冊表,所以我需要確保STA對象在STA線程中創建,並且對於MTA對象也是如此。以下是我寫作的一個樣本,作爲概念證明,並不總是按照我的預期行事。COM線程/公寓行爲與編組工廠不一致
LPSTREAM factory_stream = NULL; //GLOBAL VARIABLE FOR TEST
DWORD __stdcall FactoryThread(LPVOID param)
{
CoInitialize(NULL);
//CoInitializeEx(NULL, COINIT_MULTITHREADED);
cout << GetCurrentThreadId(); //THREAD_ID_2
CustomClassFactory *factory = new CustomClassFactory();
factory->AddRef();
CoMarshalInterThreadInterfaceInStream(IID_IClassFactory, (IClassFactory*)factory, &factory_stream);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
factory->Release();
CoUninitialize();
return 0;
}
這裏是我的主要功能的相關部分。
//CoInitialize(NULL);
CoInitializeEx(NULL, COINIT_MULTITHREADED);
cout << GetCurrentThreadId(); //THREAD_ID_1
HANDLE regThread = CreateThread(NULL, 0, FactoryThread, NULL, 0, NULL);
Sleep(5000); //ensures that the factory is registered
IClassFactory *factory = NULL;
CoGetInterfaceAndReleaseStream(factory_stream, IID_IClassFactory, (void**)&factory);
DWORD regNum = 0;
HRESULT res = CoRegisterClassObject(clsid, factory, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, ®Num);
{
TestComObjLib::ITestComObjPtr ptr;
HRESULT hr = ptr.CreateInstance(__uuidof(TestComObjLib::TestComObjCoClass), NULL);
ptr->OutputOwningThreadId(); //THREAD_ID_3 is just from cout << GetCurrentThreadId()
TestComObjLib::ITestComObjPtr ptr2;
HRESULT hr = ptr2.CreateInstance(__uuidof(TestComObjLib::TestComObjCoClass), NULL);
ptr2->OutputOwningThreadId(); //THREAD_ID_4
}
CoRevokeClassObject(regNum);
CoUninitialize();
當時的想法是,既然註冊表不應與CoRegisterClassObject使用,我需要手動創建公寓在STA線程對象,而不是目前的MTA線程,反之亦然。我注意到,當不使用CoRegisterClassObject時,CoGetClassObject產生一個新的線程並在該線程中調用DllGetClassObject,所以我認爲只需要在STA中創建類工廠,然後這些對象就會存在。
我看到的問題是,在上面的例子中,線程ID並不總是最終看起來像我期望他們。如果FactoryThread初始化爲Apartment線程,並且主線程爲多線程,那麼THREAD_ID_2 == THREAD_ID_3 == THREAD_ID_4!= THREAD_ID_1按預期(工廠正在創建這些對象,並且它們可以存在於工廠線程中)。如果那些線程模型被切換,那麼thread_id_3 == thread_id_4,但它們不同於thread_id_2和thread_id_1,即使com對象可以在線程2中創建。
這看起來不一致,並且可能會導致不希望的行爲涉及另一個線程。當僅僅依靠註冊表而不使用coregisterclassobject時,如果我在STA中創建了一個自由線程對象,該對象將在由MTA生成的com中生成的另一個線程中創建,然後如果我生成第三個線程也是在一個STA中,創建這個對象將會把它放到第一個產生的MTA線程中,而不是一個新的線程(如果對象的線程模型和線程的公寓類型被顛倒過來,也是如此)。但是,如果我要使用coregisterclassobject來創建自己的工廠,並且該對象是多線程的,但線程位於STA中,那麼創建這些多線程對象的每個新線程都會生成一個新的MTA線程,這似乎是浪費和不一致的與通常發生的事情。
明白了。我沒有意識到COM與STA和MTA線程的通信方式不同。謝謝你的幫助。 – bdwain