2013-07-12 4 views
0

coregisterclassobject를 사용하여 등록 할 사용자 정의 클래스 팩토리를 테스트 중이며 스레드 문제를 일으키는 것으로 나타났습니다.CoRegisterClassObject가 스레드 안전성을 깨뜨림

테스트 com 객체를 생성하고 그 인스턴스를 생성했으며 모든 것이 예상대로 동작했습니다. 그것은 inproc 서버이며 레지스트리에서 ThreadingModel은 "Apartment"입니다. 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 directyl을로드하고 DllGetClassObject를 호출하여 com이 정의한 클래스 팩토리를 가져오고 그 클래스 인스턴스에서 createinstance를 호출합니다. HelloWorld에 대한 호출은 여전히 ​​작동하지만, 왜 스레딩이 예상 한 것이 아닌지 잘 모르겠습니다.

답변

3

클래스 팩터 리를 명시 적으로 CoRegisterClassObject으로 등록하면 레지스트리가 완전히 무시됩니다. 객체가 레지스트리에 언급되지 않은 경우에도 여전히 작동합니다.

레지스트리는 결코 문의되지 않으므로 여기에 지정된 스레딩 모델은 부적합합니다. 귀하의 물건은 CoRegisterClassObject (정확히는 IClassFactory::CreateInstance)이라는 아파트에 살고있는 것으로 간주되며, 클래스 팩토리는 실제로 다른 아파트에 물건을 만든 다음 호출자에게 다시 정렬되도록 속임수를 쓸 수 있습니다. .

+0

감사합니다. 다른 아파트에서 만든 물건을 얻으려면 구체적인 트릭을 알고 있습니까? – bdwain

+1

음, 실을 돌려서 원하는 아파트에 가입 시키십시오. 여러분은 어떻게 든 객체를 생성해야한다는 것을 알린다. (커스텀 메시지를 보내거나, 스레드가 기다리는 이벤트를 알리는 등). 스레드는 객체를 생성하고'CreateInstance'에있는 스레드 (예 :'IGlobalInterfaceTable' 또는'CoMarshalInterThreadInterfaceInStream' /'CoGetInterfaceAndReleaseStream')로 객체를 마샬링합니다. 그런 다음 CreateInstace는 결과 프록시를 호출자에게 리턴합니다. 'CAtlAutoThreadModule'은 실습 예제를 원한다면이 게임의 버전을 재생합니다. –

+0

도움을 주셔서 감사합니다. – bdwain