4

发现问题/崩溃的关键,请参阅帖子底部。

在创建ISpVoiceusing的实例时CoCreateInstance,似乎第一个之后的实例一旦第一个说话就不能说话。也就是说,如果pVoice先说话,pVoice2就不会说话。如果pVoice2先开口,pVoice就不会开口。创建/分配的顺序似乎无关紧要。

当我说“不会说话”时,我ISpVoice::Speak的意思是:调用立即返回结果S_OK;没有合成声音。

更正:上述情况发生在D版本未附加调试器时。附加 Visual Studio 调试器后,在vtjpnsapi50.dll!10004e65. 此外,无论是否附加了调试器或生成了调试信息,C++ 版本都会发生访问冲突。

sleep在对 Speak 的调用之间插入一个调用不会改变任何东西(当然,除了它会插入一个延迟)。

D 中的复制(C++ 等效如下):

import std.c.windows.com;
import core.sys.windows.windows;
import speech.windows.sapi;

import std.stdio;

int main()
{
    if (FAILED(CoInitialize(null)))
        return 1;

    scope(exit) CoUninitialize();

    ISpVoice pVoice;
    HRESULT hr = CoCreateInstance(&CLSID_SpVoice, null, CLSCTX_ALL, &IID_ISpVoice, cast(void**)&pVoice);
    assert(hr == S_OK);
    hr = pVoice.Speak("Hello world", 0, null); // This speaks fine
    assert(hr == S_OK);

    ISpVoice pVoice2;
    hr = CoCreateInstance(&CLSID_SpVoice, null, CLSCTX_ALL, &IID_ISpVoice, cast(void**)&pVoice2);
    assert(hr == S_OK);
    hr = pVoice2.Speak("hello again", 0, null); // This returns immediately
    assert(hr == S_OK); // Yet it still returns S_OK

    hr = pVoice.Speak("first voice again", 0, null); // This speaks fine too, immediately after "hello world" finishes
    assert(hr == S_OK);

    // The two objects are indeed at different memory addresses
    writefln("voice 1: %s, voice 2: %s", cast(void*)pVoice, cast(void*)pVoice2);

    pVoice.Release();
    pVoice = null;

    pVoice2.Release();
    pVoice2 = null;

    return 0;
}

这是等效的 C++ 程序:

#include <sapi.h>
#include<Windows.h>

int main()
{
    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
        return 1;

    ISpVoice* pVoice;
    HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice);
    hr = pVoice->Speak(L"Hello world", 0, NULL); // This speaks fine

    ISpVoice* pVoice2;
    hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice2);
    hr = pVoice2->Speak(L"hello again", 0, NULL); // This causes an access violation

    hr = pVoice->Speak(L"first voice again", 0, NULL);

    pVoice->Release();
    pVoice = NULL;

    pVoice2->Release();
    pVoice2 = NULL;

    CoUninitialize();

    return 0;
}

在上面的例子中,两个声音被分配了相同的参数,并且第一个说话的声音正常工作。在 D 版本中,当没有附加调试器时,第二次调用SpeakonpVoice也有效。

如果有人知道可能导致这种情况的原因,或者知道任何使用多个语音对象的开源软件,请告诉我,谢谢!

编辑 这只发生在 NeoSpeech 的声音中。它适用于 Microsoft 和 eSpeak 的声音。我仍然想知道是否有什么办法可以解决这个问题(NeoSpeech 有一些非常非常好的声音......)。

4

0 回答 0