C++ MSAPI 5: SetNotifyCallbackFunction not working

2020-02-14 05:12发布

So I've tried the MSAPI 5.4 TTS with event example. Now I create an cmd prompt app that utilize the SetNotifyCallbackFunction but the function that I've pass is not being called. I'm not an expert in C++ so I am having difficulty in solving this one, can anyone point me in the right direction or at least give me a good example of SetNotifyCallbackFunction?

Here is a simplified version of my code:

typedef void __stdcall SPNOTIFYCALLBACK(WPARAM wParam, LPARAM lParam);

void __stdcall outsideeventFunction(WPARAM, LPARAM);

void __stdcall outsideeventFunction(WPARAM wParam, LPARAM lParam){
    std::cout << "Event called::wParam: " << wParam << " lParam: " << lParam << std::endl;
    SPEVENT eventItem;
    memset(&eventItem, 0, sizeof(SPEVENT));
    while (SUCCEEDED(pV->GetEvents(1, &eventItem, NULL)))
    {
        bool exitNa = false;
        switch (eventItem.eEventId)
        {
        case SPEI_WORD_BOUNDARY:
            SPVOICESTATUS eventStatus;
            pV->GetStatus(&eventStatus, NULL);
            ULONG start, end;
            start = eventStatus.ulInputWordPos;
            end = eventStatus.ulInputWordLen;
            std::cout << "From event Test: " << start << ", " << end << std::endl;
            std::cout << "From event Length: " << theString.length() - 1 << ", " << start + end << std::endl;
            if (theString.length() - 1 <= start + end){
                std::cout << "From event Exit!" << std::endl;
                exitNa = true;
            }
            break;
        }

        SpClearEvent(&eventItem);
        if (exitNa){
            break;
        }
    }
    return;
}

int _tmain(int argc, TCHAR* argv [], TCHAR* envp [])
{
    pV = NULL;
    std::string nativeString("Hello world, this is a test! For the purpose of a longer message, I'll add another sentence. And here comes the new sentence.");
    SPNOTIFYCALLBACK *cb = &outsideeventFunction;
    if (FAILED(::CoInitialize(NULL)))
        return FALSE;

    HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pV);
    if (SUCCEEDED(hr))
    {
        if (SUCCEEDED(pV->SetNotifyCallbackFunction(cb, 0, 0))){
            std::cout << "Success adding callback" << std::endl;
        }

        ULONGLONG ullMyEvents = SPFEI(SPEI_WORD_BOUNDARY);
        pV->SetInterest(ullMyEvents, ullMyEvents);
    }

    theString = std::wstring(nativeString.begin(), nativeString.end());

    printf("Speak: %s\n", nativeString.c_str());
    hr = pV->Speak(theString.c_str(), SPF_ASYNC, NULL);
    pV->WaitUntilDone(INFINITE);

    std::system("pause");
    pV->Release();
    pV = NULL;
    ::CoUninitialize();
    return TRUE;
}

The result of this app is that the synthesizing of words are done smoothly, but the outsideeventFunction is never been called. As you can see the SetInterest is properly set. How I can fix this?

1条回答
Root(大扎)
2楼-- · 2020-02-14 05:48

Two problems:

1) SAPI doesn't let you reassign event targets, so the line

pV->SetNotifyWin32Event();

will always fail.

2) You need to pump messages to get events delivered. So instead of calling

pV->WaitUntilDone(INFINITE);

you need to get the handle and pump messages until the event is set:

HANDLE hWait = pV->SpeakCompleteEvent();
WaitAndPumpMessagesWithTimeout(hWait, INFINITE);

HRESULT WaitAndPumpMessagesWithTimeout(HANDLE hWaitHandle, DWORD dwMilliseconds)
{
    HRESULT hr = S_OK;
    BOOL fContinue = TRUE;

    while (fContinue)
    {
        DWORD dwWaitId = ::MsgWaitForMultipleObjectsEx(1, &hWaitHandle, dwMilliseconds, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
        switch (dwWaitId)
        {
        case WAIT_OBJECT_0:
            {
                fContinue = FALSE;
            }
            break;

        case WAIT_OBJECT_0 + 1:
            {
                MSG Msg;
                while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
                {
                    ::TranslateMessage(&Msg);
                    ::DispatchMessage(&Msg);
                }
            }
            break;

        case WAIT_TIMEOUT:
            {
                hr = S_FALSE;
                fContinue = FALSE;
            }
            break;

        default:// Unexpected error
            {
                fContinue = FALSE;
                hr = E_FAIL;
            }
            break;
        }
    }
    return hr;
}
查看更多
登录 后发表回答