ReactOS 0.4.15-dev-7942-gd23573b
locale.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/locale.c
5 * PURPOSE: Locale (Language) Support for the Executive
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Thomas Weidenmueller (w3seek@reactos.org
9 */
10
11/* INCLUDES ******************************************************************/
12
13#include <ntoskrnl.h>
14#define NDEBUG
15#include <debug.h>
16
17/* GLOBALS *******************************************************************/
18
19/* System IDs: EN_US */
22
23/* UI/Thread IDs: Same as system */
26
27/* DEFINES *******************************************************************/
28
29#define BOGUS_LOCALE_ID 0xFFFF0000
30
31/* PRIVATE FUNCTIONS *********************************************************/
32
45static
46__inline
50{
52
53 /* Is this a null-terminated string type? */
54 if (LocaleData->Type != REG_SZ)
55 {
56 return FALSE;
57 }
58
59 /* Does it have a consistent length? */
60 if (LocaleData->DataLength < sizeof(WCHAR))
61 {
62 return FALSE;
63 }
64
65 /* Is the locale set and null-terminated? */
66 Data = (PWSTR)LocaleData->Data;
67 if (Data[0] != L'1' || Data[1] != UNICODE_NULL)
68 {
69 return FALSE;
70 }
71
72 /* All of the conditions above are met */
73 return TRUE;
74}
75
101static
105{
107 HANDLE NlsLocaleKey = NULL, AltSortKey = NULL, LangGroupKey = NULL;
108 OBJECT_ATTRIBUTES NlsLocalKeyAttrs, AltSortKeyAttrs, LangGroupKeyAttrs;
110 WCHAR ValueBuffer[20], LocaleIdBuffer[20];
112 UNICODE_STRING LocaleIdString;
113 static UNICODE_STRING NlsLocaleKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale");
114 static UNICODE_STRING AltSortKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Locale\\Alternate Sorts");
115 static UNICODE_STRING LangGroupPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Nls\\Language Groups");
116
117 /* Initialize the registry path attributes */
118 InitializeObjectAttributes(&NlsLocalKeyAttrs,
119 &NlsLocaleKeyPath,
121 NULL,
122 NULL);
123
124 InitializeObjectAttributes(&AltSortKeyAttrs,
125 &AltSortKeyPath,
127 NULL,
128 NULL);
129
130 InitializeObjectAttributes(&LangGroupKeyAttrs,
131 &LangGroupPath,
133 NULL,
134 NULL);
135
136 /* Copy the locale ID into a buffer */
137 swprintf(LocaleIdBuffer,
138 L"%08lx",
139 (ULONG)LocaleId);
140
141 /* And build the LCID string */
142 RtlInitUnicodeString(&LocaleIdString, LocaleIdBuffer);
143
144 /* Open the NLS locale key */
145 Status = ZwOpenKey(&NlsLocaleKey,
147 &NlsLocalKeyAttrs);
148 if (!NT_SUCCESS(Status))
149 {
150 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", NlsLocaleKeyPath, Status);
151 return Status;
152 }
153
154 /* Open the NLS alternate sort locales key */
155 Status = ZwOpenKey(&AltSortKey,
157 &AltSortKeyAttrs);
158 if (!NT_SUCCESS(Status))
159 {
160 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", AltSortKeyPath, Status);
161 goto Quit;
162 }
163
164 /* Open the NLS language groups key */
165 Status = ZwOpenKey(&LangGroupKey,
167 &LangGroupKeyAttrs);
168 if (!NT_SUCCESS(Status))
169 {
170 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", LangGroupPath, Status);
171 goto Quit;
172 }
173
174 /* Check if the captured locale ID exists in the list of other locales */
175 BufferKey = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
176 Status = ZwQueryValueKey(NlsLocaleKey,
177 &LocaleIdString,
179 BufferKey,
180 sizeof(ValueBuffer),
182 if (!NT_SUCCESS(Status))
183 {
184 /* We failed, retry by looking at the alternate sorts locales */
185 Status = ZwQueryValueKey(AltSortKey,
186 &LocaleIdString,
188 BufferKey,
189 sizeof(ValueBuffer),
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT1("Failed to query value from Alternate Sorts key (Status 0x%lx)\n", Status);
194 goto Quit;
195 }
196 }
197
198 /* Ensure the queried locale is of the right key type with a sane length */
199 if (BufferKey->Type != REG_SZ ||
200 BufferKey->DataLength < sizeof(WCHAR))
201 {
202 DPRINT1("The queried locale is of bad value type or length (Type %lu, DataLength %lu)\n",
203 BufferKey->Type, BufferKey->DataLength);
205 goto Quit;
206 }
207
208 /* We got what we need, now query the locale from the language groups */
209 RtlInitUnicodeString(&LocaleIdString, (PWSTR)BufferKey->Data);
210 Status = ZwQueryValueKey(LangGroupKey,
211 &LocaleIdString,
213 BufferKey,
214 sizeof(ValueBuffer),
216 if (!NT_SUCCESS(Status))
217 {
218 DPRINT1("Failed to query value from Language Groups key (Status 0x%lx)\n", Status);
219 goto Quit;
220 }
221
222 /*
223 * We have queried the locale with its data. However we are not finished here yet,
224 * because the locale data could be malformed or the locale itself was not set
225 * so ensure all of these conditions are met.
226 */
227 if (!ExpValidateNlsLocaleData(BufferKey))
228 {
229 DPRINT1("The locale data is not valid!\n");
231 }
232
233Quit:
234 if (LangGroupKey != NULL)
235 {
236 ZwClose(LangGroupKey);
237 }
238
239 if (AltSortKey != NULL)
240 {
241 ZwClose(AltSortKey);
242 }
243
244 if (NlsLocaleKey != NULL)
245 {
246 ZwClose(NlsLocaleKey);
247 }
248
249 return Status;
250}
251
253NTAPI
255 OUT LANGID* LanguageId)
256{
257 UCHAR ValueBuffer[256];
261 RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
263 UNICODE_STRING ValueString;
265 ULONG Value;
266 HANDLE UserKey;
269 PAGED_CODE();
270
271 /* Setup the key name */
273
274 /* Open the use key */
276 if (!NT_SUCCESS(Status)) return Status;
277
278 /* Initialize the attributes and open the key */
280 &KeyName,
282 UserKey,
283 NULL);
285 if (NT_SUCCESS(Status))
286 {
287 /* Set buffer and query the current value */
288 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
289 Status = ZwQueryValueKey(KeyHandle,
290 &ValueName,
292 ValueBuffer,
293 sizeof(ValueBuffer),
294 &ValueLength);
295 if (NT_SUCCESS(Status))
296 {
297 /* Success, is the value the right type? */
298 if (ValueInfo->Type == REG_SZ)
299 {
300 /* It is. Initialize the data and convert it */
301 RtlInitUnicodeString(&ValueString, (PWSTR)ValueInfo->Data);
302 Status = RtlUnicodeStringToInteger(&ValueString, 16, &Value);
303 if (NT_SUCCESS(Status))
304 {
305 /* Return the language */
306 *LanguageId = (USHORT)Value;
307 }
308 }
309 else
310 {
311 /* Fail */
313 }
314 }
315
316 /* Close the key */
318 }
319
320 /* Close the user key and return */
321 ZwClose(UserKey);
322 return Status;
323}
324
326NTAPI
328 IN LANGID LanguageId)
329{
331 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
333 WCHAR ValueBuffer[8];
335 HANDLE UserHandle;
338 PAGED_CODE();
339
340 /* Check that the passed language ID is not bogus */
341 if (LanguageId & BOGUS_LOCALE_ID)
342 {
344 }
345
346 /* Setup the key name */
348
349 /* Open the use key */
350 Status = RtlOpenCurrentUser(KEY_WRITE, &UserHandle);
351 if (!NT_SUCCESS(Status)) return Status;
352
353 /* Initialize the attributes */
355 &KeyName,
357 UserHandle,
358 NULL);
359
360 /* Validate the language ID */
362 if (NT_SUCCESS(Status))
363 {
364 /* Open the key */
366 if (NT_SUCCESS(Status))
367 {
368 /* Setup the value name */
369 ValueLength = swprintf(ValueBuffer,
370 L"%04lX",
371 (ULONG)LanguageId);
372
373 /* Set the length for the call and set the value */
374 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
375 Status = ZwSetValueKey(KeyHandle,
376 &ValueName,
377 0,
378 REG_SZ,
379 ValueBuffer,
381
382 /* Close the handle for this key */
384 }
385 }
386
387 /* Close the user key and return status */
388 ZwClose(UserHandle);
389 return Status;
390}
391
392/* PUBLIC FUNCTIONS **********************************************************/
393
395NTAPI
397 OUT PLCID DefaultLocaleId)
398{
400 PAGED_CODE();
401
402 /* Enter SEH for probing */
404 {
405 /* Check if we came from user mode */
407 {
408 /* Probe the language ID */
409 ProbeForWriteLangId(DefaultLocaleId);
410 }
411
412 /* Check if we have a user profile */
413 if (UserProfile)
414 {
415 /* Return session wide thread locale */
416 *DefaultLocaleId = MmGetSessionLocaleId();
417 }
418 else
419 {
420 /* Return system locale */
421 *DefaultLocaleId = PsDefaultSystemLocaleId;
422 }
423 }
425 {
426 /* Get exception code */
428 }
429 _SEH2_END;
430
431 /* Return status */
432 return Status;
433}
434
436NTAPI
438 IN LCID DefaultLocaleId)
439{
443 UNICODE_STRING LocaleString;
446 WCHAR ValueBuffer[20];
447 HANDLE UserKey = NULL;
449 UCHAR KeyValueBuffer[256];
450 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
451 PAGED_CODE();
452
453 /* Check that the passed locale ID is not bogus */
454 if (DefaultLocaleId & BOGUS_LOCALE_ID)
455 {
457 }
458
459 /* Check if we have a profile */
460 if (UserProfile)
461 {
462 /* Open the user's key */
464 if (!NT_SUCCESS(Status)) return Status;
465
466 /* Initialize the registry location */
467 RtlInitUnicodeString(&KeyName, L"Control Panel\\International");
469 }
470 else
471 {
472 /* Initialize the system registry location */
474 L"\\Registry\\Machine\\System\\CurrentControlSet"
475 L"\\Control\\Nls\\Language");
476 RtlInitUnicodeString(&ValueName, L"Default");
477 }
478
479 /* Initialize the object attributes */
481 &KeyName,
483 UserKey,
484 NULL);
485
486 /* Check if we don't have a default locale yet */
487 if (!DefaultLocaleId)
488 {
489 /* Open the key for reading */
491 if (!NT_SUCCESS(Status))
492 {
493 goto Cleanup;
494 }
495
496 /* Query the key value */
497 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
498 Status = ZwQueryValueKey(KeyHandle,
499 &ValueName,
501 KeyValueInformation,
502 sizeof(KeyValueBuffer),
503 &ValueLength);
504 if (!NT_SUCCESS(Status))
505 {
506 goto Cleanup;
507 }
508
509 /* Check if this is a REG_DWORD */
510 if ((KeyValueInformation->Type == REG_DWORD) &&
511 (KeyValueInformation->DataLength == sizeof(ULONG)))
512 {
513 /* It contains the LCID as a DWORD */
514 DefaultLocaleId = *((ULONG*)KeyValueInformation->Data);
515 }
516 /* Otherwise check for a REG_SZ */
517 else if (KeyValueInformation->Type == REG_SZ)
518 {
519 /* Initialize a unicode string from the value data */
520 LocaleString.Buffer = (PWCHAR)KeyValueInformation->Data;
521 LocaleString.Length = (USHORT)KeyValueInformation->DataLength;
522 LocaleString.MaximumLength = LocaleString.Length;
523
524 /* Convert the hex string to a number */
525 RtlUnicodeStringToInteger(&LocaleString, 16, &DefaultLocaleId);
526 }
527 else
528 {
530 }
531 }
532 else
533 {
534 /* We have a locale, validate it */
535 Status = ExpValidateNlsLocaleId(DefaultLocaleId);
536 if (NT_SUCCESS(Status))
537 {
538 /* Open the key now */
540 if (NT_SUCCESS(Status))
541 {
542 /* Check if we had a profile */
543 if (UserProfile)
544 {
545 /* Fill in the buffer */
546 ValueLength = swprintf(ValueBuffer,
547 L"%08lx",
548 (ULONG)DefaultLocaleId);
549 }
550 else
551 {
552 /* Fill in the buffer */
553 ValueLength = swprintf(ValueBuffer,
554 L"%04lx",
555 (ULONG)DefaultLocaleId & 0xFFFF);
556 }
557
558 /* Set the length for the registry call */
559 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
560
561 /* Now write the actual value */
562 Status = ZwSetValueKey(KeyHandle,
563 &ValueName,
564 0,
565 REG_SZ,
566 ValueBuffer,
568 }
569 }
570 }
571
572Cleanup:
573
574 /* Close the locale key */
575 if (KeyHandle)
576 {
578 }
579
580 /* Close the user key */
581 if (UserKey)
582 {
583 ObCloseHandle(UserKey, KernelMode);
584 }
585
586 /* Check for success */
587 if (NT_SUCCESS(Status))
588 {
589 /* Check if it was for a user */
590 if (UserProfile)
591 {
592 /* Set the session wide thread locale */
593 MmSetSessionLocaleId(DefaultLocaleId);
594 }
595 else
596 {
597 /* Set system locale */
598 PsDefaultSystemLocaleId = DefaultLocaleId;
599 }
600 }
601
602 /* Return status */
603 return Status;
604}
605
606/*
607 * @implemented
608 */
610NTAPI
612{
614 PAGED_CODE();
615
616 /* Enter SEH for probing */
618 {
619 /* Check if we came from user mode */
621 {
622 /* Probe the Language ID */
623 ProbeForWriteLangId(LanguageId);
624 }
625
626 /* Return it */
627 *LanguageId = PsInstallUILanguageId;
628 }
630 {
631 /* Get exception code */
633 }
634 _SEH2_END;
635
636 /* Return status */
637 return Status;
638}
639
640/*
641 * @implemented
642 */
644NTAPI
646{
648 LANGID SafeLanguageId;
649 PAGED_CODE();
650
651 /* Call the executive helper routine */
652 Status = ExpGetCurrentUserUILanguage(L"MultiUILanguageId", &SafeLanguageId);
653
654 /* Enter SEH for probing */
656 {
657 /* Check if we came from user mode */
659 {
660 /* Probe the Language ID */
661 ProbeForWriteLangId(LanguageId);
662 }
663
664 if (NT_SUCCESS(Status))
665 {
666 /* Success, return the language */
667 *LanguageId = SafeLanguageId;
668 }
669 else
670 {
671 /* Failed, use fallback value */
672 // NOTE: Windows doesn't use PsDefaultUILanguageId.
673 *LanguageId = PsInstallUILanguageId;
674 }
675 }
677 {
678 /* Return exception code */
680 }
681 _SEH2_END;
682
683 /* Return success */
684 return STATUS_SUCCESS;
685}
686
687/*
688 * @implemented
689 */
691NTAPI
693{
695 PAGED_CODE();
696
697 /* Check if the caller specified a language id */
698 if (LanguageId)
699 {
700 /* Set the pending MUI language id */
701 Status = ExpSetCurrentUserUILanguage(L"MUILanguagePending", LanguageId);
702 }
703 else
704 {
705 /* Otherwise get the pending MUI language id */
706 Status = ExpGetCurrentUserUILanguage(L"MUILanguagePending", &LanguageId);
707 if (!NT_SUCCESS(Status))
708 {
709 return Status;
710 }
711
712 /* And apply it as actual */
713 Status = ExpSetCurrentUserUILanguage(L"MultiUILanguageId", LanguageId);
714 }
715
716 return Status;
717}
718
719/* EOF */
#define PAGED_CODE()
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_In_ ULONG _In_ BATTERY_QUERY_INFORMATION_LEVEL _In_ LONG _In_ ULONG _Out_ PULONG ReturnedLength
Definition: batclass.h:188
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define swprintf
Definition: precomp.h:40
static const WCHAR Cleanup[]
Definition: register.c:80
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:349
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define REG_SZ
Definition: layer.c:22
USHORT LANGID
Definition: mui.h:9
if(dx< 0)
Definition: linetemp.h:194
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define _In_
Definition: ms_sal.h:308
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
#define KernelMode
Definition: asm.h:34
#define KeGetPreviousMode()
Definition: ketypes.h:1115
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
NTSYSAPI NTSTATUS NTAPI RtlOpenCurrentUser(_In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE KeyHandle)
@ KeyValuePartialInformation
Definition: nt_native.h:1182
#define KEY_READ
Definition: nt_native.h:1023
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToInteger(PUNICODE_STRING String, ULONG Base, PULONG Value)
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
#define KEY_WRITE
Definition: nt_native.h:1031
#define KEY_SET_VALUE
Definition: nt_native.h:1017
* PLCID
Definition: ntbasedef.h:509
#define UNICODE_NULL
#define SORT_DEFAULT
#define MAKELCID(lgid, srtid)
static NTSTATUS ExpValidateNlsLocaleId(_In_ LCID LocaleId)
Validates a NLS locale. Whether a locale is valid or not depends on the following conditions:
Definition: locale.c:103
static __inline BOOLEAN ExpValidateNlsLocaleData(_In_ PKEY_VALUE_PARTIAL_INFORMATION LocaleData)
Validates the registry data of a NLS locale.
Definition: locale.c:48
NTSTATUS NTAPI NtQueryInstallUILanguage(OUT LANGID *LanguageId)
Definition: locale.c:611
LANGID PsDefaultUILanguageId
Definition: locale.c:25
LANGID PsInstallUILanguageId
Definition: locale.c:21
#define BOGUS_LOCALE_ID
Definition: locale.c:29
NTSTATUS NTAPI NtQueryDefaultLocale(IN BOOLEAN UserProfile, OUT PLCID DefaultLocaleId)
Definition: locale.c:396
LCID PsDefaultSystemLocaleId
Definition: locale.c:20
NTSTATUS NTAPI ExpSetCurrentUserUILanguage(IN PCWSTR MuiName, IN LANGID LanguageId)
Definition: locale.c:327
NTSTATUS NTAPI NtSetDefaultUILanguage(IN LANGID LanguageId)
Definition: locale.c:692
NTSTATUS NTAPI NtQueryDefaultUILanguage(OUT LANGID *LanguageId)
Definition: locale.c:645
LCID PsDefaultThreadLocaleId
Definition: locale.c:24
NTSTATUS NTAPI ExpGetCurrentUserUILanguage(IN PCWSTR MuiName, OUT LANGID *LanguageId)
Definition: locale.c:254
NTSTATUS NTAPI NtSetDefaultLocale(IN BOOLEAN UserProfile, IN LCID DefaultLocaleId)
Definition: locale.c:437
ULONG NTAPI MmGetSessionLocaleId(VOID)
Definition: session.c:56
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI ObCloseHandle(IN HANDLE Handle, IN KPROCESSOR_MODE AccessMode)
Definition: obhandle.c:3379
unsigned short USHORT
Definition: pedump.c:61
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define REG_DWORD
Definition: sdbapi.c:596
#define LANGIDFROMLCID(l)
Definition: nls.h:18
DWORD LCID
Definition: nls.h:13
#define ProbeForWriteLangId(Ptr)
Definition: probe.h:44
#define STATUS_SUCCESS
Definition: shellext.h:65
Data(int index, int value)
Definition: sort_test.cpp:78
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2699
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_ PCUNICODE_STRING _In_ PCUNICODE_STRING _In_ LCID LocaleId
Definition: wdfpdo.h:437
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180