问题:我在一个线程中启动MS文本到语音引擎,以避免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 :(得分:5)
首先,你的问题是你期望在你的DllMain()运行时运行文件的静态初始化程序时启动的线程,但你却没有做任何事情来与它同步。当然,如果您正在做一些与之同步的事情,那么您将会因为我发布的链接中详细说明的问题而违反您的other question ...
其次,COM接口指针通常是特定于线程的。通常,您不能通过CoCreateInstance()
或QueryInterface()
获取一个线程,然后只在另一个线程中使用它。为了能够在另一个线程中使用接口指针,您需要使用CoMarshalInterface()
之类的内容将其封送到该线程(请参阅here)。但在你能做到这一点之前,你需要确保你已经在线程上初始化了COM,并且由于我在回答你上一个问题时提出的所有原因你不能这样做。
第三,你没有理由在你的CoUninitialize()
中调用DllMain()
作为a)你不知道你被叫什么线程和b)你不负责打电话{ {1}}在应用程序拥有的随机线程上。
第四,CoInitialize()
的调用非常糟糕,原因是我在回复你之前的问题时发布的this link中指出的原因。
因此,总而言之,正如我在回答您的其他问题时所说,您无法在LoadLibrary()
中执行您想要执行的操作。它不是这样做的地方。正如我之前所说,当你收到DllMain()
通知时,你可以做的就是运行一个线程,但是当你这样做时遵守规则,这样你就不会死锁并在那里加载你的COM对象。然后,您只能从该线程访问接口指针,并且您必须进行自己的编组操作,以便将调用DLL的线程中的值传递给COM线程。即便如此,你可能还有一种更好的方法可以做你正在做的事情(例如暴露你正在建造的所有东西,因为它是自己的COM对象)但是你没有给任何人提供足够的背景来提出答案你真正的问题。
哦,最后......你正在使用的XPThreads是基于有缺陷的假设,你必须等待从DLL_PROCESS_ATTACH
返回的线程句柄,你没有,你可以只是在您创建线程后关闭它,因为您不想等待它。您可能希望查看this question,了解为什么您可能不应该使用CreateThread()
,而应该使用CreateThread()
。