mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
Implemented EnumLanguageGroupLocalesA, EnumLanguageGroupLocalesW, EnumUILanguagesW, EnumUILanguagesA, GetUserGeoID, SetUserGeoID (from Wine)
svn path=/trunk/; revision=32827
This commit is contained in:
parent
a4d30ed637
commit
fe24e2761f
1 changed files with 341 additions and 17 deletions
|
@ -31,6 +31,23 @@
|
||||||
|
|
||||||
//static RTL_CRITICAL_SECTION LocalesListLock;
|
//static RTL_CRITICAL_SECTION LocalesListLock;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UILANGUAGE_ENUMPROCA procA;
|
||||||
|
UILANGUAGE_ENUMPROCW procW;
|
||||||
|
} u;
|
||||||
|
DWORD flags;
|
||||||
|
LONG_PTR param;
|
||||||
|
} ENUM_UILANG_CALLBACK;
|
||||||
|
|
||||||
|
static const WCHAR szLocaleKeyName[] = {
|
||||||
|
'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
|
||||||
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
||||||
|
'C','o','n','t','r','o','l','\\','N','l','s','\\','L','o','c','a','l','e',0
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @implemented
|
* @implemented
|
||||||
* RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
|
* RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42
|
||||||
|
@ -263,8 +280,151 @@ EnumDateFormatsExW(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL NLS_RegEnumValue(HANDLE hKey, UINT ulIndex,
|
||||||
|
LPWSTR szValueName, ULONG valueNameSize,
|
||||||
|
LPWSTR szValueData, ULONG valueDataSize)
|
||||||
|
{
|
||||||
|
BYTE buffer[80];
|
||||||
|
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
|
||||||
|
DWORD dwLen;
|
||||||
|
|
||||||
|
if (NtEnumerateValueKey( hKey, ulIndex, KeyValueFullInformation,
|
||||||
|
buffer, sizeof(buffer), &dwLen ) != STATUS_SUCCESS ||
|
||||||
|
info->NameLength > valueNameSize ||
|
||||||
|
info->DataLength > valueDataSize)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("info->Name %s info->DataLength %d\n", info->Name, info->DataLength);
|
||||||
|
|
||||||
|
memcpy( szValueName, info->Name, info->NameLength);
|
||||||
|
szValueName[info->NameLength / sizeof(WCHAR)] = '\0';
|
||||||
|
memcpy( szValueData, buffer + info->DataOffset, info->DataLength );
|
||||||
|
szValueData[info->DataLength / sizeof(WCHAR)] = '\0';
|
||||||
|
|
||||||
|
DPRINT("returning %s %s\n", szValueName, szValueData);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName)
|
||||||
|
{
|
||||||
|
UNICODE_STRING keyName;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
HANDLE hkey;
|
||||||
|
|
||||||
|
RtlInitUnicodeString( &keyName, szKeyName );
|
||||||
|
InitializeObjectAttributes(&attr, &keyName, 0, hRootKey, NULL);
|
||||||
|
|
||||||
|
if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS)
|
||||||
|
hkey = 0;
|
||||||
|
|
||||||
|
return hkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Callback function ptrs for EnumLanguageGrouplocalesA/W */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
LANGGROUPLOCALE_ENUMPROCA procA;
|
||||||
|
LANGGROUPLOCALE_ENUMPROCW procW;
|
||||||
|
DWORD dwFlags;
|
||||||
|
LGRPID lgrpid;
|
||||||
|
LONG_PTR lParam;
|
||||||
|
} ENUMLANGUAGEGROUPLOCALE_CALLBACKS;
|
||||||
|
|
||||||
|
/* Internal implementation of EnumLanguageGrouplocalesA/W */
|
||||||
|
static BOOL NLS_EnumLanguageGroupLocales(ENUMLANGUAGEGROUPLOCALE_CALLBACKS *lpProcs)
|
||||||
|
{
|
||||||
|
static const WCHAR szAlternateSortsKeyName[] = {
|
||||||
|
'A','l','t','e','r','n','a','t','e',' ','S','o','r','t','s','\0'
|
||||||
|
};
|
||||||
|
WCHAR szNumber[10], szValue[4];
|
||||||
|
HANDLE hKey;
|
||||||
|
BOOL bContinue = TRUE, bAlternate = FALSE;
|
||||||
|
LGRPID lgrpid;
|
||||||
|
ULONG ulIndex = 1; /* Ignore default entry of 1st key */
|
||||||
|
|
||||||
|
if (!lpProcs || !lpProcs->lgrpid || lpProcs->lgrpid > LGRPID_ARMENIAN)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpProcs->dwFlags)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hKey = NLS_RegOpenKey( 0, szLocaleKeyName );
|
||||||
|
|
||||||
|
if (!hKey)
|
||||||
|
DPRINT("NLS registry key not found. Please apply the default registry file 'wine.inf'\n");
|
||||||
|
|
||||||
|
while (bContinue)
|
||||||
|
{
|
||||||
|
if (NLS_RegEnumValue( hKey, ulIndex, szNumber, sizeof(szNumber),
|
||||||
|
szValue, sizeof(szValue) ))
|
||||||
|
{
|
||||||
|
lgrpid = wcstoul( szValue, NULL, 16 );
|
||||||
|
|
||||||
|
DPRINT("lcid %s, grpid %d (%smatched)\n", szNumber,
|
||||||
|
lgrpid, lgrpid == lpProcs->lgrpid ? "" : "not ");
|
||||||
|
|
||||||
|
if (lgrpid == lpProcs->lgrpid)
|
||||||
|
{
|
||||||
|
LCID lcid;
|
||||||
|
|
||||||
|
lcid = wcstoul( szNumber, NULL, 16 );
|
||||||
|
|
||||||
|
/* FIXME: native returns extra text for a few (17/150) locales, e.g:
|
||||||
|
* '00000437 ;Georgian'
|
||||||
|
* At present we only pass the LCID string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (lpProcs->procW)
|
||||||
|
bContinue = lpProcs->procW( lgrpid, lcid, szNumber, lpProcs->lParam );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char szNumberA[sizeof(szNumber)/sizeof(WCHAR)];
|
||||||
|
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, szNumber, -1, szNumberA, sizeof(szNumberA), 0, 0);
|
||||||
|
|
||||||
|
bContinue = lpProcs->procA( lgrpid, lcid, szNumberA, lpProcs->lParam );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ulIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Finished enumerating this key */
|
||||||
|
if (!bAlternate)
|
||||||
|
{
|
||||||
|
/* Enumerate alternate sorts also */
|
||||||
|
hKey = NLS_RegOpenKey( hKey, szAlternateSortsKeyName );
|
||||||
|
bAlternate = TRUE;
|
||||||
|
ulIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bContinue = FALSE; /* Finished both keys */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bContinue)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hKey)
|
||||||
|
NtClose( hKey );
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
|
@ -274,13 +434,22 @@ EnumLanguageGroupLocalesA(
|
||||||
DWORD dwFlags,
|
DWORD dwFlags,
|
||||||
LONG_PTR lParam)
|
LONG_PTR lParam)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
|
||||||
return 0;
|
|
||||||
|
DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam);
|
||||||
|
|
||||||
|
callbacks.procA = lpLangGroupLocaleEnumProc;
|
||||||
|
callbacks.procW = NULL;
|
||||||
|
callbacks.dwFlags = dwFlags;
|
||||||
|
callbacks.lgrpid = LanguageGroup;
|
||||||
|
callbacks.lParam = lParam;
|
||||||
|
|
||||||
|
return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
|
@ -290,8 +459,17 @@ EnumLanguageGroupLocalesW(
|
||||||
DWORD dwFlags,
|
DWORD dwFlags,
|
||||||
LONG_PTR lParam)
|
LONG_PTR lParam)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
|
||||||
return 0;
|
|
||||||
|
DPRINT("(%p,0x%08X,0x%08X,0x%08lX)\n", lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam);
|
||||||
|
|
||||||
|
callbacks.procA = NULL;
|
||||||
|
callbacks.procW = lpLangGroupLocaleEnumProc;
|
||||||
|
callbacks.dwFlags = dwFlags;
|
||||||
|
callbacks.lgrpid = LanguageGroup;
|
||||||
|
callbacks.lParam = lParam;
|
||||||
|
|
||||||
|
return NLS_EnumLanguageGroupLocales( lpLangGroupLocaleEnumProc ? &callbacks : NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -503,8 +681,19 @@ EnumSystemLocalesW (
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL CALLBACK enum_uilang_proc_a( HMODULE hModule, LPCSTR type,
|
||||||
|
LPCSTR name, WORD LangID, LONG_PTR lParam )
|
||||||
|
{
|
||||||
|
ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam;
|
||||||
|
char buf[20];
|
||||||
|
|
||||||
|
sprintf(buf, "%08x", (UINT)LangID);
|
||||||
|
return enum_uilang->u.procA( buf, enum_uilang->param );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
|
@ -513,13 +702,42 @@ EnumUILanguagesA(
|
||||||
DWORD dwFlags,
|
DWORD dwFlags,
|
||||||
LONG_PTR lParam)
|
LONG_PTR lParam)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
ENUM_UILANG_CALLBACK enum_uilang;
|
||||||
return 0;
|
|
||||||
|
DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam);
|
||||||
|
|
||||||
|
if(!lpUILanguageEnumProc) {
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(dwFlags) {
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_uilang.u.procA = lpUILanguageEnumProc;
|
||||||
|
enum_uilang.flags = dwFlags;
|
||||||
|
enum_uilang.param = lParam;
|
||||||
|
|
||||||
|
EnumResourceLanguagesA( hCurrentModule, (LPCSTR)RT_STRING,
|
||||||
|
(LPCSTR)LOCALE_ILANGUAGE, enum_uilang_proc_a,
|
||||||
|
(LONG_PTR)&enum_uilang);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK enum_uilang_proc_w( HMODULE hModule, LPCWSTR type,
|
||||||
|
LPCWSTR name, WORD LangID, LONG_PTR lParam )
|
||||||
|
{
|
||||||
|
static const WCHAR formatW[] = {'%','0','8','x',0};
|
||||||
|
ENUM_UILANG_CALLBACK *enum_uilang = (ENUM_UILANG_CALLBACK *)lParam;
|
||||||
|
WCHAR buf[20];
|
||||||
|
|
||||||
|
swprintf( buf, formatW, (UINT)LangID );
|
||||||
|
return enum_uilang->u.procW( buf, enum_uilang->param );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
|
@ -528,8 +746,28 @@ EnumUILanguagesW(
|
||||||
DWORD dwFlags,
|
DWORD dwFlags,
|
||||||
LONG_PTR lParam)
|
LONG_PTR lParam)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
ENUM_UILANG_CALLBACK enum_uilang;
|
||||||
return 0;
|
|
||||||
|
DPRINT("%p, %x, %lx\n", lpUILanguageEnumProc, dwFlags, lParam);
|
||||||
|
|
||||||
|
|
||||||
|
if(!lpUILanguageEnumProc) {
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(dwFlags) {
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_uilang.u.procW = lpUILanguageEnumProc;
|
||||||
|
enum_uilang.flags = dwFlags;
|
||||||
|
enum_uilang.param = lParam;
|
||||||
|
|
||||||
|
EnumResourceLanguagesW( hCurrentModule, (LPCWSTR)RT_STRING,
|
||||||
|
(LPCWSTR)LOCALE_ILANGUAGE, enum_uilang_proc_w,
|
||||||
|
(LONG_PTR)&enum_uilang);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1285,6 +1523,35 @@ GetUserDefaultUILanguage(VOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* create_registry_key
|
||||||
|
*
|
||||||
|
* Create the Control Panel\\International registry key.
|
||||||
|
*/
|
||||||
|
static inline HANDLE create_registry_key(void)
|
||||||
|
{
|
||||||
|
static const WCHAR intlW[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
|
||||||
|
'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
UNICODE_STRING nameW;
|
||||||
|
HANDLE hkey;
|
||||||
|
|
||||||
|
if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey ) != STATUS_SUCCESS) return 0;
|
||||||
|
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = hkey;
|
||||||
|
attr.ObjectName = &nameW;
|
||||||
|
attr.Attributes = 0;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
RtlInitUnicodeString( &nameW, intlW );
|
||||||
|
|
||||||
|
if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hkey = 0;
|
||||||
|
NtClose( attr.RootDirectory );
|
||||||
|
return hkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
@ -1293,8 +1560,36 @@ STDCALL
|
||||||
GetUserGeoID(
|
GetUserGeoID(
|
||||||
GEOCLASS GeoClass)
|
GEOCLASS GeoClass)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
GEOID ret = GEOID_NOT_AVAILABLE;
|
||||||
return 0;
|
static const WCHAR geoW[] = {'G','e','o',0};
|
||||||
|
static const WCHAR nationW[] = {'N','a','t','i','o','n',0};
|
||||||
|
WCHAR bufferW[40], *end;
|
||||||
|
DWORD count;
|
||||||
|
HANDLE hkey, hSubkey = 0;
|
||||||
|
UNICODE_STRING keyW;
|
||||||
|
const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW;
|
||||||
|
RtlInitUnicodeString( &keyW, nationW );
|
||||||
|
count = sizeof(bufferW);
|
||||||
|
|
||||||
|
if(!(hkey = create_registry_key())) return ret;
|
||||||
|
|
||||||
|
switch( GeoClass ){
|
||||||
|
case GEOCLASS_NATION:
|
||||||
|
if ((hSubkey = NLS_RegOpenKey(hkey, geoW)))
|
||||||
|
{
|
||||||
|
if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation,
|
||||||
|
(LPBYTE)bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength)
|
||||||
|
ret = wcstol((LPCWSTR)info->Data, &end, 10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GEOCLASS_REGION:
|
||||||
|
DPRINT("GEOCLASS_REGION not handled yet\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NtClose(hkey);
|
||||||
|
if (hSubkey) NtClose(hSubkey);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1806,15 +2101,44 @@ SetUserDefaultUILanguage(LANGID LangId)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
SetUserGeoID(
|
SetUserGeoID(
|
||||||
GEOID GeoId)
|
GEOID GeoId)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
static const WCHAR geoW[] = {'G','e','o',0};
|
||||||
return 0;
|
static const WCHAR nationW[] = {'N','a','t','i','o','n',0};
|
||||||
|
static const WCHAR formatW[] = {'%','i',0};
|
||||||
|
UNICODE_STRING nameW,keyW;
|
||||||
|
WCHAR bufferW[10];
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
HANDLE hkey;
|
||||||
|
|
||||||
|
if(!(hkey = create_registry_key())) return FALSE;
|
||||||
|
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = hkey;
|
||||||
|
attr.ObjectName = &nameW;
|
||||||
|
attr.Attributes = 0;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
RtlInitUnicodeString( &nameW, geoW );
|
||||||
|
RtlInitUnicodeString( &keyW, nationW );
|
||||||
|
|
||||||
|
if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
|
||||||
|
|
||||||
|
{
|
||||||
|
NtClose(attr.RootDirectory);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
swprintf(bufferW, formatW, GeoId);
|
||||||
|
NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (wcslen(bufferW) + 1) * sizeof(WCHAR));
|
||||||
|
NtClose(attr.RootDirectory);
|
||||||
|
NtClose(hkey);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue