Thread: SAPI and UNICODE

  1. #1
    Registered User
    Join Date
    Sep 2003
    Posts
    4

    SAPI and UNICODE

    hello;

    With the SAPI you need to send your data as a "unsigned short" (at least as far as i know), so i get my data

    StxtL = GetWindowTextLength(SpEDT);
    StxtB = (PTSTR) malloc ((StxtL + 1) * sizeof (TCHAR)) ;
    GetWindowText(SpEDT,StxtB,StxtL + 1);


    so now StxtB has my text but how can i send that as a "unsigned short"?

    Also when i define _UNICODE i get 52 errors in my "microsoft speech sdk 5.1\include\spdebug.h" anyone know why this could be?

    thanks for your time.

  2. #2
    Master of the Universe! velius's Avatar
    Join Date
    Sep 2003
    Posts
    219
    What function are you trying to send your data with? Is it SendMessage()? Or something else?
    While you're breakin' down my back n'
    I been rackin' out my brain
    It don't matter how we make it
    'Cause it always ends the same
    You can push it for more mileage
    But your flaps r' wearin' thin
    And I could sleep on it 'til mornin'
    But this nightmare never ends
    Don't forget to call my lawyers
    With ridiculous demands
    An you can take the pity so far
    But it's more than I can stand
    'Cause this couchtrip's gettin' older
    Tell me how long has it been
    'Cause 5 years is forever
    An you haven't grown up yet
    -- You Could Be Mine - Guns N' Roses

  3. #3
    Registered User
    Join Date
    Sep 2003
    Posts
    4
    nah im sending my data as follows

    Code:
    ISpVoice * pVoice = NULL;
    
           HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
        
    	
    	if( SUCCEEDED( hr ) )
        {
    
            hr = pVoice->Speak(StxtB,0, NULL);
    .
    .
    .
    now this doesnt work because you cannont convert from char* to unsigned short *.


    thanks for your reply.

  4. #4
    Master of the Universe! velius's Avatar
    Join Date
    Sep 2003
    Posts
    219
    You can do a type cast. Alot of Microsoft's API's require a type cast as some point.
    While you're breakin' down my back n'
    I been rackin' out my brain
    It don't matter how we make it
    'Cause it always ends the same
    You can push it for more mileage
    But your flaps r' wearin' thin
    And I could sleep on it 'til mornin'
    But this nightmare never ends
    Don't forget to call my lawyers
    With ridiculous demands
    An you can take the pity so far
    But it's more than I can stand
    'Cause this couchtrip's gettin' older
    Tell me how long has it been
    'Cause 5 years is forever
    An you haven't grown up yet
    -- You Could Be Mine - Guns N' Roses

  5. #5
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    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);

Popular pages Recent additions subscribe to a feed