CoRegisterClassObject нарушает безопасность потоков

Я тестирую фабрику пользовательских классов, которая будет зарегистрирована с помощью coregisterclassobject, и замечаю, что это вызывает проблемы с многопоточностью.

Я создал тестовый объект com и создал его экземпляр, и все вело себя как ожидалось. Это сервер inproc, и в реестре его ThreadingModel называется «Квартира». Если я вызываю CoInitializeEx с apartment_threaded, он создает объект в том же потоке, а если я вызываю его с COINIT_MULTITHREADED, он создает его в отдельном потоке, как и должно (так как он не может быть создан в многопоточной квартире).

Однако, если я сначала создаю экземпляр своей фабрики пользовательских классов и регистрирую его в coregisterclassobject, объект всегда создается в одном потоке, даже если модель потока не соответствует квартире потока. Я думал, что использование coregisterclassobject не изменит того факта, что поток находится в многопоточной квартире, а объект может быть только в однопоточной квартире.

CoInitializeEx(NULL, COINIT_MULTITHREADED);
//CustomClassFactory *factory = new CustomClassFactory();
DWORD regNum = 0;
CLSID clsid = __uuidof(TestComObjLib::TestComObjCoClass);
//CoRegisterClassObject(clsid, factory, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regNum);
{
TestComObjLib::ITestComObjPtr ptr;
HRESULT hr = ptr.CreateInstance(clsid, NULL);
if(ptr){
auto str = ptr->HelloWorld();
cout << str << endl;
}
}
//CoRevokeClassObject(regNum);
CoUninitialize();

Вышеуказанное порождает новые потоки, как и ожидалось, но если я раскомментирую закомментированные строки, COM не создаст никаких новых потоков. Моя фабрика классов не делает ничего странного. Он просто загружает директорию dll и вызывает DllGetClassObject, чтобы получить фабрику классов, которая была определена, и вызывает createinstance для этого. Вызов HelloWorld все еще работает, но я просто не уверен, почему многопоточность не соответствует ожиданиям.

0

Решение

Когда вы регистрируете фабрику классов явно с CoRegisterClassObjectВы обходите реестр целиком. Это все равно будет работать, даже если объект вообще не указан в реестре.

Поскольку с реестром никогда не обращаются, указанная там модель потоков не имеет значения. Ваш объект считается жить в квартире, которая называется CoRegisterClassObject (или, если быть точным, IClassFactory::CreateInstance будет вызван из этой квартиры; фабрика классов может разыгрывать трюки, чтобы создать объект в другой квартире, а затем направить его обратно вызывающей стороне).

3

Другие решения

Других решений пока нет …