2013-07-12 2 views
0

Je suis en train de tester une fabrique de classe personnalisée qui sera enregistrée à l'aide de coregisterclassobject, et je remarque qu'elle cause des problèmes de thread.CoRegisterClassObject rompt la sécurité des threads

J'ai créé un objet com de test et créé une instance de celui-ci, et tout s'est comporté comme prévu. C'est un serveur inproc, et dans le registre, son ThreadingModel est "Apartment". Si j'appelle CoInitializeEx avec apartment_threaded, il crée l'objet sur le même thread, et si je l'appelle avec COINIT_MULTITHREADED, il le crée sur un thread séparé comme il le devrait (puisqu'il ne peut pas être créé dans l'appartement multithread).

Cependant, si je crée d'abord une instance de ma fabrique de classe personnalisée et l'enregistre avec coregisterclassobject, l'objet est toujours créé sur le même thread, même si le modèle de thread ne correspond pas à l'appartement du thread. Je pensais que l'utilisation de coregisterclassobject ne changerait pas le fait que le thread est dans l'appartement multi-thread et l'objet ne peut être que dans un appartement à un seul thread.

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(); 

Les pontes au-dessus de nouveaux threads comme prévu, mais si je décommenter les lignes de commentaires, COM ne crée pas de nouvelles discussions. Mon usine de classe ne fait rien de bizarre. Il charge juste le dll directyl et appelle DllGetClassObject pour obtenir l'usine de classe que com a définie et appelle createinstance sur cela. L'appel à HelloWorld fonctionne toujours, mais je ne sais pas exactement pourquoi le threading n'est pas ce que je m'attendais.

Répondre

3

Lorsque vous enregistrez explicitement la fabrique de classes avec CoRegisterClassObject, vous ignorez entièrement le registre. Cela fonctionnerait même si l'objet n'est pas mentionné dans le registre.

Étant donné que le registre n'est jamais consulté, le modèle de thread spécifié n'est pas pertinent. Votre objet est considéré comme vivant dans l'appartement qui a appelé CoRegisterClassObject (ou plus précisément, IClassFactory::CreateInstance serait appelé à partir de cet appartement, l'usine de classe peut jouer des astuces pour obtenir son objet effectivement créé dans un appartement différent, puis ramené à l'appelant) .

+0

Merci. Connaissez-vous des astuces spécifiques pour obtenir l'objet créé dans un appartement différent? – bdwain

+1

Eh bien, vous faites tourner un fil et le faire rejoindre l'appartement que vous voulez. Vous lui dites en quelque sorte qu'il doit créer l'objet (envoyer un message personnalisé, signaler un événement sur lequel le thread attend, ou une autre). Le thread crée l'objet et le ramène au thread situé dans 'CreateInstance' (par exemple, avec' IGlobalInterfaceTable', ou 'CoMarshalInterThreadInterfaceInStream' /' CoGetInterfaceAndReleaseStream'). 'CreateInstace' renvoie ensuite le proxy résultant à l'appelant. 'CAtlAutoThreadModule' joue une version de ce jeu, au cas où vous voudriez un exemple de travail à étudier. –

+0

Merci beaucoup pour votre aide. – bdwain