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 LCID PsDefaultThreadLocaleId = 0x00000409; 25 LANGID PsDefaultUILanguageId = LANGIDFROMLCID(0x00000409); 26 27 /* PRIVATE FUNCTIONS *********************************************************/ 28 29 NTSTATUS 30 NTAPI 31 ExpGetCurrentUserUILanguage(IN PCWSTR 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\\Desktop"); 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 | OBJ_KERNEL_HANDLE, 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 93 /* Close the key */ 94 ZwClose(KeyHandle); 95 } 96 97 /* Close the user key and return */ 98 ZwClose(UserKey); 99 return Status; 100 } 101 102 NTSTATUS 103 NTAPI 104 ExpSetCurrentUserUILanguage(IN PCWSTR 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 /* Initialize 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 // NOTE: Windows doesn't use PsDefaultUILanguageId. 430 *LanguageId = PsInstallUILanguageId; 431 } 432 } 433 _SEH2_EXCEPT(ExSystemExceptionFilter()) 434 { 435 /* Return exception code */ 436 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 437 } 438 _SEH2_END; 439 440 /* Return success */ 441 return STATUS_SUCCESS; 442 } 443 444 /* 445 * @implemented 446 */ 447 NTSTATUS 448 NTAPI 449 NtSetDefaultUILanguage(IN LANGID LanguageId) 450 { 451 NTSTATUS Status; 452 PAGED_CODE(); 453 454 /* Check if the caller specified a language id */ 455 if (LanguageId) 456 { 457 /* Set the pending MUI language id */ 458 Status = ExpSetCurrentUserUILanguage(L"MUILanguagePending", LanguageId); 459 } 460 else 461 { 462 /* Otherwise get the pending MUI language id */ 463 Status = ExpGetCurrentUserUILanguage(L"MUILanguagePending", &LanguageId); 464 if (!NT_SUCCESS(Status)) 465 { 466 return Status; 467 } 468 469 /* And apply it as actual */ 470 Status = ExpSetCurrentUserUILanguage(L"MultiUILanguageId", LanguageId); 471 } 472 473 return Status; 474 } 475 476 /* EOF */ 477