ReactOS 0.4.17-dev-116-ga4b6fe9
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
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, L"%08lx", (ULONG)LocaleId);
138
139 /* And build the LCID string */
140 RtlInitUnicodeString(&LocaleIdString, LocaleIdBuffer);
141
142 /* Open the NLS locale key */
143 Status = ZwOpenKey(&NlsLocaleKey,
145 &NlsLocalKeyAttrs);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", NlsLocaleKeyPath, Status);
149 return Status;
150 }
151
152 /* Open the NLS alternate sort locales key */
153 Status = ZwOpenKey(&AltSortKey,
155 &AltSortKeyAttrs);
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", AltSortKeyPath, Status);
159 goto Quit;
160 }
161
162 /* Open the NLS language groups key */
163 Status = ZwOpenKey(&LangGroupKey,
165 &LangGroupKeyAttrs);
166 if (!NT_SUCCESS(Status))
167 {
168 DPRINT1("Failed to open %wZ (Status 0x%lx)\n", LangGroupPath, Status);
169 goto Quit;
170 }
171
172 /* Check if the captured locale ID exists in the list of other locales */
173 BufferKey = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
174 Status = ZwQueryValueKey(NlsLocaleKey,
175 &LocaleIdString,
177 BufferKey,
178 sizeof(ValueBuffer),
180 if (!NT_SUCCESS(Status))
181 {
182 /* We failed, retry by looking at the alternate sorts locales */
183 Status = ZwQueryValueKey(AltSortKey,
184 &LocaleIdString,
186 BufferKey,
187 sizeof(ValueBuffer),
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT1("Failed to query value from Alternate Sorts key (Status 0x%lx)\n", Status);
192 goto Quit;
193 }
194 }
195
196 /* Ensure the queried locale is of the right key type with a sane length */
197 if (BufferKey->Type != REG_SZ ||
198 BufferKey->DataLength < sizeof(WCHAR))
199 {
200 DPRINT1("The queried locale is of bad value type or length (Type %lu, DataLength %lu)\n",
201 BufferKey->Type, BufferKey->DataLength);
203 goto Quit;
204 }
205
206 /* We got what we need, now query the locale from the language groups */
207 RtlInitUnicodeString(&LocaleIdString, (PWSTR)BufferKey->Data);
208 Status = ZwQueryValueKey(LangGroupKey,
209 &LocaleIdString,
211 BufferKey,
212 sizeof(ValueBuffer),
214 if (!NT_SUCCESS(Status))
215 {
216 DPRINT1("Failed to query value from Language Groups key (Status 0x%lx)\n", Status);
217 goto Quit;
218 }
219
220 /*
221 * We have queried the locale with its data. However we are not finished here yet,
222 * because the locale data could be malformed or the locale itself was not set
223 * so ensure all of these conditions are met.
224 */
225 if (!ExpValidateNlsLocaleData(BufferKey))
226 {
227 DPRINT1("The locale data is not valid!\n");
229 }
230
231Quit:
232 if (LangGroupKey != NULL)
233 {
234 ZwClose(LangGroupKey);
235 }
236
237 if (AltSortKey != NULL)
238 {
239 ZwClose(AltSortKey);
240 }
241
242 if (NlsLocaleKey != NULL)
243 {
244 ZwClose(NlsLocaleKey);
245 }
246
247 return Status;
248}
249
251NTAPI
253 OUT LANGID* LanguageId)
254{
255 UCHAR ValueBuffer[256];
259 RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
261 UNICODE_STRING ValueString;
263 ULONG Value;
264 HANDLE UserKey;
267 PAGED_CODE();
268
269 /* Setup the key name */
271
272 /* Open the use key */
274 if (!NT_SUCCESS(Status)) return Status;
275
276 /* Initialize the attributes and open the key */
278 &KeyName,
280 UserKey,
281 NULL);
283 if (NT_SUCCESS(Status))
284 {
285 /* Set buffer and query the current value */
286 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
287 Status = ZwQueryValueKey(KeyHandle,
288 &ValueName,
290 ValueBuffer,
291 sizeof(ValueBuffer),
292 &ValueLength);
293 if (NT_SUCCESS(Status))
294 {
295 /* Success, is the value the right type? */
296 if (ValueInfo->Type == REG_SZ)
297 {
298 /* It is. Initialize the data and convert it */
299 RtlInitUnicodeString(&ValueString, (PWSTR)ValueInfo->Data);
300 Status = RtlUnicodeStringToInteger(&ValueString, 16, &Value);
301 if (NT_SUCCESS(Status))
302 {
303 /* Return the language */
304 *LanguageId = (USHORT)Value;
305 }
306 }
307 else
308 {
309 /* Fail */
311 }
312 }
313
314 /* Close the key */
316 }
317
318 /* Close the user key and return */
319 ZwClose(UserKey);
320 return Status;
321}
322
324NTAPI
326 IN LANGID LanguageId)
327{
329 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"Control Panel\\Desktop");
331 WCHAR ValueBuffer[8];
333 HANDLE UserHandle;
336 PAGED_CODE();
337
338 /* Check that the passed language ID is not bogus */
339 if (LanguageId & BOGUS_LOCALE_ID)
340 {
342 }
343
344 /* Setup the key name */
346
347 /* Open the use key */
348 Status = RtlOpenCurrentUser(KEY_WRITE, &UserHandle);
349 if (!NT_SUCCESS(Status)) return Status;
350
351 /* Initialize the attributes */
353 &KeyName,
355 UserHandle,
356 NULL);
357
358 /* Validate the language ID */
360 if (NT_SUCCESS(Status))
361 {
362 /* Open the key */
364 if (NT_SUCCESS(Status))
365 {
366 /* Setup the value name */
367 ValueLength = _swprintf(ValueBuffer, L"%04lX", (ULONG)LanguageId);
368
369 /* Set the length for the call and set the value */
370 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
371 Status = ZwSetValueKey(KeyHandle,
372 &ValueName,
373 0,
374 REG_SZ,
375 ValueBuffer,
377
378 /* Close the handle for this key */
380 }
381 }
382
383 /* Close the user key and return status */
384 ZwClose(UserHandle);
385 return Status;
386}
387
388/* PUBLIC FUNCTIONS **********************************************************/
389
391NTAPI
393 OUT PLCID DefaultLocaleId)
394{
396 PAGED_CODE();
397
398 /* Enter SEH for probing */
400 {
401 /* Check if we came from user mode */
403 {
404 /* Probe the language ID */
405 ProbeForWriteLangId(DefaultLocaleId);
406 }
407
408 /* Check if we have a user profile */
409 if (UserProfile)
410 {
411 /* Return session wide thread locale */
412 *DefaultLocaleId = MmGetSessionLocaleId();
413 }
414 else
415 {
416 /* Return system locale */
417 *DefaultLocaleId = PsDefaultSystemLocaleId;
418 }
419 }
421 {
422 /* Get exception code */
424 }
425 _SEH2_END;
426
427 /* Return status */
428 return Status;
429}
430
432NTAPI
434 IN LCID DefaultLocaleId)
435{
439 UNICODE_STRING LocaleString;
442 WCHAR ValueBuffer[20];
443 HANDLE UserKey = NULL;
445 UCHAR KeyValueBuffer[256];
446 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
447 PAGED_CODE();
448
449 /* Check that the passed locale ID is not bogus */
450 if (DefaultLocaleId & BOGUS_LOCALE_ID)
451 {
453 }
454
455 /* Check if we have a profile */
456 if (UserProfile)
457 {
458 /* Open the user's key */
460 if (!NT_SUCCESS(Status)) return Status;
461
462 /* Initialize the registry location */
463 RtlInitUnicodeString(&KeyName, L"Control Panel\\International");
465 }
466 else
467 {
468 /* Initialize the system registry location */
470 L"\\Registry\\Machine\\System\\CurrentControlSet"
471 L"\\Control\\Nls\\Language");
472 RtlInitUnicodeString(&ValueName, L"Default");
473 }
474
475 /* Initialize the object attributes */
477 &KeyName,
479 UserKey,
480 NULL);
481
482 /* Check if we don't have a default locale yet */
483 if (!DefaultLocaleId)
484 {
485 /* Open the key for reading */
487 if (!NT_SUCCESS(Status))
488 {
489 goto Cleanup;
490 }
491
492 /* Query the key value */
493 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
494 Status = ZwQueryValueKey(KeyHandle,
495 &ValueName,
497 KeyValueInformation,
498 sizeof(KeyValueBuffer),
499 &ValueLength);
500 if (!NT_SUCCESS(Status))
501 {
502 goto Cleanup;
503 }
504
505 /* Check if this is a REG_DWORD */
506 if ((KeyValueInformation->Type == REG_DWORD) &&
507 (KeyValueInformation->DataLength == sizeof(ULONG)))
508 {
509 /* It contains the LCID as a DWORD */
510 DefaultLocaleId = *((ULONG*)KeyValueInformation->Data);
511 }
512 /* Otherwise check for a REG_SZ */
513 else if (KeyValueInformation->Type == REG_SZ)
514 {
515 /* Initialize a unicode string from the value data */
516 LocaleString.Buffer = (PWCHAR)KeyValueInformation->Data;
517 LocaleString.Length = (USHORT)KeyValueInformation->DataLength;
518 LocaleString.MaximumLength = LocaleString.Length;
519
520 /* Convert the hex string to a number */
521 RtlUnicodeStringToInteger(&LocaleString, 16, &DefaultLocaleId);
522 }
523 else
524 {
526 }
527 }
528 else
529 {
530 /* We have a locale, validate it */
531 Status = ExpValidateNlsLocaleId(DefaultLocaleId);
532 if (NT_SUCCESS(Status))
533 {
534 /* Open the key now */
536 if (NT_SUCCESS(Status))
537 {
538 /* Check if we had a profile */
539 if (UserProfile)
540 {
541 /* Fill in the buffer */
542 ValueLength = _swprintf(ValueBuffer,
543 L"%08lx",
544 (ULONG)DefaultLocaleId);
545 }
546 else
547 {
548 /* Fill in the buffer */
549 ValueLength = _swprintf(ValueBuffer,
550 L"%04lx",
551 (ULONG)DefaultLocaleId & 0xFFFF);
552 }
553
554 /* Set the length for the registry call */
555 ValueLength = (ValueLength + 1) * sizeof(WCHAR);
556
557 /* Now write the actual value */
558 Status = ZwSetValueKey(KeyHandle,
559 &ValueName,
560 0,
561 REG_SZ,
562 ValueBuffer,
564 }
565 }
566 }
567
568Cleanup:
569
570 /* Close the locale key */
571 if (KeyHandle)
572 {
574 }
575
576 /* Close the user key */
577 if (UserKey)
578 {
579 ObCloseHandle(UserKey, KernelMode);
580 }
581
582 /* Check for success */
583 if (NT_SUCCESS(Status))
584 {
585 /* Check if it was for a user */
586 if (UserProfile)
587 {
588 /* Set the session wide thread locale */
589 MmSetSessionLocaleId(DefaultLocaleId);
590 }
591 else
592 {
593 /* Set system locale */
594 PsDefaultSystemLocaleId = DefaultLocaleId;
595 }
596 }
597
598 /* Return status */
599 return Status;
600}
601
602/*
603 * @implemented
604 */
606NTAPI
608{
610 PAGED_CODE();
611
612 /* Enter SEH for probing */
614 {
615 /* Check if we came from user mode */
617 {
618 /* Probe the Language ID */
619 ProbeForWriteLangId(LanguageId);
620 }
621
622 /* Return it */
623 *LanguageId = PsInstallUILanguageId;
624 }
626 {
627 /* Get exception code */
629 }
630 _SEH2_END;
631
632 /* Return status */
633 return Status;
634}
635
636/*
637 * @implemented
638 */
640NTAPI
642{
644 LANGID SafeLanguageId;
645 PAGED_CODE();
646
647 /* Call the executive helper routine */
648 Status = ExpGetCurrentUserUILanguage(L"MultiUILanguageId", &SafeLanguageId);
649
650 /* Enter SEH for probing */
652 {
653 /* Check if we came from user mode */
655 {
656 /* Probe the Language ID */
657 ProbeForWriteLangId(LanguageId);
658 }
659
660 if (NT_SUCCESS(Status))
661 {
662 /* Success, return the language */
663 *LanguageId = SafeLanguageId;
664 }
665 else
666 {
667 /* Failed, use fallback value */
668 // NOTE: Windows doesn't use PsDefaultUILanguageId.
669 *LanguageId = PsInstallUILanguageId;
670 }
671 }
673 {
674 /* Return exception code */
676 }
677 _SEH2_END;
678
679 /* Return success */
680 return STATUS_SUCCESS;
681}
682
683/*
684 * @implemented
685 */
687NTAPI
689{
691 PAGED_CODE();
692
693 /* Check if the caller specified a language id */
694 if (LanguageId)
695 {
696 /* Set the pending MUI language id */
697 Status = ExpSetCurrentUserUILanguage(L"MUILanguagePending", LanguageId);
698 }
699 else
700 {
701 /* Otherwise get the pending MUI language id */
702 Status = ExpGetCurrentUserUILanguage(L"MUILanguagePending", &LanguageId);
703 if (!NT_SUCCESS(Status))
704 {
705 return Status;
706 }
707
708 /* And apply it as actual */
709 Status = ExpSetCurrentUserUILanguage(L"MultiUILanguageId", LanguageId);
710 }
711
712 return Status;
713}
714
715/* EOF */
#define PAGED_CODE()
#define __inline
Definition: _wctype.cpp:15
unsigned char BOOLEAN
Definition: actypes.h:127
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:33
#define RTL_CONSTANT_STRING(s)
Definition: combase.c:35
#define REG_SZ
Definition: locale.c:45
static const WCHAR Cleanup[]
Definition: register.c:80
#define L(x)
Definition: resources.c:13
Status
Definition: gdiplustypes.h:25
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:349
USHORT LANGID
Definition: mui.h:9
if(dx< 0)
Definition: linetemp.h:194
#define _swprintf(buf, format,...)
Definition: sprintf.c:56
static PWSTR
Definition: locale.c:83
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:115
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
#define KeGetPreviousMode()
Definition: ketypes.h:1115
#define KernelMode
Definition: asm.h:38
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
NTSYSAPI NTSTATUS NTAPI RtlOpenCurrentUser(_In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE KeyHandle)
#define _In_
Definition: no_sal2.h:158
@ KeyValuePartialInformation
Definition: nt_native.h:1185
#define KEY_READ
Definition: nt_native.h:1026
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:1019
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
#define KEY_WRITE
Definition: nt_native.h:1034
#define KEY_SET_VALUE
Definition: nt_native.h:1020
* PLCID
Definition: ntbasedef.h:521
#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:607
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:392
LCID PsDefaultSystemLocaleId
Definition: locale.c:20
NTSTATUS NTAPI ExpSetCurrentUserUILanguage(IN PCWSTR MuiName, IN LANGID LanguageId)
Definition: locale.c:325
NTSTATUS NTAPI NtSetDefaultUILanguage(IN LANGID LanguageId)
Definition: locale.c:688
NTSTATUS NTAPI NtQueryDefaultUILanguage(OUT LANGID *LanguageId)
Definition: locale.c:641
LCID PsDefaultThreadLocaleId
Definition: locale.c:24
NTSTATUS NTAPI ExpGetCurrentUserUILanguage(IN PCWSTR MuiName, OUT LANGID *LanguageId)
Definition: locale.c:252
NTSTATUS NTAPI NtSetDefaultLocale(IN BOOLEAN UserProfile, IN LCID DefaultLocaleId)
Definition: locale.c:433
ULONG NTAPI MmGetSessionLocaleId(VOID)
Definition: session.c:56
NTSTATUS NTAPI ObCloseHandle(IN HANDLE Handle, IN KPROCESSOR_MODE AccessMode)
Definition: obhandle.c:3379
short WCHAR
Definition: pedump.c:58
unsigned short USHORT
Definition: pedump.c:61
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:207
#define REG_DWORD
Definition: sdbapi.c:615
#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
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
unsigned char UCHAR
Definition: typedefs.h:53
#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:2705
_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