Fix splitting of cells (noticed by Hartmut).
[reactos.git] / reactos / ntoskrnl / ps / locale.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/locale.c
6 * PURPOSE: Locale support
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /* GLOBALS *******************************************************************/
20
21 /*
22 * Default setting: LANG_NEUTRAL, SUBLANG_NEUTRAL, SORT_DEFAULT
23 */
24 LCID PsDefaultThreadLocaleId = 0;
25 LCID PsDefaultSystemLocaleId = 0;
26 BOOL PsDefaultThreadLocaleInitialized = FALSE;
27
28 static LANGID PsInstallUILanguageId = 0;
29
30 #define VALUE_BUFFER_SIZE 256
31
32 /* FUNCTIONS *****************************************************************/
33
34 /*
35 * FUNCTION:
36 * Initializes the default locale.
37 * Reads default locale from registry, if available
38 * ARGUMENTS:
39 * None.
40 * Returns:
41 * None.
42 */
43 VOID
44 INIT_FUNCTION
45 NTAPI
46 PiInitDefaultLocale(VOID)
47 {
48 OBJECT_ATTRIBUTES ObjectAttributes;
49 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
50 UNICODE_STRING ValueName;
51 HANDLE KeyHandle;
52 ULONG ValueLength;
53 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
54 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
55 UNICODE_STRING ValueString;
56 ULONG Value;
57 NTSTATUS Status;
58
59 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
60
61 InitializeObjectAttributes(&ObjectAttributes,
62 &KeyName,
63 OBJ_CASE_INSENSITIVE,
64 NULL,
65 NULL);
66 Status = ZwOpenKey(&KeyHandle,
67 KEY_QUERY_VALUE,
68 &ObjectAttributes);
69 if (NT_SUCCESS(Status))
70 {
71 /* Read system locale */
72 RtlInitUnicodeString(&ValueName,
73 L"Default");
74 Status = ZwQueryValueKey(KeyHandle,
75 &ValueName,
76 KeyValuePartialInformation,
77 ValueBuffer,
78 VALUE_BUFFER_SIZE,
79 &ValueLength);
80 if ((NT_SUCCESS(Status)) && (ValueInfo->Type == REG_SZ))
81 {
82 ValueString.Length = ValueInfo->DataLength;
83 ValueString.MaximumLength = ValueInfo->DataLength;
84 ValueString.Buffer = (PWSTR)ValueInfo->Data;
85
86 Status = RtlUnicodeStringToInteger(&ValueString,
87 16,
88 &Value);
89 if (NT_SUCCESS(Status))
90 {
91 DPRINT("System locale: %08lx\n", Value);
92 PsDefaultSystemLocaleId = (LCID)Value;
93 }
94 }
95
96 /* Read install language id */
97 RtlInitUnicodeString(&ValueName,
98 L"InstallLanguage");
99 Status = ZwQueryValueKey(KeyHandle,
100 &ValueName,
101 KeyValuePartialInformation,
102 ValueBuffer,
103 VALUE_BUFFER_SIZE,
104 &ValueLength);
105 if ((NT_SUCCESS(Status)) && (ValueInfo->Type == REG_SZ))
106 {
107 ValueString.Length = ValueInfo->DataLength;
108 ValueString.MaximumLength = ValueInfo->DataLength;
109 ValueString.Buffer = (PWSTR)ValueInfo->Data;
110
111 Status = RtlUnicodeStringToInteger(&ValueString,
112 16,
113 &Value);
114 if (NT_SUCCESS(Status))
115 {
116 DPRINT("Install language id: %04lx\n", Value);
117 PsInstallUILanguageId = (LANGID)Value;
118 }
119 }
120
121 ZwClose(KeyHandle);
122 }
123 }
124
125
126 /*
127 * FUNCTION:
128 * Initializes the default thread locale.
129 * Reads default locale from registry, if available
130 * ARGUMENTS:
131 * None.
132 * Returns:
133 * None.
134 */
135 VOID STDCALL
136 PiInitThreadLocale(VOID)
137 {
138 OBJECT_ATTRIBUTES ObjectAttributes;
139 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User\\.Default\\Control Panel\\International");
140 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"Locale");
141 HANDLE KeyHandle;
142 ULONG ValueLength;
143 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
144 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
145 UNICODE_STRING ValueString;
146 ULONG LocaleValue;
147 NTSTATUS Status;
148
149 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
150
151 /* read default thread locale */
152 InitializeObjectAttributes(&ObjectAttributes,
153 &KeyName,
154 OBJ_CASE_INSENSITIVE,
155 NULL,
156 NULL);
157 Status = ZwOpenKey(&KeyHandle,
158 KEY_QUERY_VALUE,
159 &ObjectAttributes);
160 if (NT_SUCCESS(Status))
161 {
162 Status = ZwQueryValueKey(KeyHandle,
163 &ValueName,
164 KeyValuePartialInformation,
165 ValueBuffer,
166 VALUE_BUFFER_SIZE,
167 &ValueLength);
168 if ((NT_SUCCESS(Status)) && (ValueInfo->Type == REG_SZ))
169 {
170 ValueString.Length = ValueInfo->DataLength;
171 ValueString.MaximumLength = ValueInfo->DataLength;
172 ValueString.Buffer = (PWSTR)ValueInfo->Data;
173
174 Status = RtlUnicodeStringToInteger(&ValueString,
175 16,
176 &LocaleValue);
177 if (NT_SUCCESS(Status))
178 {
179 DPRINT("Thread locale: %08lu\n", LocaleValue);
180 PsDefaultThreadLocaleId = (LCID)LocaleValue;
181 }
182 }
183 ZwClose(KeyHandle);
184 }
185
186 PsDefaultThreadLocaleInitialized = TRUE;
187 }
188
189
190 /*
191 * FUNCTION:
192 * Returns the default locale.
193 * ARGUMENTS:
194 * UserProfile = If TRUE then the locale for this thread is returned,
195 * otherwise the locale for the system is returned.
196 * DefaultLocaleId = Points to a variable that receives the locale id.
197 * Returns:
198 * Status.
199 */
200 NTSTATUS STDCALL
201 NtQueryDefaultLocale(IN BOOLEAN UserProfile,
202 OUT PLCID DefaultLocaleId)
203 {
204 NTSTATUS Status = STATUS_SUCCESS;
205
206 PAGED_CODE();
207
208 _SEH_TRY
209 {
210 if (KeGetPreviousMode() != KernelMode)
211 {
212 ProbeForWriteLangid(DefaultLocaleId);
213 }
214
215 if (UserProfile)
216 {
217 if (!PsDefaultThreadLocaleInitialized)
218 {
219 PiInitThreadLocale();
220 }
221
222 /* set thread locale */
223 *DefaultLocaleId = PsDefaultThreadLocaleId;
224 }
225 else
226 {
227 /* set system locale */
228 *DefaultLocaleId = PsDefaultSystemLocaleId;
229 }
230 }
231 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
232 {
233 Status = _SEH_GetExceptionCode();
234 }
235 _SEH_END;
236
237 return Status;
238 }
239
240
241 /*
242 * FUNCTION:
243 * Sets the default locale.
244 * ARGUMENTS:
245 * ThreadOrSystem = If TRUE then the locale for this thread is set,
246 * otherwise the locale for the system is set.
247 * DefaultLocaleId = The locale id to be set.
248 * Returns:
249 * Status.
250 */
251 NTSTATUS STDCALL
252 NtSetDefaultLocale(IN BOOLEAN UserProfile,
253 IN LCID DefaultLocaleId)
254 {
255 OBJECT_ATTRIBUTES ObjectAttributes;
256 UNICODE_STRING KeyName;
257 UNICODE_STRING ValueName;
258 HANDLE KeyHandle;
259 ULONG ValueLength;
260 WCHAR ValueBuffer[20];
261 HANDLE UserKey = NULL;
262 NTSTATUS Status;
263
264 PAGED_CODE();
265
266 if (UserProfile)
267 {
268 /* thread locale */
269 Status = RtlOpenCurrentUser(KEY_WRITE,
270 &UserKey);
271 if (!NT_SUCCESS(Status))
272 return(Status);
273 RtlInitUnicodeString(&KeyName,
274 L"Control Panel\\International");
275 RtlInitUnicodeString(&ValueName,
276 L"Locale");
277 }
278 else
279 {
280 /* system locale */
281 RtlInitUnicodeString(&KeyName,
282 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
283 RtlInitUnicodeString(&ValueName,
284 L"Default");
285 }
286
287 InitializeObjectAttributes(&ObjectAttributes,
288 &KeyName,
289 OBJ_CASE_INSENSITIVE,
290 UserKey,
291 NULL);
292 Status = ZwOpenKey(&KeyHandle,
293 KEY_SET_VALUE,
294 &ObjectAttributes);
295 if (!NT_SUCCESS(Status))
296 {
297 if (UserKey != NULL)
298 {
299 ZwClose(UserKey);
300 }
301 return(Status);
302 }
303
304 if (UserProfile)
305 {
306 ValueLength = swprintf(ValueBuffer,
307 L"%08lx",
308 (ULONG)DefaultLocaleId);
309 }
310 else
311 {
312 ValueLength = swprintf(ValueBuffer,
313 L"%04lx",
314 (ULONG)DefaultLocaleId & 0xFFFF);
315 }
316 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
317
318 Status = ZwSetValueKey(KeyHandle,
319 &ValueName,
320 0,
321 REG_SZ,
322 ValueBuffer,
323 ValueLength);
324
325 ZwClose(KeyHandle);
326 if (UserKey != NULL)
327 {
328 ZwClose(UserKey);
329 }
330
331 if (!NT_SUCCESS(Status))
332 {
333 return(Status);
334 }
335
336 if (UserProfile)
337 {
338 /* set thread locale */
339 DPRINT("Thread locale: %08lu\n", DefaultLocaleId);
340 PsDefaultThreadLocaleId = DefaultLocaleId;
341 PsDefaultThreadLocaleInitialized = TRUE;
342 }
343 else
344 {
345 /* set system locale */
346 DPRINT("System locale: %08lu\n", DefaultLocaleId);
347 PsDefaultSystemLocaleId = DefaultLocaleId;
348 }
349
350 return STATUS_SUCCESS;
351 }
352
353
354 /*
355 * @implemented
356 */
357 NTSTATUS STDCALL
358 NtQueryDefaultUILanguage(OUT PLANGID LanguageId)
359 {
360 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
361 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
362 OBJECT_ATTRIBUTES ObjectAttributes;
363 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"Control Panel\\International");
364 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"MultiUILanguageId");
365 UNICODE_STRING ValueString;
366 ULONG ValueLength;
367 ULONG Value;
368 HANDLE UserKey;
369 HANDLE KeyHandle;
370 NTSTATUS Status = STATUS_SUCCESS;
371
372 PAGED_CODE();
373
374 _SEH_TRY
375 {
376 if (KeGetPreviousMode() != KernelMode)
377 {
378 ProbeForWriteLangid(LanguageId);
379 }
380
381 *LanguageId = PsInstallUILanguageId;
382 }
383 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
384 {
385 Status = _SEH_GetExceptionCode();
386 }
387 _SEH_END;
388
389 if (!NT_SUCCESS(Status))
390 {
391 return Status;
392 }
393
394 Status = RtlOpenCurrentUser(KEY_READ,
395 &UserKey);
396 if (!NT_SUCCESS(Status))
397 {
398 Value = PsInstallUILanguageId;
399 goto ReturnSuccess;
400 }
401
402 InitializeObjectAttributes(&ObjectAttributes,
403 &KeyName,
404 OBJ_CASE_INSENSITIVE,
405 UserKey,
406 NULL);
407 Status = ZwOpenKey(&KeyHandle,
408 KEY_QUERY_VALUE,
409 &ObjectAttributes);
410 if (!NT_SUCCESS(Status))
411 {
412 Value = PsInstallUILanguageId;
413 goto ReturnSuccess;
414 }
415
416 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
417
418 Status = ZwQueryValueKey(KeyHandle,
419 &ValueName,
420 KeyValuePartialInformation,
421 ValueBuffer,
422 VALUE_BUFFER_SIZE,
423 &ValueLength);
424
425 ZwClose(KeyHandle);
426 ZwClose(UserKey);
427
428 if (!NT_SUCCESS(Status) || ValueInfo->Type != REG_SZ)
429 {
430 Value = PsInstallUILanguageId;
431 goto ReturnSuccess;
432 }
433
434 ValueString.Length = ValueInfo->DataLength;
435 ValueString.MaximumLength = ValueInfo->DataLength;
436 ValueString.Buffer = (PWSTR)ValueInfo->Data;
437
438 Status = RtlUnicodeStringToInteger(&ValueString,
439 16,
440 &Value);
441 if (!NT_SUCCESS(Status))
442 {
443 Value = PsInstallUILanguageId;
444 goto ReturnSuccess;
445 }
446
447 DPRINT("Default language id: %04lx\n", Value);
448
449 ReturnSuccess:
450 _SEH_TRY
451 {
452 *LanguageId = Value;
453 Status = STATUS_SUCCESS;
454 }
455 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
456 {
457 Status = _SEH_GetExceptionCode();
458 }
459 _SEH_END;
460
461 return Status;
462 }
463
464
465 /*
466 * @implemented
467 */
468 NTSTATUS STDCALL
469 NtQueryInstallUILanguage(OUT PLANGID LanguageId)
470 {
471 NTSTATUS Status = STATUS_SUCCESS;
472
473 PAGED_CODE();
474
475 _SEH_TRY
476 {
477 if (KeGetPreviousMode() != KernelMode)
478 {
479 ProbeForWriteLangid(LanguageId);
480 }
481
482 *LanguageId = PsInstallUILanguageId;
483 }
484 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
485 {
486 Status = _SEH_GetExceptionCode();
487 }
488 _SEH_END;
489
490 return Status;
491 }
492
493
494 /*
495 * @implemented
496 */
497 NTSTATUS STDCALL
498 NtSetDefaultUILanguage(IN LANGID LanguageId)
499 {
500 OBJECT_ATTRIBUTES ObjectAttributes;
501 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
502 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"MultiUILanguageId");
503 WCHAR ValueBuffer[8];
504 ULONG ValueLength;
505 HANDLE UserHandle;
506 HANDLE KeyHandle;
507 NTSTATUS Status;
508
509 PAGED_CODE();
510
511 Status = RtlOpenCurrentUser(KEY_WRITE,
512 &UserHandle);
513 if (!NT_SUCCESS(Status))
514 {
515 return Status;
516 }
517
518 InitializeObjectAttributes(&ObjectAttributes,
519 &KeyName,
520 OBJ_CASE_INSENSITIVE,
521 UserHandle,
522 NULL);
523
524 Status = ZwOpenKey(&KeyHandle,
525 KEY_SET_VALUE,
526 &ObjectAttributes);
527 if (!NT_SUCCESS(Status))
528 {
529 ZwClose(UserHandle);
530 return Status;
531 }
532
533 ValueLength = swprintf(ValueBuffer,
534 L"%04lX",
535 (ULONG)LanguageId);
536 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
537
538 Status = ZwSetValueKey(KeyHandle,
539 &ValueName,
540 0,
541 REG_SZ,
542 ValueBuffer,
543 ValueLength);
544
545 ZwClose(KeyHandle);
546 ZwClose(UserHandle);
547
548 return Status;
549 }
550
551 /* EOF */