xref: /reactos/base/setup/lib/settings.c (revision 21587a0e)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2004 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /* COPYRIGHT:       See COPYING in the top level directory
20  * PROJECT:         ReactOS text-mode setup
21  * FILE:            base/setup/usetup/settings.c
22  * PURPOSE:         Device settings support functions
23  * PROGRAMMERS:     Colin Finck
24  */
25 
26 /* INCLUDES *****************************************************************/
27 
28 #include "precomp.h"
29 #include "genlist.h"
30 #include "infsupp.h"
31 #include "mui.h"
32 #include "registry.h"
33 
34 #include "settings.h"
35 
36 #define NDEBUG
37 #include <debug.h>
38 
39 /* GLOBALS ******************************************************************/
40 
41 static ULONG DefaultLanguageIndex = 0;
42 
43 /* FUNCTIONS ****************************************************************/
44 
45 static
46 BOOLEAN
47 IsAcpiComputer(VOID)
48 {
49     UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
50     UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
51     UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
52     OBJECT_ATTRIBUTES ObjectAttributes;
53     PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
54     ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
55     PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
56     ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
57     ULONG RequiredSize;
58     ULONG IndexDevice = 0;
59     UNICODE_STRING DeviceName, ValueName;
60     HANDLE hDevicesKey = NULL;
61     HANDLE hDeviceKey = NULL;
62     NTSTATUS Status;
63     BOOLEAN ret = FALSE;
64 
65     InitializeObjectAttributes(&ObjectAttributes,
66                                &MultiKeyPathU,
67                                OBJ_CASE_INSENSITIVE,
68                                NULL,
69                                NULL);
70     Status = NtOpenKey(&hDevicesKey,
71                        KEY_ENUMERATE_SUB_KEYS,
72                        &ObjectAttributes);
73     if (!NT_SUCCESS(Status))
74     {
75         DPRINT("NtOpenKey() failed with status 0x%08lx\n", Status);
76         goto cleanup;
77     }
78 
79     pDeviceInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, DeviceInfoLength);
80     if (!pDeviceInformation)
81     {
82         DPRINT("RtlAllocateHeap() failed\n");
83         Status = STATUS_NO_MEMORY;
84         goto cleanup;
85     }
86 
87     pValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueInfoLength);
88     if (!pValueInformation)
89     {
90         DPRINT("RtlAllocateHeap() failed\n");
91         Status = STATUS_NO_MEMORY;
92         goto cleanup;
93     }
94 
95     while (TRUE)
96     {
97         Status = NtEnumerateKey(hDevicesKey,
98                                 IndexDevice,
99                                 KeyBasicInformation,
100                                 pDeviceInformation,
101                                 DeviceInfoLength,
102                                 &RequiredSize);
103         if (Status == STATUS_NO_MORE_ENTRIES)
104             break;
105         else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
106         {
107             RtlFreeHeap(RtlGetProcessHeap(), 0, pDeviceInformation);
108             DeviceInfoLength = RequiredSize;
109             pDeviceInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, DeviceInfoLength);
110             if (!pDeviceInformation)
111             {
112                 DPRINT("RtlAllocateHeap() failed\n");
113                 Status = STATUS_NO_MEMORY;
114                 goto cleanup;
115             }
116             Status = NtEnumerateKey(hDevicesKey,
117                                     IndexDevice,
118                                     KeyBasicInformation,
119                                     pDeviceInformation,
120                                     DeviceInfoLength,
121                                     &RequiredSize);
122         }
123         if (!NT_SUCCESS(Status))
124         {
125             DPRINT("NtEnumerateKey() failed with status 0x%08lx\n", Status);
126             goto cleanup;
127         }
128         IndexDevice++;
129 
130         /* Open device key */
131         DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
132         DeviceName.Buffer = pDeviceInformation->Name;
133         InitializeObjectAttributes(&ObjectAttributes,
134                                    &DeviceName,
135                                    OBJ_CASE_INSENSITIVE,
136                                    hDevicesKey,
137                                    NULL);
138         Status = NtOpenKey(&hDeviceKey,
139                            KEY_QUERY_VALUE,
140                            &ObjectAttributes);
141         if (!NT_SUCCESS(Status))
142         {
143             DPRINT("NtOpenKey() failed with status 0x%08lx\n", Status);
144             goto cleanup;
145         }
146 
147         /* Read identifier */
148         Status = NtQueryValueKey(hDeviceKey,
149                                  &IdentifierU,
150                                  KeyValuePartialInformation,
151                                  pValueInformation,
152                                  ValueInfoLength,
153                                  &RequiredSize);
154         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
155         {
156             RtlFreeHeap(RtlGetProcessHeap(), 0, pValueInformation);
157             ValueInfoLength = RequiredSize;
158             pValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, ValueInfoLength);
159             if (!pValueInformation)
160             {
161                 DPRINT("RtlAllocateHeap() failed\n");
162                 Status = STATUS_NO_MEMORY;
163                 goto cleanup;
164             }
165             Status = NtQueryValueKey(hDeviceKey,
166                                      &IdentifierU,
167                                      KeyValuePartialInformation,
168                                      pValueInformation,
169                                      ValueInfoLength,
170                                      &RequiredSize);
171         }
172         if (!NT_SUCCESS(Status))
173         {
174             DPRINT("NtQueryValueKey() failed with status 0x%08lx\n", Status);
175             goto nextdevice;
176         }
177         else if (pValueInformation->Type != REG_SZ)
178         {
179             DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
180             goto nextdevice;
181         }
182 
183         ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
184         ValueName.Buffer = (PWCHAR)pValueInformation->Data;
185         if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
186             ValueName.Length -= sizeof(WCHAR);
187         if (RtlEqualUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE))
188         {
189             DPRINT("Found ACPI BIOS\n");
190             ret = TRUE;
191             goto cleanup;
192         }
193 
194 nextdevice:
195         NtClose(hDeviceKey);
196         hDeviceKey = NULL;
197     }
198 
199 cleanup:
200     if (pDeviceInformation)
201         RtlFreeHeap(RtlGetProcessHeap(), 0, pDeviceInformation);
202     if (pValueInformation)
203         RtlFreeHeap(RtlGetProcessHeap(), 0, pValueInformation);
204     if (hDevicesKey)
205         NtClose(hDevicesKey);
206     if (hDeviceKey)
207         NtClose(hDeviceKey);
208     return ret;
209 }
210 
211 static
212 BOOLEAN
213 GetComputerIdentifier(
214     OUT PWSTR Identifier,
215     IN ULONG IdentifierLength)
216 {
217     OBJECT_ATTRIBUTES ObjectAttributes;
218     UNICODE_STRING KeyName;
219     LPCWSTR ComputerIdentifier;
220     HANDLE ProcessorsKey;
221     PKEY_FULL_INFORMATION pFullInfo;
222     ULONG Size, SizeNeeded;
223     NTSTATUS Status;
224 
225     DPRINT("GetComputerIdentifier() called\n");
226 
227     Size = sizeof(KEY_FULL_INFORMATION);
228     pFullInfo = (PKEY_FULL_INFORMATION)RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
229     if (!pFullInfo)
230     {
231         DPRINT("RtlAllocateHeap() failed\n");
232         return FALSE;
233     }
234 
235     /* Open the processors key */
236     RtlInitUnicodeString(&KeyName,
237                          L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
238     InitializeObjectAttributes(&ObjectAttributes,
239                                &KeyName,
240                                OBJ_CASE_INSENSITIVE,
241                                NULL,
242                                NULL);
243 
244     Status = NtOpenKey(&ProcessorsKey,
245                        KEY_QUERY_VALUE,
246                        &ObjectAttributes);
247     if (!NT_SUCCESS(Status))
248     {
249         DPRINT("NtOpenKey() failed (Status 0x%lx)\n", Status);
250         RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
251         return FALSE;
252     }
253 
254     /* Get number of subkeys */
255     Status = NtQueryKey(ProcessorsKey,
256                         KeyFullInformation,
257                         pFullInfo,
258                         Size,
259                         &Size);
260     NtClose(ProcessorsKey);
261     if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
262     {
263         DPRINT("NtQueryKey() failed (Status 0x%lx)\n", Status);
264         RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
265         return FALSE;
266     }
267 
268     /* Find computer identifier */
269     if (pFullInfo->SubKeys == 0)
270     {
271         /* Something strange happened. No processor detected */
272         RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
273         return FALSE;
274     }
275 
276 #ifdef _M_AMD64
277     /* On x64 we are l33t and use the MP config by default (except when we use KDBG, which is broken) */
278 #ifndef KDBG
279     ComputerIdentifier = L"X64 MP";
280 #else
281     ComputerIdentifier = L"X64 UP";
282 #endif
283 #else
284     if (IsAcpiComputer())
285     {
286         if (pFullInfo->SubKeys == 1)
287         {
288             /* Computer is mono-CPU */
289             ComputerIdentifier = L"ACPI UP";
290         }
291         else
292         {
293             /* Computer is multi-CPUs */
294             ComputerIdentifier = L"ACPI MP";
295         }
296     }
297     else
298     {
299         if (pFullInfo->SubKeys == 1)
300         {
301             /* Computer is mono-CPU */
302             ComputerIdentifier = L"PC UP";
303         }
304         else
305         {
306             /* Computer is multi-CPUs */
307             ComputerIdentifier = L"PC MP";
308         }
309     }
310 #endif
311 
312     RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
313 
314     /* Copy computer identifier to return buffer */
315     SizeNeeded = (wcslen(ComputerIdentifier) + 1) * sizeof(WCHAR);
316     if (SizeNeeded > IdentifierLength)
317         return FALSE;
318 
319     RtlCopyMemory(Identifier, ComputerIdentifier, SizeNeeded);
320 
321     return TRUE;
322 }
323 
324 
325 /*
326  * Return values:
327  * 0x00: Failure, stop the enumeration;
328  * 0x01: Add the entry and continue the enumeration;
329  * 0x02: Skip the entry but continue the enumeration.
330  */
331 typedef UCHAR
332 (NTAPI *PPROCESS_ENTRY_ROUTINE)(
333     IN PCWSTR KeyName,
334     IN PCWSTR KeyValue,
335     OUT PVOID* UserData,
336     OUT PBOOLEAN Current,
337     IN PVOID Parameter OPTIONAL);
338 
339 static LONG
340 AddEntriesFromInfSection(
341     IN OUT PGENERIC_LIST List,
342     IN HINF InfFile,
343     IN PCWSTR SectionName,
344     IN PINFCONTEXT pContext,
345     IN PPROCESS_ENTRY_ROUTINE ProcessEntry,
346     IN PVOID Parameter OPTIONAL)
347 {
348     LONG TotalCount = 0;
349     PCWSTR KeyName;
350     PCWSTR KeyValue;
351     PVOID UserData;
352     BOOLEAN Current;
353     UCHAR RetVal;
354 
355     if (!SpInfFindFirstLine(InfFile, SectionName, NULL, pContext))
356         return -1;
357 
358     do
359     {
360         /*
361          * NOTE: Do not use INF_GetData() as it expects INF entries of exactly
362          * two fields ("key = value"); however we expect to be able to deal with
363          * entries having more than two fields, the only requirement being that
364          * the second field (field number 1) contains the field description.
365          */
366         if (!INF_GetDataField(pContext, 0, &KeyName))
367         {
368             DPRINT("INF_GetDataField() failed\n");
369             return -1;
370         }
371 
372         if (!INF_GetDataField(pContext, 1, &KeyValue))
373         {
374             DPRINT("INF_GetDataField() failed\n");
375             INF_FreeData(KeyName);
376             return -1;
377         }
378 
379         UserData = NULL;
380         Current  = FALSE;
381         RetVal = ProcessEntry(KeyName,
382                               KeyValue,
383                               &UserData,
384                               &Current,
385                               Parameter);
386         INF_FreeData(KeyName);
387         INF_FreeData(KeyValue);
388 
389         if (RetVal == 0)
390         {
391             DPRINT("ProcessEntry() failed\n");
392             return -1;
393         }
394         else if (RetVal == 1)
395         {
396             AppendGenericListEntry(List, UserData, Current);
397             ++TotalCount;
398         }
399         // else if (RetVal == 2), skip the entry.
400 
401     } while (SpInfFindNextLine(pContext, pContext));
402 
403     return TotalCount;
404 }
405 
406 static UCHAR
407 NTAPI
408 DefaultProcessEntry(
409     IN PCWSTR KeyName,
410     IN PCWSTR KeyValue,
411     OUT PVOID* UserData,
412     OUT PBOOLEAN Current,
413     IN PVOID Parameter OPTIONAL)
414 {
415     PWSTR CompareKey = (PWSTR)Parameter;
416 
417     PGENENTRY GenEntry;
418     SIZE_T IdSize, ValueSize;
419 
420     IdSize    = (wcslen(KeyName)  + 1) * sizeof(WCHAR);
421     ValueSize = (wcslen(KeyValue) + 1) * sizeof(WCHAR);
422 
423     GenEntry = RtlAllocateHeap(ProcessHeap, 0,
424                                sizeof(*GenEntry) + IdSize + ValueSize);
425     if (GenEntry == NULL)
426     {
427         /* Failure, stop enumeration */
428         DPRINT1("RtlAllocateHeap() failed\n");
429         return 0;
430     }
431 
432     GenEntry->Id    = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry));
433     GenEntry->Value = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry) + IdSize);
434     RtlStringCbCopyW((PWSTR)GenEntry->Id, IdSize, KeyName);
435     RtlStringCbCopyW((PWSTR)GenEntry->Value, ValueSize, KeyValue);
436 
437     *UserData = GenEntry;
438     *Current  = (CompareKey ? !_wcsicmp(KeyName, CompareKey) : FALSE);
439 
440     /* Add the entry */
441     return 1;
442 }
443 
444 
445 BOOLEAN
446 AddComputerTypeEntries(
447     _In_ HINF InfFile,
448     PGENERIC_LIST List,
449     _In_ PWSTR SectionName)
450 {
451     INFCONTEXT Context;
452     PCWSTR KeyName;
453     PCWSTR KeyValue;
454     WCHAR ComputerIdentifier[128];
455     WCHAR ComputerKey[32];
456     ULONG Count1, Count2;
457 
458     /* Get the computer identification */
459     if (!GetComputerIdentifier(ComputerIdentifier, 128))
460     {
461         ComputerIdentifier[0] = 0;
462     }
463 
464     DPRINT("Computer identifier: '%S'\n", ComputerIdentifier);
465 
466     /* Search for matching device identifier */
467     if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &Context))
468     {
469         /* FIXME: error message */
470         return FALSE;
471     }
472 
473     do
474     {
475         BOOLEAN FoundId;
476 
477         if (!INF_GetDataField(&Context, 1, &KeyValue))
478         {
479             /* FIXME: Handle error! */
480             DPRINT("INF_GetDataField() failed\n");
481             return FALSE;
482         }
483 
484         DPRINT("KeyValue: %S\n", KeyValue);
485         FoundId = !!wcsstr(ComputerIdentifier, KeyValue);
486         INF_FreeData(KeyValue);
487 
488         if (!FoundId)
489             continue;
490 
491         if (!INF_GetDataField(&Context, 0, &KeyName))
492         {
493             /* FIXME: Handle error! */
494             DPRINT("INF_GetDataField() failed\n");
495             return FALSE;
496         }
497 
498         DPRINT("Computer key: %S\n", KeyName);
499         RtlStringCchCopyW(ComputerKey, ARRAYSIZE(ComputerKey), KeyName);
500         INF_FreeData(KeyName);
501     } while (SpInfFindNextLine(&Context, &Context));
502 
503     Count1 = AddEntriesFromInfSection(List,
504                                       InfFile,
505                                       L"Computer",
506                                       &Context,
507                                       DefaultProcessEntry,
508                                       ComputerKey);
509     Count2 = AddEntriesFromInfSection(List,
510                                       InfFile,
511                                       L"Computer.NT" INF_ARCH,
512                                       &Context,
513                                       DefaultProcessEntry,
514                                       ComputerKey);
515     if ((Count1 == -1) && (Count2 == -1))
516     {
517         return FALSE;
518     }
519 
520     return TRUE;
521 }
522 
523 PGENERIC_LIST
524 CreateComputerTypeList(
525     IN HINF InfFile)
526 {
527     PGENERIC_LIST List;
528     BOOLEAN Success;
529 
530     List = CreateGenericList();
531     if (List == NULL)
532         return NULL;
533 
534     Success = AddComputerTypeEntries(InfFile, List, L"Map.Computer");
535     Success |= AddComputerTypeEntries(InfFile, List, L"Map.Computer.NT" INF_ARCH);
536     if (!Success)
537     {
538         DestroyGenericList(List, TRUE);
539         return NULL;
540     }
541 
542     return List;
543 }
544 
545 static
546 BOOLEAN
547 GetDisplayIdentifier(
548     OUT PWSTR Identifier,
549     IN ULONG IdentifierLength)
550 {
551     OBJECT_ATTRIBUTES ObjectAttributes;
552     UNICODE_STRING KeyName;
553     WCHAR Buffer[32];
554     HANDLE BusKey;
555     HANDLE BusInstanceKey;
556     HANDLE ControllerKey;
557     HANDLE ControllerInstanceKey;
558     ULONG BusInstance;
559     ULONG ControllerInstance;
560     ULONG BufferLength;
561     ULONG ReturnedLength;
562     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
563     NTSTATUS Status;
564 
565     DPRINT("GetDisplayIdentifier() called\n");
566 
567     /* Open the bus key */
568     RtlInitUnicodeString(&KeyName,
569                          L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter");
570     InitializeObjectAttributes(&ObjectAttributes,
571                                &KeyName,
572                                OBJ_CASE_INSENSITIVE,
573                                NULL,
574                                NULL);
575 
576     Status = NtOpenKey(&BusKey,
577                        KEY_ENUMERATE_SUB_KEYS,
578                        &ObjectAttributes);
579     if (!NT_SUCCESS(Status))
580     {
581         DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
582         return FALSE;
583     }
584 
585     BusInstance = 0;
586     while (TRUE)
587     {
588         RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", BusInstance);
589         RtlInitUnicodeString(&KeyName, Buffer);
590         InitializeObjectAttributes(&ObjectAttributes,
591                                    &KeyName,
592                                    OBJ_CASE_INSENSITIVE,
593                                    BusKey,
594                                    NULL);
595 
596         Status = NtOpenKey(&BusInstanceKey,
597                            KEY_ENUMERATE_SUB_KEYS,
598                            &ObjectAttributes);
599         if (!NT_SUCCESS(Status))
600         {
601             DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
602             NtClose(BusKey);
603             return FALSE;
604         }
605 
606         /* Open the controller type key */
607         RtlInitUnicodeString(&KeyName, L"DisplayController");
608         InitializeObjectAttributes(&ObjectAttributes,
609                                    &KeyName,
610                                    OBJ_CASE_INSENSITIVE,
611                                    BusInstanceKey,
612                                    NULL);
613 
614         Status = NtOpenKey(&ControllerKey,
615                            KEY_ENUMERATE_SUB_KEYS,
616                            &ObjectAttributes);
617         if (NT_SUCCESS(Status))
618         {
619             ControllerInstance = 0;
620 
621             while (TRUE)
622             {
623                 /* Open the pointer controller instance key */
624                 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", ControllerInstance);
625                 RtlInitUnicodeString(&KeyName, Buffer);
626                 InitializeObjectAttributes(&ObjectAttributes,
627                                            &KeyName,
628                                            OBJ_CASE_INSENSITIVE,
629                                            ControllerKey,
630                                            NULL);
631 
632                 Status = NtOpenKey(&ControllerInstanceKey,
633                                    KEY_QUERY_VALUE,
634                                    &ObjectAttributes);
635                 if (!NT_SUCCESS(Status))
636                 {
637                     DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
638                     NtClose(ControllerKey);
639                     NtClose(BusInstanceKey);
640                     NtClose(BusKey);
641                     return FALSE;
642                 }
643 
644                 /* Get controller identifier */
645                 RtlInitUnicodeString(&KeyName, L"Identifier");
646 
647                 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
648                                256 * sizeof(WCHAR);
649                 ValueInfo = (KEY_VALUE_PARTIAL_INFORMATION*) RtlAllocateHeap(RtlGetProcessHeap(),
650                                                                              0,
651                                                                              BufferLength);
652                 if (ValueInfo == NULL)
653                 {
654                     DPRINT("RtlAllocateHeap() failed\n");
655                     NtClose(ControllerInstanceKey);
656                     NtClose(ControllerKey);
657                     NtClose(BusInstanceKey);
658                     NtClose(BusKey);
659                     return FALSE;
660                 }
661 
662                 Status = NtQueryValueKey(ControllerInstanceKey,
663                                          &KeyName,
664                                          KeyValuePartialInformation,
665                                          ValueInfo,
666                                          BufferLength,
667                                          &ReturnedLength);
668                 if (NT_SUCCESS(Status))
669                 {
670                     DPRINT("Identifier: %S\n", (PWSTR)ValueInfo->Data);
671 
672                     BufferLength = min(ValueInfo->DataLength / sizeof(WCHAR), IdentifierLength);
673                     RtlCopyMemory(Identifier,
674                                   ValueInfo->Data,
675                                   BufferLength * sizeof(WCHAR));
676                     Identifier[BufferLength] = 0;
677 
678                     RtlFreeHeap(RtlGetProcessHeap(),
679                                 0,
680                                 ValueInfo);
681 
682                     NtClose(ControllerInstanceKey);
683                     NtClose(ControllerKey);
684                     NtClose(BusInstanceKey);
685                     NtClose(BusKey);
686                     return TRUE;
687                 }
688 
689                 NtClose(ControllerInstanceKey);
690 
691                 ControllerInstance++;
692             }
693 
694             NtClose(ControllerKey);
695         }
696 
697         NtClose(BusInstanceKey);
698 
699         BusInstance++;
700     }
701 
702     NtClose(BusKey);
703 
704     return FALSE;
705 }
706 
707 PGENERIC_LIST
708 CreateDisplayDriverList(
709     IN HINF InfFile)
710 {
711     PGENERIC_LIST List;
712     INFCONTEXT Context;
713     PCWSTR KeyName;
714     PCWSTR KeyValue;
715     WCHAR DisplayIdentifier[128];
716     WCHAR DisplayKey[32];
717 
718     /* Get the display identification */
719     if (!GetDisplayIdentifier(DisplayIdentifier, 128))
720     {
721         DisplayIdentifier[0] = 0;
722     }
723 
724     DPRINT("Display identifier: '%S'\n", DisplayIdentifier);
725 
726     /* Search for matching device identifier */
727     if (!SpInfFindFirstLine(InfFile, L"Map.Display", NULL, &Context))
728     {
729         /* FIXME: error message */
730         return NULL;
731     }
732 
733     do
734     {
735         BOOLEAN FoundId;
736 
737         if (!INF_GetDataField(&Context, 1, &KeyValue))
738         {
739             /* FIXME: Handle error! */
740             DPRINT("INF_GetDataField() failed\n");
741             return NULL;
742         }
743 
744         DPRINT("KeyValue: %S\n", KeyValue);
745         FoundId = !!wcsstr(DisplayIdentifier, KeyValue);
746         INF_FreeData(KeyValue);
747 
748         if (!FoundId)
749             continue;
750 
751         if (!INF_GetDataField(&Context, 0, &KeyName))
752         {
753             /* FIXME: Handle error! */
754             DPRINT("INF_GetDataField() failed\n");
755             return NULL;
756         }
757 
758         DPRINT("Display key: %S\n", KeyName);
759         RtlStringCchCopyW(DisplayKey, ARRAYSIZE(DisplayKey), KeyName);
760         INF_FreeData(KeyName);
761     } while (SpInfFindNextLine(&Context, &Context));
762 
763     List = CreateGenericList();
764     if (List == NULL)
765         return NULL;
766 
767     if (AddEntriesFromInfSection(List,
768                                  InfFile,
769                                  L"Display",
770                                  &Context,
771                                  DefaultProcessEntry,
772                                  DisplayKey) == -1)
773     {
774         DestroyGenericList(List, TRUE);
775         return NULL;
776     }
777 
778 #if 0
779     AppendGenericListEntry(List, L"Other display driver", NULL, TRUE);
780 #endif
781 
782     return List;
783 }
784 
785 
786 BOOLEAN
787 ProcessComputerFiles(
788     IN HINF InfFile,
789     IN PGENERIC_LIST List,
790     OUT PWSTR* AdditionalSectionName)
791 {
792     PGENERIC_LIST_ENTRY Entry;
793     static WCHAR SectionName[128];
794 
795     DPRINT("ProcessComputerFiles() called\n");
796 
797     Entry = GetCurrentListEntry(List);
798     if (Entry == NULL)
799         return FALSE;
800 
801     RtlStringCchPrintfW(SectionName, ARRAYSIZE(SectionName),
802                         L"Files.%s", ((PGENENTRY)GetListEntryData(Entry))->Id);
803     *AdditionalSectionName = SectionName;
804 
805     return TRUE;
806 }
807 
808 BOOLEAN
809 ProcessDisplayRegistry(
810     IN HINF InfFile,
811     IN PGENERIC_LIST List)
812 {
813     NTSTATUS Status;
814     PGENERIC_LIST_ENTRY Entry;
815     INFCONTEXT Context;
816     PCWSTR Buffer;
817     PCWSTR ServiceName;
818     ULONG StartValue;
819     ULONG Width, Height, Bpp;
820     OBJECT_ATTRIBUTES ObjectAttributes;
821     UNICODE_STRING KeyName;
822     HANDLE KeyHandle;
823     WCHAR RegPath[255];
824 
825     DPRINT("ProcessDisplayRegistry() called\n");
826 
827     Entry = GetCurrentListEntry(List);
828     if (Entry == NULL)
829         return FALSE;
830 
831     if (!SpInfFindFirstLine(InfFile, L"Display",
832                             ((PGENENTRY)GetListEntryData(Entry))->Id,
833                             &Context))
834     {
835         DPRINT1("SpInfFindFirstLine() failed\n");
836         return FALSE;
837     }
838 
839     /* Enable the correct driver */
840     if (!INF_GetDataField(&Context, 3, &ServiceName))
841     {
842         DPRINT1("INF_GetDataField() failed\n");
843         return FALSE;
844     }
845 
846     ASSERT(wcslen(ServiceName) < 10);
847     DPRINT("Service name: '%S'\n", ServiceName);
848 
849     RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
850                         L"System\\CurrentControlSet\\Services\\%s",
851                         ServiceName);
852     RtlInitUnicodeString(&KeyName, RegPath);
853     InitializeObjectAttributes(&ObjectAttributes,
854                                &KeyName,
855                                OBJ_CASE_INSENSITIVE,
856                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
857                                NULL);
858     Status = NtOpenKey(&KeyHandle,
859                        KEY_SET_VALUE,
860                        &ObjectAttributes);
861     if (!NT_SUCCESS(Status))
862     {
863         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
864         return FALSE;
865     }
866 
867     StartValue = 1;
868     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
869                                    L"Start",
870                                    REG_DWORD,
871                                    &StartValue,
872                                    sizeof(StartValue));
873     NtClose(KeyHandle);
874     if (!NT_SUCCESS(Status))
875     {
876         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
877         return FALSE;
878     }
879 
880     /* Set the resolution */
881 
882     if (!INF_GetDataField(&Context, 4, &Buffer))
883     {
884         DPRINT1("INF_GetDataField() failed\n");
885         return FALSE;
886     }
887 
888     RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
889                         L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0",
890                         ServiceName);
891     DPRINT("RegPath: '%S'\n", RegPath);
892     RtlInitUnicodeString(&KeyName, RegPath);
893     InitializeObjectAttributes(&ObjectAttributes,
894                                &KeyName,
895                                OBJ_CASE_INSENSITIVE,
896                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
897                                NULL);
898     Status = NtOpenKey(&KeyHandle,
899                        KEY_SET_VALUE,
900                        &ObjectAttributes);
901     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
902     {
903         /* Try without Hardware Profile part */
904         RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
905                             L"System\\CurrentControlSet\\Services\\%s\\Device0",
906                             ServiceName);
907         RtlInitUnicodeString(&KeyName, RegPath);
908         Status = NtOpenKey(&KeyHandle,
909                            KEY_SET_VALUE,
910                            &ObjectAttributes);
911     }
912     if (!NT_SUCCESS(Status))
913     {
914         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
915         return FALSE;
916     }
917 
918     Width = wcstoul(Buffer, NULL, 10);
919     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
920                                    L"DefaultSettings.XResolution",
921                                    REG_DWORD,
922                                    &Width,
923                                    sizeof(Width));
924     if (!NT_SUCCESS(Status))
925     {
926         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
927         NtClose(KeyHandle);
928         return FALSE;
929     }
930 
931     if (!INF_GetDataField(&Context, 5, &Buffer))
932     {
933         DPRINT1("INF_GetDataField() failed\n");
934         NtClose(KeyHandle);
935         return FALSE;
936     }
937 
938     Height = wcstoul(Buffer, 0, 0);
939     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
940                                    L"DefaultSettings.YResolution",
941                                    REG_DWORD,
942                                    &Height,
943                                    sizeof(Height));
944     if (!NT_SUCCESS(Status))
945     {
946         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
947         NtClose(KeyHandle);
948         return FALSE;
949     }
950 
951     if (!INF_GetDataField(&Context, 6, &Buffer))
952     {
953         DPRINT1("INF_GetDataField() failed\n");
954         NtClose(KeyHandle);
955         return FALSE;
956     }
957 
958     Bpp = wcstoul(Buffer, 0, 0);
959     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
960                                    L"DefaultSettings.BitsPerPel",
961                                    REG_DWORD,
962                                    &Bpp,
963                                    sizeof(Bpp));
964     if (!NT_SUCCESS(Status))
965     {
966         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
967         NtClose(KeyHandle);
968         return FALSE;
969     }
970 
971     NtClose(KeyHandle);
972 
973     DPRINT("ProcessDisplayRegistry() done\n");
974 
975     return TRUE;
976 }
977 
978 BOOLEAN
979 ProcessLocaleRegistry(
980     IN PGENERIC_LIST List)
981 {
982     PGENERIC_LIST_ENTRY Entry;
983     PCWSTR LanguageId;
984     OBJECT_ATTRIBUTES ObjectAttributes;
985     UNICODE_STRING KeyName;
986     UNICODE_STRING ValueName;
987 
988     HANDLE KeyHandle;
989     NTSTATUS Status;
990 
991     Entry = GetCurrentListEntry(List);
992     if (Entry == NULL)
993         return FALSE;
994 
995     LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id;
996     if (LanguageId == NULL)
997         return FALSE;
998 
999     DPRINT("LanguageId: %S\n", LanguageId);
1000 
1001     /* Open the default users locale key */
1002     RtlInitUnicodeString(&KeyName,
1003                          L".DEFAULT\\Control Panel\\International");
1004 
1005     InitializeObjectAttributes(&ObjectAttributes,
1006                                &KeyName,
1007                                OBJ_CASE_INSENSITIVE,
1008                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
1009                                NULL);
1010 
1011     Status = NtOpenKey(&KeyHandle,
1012                        KEY_SET_VALUE,
1013                        &ObjectAttributes);
1014     if (!NT_SUCCESS(Status))
1015     {
1016         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1017         return FALSE;
1018     }
1019 
1020     /* Set default user locale */
1021     RtlInitUnicodeString(&ValueName, L"Locale");
1022     Status = NtSetValueKey(KeyHandle,
1023                            &ValueName,
1024                            0,
1025                            REG_SZ,
1026                            (PVOID)LanguageId,
1027                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1028     NtClose(KeyHandle);
1029     if (!NT_SUCCESS(Status))
1030     {
1031         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1032         return FALSE;
1033     }
1034 
1035     /* Skip first 4 zeroes */
1036     if (wcslen(LanguageId) >= 4)
1037         LanguageId += 4;
1038 
1039     /* Open the NLS language key */
1040     RtlInitUnicodeString(&KeyName,
1041                          L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
1042 
1043     InitializeObjectAttributes(&ObjectAttributes,
1044                                &KeyName,
1045                                OBJ_CASE_INSENSITIVE,
1046                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1047                                NULL);
1048 
1049     Status = NtOpenKey(&KeyHandle,
1050                        KEY_SET_VALUE,
1051                        &ObjectAttributes);
1052     if (!NT_SUCCESS(Status))
1053     {
1054         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1055         return FALSE;
1056     }
1057 
1058     /* Set default language */
1059     RtlInitUnicodeString(&ValueName, L"Default");
1060     Status = NtSetValueKey(KeyHandle,
1061                            &ValueName,
1062                            0,
1063                            REG_SZ,
1064                            (PVOID)LanguageId,
1065                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1066     if (!NT_SUCCESS(Status))
1067     {
1068         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1069         NtClose(KeyHandle);
1070         return FALSE;
1071     }
1072 
1073     /* Set install language */
1074     RtlInitUnicodeString(&ValueName, L"InstallLanguage");
1075     Status = NtSetValueKey(KeyHandle,
1076                            &ValueName,
1077                            0,
1078                            REG_SZ,
1079                            (PVOID)LanguageId,
1080                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1081     NtClose(KeyHandle);
1082     if (!NT_SUCCESS(Status))
1083     {
1084         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1085         return FALSE;
1086     }
1087 
1088     return TRUE;
1089 }
1090 
1091 
1092 PGENERIC_LIST
1093 CreateKeyboardDriverList(
1094     IN HINF InfFile)
1095 {
1096     PGENERIC_LIST List;
1097     INFCONTEXT Context;
1098 
1099     List = CreateGenericList();
1100     if (List == NULL)
1101         return NULL;
1102 
1103     if (AddEntriesFromInfSection(List,
1104                                  InfFile,
1105                                  L"Keyboard",
1106                                  &Context,
1107                                  DefaultProcessEntry,
1108                                  NULL) == -1)
1109     {
1110         DestroyGenericList(List, TRUE);
1111         return NULL;
1112     }
1113 
1114     return List;
1115 }
1116 
1117 
1118 ULONG
1119 GetDefaultLanguageIndex(VOID)
1120 {
1121     return DefaultLanguageIndex;
1122 }
1123 
1124 typedef struct _LANG_ENTRY_PARAM
1125 {
1126     ULONG uIndex;
1127     PWCHAR DefaultLanguage;
1128 } LANG_ENTRY_PARAM, *PLANG_ENTRY_PARAM;
1129 
1130 static UCHAR
1131 NTAPI
1132 ProcessLangEntry(
1133     IN PCWSTR KeyName,
1134     IN PCWSTR KeyValue,
1135     OUT PVOID* UserData,
1136     OUT PBOOLEAN Current,
1137     IN PVOID Parameter OPTIONAL)
1138 {
1139     PLANG_ENTRY_PARAM LangEntryParam = (PLANG_ENTRY_PARAM)Parameter;
1140 
1141     PGENENTRY GenEntry;
1142     SIZE_T IdSize, ValueSize;
1143 
1144     if (!IsLanguageAvailable(KeyName))
1145     {
1146         /* The specified language is unavailable, skip the entry */
1147         return 2;
1148     }
1149 
1150     IdSize    = (wcslen(KeyName)  + 1) * sizeof(WCHAR);
1151     ValueSize = (wcslen(KeyValue) + 1) * sizeof(WCHAR);
1152 
1153     GenEntry = RtlAllocateHeap(ProcessHeap, 0,
1154                                sizeof(*GenEntry) + IdSize + ValueSize);
1155     if (GenEntry == NULL)
1156     {
1157         /* Failure, stop enumeration */
1158         DPRINT1("RtlAllocateHeap() failed\n");
1159         return 0;
1160     }
1161 
1162     GenEntry->Id    = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry));
1163     GenEntry->Value = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry) + IdSize);
1164     RtlStringCbCopyW((PWSTR)GenEntry->Id, IdSize, KeyName);
1165     RtlStringCbCopyW((PWSTR)GenEntry->Value, ValueSize, KeyValue);
1166 
1167     *UserData = GenEntry;
1168     *Current  = FALSE;
1169 
1170     if (!_wcsicmp(KeyName, LangEntryParam->DefaultLanguage))
1171         DefaultLanguageIndex = LangEntryParam->uIndex;
1172 
1173     LangEntryParam->uIndex++;
1174 
1175     /* Add the entry */
1176     return 1;
1177 }
1178 
1179 PGENERIC_LIST
1180 CreateLanguageList(
1181     IN HINF InfFile,
1182     OUT PWSTR DefaultLanguage)
1183 {
1184     PGENERIC_LIST List;
1185     INFCONTEXT Context;
1186     PCWSTR KeyValue;
1187 
1188     LANG_ENTRY_PARAM LangEntryParam;
1189 
1190     LangEntryParam.uIndex = 0;
1191     LangEntryParam.DefaultLanguage = DefaultLanguage;
1192 
1193     /* Get default language id */
1194     if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLanguage", &Context))
1195         return NULL;
1196 
1197     if (!INF_GetData(&Context, NULL, &KeyValue))
1198         return NULL;
1199 
1200     wcscpy(DefaultLanguage, KeyValue);
1201 
1202     List = CreateGenericList();
1203     if (List == NULL)
1204         return NULL;
1205 
1206     if (AddEntriesFromInfSection(List,
1207                                  InfFile,
1208                                  L"Language",
1209                                  &Context,
1210                                  ProcessLangEntry,
1211                                  &LangEntryParam) == -1)
1212     {
1213         DestroyGenericList(List, TRUE);
1214         return NULL;
1215     }
1216 
1217     /* Only one language available, make it the default one */
1218     if (LangEntryParam.uIndex == 1)
1219     {
1220         DefaultLanguageIndex = 0;
1221         wcscpy(DefaultLanguage,
1222                ((PGENENTRY)GetListEntryData(GetFirstListEntry(List)))->Id);
1223     }
1224 
1225     return List;
1226 }
1227 
1228 
1229 PGENERIC_LIST
1230 CreateKeyboardLayoutList(
1231     IN HINF InfFile,
1232     IN PCWSTR LanguageId,
1233     OUT PWSTR DefaultKBLayout)
1234 {
1235     PGENERIC_LIST List;
1236     INFCONTEXT Context;
1237     PCWSTR KeyValue;
1238     const MUI_LAYOUTS* LayoutsList;
1239     ULONG uIndex = 0;
1240 
1241     /* Get default layout id */
1242     if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLayout", &Context))
1243         return NULL;
1244 
1245     if (!INF_GetData(&Context, NULL, &KeyValue))
1246         return NULL;
1247 
1248     wcscpy(DefaultKBLayout, KeyValue);
1249 
1250     List = CreateGenericList();
1251     if (List == NULL)
1252         return NULL;
1253 
1254     LayoutsList = MUIGetLayoutsList(LanguageId);
1255 
1256     do
1257     {
1258         // NOTE: See https://svn.reactos.org/svn/reactos?view=revision&revision=68354
1259         if (AddEntriesFromInfSection(List,
1260                                      InfFile,
1261                                      L"KeyboardLayout",
1262                                      &Context,
1263                                      DefaultProcessEntry,
1264                                      DefaultKBLayout) == -1)
1265         {
1266             DestroyGenericList(List, TRUE);
1267             return NULL;
1268         }
1269 
1270         uIndex++;
1271 
1272     } while (LayoutsList[uIndex].LangID != 0);
1273 
1274     /* Check whether some keyboard layouts have been found */
1275     /* FIXME: Handle this case */
1276     if (GetNumberOfListEntries(List) == 0)
1277     {
1278         DPRINT1("No keyboard layouts have been found\n");
1279         DestroyGenericList(List, TRUE);
1280         return NULL;
1281     }
1282 
1283     return List;
1284 }
1285 
1286 
1287 BOOLEAN
1288 ProcessKeyboardLayoutRegistry(
1289     IN PGENERIC_LIST List,
1290     IN PCWSTR LanguageId)
1291 {
1292     PGENERIC_LIST_ENTRY Entry;
1293     PCWSTR pszLayoutId;
1294     KLID LayoutId;
1295     const MUI_LAYOUTS* LayoutsList;
1296     MUI_LAYOUTS NewLayoutsList[20]; // HACK: Hardcoded fixed size "20" is a hack. Please verify against lang/*.h
1297     ULONG uIndex;
1298     ULONG uOldPos = 0;
1299 
1300     Entry = GetCurrentListEntry(List);
1301     if (Entry == NULL)
1302         return FALSE;
1303 
1304     pszLayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id;
1305     LayoutId = (KLID)(pszLayoutId ? wcstoul(pszLayoutId, NULL, 16) : 0);
1306     if (LayoutId == 0)
1307         return FALSE;
1308 
1309     LayoutsList = MUIGetLayoutsList(LanguageId);
1310 
1311     /* If the keyboard layout is already at the top of the list, we are done */
1312     if (LayoutsList[0].LayoutID == LayoutId)
1313         return TRUE;
1314 
1315     /* Otherwise, move it up to the top of the list */
1316     for (uIndex = 1; LayoutsList[uIndex].LangID != 0; ++uIndex)
1317     {
1318         if (LayoutsList[uIndex].LayoutID == LayoutId)
1319         {
1320             uOldPos = uIndex;
1321             continue;
1322         }
1323 
1324         NewLayoutsList[uIndex].LangID   = LayoutsList[uIndex].LangID;
1325         NewLayoutsList[uIndex].LayoutID = LayoutsList[uIndex].LayoutID;
1326     }
1327 
1328     NewLayoutsList[uIndex].LangID    = 0;
1329     NewLayoutsList[uIndex].LayoutID  = 0;
1330     NewLayoutsList[uOldPos].LangID   = LayoutsList[0].LangID;
1331     NewLayoutsList[uOldPos].LayoutID = LayoutsList[0].LayoutID;
1332     NewLayoutsList[0].LangID         = LayoutsList[uOldPos].LangID;
1333     NewLayoutsList[0].LayoutID       = LayoutsList[uOldPos].LayoutID;
1334 
1335     return AddKbLayoutsToRegistry(NewLayoutsList);
1336 }
1337 
1338 #if 0
1339 BOOLEAN
1340 ProcessKeyboardLayoutFiles(
1341     IN PGENERIC_LIST List)
1342 {
1343     return TRUE;
1344 }
1345 #endif
1346 
1347 BOOLEAN
1348 SetGeoID(
1349     _In_ GEOID GeoId)
1350 {
1351     NTSTATUS Status;
1352     OBJECT_ATTRIBUTES ObjectAttributes;
1353     UNICODE_STRING Name;
1354     HANDLE KeyHandle;
1355     /*
1356      * Buffer big enough to hold the NULL-terminated string L"4294967295",
1357      * corresponding to the literal 0xFFFFFFFF (MAXULONG) in decimal.
1358      */
1359     WCHAR Value[sizeof("4294967295")];
1360 
1361     Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", GeoId);
1362     ASSERT(NT_SUCCESS(Status));
1363 
1364     RtlInitUnicodeString(&Name,
1365                          L".DEFAULT\\Control Panel\\International\\Geo");
1366     InitializeObjectAttributes(&ObjectAttributes,
1367                                &Name,
1368                                OBJ_CASE_INSENSITIVE,
1369                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
1370                                NULL);
1371     Status = NtOpenKey(&KeyHandle,
1372                        KEY_SET_VALUE,
1373                        &ObjectAttributes);
1374     if (!NT_SUCCESS(Status))
1375     {
1376         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1377         return FALSE;
1378     }
1379 
1380     RtlInitUnicodeString(&Name, L"Nation");
1381     Status = NtSetValueKey(KeyHandle,
1382                            &Name,
1383                            0,
1384                            REG_SZ,
1385                            (PVOID)Value,
1386                            (wcslen(Value) + 1) * sizeof(WCHAR));
1387     NtClose(KeyHandle);
1388     if (!NT_SUCCESS(Status))
1389     {
1390         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1391         return FALSE;
1392     }
1393 
1394     return TRUE;
1395 }
1396 
1397 
1398 BOOLEAN
1399 SetDefaultPagefile(
1400     IN WCHAR Drive)
1401 {
1402     NTSTATUS Status;
1403     HANDLE KeyHandle;
1404     OBJECT_ATTRIBUTES ObjectAttributes;
1405     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1406     UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1407     WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1408 
1409     InitializeObjectAttributes(&ObjectAttributes,
1410                                &KeyName,
1411                                OBJ_CASE_INSENSITIVE,
1412                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1413                                NULL);
1414     Status = NtOpenKey(&KeyHandle,
1415                        KEY_ALL_ACCESS,
1416                        &ObjectAttributes);
1417     if (!NT_SUCCESS(Status))
1418         return FALSE;
1419 
1420     ValueBuffer[0] = Drive;
1421 
1422     NtSetValueKey(KeyHandle,
1423                   &ValueName,
1424                   0,
1425                   REG_MULTI_SZ,
1426                   (PVOID)&ValueBuffer,
1427                   sizeof(ValueBuffer));
1428 
1429     NtClose(KeyHandle);
1430     return TRUE;
1431 }
1432 
1433 /* EOF */
1434