//======================================================================= // // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. // // File: osdet.cpp // // Description: // // Ported to lib from V3 SLM DLL sources // //======================================================================= #include #include #include #include #include #include #include "wusafefn.h" #include // Forwared Declarations static LANGID CorrectGetSystemDefaultLangID(BOOL& bIsNT4, BOOL& bIsW95); static LANGID CorrectGetUserDefaultLangID(BOOL& bIsNT4, BOOL& bIsW95); static WORD CorrectGetACP(void); static WORD CorrectGetOEMCP(void); static LANGID MapLangID(LANGID langid); static bool FIsNECMachine(); static int aton(LPCTSTR ptr); static int atoh(LPCTSTR ptr); // // Constants and defines // const LANGID LANGID_ENGLISH = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); // 0x0409 const LANGID LANGID_GREEK = MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT); // 0x0408 const LANGID LANGID_JAPANESE = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT); // 0x0411 const LANGID LANGID_ARABIC = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA); // 0x0401 const LANGID LANGID_HEBREW = MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT); // 0x040D const LANGID LANGID_THAI = MAKELANGID(LANG_THAI, SUBLANG_DEFAULT); // 0x041E const TCHAR Win98_REGPATH_MACHLCID[] = _T("Control Panel\\Desktop\\ResourceLocale"); const TCHAR REGPATH_CODEPAGE[] = _T("SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage"); const TCHAR REGKEY_OEMCP[] = _T("OEMCP"); const TCHAR REGKEY_ACP[] = _T("ACP"); const TCHAR REGKEY_LOCALE[] = _T("Locale"); const TCHAR REGKEY_IE[] = _T("Software\\Microsoft\\Internet Explorer"); const TCHAR REGKEY_VERSION[] = _T("Version"); const TCHAR REGKEY_CP_INTERNATIONAL[] = _T(".DEFAULT\\Control Panel\\International"); const TCHAR REGKEY_CP_RESOURCELOCAL[] = _T("Control Panel\\Desktop\\ResourceLocale"); const TCHAR KERNEL32_DLL[] = _T("kernel32.dll"); const WORD CODEPAGE_ARABIC = 1256; const WORD CODEPAGE_HEBREW = 1255; const WORD CODEPAGE_THAI = 874; const WORD CODEPAGE_GREEK_MS = 737; const WORD CODEPAGE_GREEK_IBM = 869; // ISO code for Greek OS's on Windows 98 ONLY. const TCHAR ISOCODE_GREEK_MS[] = _T("el_MS"); const TCHAR ISOCODE_GREEK_IBM[] = _T("el_IBM"); // Registry keys to determine NEC machines const TCHAR NT5_REGPATH_MACHTYPE[] = _T("HARDWARE\\DESCRIPTION\\System"); const TCHAR NT5_REGKEY_MACHTYPE[] = _T("Identifier"); const TCHAR REGVAL_MACHTYPE_AT[] = _T("AT/AT COMPATIBLE"); const TCHAR REGVAL_MACHTYPE_NEC[] = _T("NEC PC-98"); const TCHAR REGVAL_GREEK_IBM[] = _T("869"); // Platform strings const TCHAR SZ_PLAT_WIN95[] = _T("w95"); const TCHAR SZ_PLAT_WIN98[] = _T("w98"); const TCHAR SZ_PLAT_WINME[] = _T("mil"); const TCHAR SZ_PLAT_NT4[] = _T("NT4"); const TCHAR SZ_PLAT_W2K[] = _T("W2k"); const TCHAR SZ_PLAT_WHISTLER[] = _T("Whi"); const TCHAR SZ_PLAT_UNKNOWN[] = _T("unk"); #define LOOKUP_OEMID(keybdid) HIBYTE(LOWORD((keybdid))) #define PC98_KEYBOARD_ID 0x0D // // Globals // // // We derive this from WINVER >= 0x0500 section of winnls.h // typedef LANGID (WINAPI * PFN_GetUserDefaultUILanguage) (void); typedef LANGID (WINAPI * PFN_GetSystemDefaultUILanguage) (void); typedef struct { LANGID langidUser; TCHAR * pszISOCode; } USER_LANGID; typedef struct { LANGID langidMachine; TCHAR * pszDefaultISOCode; int cElems; const USER_LANGID * grLangidUser; } MACH_LANGID; // We give a Japanese NEC machine its own ISO code. #define LANGID_JAPANESE 0x0411 #define ISOCODE_NEC _T("nec") #define ISOCODE_EN _T("en") #define grsize(langid) (sizeof(gr##langid) / sizeof(USER_LANGID)) // These are all the user langids associated with a particular machine. // NTRAID#NTBUG9-220063-2000/12/13-waltw 220063 IU: Specify mappings between GetSystemDefaultUILanguage LANGID and ISO/639/1988 // From Industry Update XML Schema.doc // 3.1 Language Codes // The languages are defined by ISO 639. They are represented by lowercase 2 letter symbols such as "en" for English, "fr" for French etc. // // 3.2 Country Codes // The country codes are defined in ISO 3166-1, using the Alpha-2 representation (two letter symbols). // // 3.3 Representation in Industry Update // Industry Update uses the RFC 1766 standard to manage the representation of language+locale symbols. // 3.3.1 Simple Case - Language Alone // When no regional flavor is considered for a language, or when it pertains to the "standard" version of the language, such as Portuguese as spoken in Portugal, it uses a straight ISO 639 symbol: // en, fr, de // // 3.3.2 Regional Variants // Managed by the RFCThe lowercase version of the Alpha-2 ISO 3166-1 country (or region) code is hyphenated to the language code, e.g. en-us, en-ca, fr-be, fr-ca, zh-hk, zh-tw… const USER_LANGID gr0404[] = {{0x0804,_T("zh-CN")},{0x1004,_T("zh-CN")}}; const USER_LANGID gr0407[] = {{0x0c07,_T("de-AT")},{0x0807,_T("de-CH")}}; const USER_LANGID gr0409[] = {{0x1c09,_T("en-ZA")},{0x0809,_T("en-GB")},{0x0c09,_T("en-AU")},{0x1009,_T("en-CA")}, {0x1409,_T("en-NZ")},{0x1809,_T("en-IE")}}; const USER_LANGID gr040c[] = {{0x080c,_T("fr-BE")},{0x0c0c,_T("fr-CA")},{0x100c,_T("fr-CH")}}; const USER_LANGID gr0410[] = {{0x0810,_T("it-CH")}}; const USER_LANGID gr0413[] = {{0x0813,_T("nl-BE")}}; const USER_LANGID gr0416[] = {{0x0816,_T("pt")}}; const USER_LANGID gr080a[] = {{0x040a,_T("es")},{0x080a,_T("es-MX")},{0x200a,_T("es-VE")},{0x240a,_T("es-CO")}, {0x280a,_T("es-PE")},{0x2c0a,_T("es-AR")},{0x300a,_T("es-EC")},{0x340a,_T("es-CL")}}; const USER_LANGID gr0c0a[] = {{0x040a,_T("es")},{0x080a,_T("es-MX")},{0x200a,_T("es-VE")},{0x240a,_T("es-CO")}, {0x280a,_T("es-PE")},{0x2c0a,_T("es-AR")},{0x300a,_T("es-EC")},{0x340a,_T("es-CL")}}; // These are all the machine langids. If there isn't an associated array of user langids, then // the user langid is irrelevant, and the default ISO language code should be used. If there is // an associated array of user langids, then it should be searched first and the specific langid used. // If no match is found in the user langids, then the default langid is used. const MACH_LANGID grLangids[] = { { 0x0401, _T("ar"), 0, NULL }, { 0x0403, _T("ca"), 0, NULL }, { 0x0404, _T("zh-TW"), grsize(0404), gr0404 }, { 0x0405, _T("cs"), 0, NULL }, { 0x0406, _T("da"), 0, NULL }, { 0x0407, _T("de"), grsize(0407), gr0407 }, { 0x0408, _T("el"), 0, NULL }, { 0x0409, _T("en"), grsize(0409), gr0409 }, { 0x040b, _T("fi"), 0, NULL }, { 0x040c, _T("fr"), grsize(040c), gr040c }, { 0x040d, _T("iw"), 0, NULL }, { 0x040e, _T("hu"), 0, NULL }, { 0x0410, _T("it"), grsize(0410), gr0410 }, { 0x0411, _T("ja"), 0, NULL }, { 0x0412, _T("ko"), 0, NULL }, { 0x0413, _T("nl"), grsize(0413), gr0413 }, { 0x0414, _T("no"), 0, NULL }, { 0x0415, _T("pl"), 0, NULL }, { 0x0416, _T("pt-BR"), grsize(0416), gr0416 }, { 0x0419, _T("ru"), 0, NULL }, { 0x041b, _T("sk"), 0, NULL }, { 0x041d, _T("sv"), 0, NULL }, { 0x041e, _T("th"), 0, NULL }, { 0x041f, _T("tr"), 0, NULL }, { 0x0424, _T("sl"), 0, NULL }, { 0x042d, _T("eu"), 0, NULL }, { 0x0804, _T("zh-CN"), 0, NULL }, { 0x080a, _T("es"), grsize(080a), gr080a }, { 0x0816, _T("pt"), 0, NULL }, { 0x0c0a, _T("es"), grsize(0c0a), gr0c0a } }; #define cLangids (sizeof(grLangids) / sizeof(MACH_LANGID)) static LANGID MapLangID(LANGID langid) { switch (PRIMARYLANGID(langid)) { case LANG_ARABIC: langid = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA); break; case LANG_CHINESE: if (SUBLANGID(langid) != SUBLANG_CHINESE_TRADITIONAL) langid = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED); break; case LANG_DUTCH: langid = MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH); break; case LANG_GERMAN: langid = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN); break; case LANG_ENGLISH: if (SUBLANGID(langid) != SUBLANG_ENGLISH_UK) langid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); break; case LANG_FRENCH: langid = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH); break; case LANG_ITALIAN: langid = MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN); break; case LANG_KOREAN: langid = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); break; case LANG_NORWEGIAN: langid = MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL); break; case LANG_PORTUGUESE: // We support both SUBLANG_PORTUGUESE and SUBLANG_PORTUGUESE_BRAZILIAN break; case LANG_SPANISH: langid = MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH); break; case LANG_SWEDISH: langid = MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH); break; }; return langid; } // return user language ID LANGID WINAPI GetUserLangID() { LOG_Block("GetUserLangID"); #ifdef __WUIUTEST // language spoofing HKEY hKey; DWORD dwLangID = 0; int error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUIUTEST, 0, KEY_READ, &hKey); if (ERROR_SUCCESS == error) { DWORD dwSize = sizeof(dwLangID); error = RegQueryValueEx(hKey, REGVAL_USER_LANGID, 0, 0, (LPBYTE)&dwLangID, &dwSize); RegCloseKey(hKey); if (ERROR_SUCCESS == error) { return (WORD) dwLangID; } } #endif WORD wCodePage = 0; BOOL bIsNT4 = FALSE; BOOL bIsW95 = FALSE; // // get base language id // LANGID langidCurrent = CorrectGetUserDefaultLangID(bIsNT4, bIsW95); // Passed by reference // // // special handling for languages // // // switch (langidCurrent) // { // case LANGID_ENGLISH: // // // enabled langauges // wCodePage = CorrectGetACP(); // if (CODEPAGE_ARABIC != wCodePage && // CODEPAGE_HEBREW != wCodePage && // CODEPAGE_THAI != wCodePage) // { // wCodePage = 0; // } // break; // // case LANGID_GREEK: // // // Greek IBM? // wCodePage = CorrectGetOEMCP(); // if (wCodePage != CODEPAGE_GREEK_IBM) // { // // if its not Greek IBM we assume its MS. The language code for Greek MS does not include // // the code page // wCodePage = 0; // } // break; // // case LANGID_JAPANESE: // // if (FIsNECMachine()) // { // wCodePage = 1; // } // // break; // // default: // // map language to the ones we support // langidCurrent = MapLangID(langidCurrent); // break; // } // // Special treatment of NT4 and W95 languages. // On NT4, Enabled Arabic, Thai, and Hebrew systems report as fully localized but we want to map them to Enabled // On W95, Enabled Thai is reported as Thai but we want to map to Enabled Thai // if (bIsNT4) { // NT4 switch (langidCurrent) { case LANGID_ARABIC: langidCurrent = LANGID_ENGLISH; break; case LANGID_HEBREW: langidCurrent = LANGID_ENGLISH; break; case LANGID_THAI: langidCurrent = LANGID_ENGLISH; break; } } else if (bIsW95) { // W95 - only tweek Thai if (langidCurrent == LANGID_THAI) { // wCodePage = CODEPAGE_THAI; langidCurrent = LANGID_ENGLISH; } } LOG_Driver(_T("Returning 0x%04x"), langidCurrent); return langidCurrent; } // return system language ID LANGID WINAPI GetSystemLangID() { LOG_Block("GetSystemLangID"); #ifdef __WUIUTEST // language spoofing HKEY hKey; DWORD dwLangID = 0; int error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUIUTEST, 0, KEY_READ, &hKey); if (ERROR_SUCCESS == error) { DWORD dwSize = sizeof(dwLangID); error = RegQueryValueEx(hKey, REGVAL_OS_LANGID, 0, 0, (LPBYTE)&dwLangID, &dwSize); RegCloseKey(hKey); if (ERROR_SUCCESS == error) { return (WORD) dwLangID; } } #endif WORD wCodePage = 0; BOOL bIsNT4 = FALSE; BOOL bIsW95 = FALSE; // // get base language id // LANGID langidCurrent = CorrectGetSystemDefaultLangID(bIsNT4, bIsW95); // Passed by reference // // // special handling for languages // // // switch (langidCurrent) // { // case LANGID_ENGLISH: // // // enabled langauges // wCodePage = CorrectGetACP(); // if (CODEPAGE_ARABIC != wCodePage && // CODEPAGE_HEBREW != wCodePage && // CODEPAGE_THAI != wCodePage) // { // wCodePage = 0; // } // break; // // case LANGID_GREEK: // // // Greek IBM? // wCodePage = CorrectGetOEMCP(); // if (wCodePage != CODEPAGE_GREEK_IBM) // { // // if its not Greek IBM we assume its MS. The language code for Greek MS does not include // // the code page // wCodePage = 0; // } // break; // // case LANGID_JAPANESE: // // if (FIsNECMachine()) // { // wCodePage = 1; // } // // break; // // default: // // map language to the ones we support // langidCurrent = MapLangID(langidCurrent); // break; // } // // Special treatment of NT4 and W95 languages. // On NT4, Enabled Arabic, Thai, and Hebrew systems report as fully localized but we want to map them to Enabled // On W95, Enabled Thai is reported as Thai but we want to map to Enabled Thai // if (bIsNT4) { // NT4 switch (langidCurrent) { case LANGID_ARABIC: langidCurrent = LANGID_ENGLISH; break; case LANGID_HEBREW: langidCurrent = LANGID_ENGLISH; break; case LANGID_THAI: langidCurrent = LANGID_ENGLISH; break; } } else if (bIsW95) { // W95 if (langidCurrent == LANGID_THAI) { // wCodePage = CODEPAGE_THAI; langidCurrent = LANGID_ENGLISH; } } LOG_Driver(_T("Returning 0x%04x"), langidCurrent); return langidCurrent; } HRESULT WINAPI DetectClientIUPlatform(PIU_PLATFORM_INFO pIuPlatformInfo) { LOG_Block("DetectClientIUPlatform"); HRESULT hr = S_OK; if (!pIuPlatformInfo) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; } ZeroMemory(pIuPlatformInfo, sizeof(IU_PLATFORM_INFO)); OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( !GetVersionEx(&osverinfo) ) { LOG_ErrorMsg(GetLastError()); return HRESULT_FROM_WIN32(GetLastError()); } #ifdef __WUIUTEST // platform spoofing HKEY hKey; int error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUIUTEST, 0, KEY_READ, &hKey); if (ERROR_SUCCESS == error) { DWORD dwSize = sizeof(DWORD); RegQueryValueEx(hKey, REGVAL_MAJORVER, 0, 0, (LPBYTE)&osverinfo.dwMajorVersion, &dwSize); RegQueryValueEx(hKey, REGVAL_MINORVER, 0, 0, (LPBYTE)&osverinfo.dwMinorVersion, &dwSize); RegQueryValueEx(hKey, REGVAL_BLDNUMBER, 0, 0, (LPBYTE)&osverinfo.dwBuildNumber, &dwSize); RegQueryValueEx(hKey, REGVAL_PLATFORMID, 0, 0, (LPBYTE)&osverinfo.dwPlatformId, &dwSize); int cchValueSize; (void) SafeRegQueryStringValueCch(hKey, REGVAL_SZCSDVER, osverinfo.szCSDVersion, ARRAYSIZE(osverinfo.szCSDVersion), &cchValueSize); RegCloseKey(hKey); } #endif if ( VER_PLATFORM_WIN32_WINDOWS == osverinfo.dwPlatformId || ( VER_PLATFORM_WIN32_NT == osverinfo.dwPlatformId && 5 > osverinfo.dwMajorVersion ) ) { // // We're on a Win9x platform or NT < 5.0 (Win2K) - just copy OSVERSIONINFO // memcpy(&pIuPlatformInfo->osVersionInfoEx, &osverinfo, sizeof(OSVERSIONINFO)); // // For Win9x platforms, remove redundant Major/Minor info from high word of build // if (VER_PLATFORM_WIN32_WINDOWS == osverinfo.dwPlatformId) { pIuPlatformInfo->osVersionInfoEx.dwBuildNumber = (0x0000FFFF & pIuPlatformInfo->osVersionInfoEx.dwBuildNumber); } } else { // // We're on Win2K or greater, get and copy OSVERSIONINFOEX // OSVERSIONINFOEX osverinfoex; osverinfoex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if ( !GetVersionEx((OSVERSIONINFO*)&osverinfoex) ) { LOG_ErrorMsg(GetLastError()); return HRESULT_FROM_WIN32(GetLastError()); } memcpy(&pIuPlatformInfo->osVersionInfoEx, &osverinfoex, sizeof(OSVERSIONINFOEX)); } // // Fill in the OEM BSTRs // if (FAILED(hr = GetOemBstrs(pIuPlatformInfo->bstrOEMManufacturer, pIuPlatformInfo->bstrOEMModel, pIuPlatformInfo->bstrOEMSupportURL))) { goto FreeBSTRsAndReturnError; } // // Fill in pIuPlatformInfo->fIsAdministrator // pIuPlatformInfo->fIsAdministrator = IsAdministrator(); return S_OK; FreeBSTRsAndReturnError: SafeSysFreeString(pIuPlatformInfo->bstrOEMManufacturer); SafeSysFreeString(pIuPlatformInfo->bstrOEMModel); SafeSysFreeString(pIuPlatformInfo->bstrOEMSupportURL); return hr; } static int atoh(LPCTSTR ptr) { int i = 0; //skip 0x if present if ( ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X') ) ptr += 2; for(;;) // until break { TCHAR ch = *ptr; if ('0' <= ch && ch <= '9') ch -= '0'; else if ('a' <= ch && ch <= 'f') ch -= ('a' - 10); else if ('A' <= ch && ch <= 'F') ch -= ('A' - 10); else break; i = 16 * i + (int)ch; ptr++; } return i; } static int aton(LPCTSTR ptr) { int i = 0; while ('0' <= *ptr && *ptr <= '9') { i = 10 * i + (int)(*ptr - '0'); ptr ++; } return i; } static LANGID CorrectGetSystemDefaultLangID(BOOL& bIsNT4, BOOL& bIsW95) { LOG_Block("CorrectGetSystemDefaultLangID"); LANGID langidMachine = LANGID_ENGLISH; // default is english bIsNT4 = FALSE; bIsW95 = FALSE; TCHAR szMachineLCID[MAX_PATH]; OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx(&osverinfo) ) { if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) { // if (5 == osverinfo.dwMajorVersion) { // langidMachine = GetSystemDefaultLangID(); typedef LANGID (WINAPI *PFN_GetSystemDefaultUILanguage)(void); // //kernel32.dll will always be loaded in process // HMODULE hLibModule = GetModuleHandle(KERNEL32_DLL); if (hLibModule) { PFN_GetSystemDefaultUILanguage fpnGetSystemDefaultUILanguage = (PFN_GetSystemDefaultUILanguage)GetProcAddress(hLibModule, "GetSystemDefaultUILanguage"); if (NULL != fpnGetSystemDefaultUILanguage) { langidMachine = fpnGetSystemDefaultUILanguage(); if (0 == langidMachine) { LOG_Driver(_T("GetSystemDefaultUILanguage() returned 0, setting langidMachine back to LANGID_ENGLISH")); langidMachine = LANGID_ENGLISH; } } } } else { // Get the OS lang from the registry to correct NT4 bug in // GetSystemDefaultLangID -- it returns the UI lang and // the UI bits get installed (incorrect) as opposed to the actual OS // lang bits. HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_USERS, REGKEY_CP_INTERNATIONAL, 0, KEY_QUERY_VALUE, &hKey)) { int cchValueSize = ARRAYSIZE(szMachineLCID); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, REGKEY_LOCALE, szMachineLCID, cchValueSize, &cchValueSize))) { langidMachine = LANGIDFROMLCID(atoh(szMachineLCID)); } else { LOG_Driver(_T("Failed to get langid from \"Locale\" registry value - defaults to LANGID_ENGLISH")); } RegCloseKey(hKey); } else { LOG_Driver(_T("Failed to open \"HKCU\\.DEFAULT\\Control Panel\\International\" - defaults to LANGID_ENGLISH")); } } if (osverinfo.dwMajorVersion == 4) // NT 4 { bIsNT4 = TRUE; } } else { // // hack around a problem introduced in Win95 and still existing // in Win98 whereby the System Langid is the same as the User Langid. // We must look in the registry to get the real value. // HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_CP_RESOURCELOCAL, 0, KEY_QUERY_VALUE, &hKey)) { int cchValueSize = ARRAYSIZE(szMachineLCID); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, NULL, szMachineLCID, cchValueSize, &cchValueSize))) { langidMachine = LANGIDFROMLCID(atoh(szMachineLCID)); } else { LOG_Driver(_T("Failed to get (Default) from \"HKCU\\Control Panel\\Desktop\\ResourceLocale\" - defaults to LANGID_ENGLISH")); } RegCloseKey(hKey); } else { LOG_Driver(_T("Failed to open \"HKCU\\Control Panel\\Desktop\\ResourceLocale\" - defaults to LANGID_ENGLISH")); } if ((osverinfo.dwMajorVersion == 4) && (osverinfo.dwMinorVersion <= 0)) // Windows 95 { bIsW95 = TRUE; } } } return langidMachine; } static LANGID CorrectGetUserDefaultLangID(BOOL& bIsNT4, BOOL& bIsW95) { LOG_Block("CorrectGetUserDefaultLangID"); LANGID langidMachine = LANGID_ENGLISH; // default is english bIsNT4 = FALSE; bIsW95 = FALSE; TCHAR szMachineLCID[MAX_PATH]; OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx(&osverinfo) ) { if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) { // // We shouldn't be using this function from NT, so just default to LANGID_ENGLISH // and log a message. This function will hopefully go away when we port to downlevel OS's // LOG_ErrorMsg(E_INVALIDARG); } else { // // hack around a problem introduced in Win95 and still existing // in Win98 whereby the System Langid is the same as the User Langid. // We must look in the registry to get the real value. // HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_CP_INTERNATIONAL, 0, KEY_QUERY_VALUE, &hKey)) { int cchValueSize = ARRAYSIZE(szMachineLCID); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, NULL, szMachineLCID, cchValueSize, &cchValueSize))) { langidMachine = LANGIDFROMLCID(atoh(szMachineLCID)); } else { LOG_Driver(_T("Failed to get (Default) from \"HKCU\\Control Panel\\Desktop\\ResourceLocale\" - defaults to LANGID_ENGLISH")); } RegCloseKey(hKey); } else { LOG_Driver(_T("Failed to open \"HKCU\\Control Panel\\Desktop\\ResourceLocale\" - defaults to LANGID_ENGLISH")); } if ((osverinfo.dwMajorVersion == 4) && (osverinfo.dwMinorVersion <= 0)) // Windows 95 { bIsW95 = TRUE; } } } return langidMachine; } static WORD CorrectGetACP(void) { LOG_Block("CorrectGetACP"); WORD wCodePage = 0; HKEY hKey; if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szCodePage[MAX_PATH]; int cchValueSize = ARRAYSIZE(szCodePage); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, REGKEY_ACP, szCodePage, cchValueSize, &cchValueSize))) { wCodePage = (WORD)aton(szCodePage); } else { LOG_Driver(_T("Failed SafeRegQueryStringValueCch in CorrectGetACP - defaulting to code page 0")); } RegCloseKey(hKey); } else { LOG_Driver(_T("Failed RegOpenKeyEx in CorrectGetACP - defaulting to code page 0")); } return wCodePage; } static WORD CorrectGetOEMCP(void) { LOG_Block("CorrectGetOEMCP"); WORD wCodePage = 0; HKEY hKey; if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szCodePage[MAX_PATH]; int cchValueSize = ARRAYSIZE(szCodePage); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, REGKEY_OEMCP, szCodePage, cchValueSize, &cchValueSize))) { wCodePage = (WORD)aton(szCodePage); } else { LOG_Driver(_T("Failed SafeRegQueryStringValueCch in CorrectGetOEMCP - defaulting to code page 0")); } RegCloseKey(hKey); } else { LOG_Driver(_T("Failed RegOpenKeyEx in CorrectGetOEMCP - defaulting to code page 0")); } return wCodePage; } static bool FIsNECMachine() { LOG_Block("FIsNECMachine"); bool fNEC = false; OSVERSIONINFO osverinfo; LONG lErr; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osverinfo)) { if (osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { HKEY hKey; TCHAR tszMachineType[50]; int cchValueSize; if (ERROR_SUCCESS == (lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT5_REGPATH_MACHTYPE, 0, KEY_QUERY_VALUE, &hKey))) { cchValueSize = ARRAYSIZE(tszMachineType); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, NT5_REGKEY_MACHTYPE, tszMachineType, cchValueSize, &cchValueSize))) { if (lstrcmp(tszMachineType, REGVAL_MACHTYPE_NEC) == 0) { fNEC = true; } } else { LOG_ErrorMsg(lErr); LOG_Driver(_T("Failed SafeRegQueryStringValueCch in FIsNECMachine - defaulting to fNEC = false")); } RegCloseKey(hKey); } else { LOG_ErrorMsg(lErr); LOG_Driver(_T("Failed RegOpenKeyEx in FIsNECMachine - defaulting to fNEC = false")); } } else // enOSWin98 { // All NEC machines have NEC keyboards for Win98. NEC // machine detection is based on this. if (LOOKUP_OEMID(GetKeyboardType(1)) == PC98_KEYBOARD_ID) { fNEC = true; } else { LOG_Driver(_T("LOOKUP_OEMID(GetKeyboardType(1)) == PC98_KEYBOARD_ID was FALSE: defaulting to fNEC = false")); } } } return fNEC; } // // NOTES: If you pass in a NULL pointer you'll get it right back. // dwcBuffLen is in characters, not bytes. // LPTSTR GetIdentPlatformString(LPTSTR pszPlatformBuff, DWORD dwcBuffLen) { HRESULT hr=S_OK; LOG_Block("GetIdentPlatformString"); if (NULL == pszPlatformBuff || 1 > dwcBuffLen) { LOG_ErrorMsg(E_INVALIDARG); return pszPlatformBuff; } LPTSTR szOSNamePtr = (LPTSTR) SZ_PLAT_UNKNOWN; OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osverinfo)) { if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { // ADD CHECK FOR NEPTUNE HERE!!!!! if ( osverinfo.dwMinorVersion >= 90) // Millenium { szOSNamePtr = (LPTSTR) SZ_PLAT_WINME; } else if (osverinfo.dwMinorVersion > 0 && osverinfo.dwMinorVersion < 90) // Windows 98 { szOSNamePtr = (LPTSTR) SZ_PLAT_WIN98; } else // Windows 95 { szOSNamePtr = (LPTSTR) SZ_PLAT_WIN95; } } else // osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT { if ( osverinfo.dwMajorVersion == 4 ) // NT 4 { szOSNamePtr = (LPTSTR) SZ_PLAT_NT4; } else if (osverinfo.dwMajorVersion == 5) // NT 5 { if (0 == osverinfo.dwMinorVersion) { szOSNamePtr = (LPTSTR) SZ_PLAT_W2K; } else if (1 <= osverinfo.dwMinorVersion) { szOSNamePtr = (LPTSTR) SZ_PLAT_WHISTLER; } } } } if(lstrlen(szOSNamePtr) + 1 > (int) dwcBuffLen) { pszPlatformBuff[0] = 0; } else { //The length is validated above. So this function cannot possibly fail hr=StringCchCopyEx(pszPlatformBuff,dwcBuffLen,szOSNamePtr,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) pszPlatformBuff[0] = 0; } return pszPlatformBuff; } // // GetIdentLocaleString and related functions ported from Drizzle Utils // ///////////////////////////////////////////////////////////////////////////// // DistinguishGreekOSs // Append additional code to distinguish the Greek OS version. // // Parameters: // pszISOCodeOut- // Greek-specific ISO code is appended to this parameter. ///////////////////////////////////////////////////////////////////////////// void DistinguishGreekOSs(const TCHAR*& pszISOCodeOut /* out */) { LOG_Block("DistinguishGreekOSs"); // // Default ISO code to Greek OS (MS). // pszISOCodeOut = ISOCODE_GREEK_MS; // // Determine from the registry which version of Greek OS. There are // two versions of the Greek OS. // HKEY hKey; DWORD type; TCHAR tszOSType[50]; int cchValueSize; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { cchValueSize = ARRAYSIZE(tszOSType); if (SUCCEEDED(SafeRegQueryStringValueCch(hKey, REGKEY_OEMCP, tszOSType, cchValueSize, &cchValueSize))) { if (0 == lstrcmp(tszOSType, REGVAL_GREEK_IBM)) { // Greek2 pszISOCodeOut = ISOCODE_GREEK_IBM; } } RegCloseKey(hKey); } } ///////////////////////////////////////////////////////////////////////////// // HandleExceptionCases // Take care of a few exception cases (i.e. Greek OS). // // Parameters: // langidMachine- // Contains a language id for the current OS. // // pszISOCode- // Points to a valid language id string for the current OS. ///////////////////////////////////////////////////////////////////////////// inline void HandleExceptionCases(const LANGID& langidMachine, /* in */ const TCHAR*& pszISOCode /* out */) { LOG_Block("HandleExceptionCases"); // NEC machines are treated as having their own langid. // See if we have a Japanese machine, then check if it // is NEC. if (LANGID_JAPANESE == langidMachine) { if (FIsNECMachine()) { pszISOCode = ISOCODE_NEC; } return; } // Windows 98 has two versions of Greek OS distinguished // only by a key in the registry. if(LANGID_GREEK == langidMachine) { OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (! GetVersionEx(&osverinfo)) { return; } if (osverinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { if (osverinfo.dwMinorVersion > 0) { DistinguishGreekOSs(pszISOCode); } return; } } } ///////////////////////////////////////////////////////////////////////////// // langidCorrectGetSystemDefaultLangID // Make this return what GetSystemDefaultLangID should have returned // under Win98. // // Parameters: // // Comments : ///////////////////////////////////////////////////////////////////////////// LANGID langidCorrectGetSystemDefaultLangID(void) { LOG_Block("langidCorrectGetSystemDefaultLangID"); LANGID langidMachine = LANGID_ENGLISH; // default is english OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx(&osverinfo) ) { if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) { langidMachine = GetSystemDefaultLangID(); } else { // hack around a problem introduced in Win95 and still existing // in Win98 whereby the System Langid is the same as the User Langid. // We must look in the registry to get the real value. HKEY hKey; // determine if we should log transmissions if ( RegOpenKeyEx( HKEY_CURRENT_USER, Win98_REGPATH_MACHLCID, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { TCHAR tszMachineLCID[MAX_PATH]; int cchValueSize = ARRAYSIZE(tszMachineLCID); if (FAILED(SafeRegQueryStringValueCch(hKey, NULL, tszMachineLCID, cchValueSize, &cchValueSize))) { //The size of tszMachineLCID is much larger than the Source string. So cannot possibly fail if(FAILED(StringCchCopyEx(tszMachineLCID,MAX_PATH,_T("00000409"),NULL,NULL,MISTSAFE_STRING_FLAGS))) return langidMachine; } // Now convert to hexadecimal. langidMachine = LANGIDFROMLCID(atoh(tszMachineLCID)); RegCloseKey(hKey); } } } return langidMachine; } // // NOTES: If you pass in a NULL pointer you'll get it right back. // dwcBuffLen is in characters, not bytes. // LPTSTR GetIdentLocaleString(LPTSTR pszISOCode, DWORD dwcBuffLen) { LOG_Block("GetIdentLocaleString"); HRESULT hr=S_OK; if (NULL == pszISOCode || 1 > dwcBuffLen) { LOG_ErrorMsg(E_INVALIDARG); return pszISOCode; } // if we don't find any matching machine langids, we go to the english page. LPTSTR pszISOCodePtr = ISOCODE_EN; // First get the system and user LCID. LANGID langidMachine = langidCorrectGetSystemDefaultLangID(); // First, locate the machine langid in the table. for ( int iMachine = 0; iMachine < cLangids; iMachine++ ) { if ( grLangids[iMachine].langidMachine == langidMachine ) { // set the default langid in case we don't find a matching user langid. pszISOCodePtr = grLangids[iMachine].pszDefaultISOCode; // Found the machine langid, now lookup the user langid if ( grLangids[iMachine].cElems != 0 ) { LANGID langidUser = GetUserDefaultLangID(); // We check for specific user langids for ( int iUser = 0; iUser < grLangids[iMachine].cElems; iUser++ ) { if ( grLangids[iMachine].grLangidUser[iUser].langidUser == langidUser ) { pszISOCodePtr = grLangids[iMachine].grLangidUser[iUser].pszISOCode; break; } } } break; } } // Take care of a few exceptions. // HandleExceptionCases(langidMachine, pszISOCodePtr); if(lstrlen(pszISOCodePtr) + 1 > (int) dwcBuffLen) { pszISOCode[0] = 0; } else { hr=StringCchCopyEx(pszISOCode,dwcBuffLen,pszISOCodePtr,NULL,NULL,MISTSAFE_STRING_FLAGS); //cannot possibly fail since length is already validated if(FAILED(hr)) { pszISOCode[0] = 0; } } return pszISOCode; } BOOL LookupLocaleStringFromLCID(LCID lcid, LPTSTR pszISOCode, DWORD cchISOCode) { LOG_Block("LookupLocaleStringFromLCID"); TCHAR szCountry[MAX_PATH]; BOOL fRet = FALSE; if (GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, pszISOCode, cchISOCode) == FALSE) { LOG_ErrorMsg(GetLastError()); goto done; } szCountry[0] = _T('-'); if (GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, szCountry + 1, ARRAYSIZE(szCountry) - 1) == FALSE) { LOG_ErrorMsg(GetLastError()); goto done; } else { HRESULT hr; hr = StringCchCatEx(pszISOCode, cchISOCode, szCountry, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); LOG_ErrorMsg(hr); pszISOCode[0] = _T('\0'); goto done; } } fRet = TRUE; done: return fRet; } // // NOTES: If you pass in a NULL pointer you'll get it right back. // dwcBuffLen is in characters, not bytes. // LPTSTR LookupLocaleString(LPTSTR pszISOCode, DWORD dwcBuffLen, BOOL fIsUser) { LOG_Block("LookupLocaleString"); TCHAR szCtryName[MAX_PATH]; LANGID langid = 0; LCID lcid = 0; PFN_GetUserDefaultUILanguage pfnGetUserDefaultUILanguage = NULL; PFN_GetSystemDefaultUILanguage pfnGetSystemDefaultUILanguage = NULL; HMODULE hModule = NULL; HRESULT hr=S_OK; if (NULL == pszISOCode) { LOG_ErrorMsg(ERROR_INVALID_PARAMETER); return NULL; } // // If we hit an error, return a "Error" string // const TCHAR szError[] = _T("Error"); if (lstrlen(szError) < (int) dwcBuffLen) { hr=StringCchCopyEx(pszISOCode,dwcBuffLen,szError,NULL,NULL,MISTSAFE_STRING_FLAGS); //This should not ideally happen if(FAILED(hr)) { LOG_ErrorMsg(HRESULT_CODE(hr)); pszISOCode[0] = 0; goto CleanUp; } } else { pszISOCode[0] = 0; } OSVERSIONINFO osverinfo; osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx(&osverinfo) ) { if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT && 5 <= osverinfo.dwMajorVersion) { // // Windows 2000 and greater (Windows XP) // //kernel32.dll will always be loaded in process // hModule = GetModuleHandle(KERNEL32_DLL); if (NULL == hModule) { LOG_ErrorMsg(GetLastError()); goto CleanUp; } if (TRUE == fIsUser) { // // We want the MUI language rather than the LOCALE_USER_DEFAULT and we are >= Win2k // pfnGetUserDefaultUILanguage = (PFN_GetUserDefaultUILanguage) GetProcAddress(hModule, "GetUserDefaultUILanguage"); if (NULL == pfnGetUserDefaultUILanguage) { LOG_ErrorMsg(GetLastError()); goto CleanUp; } langid = pfnGetUserDefaultUILanguage(); if (0 == langid) { LOG_ErrorMsg(E_FAIL); goto CleanUp; } lcid = MAKELCID(langid, SORT_DEFAULT); } else { pfnGetSystemDefaultUILanguage = (PFN_GetSystemDefaultUILanguage) GetProcAddress(hModule, "GetSystemDefaultUILanguage"); if (NULL == pfnGetSystemDefaultUILanguage) { LOG_ErrorMsg(GetLastError()); goto CleanUp; } langid = pfnGetSystemDefaultUILanguage(); if (0 == langid) { LOG_ErrorMsg(E_FAIL); goto CleanUp; } lcid = MAKELCID(langid, SORT_DEFAULT); } if (FALSE == fIsUser && FIsNECMachine()) { // // 523660 Website is not distinguishing the JA_NEC and JA machine types // // For context="OS", special case NEC machines and just return "nec" for // lstrcpyn(pszISOCode, _T("nec"), (int) dwcBuffLen); } else { // don't check for error return because the previous code didn't LookupLocaleStringFromLCID(lcid, pszISOCode, dwcBuffLen); } } else { // // Use methods ported from V3 to get local strings // // if we don't find any matching machine langids, we go to the english page. LPTSTR pszISOCodePtr = ISOCODE_EN; // First get the system or user LCID. LANGID langidMachine = fIsUser ? GetUserLangID() : GetSystemLangID(); // First, locate the machine langid in the table. for ( int iMachine = 0; iMachine < cLangids; iMachine++ ) { if ( grLangids[iMachine].langidMachine == langidMachine ) { // set the default langid in case we don't find a matching user langid. pszISOCodePtr = grLangids[iMachine].pszDefaultISOCode; // Found the machine langid, now lookup the user langid if ( grLangids[iMachine].cElems != 0 ) { LANGID langidUser = fIsUser ? GetUserDefaultLangID() : GetSystemDefaultLangID(); // We check for specific user langids for ( int iUser = 0; iUser < grLangids[iMachine].cElems; iUser++ ) { if ( grLangids[iMachine].grLangidUser[iUser].langidUser == langidUser ) { pszISOCodePtr = grLangids[iMachine].grLangidUser[iUser].pszISOCode; break; } } } break; } } // Take care of a few exceptions. // HandleExceptionCases(langidMachine, pszISOCodePtr); if(lstrlen(pszISOCodePtr) < (int) dwcBuffLen) { hr=StringCchCopyEx(pszISOCode,dwcBuffLen,pszISOCodePtr,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { LOG_ErrorMsg(HRESULT_CODE(hr)); pszISOCode[0] = 0; goto CleanUp; } } } } else { LOG_ErrorMsg(GetLastError()); } CleanUp: return pszISOCode; }