2010-04-21 4 views
1

Question: Je démarre le moteur de synthèse vocale MS dans un thread, afin d'éviter un crash sur DLL_attach. Cela démarre très bien et le moteur de synthèse vocale est initialisé, mais je ne peux pas accéder à ISpVoice en dehors du thread. Comment puis-je accéder à ISpVoice en dehors du thread? Il est une variable globale après tout ...Comment accéder aux données de thread en dehors d'un thread

Vous trouvez XPThreads ici: http://www.codeproject.com/KB/threads/XPThreads.aspx

#include <windows.h> 
#include <sapi.h> 
#include "XPThreads.h" 


ISpVoice * pVoice = NULL; 

unsigned long init_engine_thread(void* param) 
{ 
Sleep(5000); 
    printf("lolthread\n"); 



    //HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 
    HRESULT hr = CoInitialize(NULL); 

    if(FAILED(hr)) 
    { 
     MessageBox(NULL, TEXT("Failed To Initialize"), TEXT("Error"), 0); 
     char buffer[2000] ; 
     sprintf(buffer, "An error occured: 0x%08X.\n", hr); 
     FILE * pFile = fopen ("c:\\temp\\CoInitialize_dll.txt" , "w"); 
     fwrite (buffer , 1 , strlen(buffer) , pFile); 
     fclose (pFile); 
    } 
    else 
    { 
     printf("trying to create instance.\n"); 
     //HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice); 
     //hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice); 
     //HRESULT hr = CoCreateInstance(__uuidof(ISpVoice), NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void **) &pVoice); 
     HRESULT hr = CoCreateInstance(__uuidof(SpVoice), NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice); 
     if(SUCCEEDED(hr)) 
     { 
      printf("Succeeded\n"); 
      hr = pVoice->Speak(L"The text to speech engine has been successfully initialized.", 0, NULL); 
     } 
     else 
     { 
      printf("failed\n"); 
      MessageBox(NULL, TEXT("Failed To Create COM instance"), TEXT("Error"), 0); 
      char buffer[2000] ; 
      sprintf(buffer, "An error occured: 0x%08X.\n", hr); 
      FILE * pFile = fopen ("c:\\temp\\CoCreateInstance_dll.txt" , "w"); 
      fwrite (buffer , 1 , strlen(buffer) , pFile); 
      fclose (pFile); 
     } 
    } 






return NULL; 
} 


XPThreads* ptrThread = new XPThreads(init_engine_thread); 


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 
{ 
switch (ul_reason_for_call) 
{ 
case DLL_PROCESS_ATTACH: 
    //init_engine(); 
    LoadLibrary(TEXT("ole32.dll")); 
    ptrThread->Run(); 
    break; 
case DLL_THREAD_ATTACH: 
    break; 
case DLL_THREAD_DETACH: 
    break; 
case DLL_PROCESS_DETACH: 
    if(pVoice != NULL) 
    { 
     pVoice->Release(); 
     pVoice = NULL; 
    } 
    CoUninitialize(); 
    break; 
} 
return TRUE; 
} 
+0

Pourriez-vous indiquer où échoue le code de cour? De plus, quel problème rencontrez-vous avec "Dll_Attach"? Notez qu'appeler LoadLibrary dans DllMain est une idée * mauvaise * - vous pouvez avoir de gros problèmes avec les verrous globaux que Windows utilise pour sérialiser le chargement de dll. Voir les remarques dans http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx. Je ne sais pas si c'est ce qui cause le problème. –

+0

Le problème d'accès est causé par le thread, pas par dllmain. Cependant, dllmain est responsable de me forcer à utiliser des threads, donc indirectement vous avez raison. –

Répondre

5

Tout d'abord, votre problème est que vous attendez le fil que vous commencez quand initialiseurs statiques du fichier sont exécutés pour avoir terminé pendant que votre DllMain() est en cours d'exécution et pourtant vous ne faites rien pour synchroniser avec elle. Bien sûr, si vous faisiez quelque chose pour synchroniser avec, alors vous seriez en train de tomber sur les problèmes qui ont été détaillés dans le lien que j'ai posté en réponse à votre other question ...

Deuxièmement, les pointeurs d'interface COM sont, généralement, thread spécifique. Vous ne pouvez généralement pas obtenir un fil unique via CoCreateInstance() ou QueryInterface(), puis l'utiliser dans un autre fil. Pour pouvoir utiliser un pointeur d'interface dans un autre thread, vous devez le marshaler sur ce thread en utilisant quelque chose comme CoMarshalInterface() (voir here). Mais avant de pouvoir le faire, vous devez vous assurer que vous avez initialisé COM sur le sujet et vous ne pouvez pas le faire pour toutes les raisons que j'ai soulevées en réponse à votre question précédente.

Troisièmement, vous avez aucune raison d'être appeler CoUninitialize() dans votre DllMain() en tant que) vous ne savez pas quel fil vous être demandées et b) vous n'étiez pas responsable d'appeler CoInitialize() sur ce thread aléatoire qui appartiennent à des intérêts par l'application.

Quatrièmement, l'appel à LoadLibrary() est TRÈS MAUVAIS pour les raisons indiquées dans this link que j'ai posté en réponse à votre question précédente. Donc, en résumé, comme je l'ai dit en réponse à votre autre question, vous ne pouvez pas faire ce que vous voulez faire DllMain(). Ce n'est pas l'endroit pour le faire. Comme je l'ai dit précédemment, ce que vous POUVEZ faire est de lancer un thread lorsque vous recevez votre notification DLL_PROCESS_ATTACH, mais respectez les règles lorsque vous le faites afin de ne pas bloquer et charger votre objet COM là-bas. Vous pouvez alors accéder UNIQUEMENT au pointeur d'interface à partir de ce thread et vous devrez effectuer votre propre rassemblement pour transmettre les valeurs des threads qui appellent votre DLL à votre thread COM. Même alors, il y a probablement une meilleure façon de faire ce que vous faites (comme exposer l'ensemble de ce que vous construisez en tant qu'objet OWN COM) mais vous ne donnez pas assez de contexte pour que quelqu'un puisse trouver une réponse au vrai problème que vous avez. Oh et enfin ... La chose XPThreads que vous utilisez est basée sur l'hypothèse imparfaite que vous devez attendre le handle de thread que vous revenez de CreateThread(), vous ne le faites pas, vous pouvez simplement le fermer après vous créez votre fil car vous n'êtes pas intéressé à l'attendre. Vous voudrez peut-être jeter un oeil à this question pour voir pourquoi vous ne devriez probablement pas utiliser CreateThread() et devrait, à la place, utiliser _beginthreadex().

Questions connexes