Implemented EnumLanguageGroupLocalesA, EnumLanguageGroupLocalesW, EnumUILanguagesW, EnumUILanguagesA, GetUserGeoID, SetUserGeoID (from Wine)

svn path=/trunk/; revision=32827
This commit is contained in:
Dmitry Chapyshev 2008-04-03 09:49:14 +00:00
parent a4d30ed637
commit fe24e2761f

View file

@ -31,6 +31,23 @@
//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
* 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
STDCALL
@ -274,13 +434,22 @@ EnumLanguageGroupLocalesA(
DWORD dwFlags,
LONG_PTR lParam)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
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
STDCALL
@ -290,8 +459,17 @@ EnumLanguageGroupLocalesW(
DWORD dwFlags,
LONG_PTR lParam)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
ENUMLANGUAGEGROUPLOCALE_CALLBACKS callbacks;
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
STDCALL
@ -513,13 +702,42 @@ EnumUILanguagesA(
DWORD dwFlags,
LONG_PTR lParam)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
ENUM_UILANG_CALLBACK enum_uilang;
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
STDCALL
@ -528,8 +746,28 @@ EnumUILanguagesW(
DWORD dwFlags,
LONG_PTR lParam)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
ENUM_UILANG_CALLBACK enum_uilang;
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
*/
@ -1293,8 +1560,36 @@ STDCALL
GetUserGeoID(
GEOCLASS GeoClass)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
GEOID ret = GEOID_NOT_AVAILABLE;
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
STDCALL
SetUserGeoID(
GEOID GeoId)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
static const WCHAR geoW[] = {'G','e','o',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;
}