Sync with trunk r63283
[reactos.git] / ntoskrnl / ex / locale.c
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 */
20 LCID PsDefaultSystemLocaleId = 0x00000409;
21 LANGID PsInstallUILanguageId = LANGIDFROMLCID(0x00000409);
22
23 /* UI/Thread IDs: Same as system */
24 LANGID PsDefaultUILanguageId = 0x00000409;
25 LCID PsDefaultThreadLocaleId = LANGIDFROMLCID(0x00000409);
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 NTSTATUS
30 NTAPI
31 ExpGetCurrentUserUILanguage(IN PWSTR MuiName,
32 OUT LANGID* LanguageId)
33 {
34 UCHAR ValueBuffer[256];
35 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
36 OBJECT_ATTRIBUTES ObjectAttributes;
37 UNICODE_STRING KeyName =
38 RTL_CONSTANT_STRING(L"Control Panel\\International");
39 UNICODE_STRING ValueName;
40 UNICODE_STRING ValueString;
41 ULONG ValueLength;
42 ULONG Value;
43 HANDLE UserKey;
44 HANDLE KeyHandle;
45 NTSTATUS Status;
46 PAGED_CODE();
47
48 /* Setup the key name */
49 RtlInitUnicodeString(&ValueName, MuiName);
50
51 /* Open the use key */
52 Status = RtlOpenCurrentUser(KEY_READ, &UserKey);
53 if (!NT_SUCCESS(Status)) return Status;
54
55 /* Initialize the attributes and open the key */
56 InitializeObjectAttributes(&ObjectAttributes,
57 &KeyName,
58 OBJ_CASE_INSENSITIVE,
59 UserKey,
60 NULL);
61 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE,&ObjectAttributes);
62 if (NT_SUCCESS(Status))
63 {
64 /* Set buffer and query the current value */
65 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
66 Status = ZwQueryValueKey(KeyHandle,
67 &ValueName,
68 KeyValuePartialInformation,
69 ValueBuffer,
70 sizeof(ValueBuffer),
71 &ValueLength);
72 if (NT_SUCCESS(Status))
73 {
74 /* Success, is the value the right type? */
75 if (ValueInfo->Type == REG_SZ)
76 {
77 /* It is. Initialize the data and convert it */
78 RtlInitUnicodeString(&ValueString, (PWSTR)ValueInfo->Data);
79 Status = RtlUnicodeStringToInteger(&ValueString, 16, &Value);
80 if (NT_SUCCESS(Status))
81 {
82 /* Return the language */
83 *LanguageId = (USHORT)Value;
84 }
85 }
86 else
87 {
88 /* Fail */
89 Status = STATUS_UNSUCCESSFUL;
90 }
91
92 /* Close the key */
93 ZwClose(KeyHandle);
94 }
95 }
96
97 /* Close the user key and return */
98 ZwClose(UserKey);
99 return Status;
100 }
101
102 NTSTATUS
103 NTAPI
104 ExpSetCurrentUserUILanguage(IN PWSTR MuiName,
105 IN LANGID LanguageId)
106 {
107 OBJECT_ATTRIBUTES ObjectAttributes;
108 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
109 UNICODE_STRING ValueName;
110 WCHAR ValueBuffer[8];
111 ULONG ValueLength;
112 HANDLE UserHandle;
113 HANDLE KeyHandle;
114 NTSTATUS Status;
115 PAGED_CODE();
116
117 /* Setup the key name */
118 RtlInitUnicodeString(&ValueName, MuiName);
119
120 /* Open the use key */
121 Status = RtlOpenCurrentUser(KEY_WRITE, &UserHandle);
122 if (!NT_SUCCESS(Status)) return Status;
123
124 /* Initialize the attributes */
125 InitializeObjectAttributes(&ObjectAttributes,
126 &KeyName,
127 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
128 UserHandle,
129 NULL);
130
131 /* Open the key */
132 Status = ZwOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes);
133 if (NT_SUCCESS(Status))
134 {
135 /* Setup the value name */
136 ValueLength = swprintf(ValueBuffer,
137 L"%04lX",
138 (ULONG)LanguageId);
139
140 /* Set the length for the call and set the value */
141 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
142 Status = ZwSetValueKey(KeyHandle,
143 &ValueName,
144 0,
145 REG_SZ,
146 ValueBuffer,
147 ValueLength);
148
149 /* Close the handle for this key */
150 ZwClose(KeyHandle);
151 }
152
153 /* Close the user key and return status */
154 ZwClose(UserHandle);
155 return Status;
156 }
157
158 /* PUBLIC FUNCTIONS **********************************************************/
159
160 NTSTATUS
161 NTAPI
162 NtQueryDefaultLocale(IN BOOLEAN UserProfile,
163 OUT PLCID DefaultLocaleId)
164 {
165 NTSTATUS Status = STATUS_SUCCESS;
166 PAGED_CODE();
167
168 /* Enter SEH for probing */
169 _SEH2_TRY
170 {
171 /* Check if we came from user mode */
172 if (KeGetPreviousMode() != KernelMode)
173 {
174 /* Probe the language ID */
175 ProbeForWriteLangid(DefaultLocaleId);
176 }
177
178 /* Check if we have a user profile */
179 if (UserProfile)
180 {
181 /* Return session wide thread locale */
182 *DefaultLocaleId = MmGetSessionLocaleId();
183 }
184 else
185 {
186 /* Return system locale */
187 *DefaultLocaleId = PsDefaultSystemLocaleId;
188 }
189 }
190 _SEH2_EXCEPT(ExSystemExceptionFilter())
191 {
192 /* Get exception code */
193 Status = _SEH2_GetExceptionCode();
194 }
195 _SEH2_END;
196
197 /* Return status */
198 return Status;
199 }
200
201 NTSTATUS
202 NTAPI
203 NtSetDefaultLocale(IN BOOLEAN UserProfile,
204 IN LCID DefaultLocaleId)
205 {
206 OBJECT_ATTRIBUTES ObjectAttributes;
207 UNICODE_STRING KeyName;
208 UNICODE_STRING ValueName;
209 UNICODE_STRING LocaleString;
210 HANDLE KeyHandle;
211 ULONG ValueLength;
212 WCHAR ValueBuffer[20];
213 HANDLE UserKey;
214 NTSTATUS Status;
215 UCHAR KeyValueBuffer[256];
216 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
217 PAGED_CODE();
218
219 /* Check if we have a profile */
220 if (UserProfile)
221 {
222 /* Open the user's key */
223 Status = RtlOpenCurrentUser(KEY_WRITE, &UserKey);
224 if (!NT_SUCCESS(Status)) return(Status);
225
226 /* Initialize the registry location */
227 RtlInitUnicodeString(&KeyName, L"Control Panel\\International");
228 RtlInitUnicodeString(&ValueName, L"Locale");
229 }
230 else
231 {
232 /* Initialize the system registry location */
233 RtlInitUnicodeString(&KeyName,
234 L"\\Registry\\Machine\\System\\CurrentControlSet"
235 L"\\Control\\Nls\\Language");
236 RtlInitUnicodeString(&ValueName, L"Default");
237 UserKey = NULL;
238 }
239
240 /* Initailize the object attributes */
241 InitializeObjectAttributes(&ObjectAttributes,
242 &KeyName,
243 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
244 UserKey,
245 NULL);
246
247 /* Check if we don't have a default locale yet */
248 if (!DefaultLocaleId)
249 {
250 /* Open the key for reading */
251 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
252 if (!NT_SUCCESS(Status))
253 {
254 KeyHandle = NULL;
255 goto Cleanup;
256 }
257
258 /* Query the key value */
259 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
260 Status = ZwQueryValueKey(KeyHandle,
261 &ValueName,
262 KeyValuePartialInformation,
263 KeyValueInformation,
264 sizeof(KeyValueBuffer),
265 &ValueLength);
266 if (!NT_SUCCESS(Status))
267 {
268 goto Cleanup;
269 }
270
271 /* Check if this is a REG_DWORD */
272 if ((KeyValueInformation->Type == REG_DWORD) &&
273 (KeyValueInformation->DataLength == sizeof(ULONG)))
274 {
275 /* It contains the LCID as a DWORD */
276 DefaultLocaleId = *((ULONG*)KeyValueInformation->Data);
277 }
278 /* Otherwise check for a REG_SZ */
279 else if (KeyValueInformation->Type == REG_SZ)
280 {
281 /* Initialize a unicode string from the value data */
282 LocaleString.Buffer = (PWCHAR)KeyValueInformation->Data;
283 LocaleString.Length = (USHORT)KeyValueInformation->DataLength;
284 LocaleString.MaximumLength = LocaleString.Length;
285
286 /* Convert the hex string to a number */
287 RtlUnicodeStringToInteger(&LocaleString, 16, &DefaultLocaleId);
288 }
289 else
290 {
291 Status = STATUS_UNSUCCESSFUL;
292 }
293 }
294 else
295 {
296 /* Otherwise, open the key */
297 Status = ZwOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes);
298 if (NT_SUCCESS(Status))
299 {
300 /* Check if we had a profile */
301 if (UserProfile)
302 {
303 /* Fill in the buffer */
304 ValueLength = swprintf(ValueBuffer,
305 L"%08lx",
306 (ULONG)DefaultLocaleId);
307 }
308 else
309 {
310 /* Fill in the buffer */
311 ValueLength = swprintf(ValueBuffer,
312 L"%04lx",
313 (ULONG)DefaultLocaleId & 0xFFFF);
314 }
315
316 /* Set the length for the registry call */
317 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
318
319 /* Now write the actual value */
320 Status = ZwSetValueKey(KeyHandle,
321 &ValueName,
322 0,
323 REG_SZ,
324 ValueBuffer,
325 ValueLength);
326 }
327 }
328
329 Cleanup:
330
331 /* Close the locale key */
332 if (KeyHandle)
333 {
334 ObCloseHandle(KeyHandle, KernelMode);
335 }
336
337 /* Close the user key */
338 if (UserKey)
339 {
340 ObCloseHandle(UserKey, KernelMode);
341 }
342
343 /* Check for success */
344 if (NT_SUCCESS(Status))
345 {
346 /* Check if it was for a user */
347 if (UserProfile)
348 {
349 /* Set the session wide thread locale */
350 MmSetSessionLocaleId(DefaultLocaleId);
351 }
352 else
353 {
354 /* Set system locale */
355 PsDefaultSystemLocaleId = DefaultLocaleId;
356 }
357 }
358
359 /* Return status */
360 return Status;
361 }
362
363 /*
364 * @implemented
365 */
366 NTSTATUS
367 NTAPI
368 NtQueryInstallUILanguage(OUT LANGID* LanguageId)
369 {
370 NTSTATUS Status = STATUS_SUCCESS;
371 PAGED_CODE();
372
373 /* Enter SEH for probing */
374 _SEH2_TRY
375 {
376 /* Check if we came from user mode */
377 if (KeGetPreviousMode() != KernelMode)
378 {
379 /* Probe the Language ID */
380 ProbeForWriteLangid(LanguageId);
381 }
382
383 /* Return it */
384 *LanguageId = PsInstallUILanguageId;
385 }
386 _SEH2_EXCEPT(ExSystemExceptionFilter())
387 {
388 /* Get exception code */
389 Status = _SEH2_GetExceptionCode();
390 }
391 _SEH2_END;
392
393 /* Return status */
394 return Status;
395 }
396
397 /*
398 * @implemented
399 */
400 NTSTATUS
401 NTAPI
402 NtQueryDefaultUILanguage(OUT LANGID* LanguageId)
403 {
404 NTSTATUS Status;
405 LANGID SafeLanguageId;
406 PAGED_CODE();
407
408 /* Call the executive helper routine */
409 Status = ExpGetCurrentUserUILanguage(L"MultiUILanguageId", &SafeLanguageId);
410
411 /* Enter SEH for probing */
412 _SEH2_TRY
413 {
414 /* Check if we came from user mode */
415 if (KeGetPreviousMode() != KernelMode)
416 {
417 /* Probe the Language ID */
418 ProbeForWriteLangid(LanguageId);
419 }
420
421 if (NT_SUCCESS(Status))
422 {
423 /* Success, return the language */
424 *LanguageId = SafeLanguageId;
425 }
426 else
427 {
428 /* Failed, use fallback value */
429 *LanguageId = PsInstallUILanguageId;
430 }
431 }
432 _SEH2_EXCEPT(ExSystemExceptionFilter())
433 {
434 /* Return exception code */
435 return _SEH2_GetExceptionCode();
436 }
437 _SEH2_END;
438
439 /* Return success */
440 return STATUS_SUCCESS;
441 }
442
443 /*
444 * @implemented
445 */
446 NTSTATUS
447 NTAPI
448 NtSetDefaultUILanguage(IN LANGID LanguageId)
449 {
450 NTSTATUS Status;
451 PAGED_CODE();
452
453 /* Check if the caller specified a language id */
454 if (LanguageId)
455 {
456 /* Set the pending MUI language id */
457 Status = ExpSetCurrentUserUILanguage(L"MUILanguagePending", LanguageId);
458 }
459 else
460 {
461 /* Otherwise get the pending MUI language id */
462 Status = ExpGetCurrentUserUILanguage(L"MUILanguagePending", &LanguageId);
463 if (!NT_SUCCESS(Status))
464 {
465 return Status;
466 }
467
468 /* And apply it as actual */
469 Status = ExpSetCurrentUserUILanguage(L"MultiUILanguageId", LanguageId);
470 }
471
472 return Status;
473 }
474
475 /* EOF */