我正在尝试使用 CoRegisterClassObject 来自定义加载包含 com 对象的 dll 的方式。我正在尝试解决当线程的单元类型与 com 对象不匹配时遇到的问题。基本思想是,由于在创建 com 对象时使用 coregisterclassobject 会忽略注册表,因此我需要确保 STA 对象是在 STA 线程中创建的,对于 MTA 对象也是如此。这是我写的一个示例,作为概念证明,它的行为并不总是像我预期的那样。
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 初始化为单元线程,主线程为多线程,则 THREAD_ID_2 == THREAD_ID_3 == THREAD_ID_4 != THREAD_ID_1 符合预期(工厂正在创建这些对象,它们可以存在于工厂的线程中)。如果切换了这些线程模型,那么 thread_id_3 == thread_id_4,但它们与 thread_id_2 和 thread_id_1 不同,即使可以在线程 2 中创建 com 对象。
这似乎不一致,并且在涉及另一个线程的情况下可能导致不需要的行为。当仅依赖注册表而不使用 coregisterclassobject 时,如果我在 STA 中创建了一个自由线程对象,则该对象将在由 MTA 中的 com 生成的不同线程中创建,然后如果我生成了第三个线程也在 STA 中,在那里创建对象会将其放入第一个 com 生成的 MTA 线程中,而不是新线程中(如果对象的线程模型和线程的单元类型颠倒了,情况也是如此)。但是,如果我要使用 coregisterclassobject 像上面那样创建自己的工厂,并且对象是多线程的,但线程在 STA 中,那么创建这些多线程对象的每个新线程都会产生一个新的 MTA 线程,