Figure 1  
Windows 9x Unicode Functions

API
Source
Windows 95
Windows 98
TextOutW
Win32 API
Yes
Yes
TextOutExW
Win32 API
Yes
Yes
GetCharWidthW
Win32 API
Yes
Yes
GetTextExtentPointW
Win32 API
Yes
Yes
GetTextExtentPoint32W
Win32 API
Yes
Yes
MessageBoxW
Win32 API
Yes
Yes
MessageBoxExW
Win32 API
Yes
Yes
lstrcpyW
Win32 API
No
Yes
lstrcatW
Win32 API
No
Yes
lstrlenW
Win32 API
No
Yes
wcs* functions
CRTL
Yes
Yes
Script* functions
Uniscribe
Yes (except Far East versions)
Yes


Figure 2   A Unicode Wrapper for RegisterClassEx

ATOM WINAPI RegisterClassExAU(CONST WNDCLASSEXW *lpWcw)
{
    WNDCLASSEXA wca                   ;
    CHAR        szClassName[MAX_NAME] ;

    wca.cbSize       = sizeof(WNDCLASSEXA) ;
    wca.cbClsExtra   = lpWcw->cbClsExtra   ;
    wca.cbWndExtra   = lpWcw->cbWndExtra   ;
    wca.hbrBackground= lpWcw->hbrBackground;
    wca.hCursor      = lpWcw->hCursor      ;
    wca.hIcon        = lpWcw->hIcon        ;
    wca.hIconSm      = lpWcw->hIconSm      ;
    wca.hInstance    = lpWcw->hInstance    ;
    wca.lpfnWndProc  = lpWcw->lpfnWndProc  ;
    wca.style        = lpWcw->style        ;

    if(NULL == lpWcw->lpszClassName) {
        return 0 ;
    }
    wca.lpszClassName   = szClassName ;

    if(!WideCharToMultiByte(CP_ACP, 0, lpWcw->lpszClassName, -1, szClassName, 
                            MAX_NAME, NULL, NULL)) {
        return 0 ;
    }

    // Note: This only works if the menu id is a constant rather than a string
    wca.lpszMenuName = (LPSTR) lpWcw->lpszMenuName ; 
    return RegisterClassExA(&wca) ;
}

Figure 3   Message Converter Function



BOOL WINAPI ConvertMessageAU(
    IN   HWND hWnd , IN UINT message , IN OUT  WPARAM *pwParam ,
    IN OUT  LPARAM *plParam)
{
    static CHAR s_sANSIchar[3] = "\0" ;
    int nReturn ;

    switch (message)
    {
    case WM_CHAR:
        // We have to go through all this malarky because DBCS characters 
        // arrive one byte at a time. In this sample application, most of
        // this code is never used because DBCS chars are handled by 	        
	// WM_IME_CHAR below. You can comment out that case 
        // (and the corresponding one in WinProc) to test this code.
        if(!s_sANSIchar[0]) {  // No lead byte already waiting for trail byte
            s_sANSIchar[0] = (CHAR) *pwParam ; 

            if(IsDBCSLeadByteEx(g_InputCodePage , *pwParam)) {
                // This is a lead byte. Save it and wait for trail byte
                return FALSE;
            }
            // Not a DBCS character. Convert to Unicode.
            MultiByteToWideChar(g_InputCodePage , 0, s_sANSIchar, 1, 
                                (LPWSTR) pwParam, 1) ;
            s_sANSIchar[0] = 0 ;    // Reset to indicate no Lead byte waiting
            return TRUE ;
        }
        else { // Have lead byte, pwParam should contain the trail byte
            s_sANSIchar[1] = (CHAR) *pwParam ;
            // Convert both bytes into one Unicode character
            MultiByteToWideChar(g_InputCodePage , 0, s_sANSIchar, 2, 
                                (LPWSTR) pwParam, 1) ;
            s_sANSIchar[0] = 0 ;    // Reset to non-waiting state
            return TRUE ;
        }

    case WM_IME_CHAR:
        // The next 3 lines replace all but one line in the WM_CHAR case above. 
        // This is why it's best to use WM_IME_CHAR rather than WM_CHAR 
        // to get DBCS chars in ANSI mode.
        s_sANSIchar[1] = LOBYTE((WORD) *pwParam) ;
        s_sANSIchar[0] = HIBYTE((WORD) *pwParam) ;
        
        nReturn = MultiByteToWideChar(g_InputCodePage , 0, s_sANSIchar, 2, 
                                      (LPWSTR) pwParam, 1) ;
        return (nReturn > 0) ;

    case WM_INPUTLANGCHANGEREQUEST:
    {
        HKL NewInputLocale = (HKL) *plParam ;

        LANGID wPrimaryLang = 
            PRIMARYLANGID(LANGIDFROMLCID(LOWORD(NewInputLocale))) ;

        // Reject change to Indic keyboards, since they are not supported in 
        // ANSI mode
        switch (wPrimaryLang) {
            case LANG_ASSAMESE :
            case LANG_BENGALI :
            case LANG_GUJARATI :
            case LANG_HINDI :
            // Other Indian scripts omitted
            case LANG_TAMIL :
            case LANG_TELUGU :
                return FALSE ;
        }
        g_InputCodePage = LangToCodePage( LOWORD(NewInputLocale) ) ; 
           // Utility defined below
        return TRUE ;
    }
    default:
        return TRUE ;
    }
}


Figure 4   Handy Windows 2000 Functions


LANGID GetSystemDefaultUILanguage() 
Returns the LANGID for the system default UI language, or 0 on failure.
LANGID GetUserDefaultUILanguage()
Returns the LANGID for the current user's UI language, or 0 on failure.
BOOL EnumUILanguages(
    UILANGUAGE_ENUMPROC lpUILanguageEnumProc, 
    // Pointer to enumeration callback function
    DWORD dwFlags, // Flags -- reserved, must be 0
    LPARAM lParam  // Parameter to pass to the callback function
) ; 
Enumerates the UI languages that are available on the system.
BOOL IsValidLanguageGroup(
    LGRPID LanguageGroup, // Language group identifier to validate
    DWORD dwFlags         // specifies validity test
) ;
IsValidLanguageGroup returns TRUE or FALSE as follows: if dwFlags is LGRPID_INSTALLED, the return value is TRUE if and only if the language of the language group identifier is both supported and installed; if dwFlags is LGRPID_SUPPORTED, the return value is TRUE if and only if language group identifier is supported.
BOOL EnumSystemLanguageGroups( 
    LANGUAGEGROUP_ENUMPROC lpLanguageGroupEnumProc, 
    // Pointer to enumeration callback function
    DWORD dwFlags, // Language groups to enumerate
    LPARAM lParam // Parameter to pass to the callback function
) ;
Enumerates the language groups that are installed or sup--ported. Set flag LGRPID_INSTALLED or LGRPID_SUPPORTED in dwFlags to specify which to enumerate.
BOOL EnumLanguageGroupLocales(
    // Pointer to Enumeration callback function
    LANGGROUPLOCALE_ENUMPROC lpLangGroupLocaleEnumProc, 
    LGRPID                   LanguageGroup, // Language group to evaluate
    DWORD                    dwFlags,   // Option flags
    LONG                     lParam     // lParam to pass the Callback function
);
Enumerates all the locales supported by a given language group.