2010-04-21 100 views
1

问题:我在一个线程中启动了MS Text-to-speech引擎,以避免DLL_attach崩溃。它开始很好,文本到语音引擎被初始化,但我不能在线程之外访问ISpVoice。如何在线程外部访问ISpVoice?这是一个全局变量,毕竟......如何访问线程外的线程数据

您可以找到XPThreads: 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

你能指出哪里的代码失败吗?另外,你对“Dll_Attach”有什么问题?请注意,调用DllMain中的LoadLibrary是一个糟糕的主意 - 您可能会遇到Windows用来序列化dll加载的全局锁的大问题。请参阅http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx中的备注。不知道这是什么原因造成的问题。 – 2010-04-21 09:04:22

+0

访问问题是由线程造成的,而不是由dllmain造成的。 但是,dllmain负责强制我使用线程,所以间接地说你是对的。 – 2010-04-21 12:04:24

回答

5

首先,你的问题是,你期待你开始时文件的静态initialisers都运行有螺纹在你的DllMain()正在运行的同时完成,但你没有做任何事情来同步它。当然,如果你正在做一些事情来同步它,那么你将会陷入我发布的链接中对你的other question ...

的详细问题。第二,COM接口指针通常是,线程特定。通常,您不能通过CoCreateInstance()QueryInterface()获得一个线程,然后在另一个线程中使用它。为了能够在另一个线程中使用接口指针,需要使用类似CoMarshalInterface()(请参阅here)将其封送到该线程。但在你做这件事之前,你需要确保你已经在线程中初始化了COM,并且你不能那样做,因为我在回答你之前的问题时提出了所有的理由。

第三,您没有理由在您的DllMain()中调用CoUninitialize()作为a)您不知道您被调用的是哪个线程,以及b)您没有责任在该随机线程上调用CoInitialize()由应用程序。

第四,由于我在回答您之前的问题时发布的this link中指出的原因,致电LoadLibrary()非常糟糕。

所以,总之,正如我在回答你的其他问题时所说的,你不能在DllMain()中做你想做的事情。这不是做这件事的地方。正如我之前所说的,当你得到你的DLL_PROCESS_ATTACH通知时,你可以做的就是运行一个线程,但是当你这样做时要遵守规则,这样你就不会死锁并在那里加载你的COM对象。然后,您可以只从该线程访问接口指针,并且必须执行自己的编组,以将调用DLL的线程中的值传递给COM线程。即使这样,也许有更好的方法来做你正在做的事情(比如公开你正在构建的所有东西,因为它是OWN COM对象),但是你没有提供足够的上下文给任何人提出答案到你有的真正的问题。

哦,最后......你使用的XPThreads是基于有缺陷的假设,你必须等待你从CreateThread()得到的线程句柄,你不需要,你可以在关闭之后关闭它你创建你的线程,因为你没有兴趣等待它。您可能想看看this question,看看您为什么不应该使用CreateThread(),而应该使用_beginthreadex()