SAPI 64-bit Issues

Microsoft Speech SDK

The Microsoft.com Speech website Microsoft Speech SDK SAPI 5.1

SAPI 5.1 64-bit Issues

Overview

This document is intended to help application developers understand and use SAPI functionality on a 64-bit platform. All the discussions below are based on native Win64 programming.

64-bit Programming

Data types:

Win64 supports large memory requirements with 64-bit addressing. All pointers (including handles) are 64 bits long. LONG, INT, BOOL, etc. are still 32 bits long. WPARAM, LPARAM, and LRESULT are pointer based, thus are 64 bits long. Some new data types are defined. For example, fixed-precision data types such as INT32 and INT64; polymorphic data types such as LONG_PTR; specific pointer-precision data types like POINTER_32.

API changes:

There are some API changes in Win64. The constants GWL_xxx, GCL_xxx and DWL_xxx have been undefined. This allows the Win64 compiler to catch errors using the old Get/SetWindowLong APIs. Change your API calls to the new Get/SetWindowLongPtr, and use the newly defined GWLP_xxx, GCLP_xxx, and DWLP_xxx constants. For example, use SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc); in Win64 you will receive an error that GWL_WNDPROC is undefined. It should be changed to:SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc); To write code that is compatible with both 32-bit and 64-bit versions of Windows, use SetWindowLongPtr.

The following functions have been added to basetsd.h: PtrToLong() and PtrToUlong(), IntToPtr() and UIntToPtr(), HandleToLong() and LongToHandle(), etc. These can help convert values of one type to another. However, IntToPtr sign-extends the INT value, UIntToPtr zero-extends the unsigned int value, LongToPtr sign-extends the long value, and ULongToPtr zero-extends the unsigned long value. Also note that PtrToLong and HandleToLong will truncate the pointer to a 32bit value. These values should not be used as pointers again.

Compiling the code:

Set /W3 compiler option, and clean up all Win64 related compiler warnings, particularly the following codes:

  • C4305: Truncation warning. For example, "return": truncation from "unsigned int64" to "long."
  • C4311: Truncation warning. For example, "type cast": pointer truncation from "int*_ptr64" to "int."
  • C4312: Conversion to bigger-size warning. For example, "type cast": conversion from "int" to "int*_ptr64" of greater size.
  • C4318: Passing zero length. For example, passing constant zero as the length to memset.
  • C4319: Not operator. For example, "~": zero extending "unsigned long" to "unsigned _int64" of greater size.
  • C4313: Calling the printf() family of routines with conflicting conversion type specifiers and arguments. For example, "printf": "%p" in format string conflicts with argument 2 of type "_int64." Another example is calling printf("%x", pointer_value); This causes a truncation of the upper 32 bits. The correct method is to call printf("%p", pointer_value).
  • C4242 and C4244: return conversion. For example, "return": conversion from "_int64" to "unsigned int," possible loss of data.

Fix all Win64 related Compiler Errors, particularly --GWL_xxx and GCL_xxx not defined as discussed above.

For additional information on 64-bit Windows programming issues, check the Platform SDK documentation. Select "Windows Development," then choose "Whistler 64-bit Edition."

SAPI issues

SAPI speech recognition (SR) interfaces are disabled in a 64-bit SAPI 5.1. SR related objects like Recognizer (both Inproc and Shared) cannot use CoCreateInstance on a 64-bit platform. Following is a list of the disabled interfaces: IspRecognizer, IspRecoContext, IspPhraseBuilder, ISpCFGEngine, IspGrammarCompiler, IspGramCompBackend, and ISpITNProcessor.

However, SAPI still supports TTS functionalities on a 64-bit platform. Because there is not a 64-bit version of sapi.lib, you cannot get the CLSIDs directly. But you can use CLSIDFromProgID() to get them. Here are the available SAPI ProgIDs on a 64-bit Windows:

CLSIDs ProgIDs
CLSID_SpVoice SAPI.SpVoice
CLSID_SpLexicon SAPI.SpLexicon
CLSID_SpUnCompressedLexicon SAPI.SpUnCompressedLexicon
CLSID_SpCompressedLexicon SAPI.SpCompressedLexicon
CLSID_SpPhoneConverter SAPI.SpPhoneConverter
CLSID_SpNullPhoneConverter SAPI.SpNullPhoneConverter
CLSID_SpObjectTokenCategory SAPI.SpObjectTokenCategory
CLSID_SpObjectTokenEnum SAPI.SpObjectTokenEnum
CLSID_SpObjectToken SAPI.SpObjectToken<
CLSID_SpDataKey SAPI.SpDataKey
CLSID_SpMMAudioEnum SAPI.SpMMAudioEnum
CLSID_SpMMAudioIn SAPI.SpMMAudioIn
CLSID_SpMMAudioOut SAPI.SpMMAudioOut
CLSID_SpStreamFormatConverter SAPI.SpStreamFormatConverter
CLSID_SpRecPlayAudio SAPI.SpRecPlayAudio
CLSID_SpStream SAPI.SpStream
CLSID_SpResourceManager SAPI.SpResourceManager
CLSID_SpNotifyTranslator SAPI.SpNotifyTranslator<

The following are used in Automation:

CLSIDs ProgIDs
CLSID_SpTextSelectionInformation SAPI.SpTextSelectionInformation
CLSID_SpAudioFormat SAPI.SpAudioFormat
CLSID_SpWaveFormatEx SAPI.SpWaveFormatEx
CLSID_SpCustomStream SAPI.SpCustomStream
CLSID_SpFileStream SAPI.SpFileStream
CLSID_SpMemoryStream SAPI.SpMemoryStream

Here is a simple example of how to use the ProgIDs on 64-bit applications:

LPCOLESTR pProgID;
CLSID clsid = GUID_NULL;
CComPtr<ISpVoice> cpVoice;
pProgID = L"SAPI.SpVoice";
hr = CLSIDFromProgID(pProgID, &clsid;);
if(SUCCEEDED(hr))
{
	hr = cpVoice.CoCreateInstance(clsid);
	if(SUCCEEDED(hr))
		hr = cpVoice->Speak(L"This is a 64 bit test.", SPF_DEFAULT, 0);
	//do some more stuff here.
}