From: Piotr Caban piotr@codeweavers.com
--- dlls/ntdll/locale.c | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 545cc628909..967bbf62354 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -195,43 +195,65 @@ void get_resource_lcids( LANGID *user, LANGID *user_neutral, LANGID *system ) }
-static NTSTATUS get_dummy_preferred_ui_language( DWORD flags, LANGID lang, ULONG *count, - WCHAR *buffer, ULONG *size ) +static NTSTATUS add_preferred_ui_language( DWORD flags, LANGID lang, WCHAR *buffer, ULONG *pos, ULONG size ) { - WCHAR name[LOCALE_NAME_MAX_LENGTH + 2]; + WCHAR name[LOCALE_NAME_MAX_LENGTH + 1]; NTSTATUS status; ULONG len;
- FIXME("(0x%lx %#x %p %p %p) returning a dummy value (current locale)\n", flags, lang, count, buffer, size); + TRACE( "adding language: %x\n", lang );
if (flags & MUI_LANGUAGE_ID) swprintf( name, ARRAY_SIZE(name), L"%04lX", lang ); else { UNICODE_STRING str;
- if (lang == LOCALE_CUSTOM_UNSPECIFIED) - NtQueryInstallUILanguage( &lang ); - str.Buffer = name; str.MaximumLength = sizeof(name); status = RtlLcidToLocaleName( lang, &str, 0, FALSE ); if (status) return status; }
- len = wcslen( name ) + 2; + len = wcslen( name ) + 1; name[len - 1] = 0; if (buffer) { - if (len > *size) + if (len + *pos > size) { - *size = len; + *pos += len; return STATUS_BUFFER_TOO_SMALL; } - memcpy( buffer, name, len * sizeof(WCHAR) ); + memcpy( buffer + *pos, name, len * sizeof(WCHAR) ); + } + + *pos += len; + return STATUS_SUCCESS; +} + + +static NTSTATUS get_dummy_preferred_ui_language( DWORD flags, LANGID lang, ULONG *count, + WCHAR *buffer, ULONG *size ) +{ + NTSTATUS status; + ULONG pos; + + FIXME("(0x%lx %#x %p %p %p) returning a dummy value (current locale)\n", flags, lang, count, buffer, size); + + if (!(flags & MUI_LANGUAGE_ID) && lang == LOCALE_CUSTOM_UNSPECIFIED) + NtQueryInstallUILanguage( &lang ); + + pos = 0; + status = add_preferred_ui_language( flags, lang, buffer, &pos, *size ); + if (status != STATUS_BUFFER_TOO_SMALL && status) return status; + if (status == STATUS_BUFFER_TOO_SMALL || pos == *size) + { + *size = pos + 1; + return STATUS_BUFFER_TOO_SMALL; } - *size = len; + + if (buffer) buffer[pos] = 0; + *size = pos + 1; *count = 1; - TRACE("returned variable content: %ld, "%s", %ld\n", *count, debugstr_w(buffer), *size); return STATUS_SUCCESS;
}
From: Piotr Caban piotr@codeweavers.com
--- dlls/ntdll/locale.c | 107 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 967bbf62354..3fae931942b 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -45,6 +45,12 @@ static struct norm_table *norm_tables[16]; static const NLS_LOCALE_HEADER *locale_table; static const WCHAR *locale_strings;
+static RTL_RUN_ONCE mui_init_once = RTL_RUN_ONCE_INIT; +static struct +{ + LCID system[2]; +} mui_settings; +
static WCHAR casemap( USHORT *table, WCHAR ch ) { @@ -194,6 +200,82 @@ void get_resource_lcids( LANGID *user, LANGID *user_neutral, LANGID *system ) *system = LANGIDFROMLCID( system_lcid ); }
+static UINT load_lang_list( HKEY hkey, const WCHAR *value, LCID *lcid ) +{ + char initial_buf[4096]; + char *buf = initial_buf; + UNICODE_STRING name; + NTSTATUS status; + UINT ret = 0; + DWORD size; + + RtlInitUnicodeString( &name, value ); + status = NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buf, sizeof(initial_buf), &size ); + while (status == STATUS_BUFFER_OVERFLOW) + { + if (buf != initial_buf) RtlFreeHeap( GetProcessHeap(), 0, buf ); + buf = RtlAllocateHeap( GetProcessHeap(), 0, size ); + status = NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buf, size, &size ); + } + if (!status && ((KEY_VALUE_PARTIAL_INFORMATION *)buf)->Type == REG_MULTI_SZ) + { + const WCHAR *p = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buf)->Data; + + while(*p) + { + if (!RtlLocaleNameToLcid( p, lcid, 0 )) + { + ret = 1; + break; + } + p += wcslen( p ) + 1; + } + } + + if (buf != initial_buf) RtlFreeHeap( GetProcessHeap(), 0, buf ); + return ret; +} + +static DWORD WINAPI load_mui_settings(RTL_RUN_ONCE *once, void *param, void **context) +{ + UNICODE_STRING mui_cached = RTL_CONSTANT_STRING( + L"Control Panel\Desktop\MuiCached" ); + UNICODE_STRING settings = RTL_CONSTANT_STRING( + L"\Registry\Machine\System\CurrentControlSet\Control\MUI\Settings" ); + static const WCHAR machine_preferred_lang[] = L"MachinePreferredUILanguages"; + static const WCHAR preferred_lang[] = L"PreferredUILanguages"; + OBJECT_ATTRIBUTES attr; + HANDLE hkey, user_hkey; + UINT count = 0; + LANGID lang; + + if (RtlOpenCurrentUser( KEY_QUERY_VALUE, &user_hkey )) user_hkey = 0; + + attr.Length = sizeof(attr); + attr.RootDirectory = user_hkey; + attr.ObjectName = &mui_cached; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (user_hkey && !NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) + { + count = load_lang_list( hkey, machine_preferred_lang, mui_settings.system ); + NtClose( hkey ); + } + + attr.RootDirectory = 0; + attr.ObjectName = &settings; + if (!count && !NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) + { + count = load_lang_list( hkey, preferred_lang, mui_settings.system ); + NtClose( hkey ); + } + NtQueryInstallUILanguage( &lang ); + if (lang != mui_settings.system[0]) mui_settings.system[count] = lang; + + if (user_hkey) NtClose( user_hkey ); + return TRUE; +}
static NTSTATUS add_preferred_ui_language( DWORD flags, LANGID lang, WCHAR *buffer, ULONG *pos, ULONG size ) { @@ -278,14 +360,33 @@ NTSTATUS WINAPI RtlGetProcessPreferredUILanguages( DWORD flags, ULONG *count, WC NTSTATUS WINAPI RtlGetSystemPreferredUILanguages( DWORD flags, ULONG unknown, ULONG *count, WCHAR *buffer, ULONG *size ) { - LANGID ui_language; + NTSTATUS status; + ULONG i, pos; + + TRACE( "%08lx, %lx, %p, %p, %p\n", flags, unknown, count, buffer, size );
if (flags & ~(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS)) return STATUS_INVALID_PARAMETER; if ((flags & MUI_LANGUAGE_NAME) && (flags & MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER; if (*size && !buffer) return STATUS_INVALID_PARAMETER;
- NtQueryInstallUILanguage( &ui_language ); - return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size ); + RtlRunOnceExecuteOnce( &mui_init_once, load_mui_settings, NULL, NULL ); + + pos = 0; + for (i = 0; i < ARRAY_SIZE(mui_settings.system) && mui_settings.system[i]; i++) + { + status = add_preferred_ui_language( flags, mui_settings.system[i], buffer, &pos, *size ); + if (status && status != STATUS_BUFFER_TOO_SMALL) return status; + } + + status = STATUS_SUCCESS; + if (buffer) + { + if (pos >= *size) status = STATUS_BUFFER_TOO_SMALL; + else buffer[pos] = 0; + } + *size = pos + 1; + *count = i; + return status; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/ntdll/locale.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 3fae931942b..90f57644ba2 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -49,6 +49,7 @@ static RTL_RUN_ONCE mui_init_once = RTL_RUN_ONCE_INIT; static struct { LCID system[2]; + LCID user[2]; } mui_settings;
@@ -242,6 +243,7 @@ static DWORD WINAPI load_mui_settings(RTL_RUN_ONCE *once, void *param, void **co L"Control Panel\Desktop\MuiCached" ); UNICODE_STRING settings = RTL_CONSTANT_STRING( L"\Registry\Machine\System\CurrentControlSet\Control\MUI\Settings" ); + UNICODE_STRING desktop = RTL_CONSTANT_STRING( L"Control Panel\Desktop" ); static const WCHAR machine_preferred_lang[] = L"MachinePreferredUILanguages"; static const WCHAR preferred_lang[] = L"PreferredUILanguages"; OBJECT_ATTRIBUTES attr; @@ -273,6 +275,17 @@ static DWORD WINAPI load_mui_settings(RTL_RUN_ONCE *once, void *param, void **co NtQueryInstallUILanguage( &lang ); if (lang != mui_settings.system[0]) mui_settings.system[count] = lang;
+ count = 0; + attr.RootDirectory = user_hkey; + attr.ObjectName = &desktop; + if (user_hkey && !NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) + { + count = load_lang_list( hkey, preferred_lang, mui_settings.user ); + NtClose( hkey ); + } + NtQueryDefaultUILanguage( &lang ); + if (lang != mui_settings.user[0]) mui_settings.user[count] = lang; + if (user_hkey) NtClose( user_hkey ); return TRUE; } @@ -410,14 +423,33 @@ NTSTATUS WINAPI RtlGetThreadPreferredUILanguages( DWORD flags, ULONG *count, WCH NTSTATUS WINAPI RtlGetUserPreferredUILanguages( DWORD flags, ULONG unknown, ULONG *count, WCHAR *buffer, ULONG *size ) { - LANGID ui_language; + NTSTATUS status; + ULONG i, pos; + + TRACE( "%08lx, %lx, %p, %p, %p\n", flags, unknown, count, buffer, size );
if (flags & ~(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER; if ((flags & MUI_LANGUAGE_NAME) && (flags & MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER; if (*size && !buffer) return STATUS_INVALID_PARAMETER;
- NtQueryDefaultUILanguage( &ui_language ); - return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size ); + RtlRunOnceExecuteOnce( &mui_init_once, load_mui_settings, NULL, NULL ); + + pos = 0; + for (i = 0; i < ARRAY_SIZE(mui_settings.user) && mui_settings.user[i]; i++) + { + status = add_preferred_ui_language( flags, mui_settings.user[i], buffer, &pos, *size ); + if (status && status != STATUS_BUFFER_TOO_SMALL) return status; + } + + status = STATUS_SUCCESS; + if (buffer) + { + if (pos >= *size) status = STATUS_BUFFER_TOO_SMALL; + else buffer[pos] = 0; + } + *size = pos + 1; + *count = i; + return status; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/ntdll/locale.c | 14 ++++++++++++++ dlls/ntdll/ntdll.spec | 1 + 2 files changed, 15 insertions(+)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 90f57644ba2..d8c30cafcb9 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -367,6 +367,20 @@ NTSTATUS WINAPI RtlGetProcessPreferredUILanguages( DWORD flags, ULONG *count, WC }
+/************************************************************************** + * RtlpQueryDefaultUILanguage (NTDLL.@) + */ +NTSTATUS WINAPI RtlpQueryDefaultUILanguage( LANGID *lang, BOOLEAN system ) +{ + TRACE( "%p, %x\n", lang, system ); + + RtlRunOnceExecuteOnce( &mui_init_once, load_mui_settings, NULL, NULL ); + + *lang = system ? mui_settings.system[0] : mui_settings.user[0]; + return STATUS_SUCCESS; +} + + /************************************************************************** * RtlGetSystemPreferredUILanguages (NTDLL.@) */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 9147cdca3cd..4ca9d153930 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1133,6 +1133,7 @@ @ stdcall RtlpNtOpenKey(ptr long ptr) @ stdcall RtlpNtQueryValueKey(long ptr ptr ptr ptr) @ stdcall RtlpNtSetValueKey(ptr long ptr long) +@ stdcall RtlpQueryDefaultUILanguage(ptr long) @ stdcall RtlpUnWaitCriticalSection(ptr) @ stdcall RtlpWaitForCriticalSection(ptr) @ stdcall RtlxAnsiStringToUnicodeSize(ptr) RtlAnsiStringToUnicodeSize
From: Piotr Caban piotr@codeweavers.com
--- dlls/ntdll/locale.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index d8c30cafcb9..6199e7d0756 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -1065,7 +1065,9 @@ NTSTATUS WINAPI RtlLcidToLocaleName( LCID lcid, UNICODE_STRING *str, ULONG flags lcid = system_lcid; break; case LOCALE_CUSTOM_UI_DEFAULT: - return STATUS_UNSUCCESSFUL; + RtlRunOnceExecuteOnce( &mui_init_once, load_mui_settings, NULL, NULL ); + lcid = mui_settings.user[0]; + break; case LOCALE_CUSTOM_UNSPECIFIED: return STATUS_INVALID_PARAMETER_1; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index c5be4cf95e2..b482a0d6b89 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -4852,6 +4852,9 @@ INT WINAPI DECLSPEC_HOTPATCH CompareStringW( LCID lcid, DWORD flags, const WCHAR { const WCHAR *locale = LOCALE_NAME_USER_DEFAULT; const NLS_LOCALE_LCID_INDEX *entry; + WCHAR buf[LOCALE_NAME_MAX_LENGTH + 1]; + UNICODE_STRING str; + NTSTATUS status;
switch (lcid) { @@ -4860,7 +4863,17 @@ INT WINAPI DECLSPEC_HOTPATCH CompareStringW( LCID lcid, DWORD flags, const WCHAR case LOCALE_SYSTEM_DEFAULT: case LOCALE_CUSTOM_DEFAULT: case LOCALE_CUSTOM_UNSPECIFIED: + break; case LOCALE_CUSTOM_UI_DEFAULT: + str.Buffer = buf; + str.MaximumLength = sizeof(buf); + status = RtlLcidToLocaleName( lcid, &str, 0, FALSE ); + if (status) + { + SetLastError( RtlNtStatusToDosError( status )); + return 0; + } + locale = buf; break; default: if (lcid == user_lcid || lcid == system_lcid) break;
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index b482a0d6b89..d83afa5cc62 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -5192,6 +5192,9 @@ INT WINAPI DECLSPEC_HOTPATCH FindNLSString( LCID lcid, DWORD flags, const WCHAR { const WCHAR *locale = LOCALE_NAME_USER_DEFAULT; const NLS_LOCALE_LCID_INDEX *entry; + WCHAR buf[LOCALE_NAME_MAX_LENGTH + 1]; + UNICODE_STRING str; + NTSTATUS status;
switch (lcid) { @@ -5200,7 +5203,17 @@ INT WINAPI DECLSPEC_HOTPATCH FindNLSString( LCID lcid, DWORD flags, const WCHAR case LOCALE_SYSTEM_DEFAULT: case LOCALE_CUSTOM_DEFAULT: case LOCALE_CUSTOM_UNSPECIFIED: + break; case LOCALE_CUSTOM_UI_DEFAULT: + str.Buffer = buf; + str.MaximumLength = sizeof(buf); + status = RtlLcidToLocaleName( lcid, &str, 0, FALSE ); + if (status) + { + SetLastError( RtlNtStatusToDosError( status )); + return 0; + } + locale = buf; break; default: if (lcid == user_lcid || lcid == system_lcid) break;
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index d83afa5cc62..9487e65a8c0 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -6975,6 +6975,9 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringW( LCID lcid, DWORD flags, const WCHAR * { const WCHAR *locale = LOCALE_NAME_USER_DEFAULT; const NLS_LOCALE_LCID_INDEX *entry; + WCHAR buf[LOCALE_NAME_MAX_LENGTH + 1]; + UNICODE_STRING str; + NTSTATUS status;
switch (lcid) { @@ -6983,7 +6986,17 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringW( LCID lcid, DWORD flags, const WCHAR * case LOCALE_SYSTEM_DEFAULT: case LOCALE_CUSTOM_DEFAULT: case LOCALE_CUSTOM_UNSPECIFIED: + break; case LOCALE_CUSTOM_UI_DEFAULT: + str.Buffer = buf; + str.MaximumLength = sizeof(buf); + status = RtlLcidToLocaleName( lcid, &str, 0, FALSE ); + if (status) + { + SetLastError( RtlNtStatusToDosError( status )); + return 0; + } + locale = buf; break; default: if (lcid == user_lcid || lcid == system_lcid) break;
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 9487e65a8c0..00e52dc7129 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -725,6 +725,9 @@ const NLS_LOCALE_DATA * WINAPI NlsValidateLocale( LCID *lcid, ULONG flags ) const NLS_LOCALE_LCNAME_INDEX *name_entry; const NLS_LOCALE_LCID_INDEX *entry; const NLS_LOCALE_DATA *locale; + WCHAR buf[LOCALE_NAME_MAX_LENGTH + 1]; + UNICODE_STRING str; + NTSTATUS status;
switch (*lcid) { @@ -735,9 +738,19 @@ const NLS_LOCALE_DATA * WINAPI NlsValidateLocale( LCID *lcid, ULONG flags ) case LOCALE_USER_DEFAULT: case LOCALE_CUSTOM_DEFAULT: case LOCALE_CUSTOM_UNSPECIFIED: - case LOCALE_CUSTOM_UI_DEFAULT: *lcid = user_lcid; return user_locale; + case LOCALE_CUSTOM_UI_DEFAULT: + str.Buffer = buf; + str.MaximumLength = sizeof(buf); + status = RtlLcidToLocaleName( *lcid, &str, 0, FALSE ); + if (!status) status = RtlLocaleNameToLcid( buf, lcid, 0 ); + if (status) + { + SetLastError( RtlNtStatusToDosError( status )); + return NULL; + } + /* fall through */ default: if (!(entry = find_lcid_entry( *lcid ))) return NULL; locale = get_locale_data( entry->idx );
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 5 ++++- include/winternl.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 00e52dc7129..5856ae38325 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -6437,7 +6437,10 @@ INT WINAPI DECLSPEC_HOTPATCH GetUserDefaultLocaleName( LPWSTR name, INT len ) */ LANGID WINAPI DECLSPEC_HOTPATCH GetUserDefaultUILanguage(void) { - return LANGIDFROMLCID( GetUserDefaultLCID() ); + LANGID lang; + + RtlpQueryDefaultUILanguage( &lang, FALSE ); + return lang; }
diff --git a/include/winternl.h b/include/winternl.h index 8406d4b8d46..d868d53e779 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -5062,6 +5062,7 @@ NTSYSAPI NTSTATUS WINAPI RtlpNtEnumerateSubKey(HANDLE,UNICODE_STRING *, ULONG); NTSYSAPI NTSTATUS WINAPI RtlpNtMakeTemporaryKey(HANDLE); NTSYSAPI NTSTATUS WINAPI RtlpNtOpenKey(PHANDLE,ACCESS_MASK,OBJECT_ATTRIBUTES*); NTSYSAPI NTSTATUS WINAPI RtlpNtSetValueKey(HANDLE,ULONG,const void*,ULONG); +NTSYSAPI NTSTATUS WINAPI RtlpQueryDefaultUILanguage(LANGID*,BOOLEAN); NTSYSAPI NTSTATUS WINAPI RtlpWaitForCriticalSection(RTL_CRITICAL_SECTION *); NTSYSAPI NTSTATUS WINAPI RtlpUnWaitCriticalSection(RTL_CRITICAL_SECTION *); NTSYSAPI NTSTATUS WINAPI TpAllocCleanupGroup(TP_CLEANUP_GROUP **);