I'm trying to use CoRegisterClassObject to customize the way I load dll's that have com objects in them. I'm trying something out that will solve a problem I was having when the thread's apartment type didn't match the com object's. The basic idea is that since using coregisterclassobject ignores the registry when creating the com object, I need to make sure that STA objects are created in STA threads, and the same for MTA objects. Here's a sample that I wrote as a proof of concept that's not always behaving as I expect.
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;
}
And here's the relevant part of my main function.
//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();
The idea was that since the registry shouldn't be used with CoRegisterClassObject, I needed to manually create the apartment threaded objects in an STA instead of the current MTA thread, and vice versa. I noticed that when not using CoRegisterClassObject, CoGetClassObject spawns a new thread and calls DllGetClassObject in that thread, so I figured the class factory just needed to be created in an STA and then the objects will live there.
The problem I'm seeing is that in the example above, the thread ids don't always end up looking like I expect them to. If FactoryThread is initialized as Apartment threaded, and the main thread as multithreaded, then THREAD_ID_2 == THREAD_ID_3 == THREAD_ID_4 != THREAD_ID_1 as expected (the factory is creating these objects and they can live in the factory's thread). If those threading models are switched though, then thread_id_3 == thread_id_4, but they are different than thread_id_2 and thread_id_1, even though the com objects can be created in thread 2.
This seems inconsistent, and can cause unwanted behavior in situations where another thread is involved. When relying only on the registry and not using coregisterclassobject, if i created a free-threaded object in a STA, the object would be created in a different thread spawned by com that was in the MTA, and then if i spawned a third thread that was also in a STA, creating the object there would put it in the first com-spawned MTA thread, not a new one (The same would be true if the object's threadingmodel and the threads' apartment types were reversed). However, if I was to use coregisterclassobject to make my own factory like above, and the object was multithreaded but the thread was in the STA, then each new thread that created these multithreaded objects would spawn a new MTA thread, which seems wasteful and inconsistent with what normally happens.