Welcome to the world of unicode.
It should be noted form the outset:
A. Most WinApi function are only availiable in the Ansi version on Win95/98/Me (unless you use the Microsoft Layer for unicode).
B. A unicode character in Windows = unsigned short
C. A unicode character string = unsigned short *
D. You can use unicode versions of functions by adding the W suffix without making your entire project unicode.
E. To make a Windows project unicode you generally need to:
#define UNICODE
#define _UNICODE
The first one is for Windows and the second one is for the c lib functions.
Code:
StxtL = GetWindowTextLength(SpEDT);
StxtB = (PTSTR) malloc ((StxtL + 1) * sizeof (TCHAR)) ;
GetWindowText(SpEDT,StxtB,StxtL + 1);
This is what that will expand to in unicode:
StxtL = GetWindowTextLengthW(SpEDT);
StxtB = (LPWSTR) malloc((StxL + 1) * sizeof(WCHAR));
GetWindowTextW(SpEDT, StxtB, StxtL + 1);
As mentioned above the unicode version will only work in NT based OSs(NT/2000/XP).
If you want compatibility you need to convert the ansi results from WinApi functions to use COM functions which generally require LPWSTRs or BSTRs.
Note that casting a LPSTR to a LPWSTR or BSTR will not work as a wide string uses two bytes to store each character.
Depending on the compiler you use there are macros/classes that make this very easy. Otherwise here is a generic function to convert an ansi string to a BSTR. Note that a BSTR can be used where a wide string is required but the reverse is not always true.
Code:
HRESULT AnsiStrToBStr(LPCSTR szAnsiIn, BSTR * lpBstrOut) {
DWORD dwSize;
if (lpBstrOut == NULL) return E_INVALIDARG;
if (szAnsiIn == NULL) { *lpBstrOut = NULL; return NOERROR; }
// Get the number of unicode characters needed to convert szAnsiIn...
dwSize = MultiByteToWideChar(CP_ACP, 0, szAnsiIn, -1, NULL, 0);
if (dwSize == 0) return HRESULT_FROM_WIN32( GetLastError() );
// Allocate a BSTR of the required length...
// Note we minus one as SysAllocString takes the length
// of the string not including the null terminator while
// dwSize includes space for the null terminator.
*lpBstrOut = SysAllocStringLen(NULL, dwSize - 1);
if (*lpBstrOut == NULL) return E_OUTOFMEMORY;
// Convert szAnsiIn into the BSTR we allocated...
if ( !MultiByteToWideChar(CP_ACP, 0, szAnsiIn, -1, *lpBstrOut, dwSize) ) {
SysFreeString(*lpBstrOut);
return HRESULT_FROM_WIN32( GetLastError() );
}
return NOERROR;
}
And the other way:
Code:
HRESULT InternalBStrToAnsiStr(BSTR bstrIn, LPSTR * lpszOut) {
DWORD dwSize;
if (lpszOut == NULL) return E_INVALIDARG;
if (bstrIn == NULL) { *lpszOut = NULL; return NOERROR; }
// Get the number of characters needed to convert bStrIn...
dwSize = WideCharToMultiByte(CP_ACP, 0, bstrIn, -1, NULL, 0, NULL, NULL);
if (dwSize == 0) return HRESULT_FROM_WIN32( GetLastError() );
// Allocate memory of the required length...
*lpszOut = malloc(dwSize);
if (*lpszOut == NULL) return E_OUTOFMEMORY;
// Convert bstrIn into the memory we allocated...
if ( !WideCharToMultiByte(CP_ACP, 0, bstrIn, -1, *lpszOut, dwSize, NULL, NULL) ) {
free(*lpszOut);
return HRESULT_FROM_WIN32( GetLastError() );
}
return NOERROR;
}
A bstr is freed with SysFreeString(bstr). Use free() to free the result from the second function.
If you already have a wide string and need a bstr then life is simple:
SysAllocString(L"my string");
Note that an L prepended to a string literal create a wide string.
I hope I haven't been too confusing. If you have more questions please post.
Final code suggestion (no error checking):
Code:
BSTR bstr = NULL;
// Use ansi versions of WinApi for compatibility...
StxtL = GetWindowTextLength(SpEDT);
StxtB = (PTSTR) malloc ((StxtL + 1) * sizeof (TCHAR)) ;
GetWindowText(SpEDT,StxtB,StxtL + 1);
// Convert to a BSTR to use in the com function...
AnsiStrToBStr(StxtB, &bstr);
// Free the ansi version which we don't need anymore...
free(StxtB);
...
hr = pVoice->Speak(bstr,0, NULL);
SysFreeString(bstr);