发现问题/崩溃的关键,请参阅帖子底部。
在创建ISpVoice
using的实例时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 版本中,当没有附加调试器时,第二次调用Speak
onpVoice
也有效。
如果有人知道可能导致这种情况的原因,或者知道任何使用多个语音对象的开源软件,请告诉我,谢谢!
编辑 这只发生在 NeoSpeech 的声音中。它适用于 Microsoft 和 eSpeak 的声音。我仍然想知道是否有什么办法可以解决这个问题(NeoSpeech 有一些非常非常好的声音......)。