我试图使用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