Как получить доступ к данным потока вне потока

Вопрос: Запускаю движок 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;
}

person Stefan Steiger    schedule 21.04.2010    source источник
comment
Не могли бы вы указать, где не работает код курса? Кроме того, какая у вас проблема с Dll_Attach? Обратите внимание, что вызов LoadLibrary внутри DllMain — это плохая идея — вы можете получить большие проблемы с глобальными блокировками, которые Windows использует для сериализации загрузки dll. См. примечания в msdn.microsoft.com/en- us/library/ms682583%28VS.85%29.aspx. Не уверен, что это является причиной проблемы.   -  person Andy Johnson    schedule 21.04.2010
comment
Проблема с доступом вызвана потоками, а не dllmain. Однако dllmain отвечает за принуждение меня к использованию потоков, так что косвенно вы правы.   -  person Stefan Steiger    schedule 21.04.2010


Ответы (1)


Во-первых, ваша проблема заключается в том, что вы ожидаете, что поток, который вы запускаете при запуске статических инициализаторов файла, будет завершен, пока работает ваш DllMain(), и при этом вы ничего не делаете для синхронизации с ним. Конечно, если бы вы делали что-то для синхронизации с ним, вы бы столкнулись с проблемами, которые были подробно описаны в ссылке, которую я разместил в ответ на ваш другой вопрос...

Во-вторых, указатели интерфейса COM, как правило, зависят от потока. Как правило, вы не можете получить его в одном потоке через CoCreateInstance() или QueryInterface(), а затем просто использовать его в другом потоке. Чтобы иметь возможность использовать указатель интерфейса в другом потоке, вам необходимо маршалировать его в этот поток, используя что-то вроде CoMarshalInterface() (см. здесь). Но прежде чем вы сможете это сделать, вам нужно убедиться, что вы инициализировали COM в потоке, а вы не можете этого сделать по всем причинам, которые я привел в ответ на ваш предыдущий вопрос.

В-третьих, у вас нет причин вызывать CoUninitialize() в своем DllMain(), поскольку а) вы понятия не имеете, в каком потоке вас вызывают, и б) вы не несете ответственности за вызов CoInitialize() в этом случайном потоке, принадлежащем приложению.

В-четвертых, обращение к LoadLibrary() ОЧЕНЬ ПЛОХО по причинам, указанным в эта ссылка, которую я разместил в ответ на ваш предыдущий вопрос.

Итак, в общем, как я уже сказал в ответ на ваш другой вопрос, вы не можете делать то, что хотите, в DllMain(). Это не место для этого. Как я уже говорил ранее, то, что вы МОЖЕТЕ сделать, это запустить поток, когда вы получите уведомление DLL_PROCESS_ATTACH, но при этом соблюдать правила, чтобы не заблокировать и не загрузить туда свой COM-объект. Затем вы можете ТОЛЬКО получить доступ к указателю интерфейса из этого потока, и вам придется выполнить собственную сортировку для передачи значений из потоков, которые вызывают вашу DLL, в ваш COM-поток. Даже тогда, вероятно, есть лучший способ сделать то, что вы делаете (например, выставить все, что вы создаете, как СОБСТВЕННЫЙ COM-объект), но вы не даете достаточного контекста, чтобы кто-либо мог придумать ответ к НАСТОЯЩЕЙ проблеме, которая у вас есть.

О, и, наконец... То, что вы используете XPThreads, основано на ошибочном предположении, что вы ДОЛЖНЫ ждать дескриптора потока, который вы возвращаете из CreateThread(), вы этого не делаете, вы можете просто закрыть его после создания своего потока так как вы не заинтересованы в том, чтобы ждать его. Вы можете взглянуть на этот вопрос, чтобы увидеть почему вам, вероятно, не следует использовать CreateThread(), а вместо этого следует использовать _beginthreadex().

person Len Holgate    schedule 21.04.2010