我在 C++ Builder 中将以下代码用于盲人的 Text-To-Speech 应用程序控件(很可能在 Delphi 中可以使用类似的示例)。主窗体已KeyPreview
检查属性以启用键 F11 预览以开始说话活动(聚焦)控件。代码原样有效,但存在一些问题。此示例在 C++ Builder 代码中,但根据我的发现,Delphi 遇到了同样的问题,我找到的解决方案是相同的。如果您有 Delphi 解决方案,请随时发布,反正它是相似的。
#include <sapi.h>
#include <WTypes.h>
//---------------------------------------------------------------------------
// Speak text string (synchronous function)
//---------------------------------------------------------------------------
bool SpeakText(UnicodeString Text)
{
ISpVoice* pVoice = NULL;
if (FAILED(::CoInitialize(NULL))) return false;
Word Saved8087CW = Default8087CW; // Disable floating point division by zero exception caused by Speak
Set8087CW(0x133f);
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if (SUCCEEDED(hr))
{
//pVoice->SpeakCompleteEvent()
//pVoice->SetSyncSpeakTimeout(1000);
hr = pVoice->Speak(WideString(Text).c_bstr(), SPF_DEFAULT, NULL);
pVoice->Release();
pVoice = NULL;
}
Set8087CW(Saved8087CW);
::CoUninitialize();
return true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
{
UnicodeString Speaker;
if (Key == VK_F11)
{
if (Screen->ActiveControl->InheritsFrom(__classid(TButton))) { Speaker += "Button, " + static_cast<TButton*>(Screen->ActiveControl)->Caption + "."; }
else if (Screen->ActiveControl->InheritsFrom(__classid(TEdit))) { Speaker += "Edit box, " + static_cast<TEdit*>(Screen->ActiveControl)->Text + "."; }
}
if (Speaker != "") SpeakText(Speaker);
}
//---------------------------------------------------------------------------
问题:
如果我不使用该函数覆盖异常, pVoice->Speak 会导致浮点除以零。
Set8087CW
这只发生在 Windows 7(也可能是 Vista 和 Windows 8)上,但不会在同一程序(编译的 exe)中的 Windows XP 上发生。有没有不使用的解决方案Set8087CW
?删除这些行将导致问题和异常。我有BCB2010。函数是同步的,在完成读取文本之前不会关闭或将控制权返回给程序。这是较长文本的问题。它还阻止程序事件。有没有办法让它异步或引入一个事件来定期检查 F11 键状态,如果再次按下 F11,它会停止读取并取消初始化对象?例如,每 300 毫秒(或每个单词后等)轮询一次按键 F11,如果按下,停止说话?还是线程运行?
SAPI 是否有一些在各个站点上写入的内存泄漏?
上面的代码可以用and
OleCheck
代替吗?CoCreateInstance
CoUninitialize
Remy Lebeau 建议的寻求解决方案的人的更新:
SavedCW = Get8087CW();
Set8087CW(SavedCW | 0x4);
hr = pVoice->Speak(WideString(Text).c_bstr(), SPF_DEFAULT | SPF_ASYNC, NULL);
pVoice->WaitUntilDone(-1); // Waits until text is done... if F11 is pressed simply go out of scope and speech will stop
Set8087CW(SavedCW);
还可以在 CodeRage 4 会话中找到详细示例:http: //cc.embarcadero.com/item/27264