Приложение на основе SAPI вызывает нарушение доступа к памяти при перечислении токенов

Я только недавно загрузил Visual Studio 2015 (сообщество), чтобы разрабатывать приложения с использованием Microsoft SAPI TTS. Я установил 5.1 SDK, а затем 5.4 SDK для речи и установил языки времени выполнения для SAPI.

До сих пор мне удавалось заставить приложение работать, используя фразы, которые я хочу, чтобы SAPI произносил как с помощью прямых аргументов, так и путем чтения SSML-файла .XML. Все функции SAPI и SSML работают Кроме за что-либо, что связано с изменением голосового токена (например., <voice xml:lang="pl-PL"><voice required="Gender:Female"> … так далее)

Я прочитал несколько форумов о том, как установить язык / голосовой токен, и я попробовал следующий код:

if(FAILED(::CoInitialized(NULL))
return false;

HRESULT                         hr = S_OK;
CComPtr<ISpVoice>               cpVoice;
CComPtr<ISpObjectTokenCategory> cpObjectCat;
CComPtr<ISpObjectToken>         cpObjectToken;
CComPtr<IEnumSpObjectTokens>    cpEnum;

hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&cpVoice);

if(SUCCEEDED(hr))
{
hr = SpGetDefaultTokenFromCategoryId(SPCAT_VOICES, &cpObjectToken);
}
if(SUCCEEDED(hr))
{
hr = SpGetCategoryFromId(SPCAT_VOICES, &cpObjectCat);
}
if(SUCCEEDED(hr))
{
hr = cpObjectCat->EnumTokens(NULL, NULL, &cpEnum);
}
if(SUCCEEDED(hr))
{
hr = cpEnum->Next(1, &cpObjectToken, NULL);
//Currently only concerned with making 1 token assign without
//throwing exception
}
if(SUCCEEDED(hr))
{
hr = cpVoice->SetVoice(cpObjectToken);
}
if(SUCCEEDED(hr))
{
hr = cpVoice->Speak(L"Hello There!", NULL, NULL);
}
//... lots of commented-out code here ...
cpVoice.Release();
::CoUninitialize();
return true; // <-- Throws Exception Here

Программа компилируется без ошибок, но выдает ошибку 0xC0000005 (нарушение доступа к памяти) в последнем операторе возврата.

Я должен был изменить заголовочный файл <sphelper.h> из-за устаревшего метода :: GetVersionExW () … мне удалось заставить его работать, используя методы из этой ссылки: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe . Чудом (и с небольшим изменением исходного кода системы, вероятно, плохой идеей), это сработало.

Я не знаю, почему программа выдает в самом конце, так как проблема должна быть в программе, обращающейся к токенам реестра. Я знаю, что обычно проблема заключается в указателях, так что мне нужно сделать, чтобы эта работа работала?

Обратите внимание, что я пытаюсь сделать cpVoice Объект использовать польский токен, «Паулина». Есть ли способ как-нибудь вручную присвоить объекту значение токена реестра?

1

Решение

Вот как вы проходите через каждый из ваших установленных голосов. pszCurTokenId будет описанием вашего голоса. Возможно, вы могли бы распечатать его на консоли или что-то еще, или просто посмотреть на значение в вашем отладчике.

Вам не нужно редактировать sphelper.h, чтобы правильно выбрать голос. Иногда SAPI может потребоваться несколько секунд, чтобы сменить голос, поэтому я буду терпелив, если будет казаться, что он завис. Я просто запустил следующий код в Windows 7 и убедился, что он работает для этой платформы.

HRESULT hr = S_OK;
CComPtr<ISpObjectToken> cpVoiceToken;
CComPtr<ISpVoice> cpVoice;

::CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = cpVoice.CoCreateInstance(CLSID_SpVoice);

ULONG ulCount = 0;
CComPtr<IEnumSpObjectTokens> cpEnum;

if(SUCCEEDED(hr))
hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);

//Get the number of voices
if(SUCCEEDED(hr))
hr = cpEnum->GetCount(&ulCount);

for(ULONG i = 0; i < ulCount; ++i) {
CSpDynamicString* szDescription;
CComPtr<ISpObjectToken> cpTempVoiceToken;
cpEnum->Item(i, &cpTempVoiceToken);
WCHAR* pszCurTokenId = NULL;
SpGetDescription(cpTempVoiceToken, &pszCurTokenId);
cpVoice->SetVoice(cpTempVoiceToken);
cpVoice->Speak(L"This is a test phrase.", SPF_DEFAULT, NULL);
cpTempVoiceToken.Release();
}

cpVoice.Release();
cpEnum.Release();
::CoUninitialize();
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]