windows-nt/Source/XPSP1/NT/enduser/windows.com/lib/detect/osdet.cpp
2020-09-26 16:20:57 +08:00

1466 lines
45 KiB
C++
Raw Blame History

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: osdet.cpp
//
// Description:
//
// Ported to lib from V3 SLM DLL sources
//
//=======================================================================
#include <windows.h>
#include <wuiutest.h>
#include <tchar.h>
#include <osdet.h>
#include <logging.h>
#include <iucommon.h>
#include "wusafefn.h"
#include<MISTSAFE.h>
// 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<74>
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 <language/>
//
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;
}