xref: /reactos/base/setup/lib/settings.c (revision b02dd8eb)
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
IsAcpiComputer(VOID)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
GetComputerIdentifier(OUT PWSTR Identifier,IN ULONG IdentifierLength)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
AddEntriesFromInfSection(IN OUT PGENERIC_LIST List,IN HINF InfFile,IN PCWSTR SectionName,IN PINFCONTEXT pContext,IN PPROCESS_ENTRY_ROUTINE ProcessEntry,IN PVOID Parameter OPTIONAL)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
DefaultProcessEntry(IN PCWSTR KeyName,IN PCWSTR KeyValue,OUT PVOID * UserData,OUT PBOOLEAN Current,IN PVOID Parameter OPTIONAL)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
AddComputerTypeEntries(_In_ HINF InfFile,PGENERIC_LIST List,_In_ PWSTR SectionName)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
CreateComputerTypeList(IN HINF InfFile)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
GetDisplayIdentifier(OUT PWSTR Identifier,IN ULONG IdentifierLength)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
CreateDisplayDriverList(IN HINF InfFile)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
ProcessComputerFiles(_In_ HINF InfFile,_In_ PCWSTR ComputerType,_Out_ PWSTR * AdditionalSectionName)787 ProcessComputerFiles(
788     _In_ HINF InfFile,
789     _In_ PCWSTR ComputerType,
790     _Out_ PWSTR* AdditionalSectionName)
791 {
792     static WCHAR SectionName[128];
793 
794     DPRINT("ProcessComputerFiles(%S) called\n", ComputerType);
795 
796     RtlStringCchPrintfW(SectionName, _countof(SectionName),
797                         L"Files.%s", ComputerType);
798     *AdditionalSectionName = SectionName;
799 
800     // TODO: More things to do?
801 
802     return TRUE;
803 }
804 
805 BOOLEAN
ProcessDisplayRegistry(_In_ HINF InfFile,_In_ PCWSTR DisplayType)806 ProcessDisplayRegistry(
807     _In_ HINF InfFile,
808     _In_ PCWSTR DisplayType)
809 {
810     NTSTATUS Status;
811     INFCONTEXT Context;
812     PCWSTR Buffer;
813     PCWSTR ServiceName;
814     ULONG StartValue;
815     ULONG Width, Height, Bpp;
816     OBJECT_ATTRIBUTES ObjectAttributes;
817     UNICODE_STRING KeyName;
818     HANDLE KeyHandle;
819     WCHAR RegPath[255];
820 
821     DPRINT("ProcessDisplayRegistry(%S) called\n", DisplayType);
822 
823     if (!SpInfFindFirstLine(InfFile, L"Display", DisplayType, &Context))
824     {
825         DPRINT1("SpInfFindFirstLine() failed\n");
826         return FALSE;
827     }
828 
829     /* Enable the correct driver */
830     if (!INF_GetDataField(&Context, 3, &ServiceName))
831     {
832         DPRINT1("INF_GetDataField() failed\n");
833         return FALSE;
834     }
835 
836     ASSERT(wcslen(ServiceName) < 10);
837     DPRINT("Service name: '%S'\n", ServiceName);
838 
839     RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
840                         L"System\\CurrentControlSet\\Services\\%s",
841                         ServiceName);
842     RtlInitUnicodeString(&KeyName, RegPath);
843     InitializeObjectAttributes(&ObjectAttributes,
844                                &KeyName,
845                                OBJ_CASE_INSENSITIVE,
846                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
847                                NULL);
848     Status = NtOpenKey(&KeyHandle,
849                        KEY_SET_VALUE,
850                        &ObjectAttributes);
851     if (!NT_SUCCESS(Status))
852     {
853         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
854         return FALSE;
855     }
856 
857     StartValue = 1;
858     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
859                                    L"Start",
860                                    REG_DWORD,
861                                    &StartValue,
862                                    sizeof(StartValue));
863     NtClose(KeyHandle);
864     if (!NT_SUCCESS(Status))
865     {
866         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
867         return FALSE;
868     }
869 
870     /* Set the resolution */
871 
872     if (!INF_GetDataField(&Context, 4, &Buffer))
873     {
874         DPRINT1("INF_GetDataField() failed\n");
875         return FALSE;
876     }
877 
878     RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
879                         L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0",
880                         ServiceName);
881     DPRINT("RegPath: '%S'\n", RegPath);
882     RtlInitUnicodeString(&KeyName, RegPath);
883     InitializeObjectAttributes(&ObjectAttributes,
884                                &KeyName,
885                                OBJ_CASE_INSENSITIVE,
886                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
887                                NULL);
888     Status = NtOpenKey(&KeyHandle,
889                        KEY_SET_VALUE,
890                        &ObjectAttributes);
891     if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
892     {
893         /* Try without Hardware Profile part */
894         RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
895                             L"System\\CurrentControlSet\\Services\\%s\\Device0",
896                             ServiceName);
897         RtlInitUnicodeString(&KeyName, RegPath);
898         Status = NtOpenKey(&KeyHandle,
899                            KEY_SET_VALUE,
900                            &ObjectAttributes);
901     }
902     if (!NT_SUCCESS(Status))
903     {
904         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
905         return FALSE;
906     }
907 
908     Width = wcstoul(Buffer, NULL, 10);
909     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
910                                    L"DefaultSettings.XResolution",
911                                    REG_DWORD,
912                                    &Width,
913                                    sizeof(Width));
914     if (!NT_SUCCESS(Status))
915     {
916         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
917         NtClose(KeyHandle);
918         return FALSE;
919     }
920 
921     if (!INF_GetDataField(&Context, 5, &Buffer))
922     {
923         DPRINT1("INF_GetDataField() failed\n");
924         NtClose(KeyHandle);
925         return FALSE;
926     }
927 
928     Height = wcstoul(Buffer, NULL, 10);
929     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
930                                    L"DefaultSettings.YResolution",
931                                    REG_DWORD,
932                                    &Height,
933                                    sizeof(Height));
934     if (!NT_SUCCESS(Status))
935     {
936         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
937         NtClose(KeyHandle);
938         return FALSE;
939     }
940 
941     if (!INF_GetDataField(&Context, 6, &Buffer))
942     {
943         DPRINT1("INF_GetDataField() failed\n");
944         NtClose(KeyHandle);
945         return FALSE;
946     }
947 
948     Bpp = wcstoul(Buffer, NULL, 10);
949     Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
950                                    L"DefaultSettings.BitsPerPel",
951                                    REG_DWORD,
952                                    &Bpp,
953                                    sizeof(Bpp));
954     if (!NT_SUCCESS(Status))
955     {
956         DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
957         NtClose(KeyHandle);
958         return FALSE;
959     }
960 
961     NtClose(KeyHandle);
962 
963     DPRINT("ProcessDisplayRegistry() done\n");
964 
965     return TRUE;
966 }
967 
968 BOOLEAN
ProcessLocaleRegistry(_In_ PCWSTR LanguageId)969 ProcessLocaleRegistry(
970     _In_ PCWSTR LanguageId)
971 {
972     OBJECT_ATTRIBUTES ObjectAttributes;
973     UNICODE_STRING KeyName;
974     UNICODE_STRING ValueName;
975     HANDLE KeyHandle;
976     NTSTATUS Status;
977 
978     DPRINT("LanguageId: %S\n", LanguageId);
979 
980     /* Open the default users locale key */
981     RtlInitUnicodeString(&KeyName,
982                          L".DEFAULT\\Control Panel\\International");
983 
984     InitializeObjectAttributes(&ObjectAttributes,
985                                &KeyName,
986                                OBJ_CASE_INSENSITIVE,
987                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
988                                NULL);
989 
990     Status = NtOpenKey(&KeyHandle,
991                        KEY_SET_VALUE,
992                        &ObjectAttributes);
993     if (!NT_SUCCESS(Status))
994     {
995         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
996         return FALSE;
997     }
998 
999     /* Set default user locale */
1000     RtlInitUnicodeString(&ValueName, L"Locale");
1001     Status = NtSetValueKey(KeyHandle,
1002                            &ValueName,
1003                            0,
1004                            REG_SZ,
1005                            (PVOID)LanguageId,
1006                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1007     NtClose(KeyHandle);
1008     if (!NT_SUCCESS(Status))
1009     {
1010         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1011         return FALSE;
1012     }
1013 
1014     /* Skip first 4 zeroes */
1015     if (wcslen(LanguageId) >= 4)
1016         LanguageId += 4;
1017 
1018     /* Open the NLS language key */
1019     RtlInitUnicodeString(&KeyName,
1020                          L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
1021 
1022     InitializeObjectAttributes(&ObjectAttributes,
1023                                &KeyName,
1024                                OBJ_CASE_INSENSITIVE,
1025                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1026                                NULL);
1027 
1028     Status = NtOpenKey(&KeyHandle,
1029                        KEY_SET_VALUE,
1030                        &ObjectAttributes);
1031     if (!NT_SUCCESS(Status))
1032     {
1033         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1034         return FALSE;
1035     }
1036 
1037     /* Set default language */
1038     RtlInitUnicodeString(&ValueName, L"Default");
1039     Status = NtSetValueKey(KeyHandle,
1040                            &ValueName,
1041                            0,
1042                            REG_SZ,
1043                            (PVOID)LanguageId,
1044                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1045     if (!NT_SUCCESS(Status))
1046     {
1047         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1048         NtClose(KeyHandle);
1049         return FALSE;
1050     }
1051 
1052     /* Set install language */
1053     RtlInitUnicodeString(&ValueName, L"InstallLanguage");
1054     Status = NtSetValueKey(KeyHandle,
1055                            &ValueName,
1056                            0,
1057                            REG_SZ,
1058                            (PVOID)LanguageId,
1059                            (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1060     NtClose(KeyHandle);
1061     if (!NT_SUCCESS(Status))
1062     {
1063         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1064         return FALSE;
1065     }
1066 
1067     return TRUE;
1068 }
1069 
1070 
1071 PGENERIC_LIST
CreateKeyboardDriverList(IN HINF InfFile)1072 CreateKeyboardDriverList(
1073     IN HINF InfFile)
1074 {
1075     PGENERIC_LIST List;
1076     INFCONTEXT Context;
1077 
1078     List = CreateGenericList();
1079     if (List == NULL)
1080         return NULL;
1081 
1082     if (AddEntriesFromInfSection(List,
1083                                  InfFile,
1084                                  L"Keyboard",
1085                                  &Context,
1086                                  DefaultProcessEntry,
1087                                  NULL) == -1)
1088     {
1089         DestroyGenericList(List, TRUE);
1090         return NULL;
1091     }
1092 
1093     return List;
1094 }
1095 
1096 
1097 ULONG
GetDefaultLanguageIndex(VOID)1098 GetDefaultLanguageIndex(VOID)
1099 {
1100     return DefaultLanguageIndex;
1101 }
1102 
1103 typedef struct _LANG_ENTRY_PARAM
1104 {
1105     ULONG uIndex;
1106     PWCHAR DefaultLanguage;
1107 } LANG_ENTRY_PARAM, *PLANG_ENTRY_PARAM;
1108 
1109 static UCHAR
1110 NTAPI
ProcessLangEntry(IN PCWSTR KeyName,IN PCWSTR KeyValue,OUT PVOID * UserData,OUT PBOOLEAN Current,IN PVOID Parameter OPTIONAL)1111 ProcessLangEntry(
1112     IN PCWSTR KeyName,
1113     IN PCWSTR KeyValue,
1114     OUT PVOID* UserData,
1115     OUT PBOOLEAN Current,
1116     IN PVOID Parameter OPTIONAL)
1117 {
1118     PLANG_ENTRY_PARAM LangEntryParam = (PLANG_ENTRY_PARAM)Parameter;
1119 
1120     PGENENTRY GenEntry;
1121     SIZE_T IdSize, ValueSize;
1122 
1123     if (!IsLanguageAvailable(KeyName))
1124     {
1125         /* The specified language is unavailable, skip the entry */
1126         return 2;
1127     }
1128 
1129     IdSize    = (wcslen(KeyName)  + 1) * sizeof(WCHAR);
1130     ValueSize = (wcslen(KeyValue) + 1) * sizeof(WCHAR);
1131 
1132     GenEntry = RtlAllocateHeap(ProcessHeap, 0,
1133                                sizeof(*GenEntry) + IdSize + ValueSize);
1134     if (GenEntry == NULL)
1135     {
1136         /* Failure, stop enumeration */
1137         DPRINT1("RtlAllocateHeap() failed\n");
1138         return 0;
1139     }
1140 
1141     GenEntry->Id    = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry));
1142     GenEntry->Value = (PCWSTR)((ULONG_PTR)GenEntry + sizeof(*GenEntry) + IdSize);
1143     RtlStringCbCopyW((PWSTR)GenEntry->Id, IdSize, KeyName);
1144     RtlStringCbCopyW((PWSTR)GenEntry->Value, ValueSize, KeyValue);
1145 
1146     *UserData = GenEntry;
1147     *Current  = FALSE;
1148 
1149     if (!_wcsicmp(KeyName, LangEntryParam->DefaultLanguage))
1150         DefaultLanguageIndex = LangEntryParam->uIndex;
1151 
1152     LangEntryParam->uIndex++;
1153 
1154     /* Add the entry */
1155     return 1;
1156 }
1157 
1158 PGENERIC_LIST
CreateLanguageList(IN HINF InfFile,OUT PWSTR DefaultLanguage)1159 CreateLanguageList(
1160     IN HINF InfFile,
1161     OUT PWSTR DefaultLanguage)
1162 {
1163     PGENERIC_LIST List;
1164     INFCONTEXT Context;
1165     PCWSTR KeyValue;
1166 
1167     LANG_ENTRY_PARAM LangEntryParam;
1168 
1169     LangEntryParam.uIndex = 0;
1170     LangEntryParam.DefaultLanguage = DefaultLanguage;
1171 
1172     /* Get default language id */
1173     if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLanguage", &Context))
1174         return NULL;
1175 
1176     if (!INF_GetData(&Context, NULL, &KeyValue))
1177         return NULL;
1178 
1179     wcscpy(DefaultLanguage, KeyValue);
1180 
1181     List = CreateGenericList();
1182     if (List == NULL)
1183         return NULL;
1184 
1185     if (AddEntriesFromInfSection(List,
1186                                  InfFile,
1187                                  L"Language",
1188                                  &Context,
1189                                  ProcessLangEntry,
1190                                  &LangEntryParam) == -1)
1191     {
1192         DestroyGenericList(List, TRUE);
1193         return NULL;
1194     }
1195 
1196     /* Only one language available, make it the default one */
1197     if (LangEntryParam.uIndex == 1)
1198     {
1199         DefaultLanguageIndex = 0;
1200         wcscpy(DefaultLanguage,
1201                ((PGENENTRY)GetListEntryData(GetFirstListEntry(List)))->Id);
1202     }
1203 
1204     return List;
1205 }
1206 
1207 
1208 PGENERIC_LIST
CreateKeyboardLayoutList(IN HINF InfFile,IN PCWSTR LanguageId,OUT PWSTR DefaultKBLayout)1209 CreateKeyboardLayoutList(
1210     IN HINF InfFile,
1211     IN PCWSTR LanguageId,
1212     OUT PWSTR DefaultKBLayout)
1213 {
1214     PGENERIC_LIST List;
1215     INFCONTEXT Context;
1216     PCWSTR KeyValue;
1217     const MUI_LAYOUTS* LayoutsList;
1218     ULONG uIndex = 0;
1219 
1220     /* Get default layout id */
1221     if (!SpInfFindFirstLine(InfFile, L"NLS", L"DefaultLayout", &Context))
1222         return NULL;
1223 
1224     if (!INF_GetData(&Context, NULL, &KeyValue))
1225         return NULL;
1226 
1227     wcscpy(DefaultKBLayout, KeyValue);
1228 
1229     List = CreateGenericList();
1230     if (List == NULL)
1231         return NULL;
1232 
1233     LayoutsList = MUIGetLayoutsList(LanguageId);
1234 
1235     do
1236     {
1237         // NOTE: See https://svn.reactos.org/svn/reactos?view=revision&revision=68354
1238         if (AddEntriesFromInfSection(List,
1239                                      InfFile,
1240                                      L"KeyboardLayout",
1241                                      &Context,
1242                                      DefaultProcessEntry,
1243                                      DefaultKBLayout) == -1)
1244         {
1245             DestroyGenericList(List, TRUE);
1246             return NULL;
1247         }
1248 
1249         uIndex++;
1250 
1251     } while (LayoutsList[uIndex].LangID != 0);
1252 
1253     /* Check whether some keyboard layouts have been found */
1254     /* FIXME: Handle this case */
1255     if (GetNumberOfListEntries(List) == 0)
1256     {
1257         DPRINT1("No keyboard layouts have been found\n");
1258         DestroyGenericList(List, TRUE);
1259         return NULL;
1260     }
1261 
1262     return List;
1263 }
1264 
1265 
1266 BOOLEAN
ProcessKeyboardLayoutRegistry(_In_ PCWSTR pszLayoutId,_In_ PCWSTR LanguageId)1267 ProcessKeyboardLayoutRegistry(
1268     _In_ PCWSTR pszLayoutId,
1269     _In_ PCWSTR LanguageId)
1270 {
1271     KLID LayoutId;
1272     const MUI_LAYOUTS* LayoutsList;
1273     MUI_LAYOUTS NewLayoutsList[20]; // HACK: Hardcoded fixed size "20" is a hack. Please verify against lang/*.h
1274     ULONG uIndex;
1275     ULONG uOldPos = 0;
1276 
1277     LayoutId = (KLID)(pszLayoutId ? wcstoul(pszLayoutId, NULL, 16) : 0);
1278     if (LayoutId == 0)
1279         return FALSE;
1280 
1281     LayoutsList = MUIGetLayoutsList(LanguageId);
1282 
1283     /* If the keyboard layout is already at the top of the list, we are done */
1284     if (LayoutsList[0].LayoutID == LayoutId)
1285         return TRUE;
1286 
1287     /* Otherwise, move it up to the top of the list */
1288     for (uIndex = 1; LayoutsList[uIndex].LangID != 0; ++uIndex)
1289     {
1290         if (LayoutsList[uIndex].LayoutID == LayoutId)
1291         {
1292             uOldPos = uIndex;
1293             continue;
1294         }
1295 
1296         NewLayoutsList[uIndex].LangID   = LayoutsList[uIndex].LangID;
1297         NewLayoutsList[uIndex].LayoutID = LayoutsList[uIndex].LayoutID;
1298     }
1299 
1300     NewLayoutsList[uIndex].LangID    = 0;
1301     NewLayoutsList[uIndex].LayoutID  = 0;
1302     NewLayoutsList[uOldPos].LangID   = LayoutsList[0].LangID;
1303     NewLayoutsList[uOldPos].LayoutID = LayoutsList[0].LayoutID;
1304     NewLayoutsList[0].LangID         = LayoutsList[uOldPos].LangID;
1305     NewLayoutsList[0].LayoutID       = LayoutsList[uOldPos].LayoutID;
1306 
1307     return AddKbLayoutsToRegistry(NewLayoutsList);
1308 }
1309 
1310 #if 0
1311 BOOLEAN
1312 ProcessKeyboardLayoutFiles(
1313     IN PGENERIC_LIST List)
1314 {
1315     return TRUE;
1316 }
1317 #endif
1318 
1319 BOOLEAN
SetGeoID(_In_ GEOID GeoId)1320 SetGeoID(
1321     _In_ GEOID GeoId)
1322 {
1323     NTSTATUS Status;
1324     OBJECT_ATTRIBUTES ObjectAttributes;
1325     UNICODE_STRING Name;
1326     HANDLE KeyHandle;
1327     /*
1328      * Buffer big enough to hold the NULL-terminated string L"4294967295",
1329      * corresponding to the literal 0xFFFFFFFF (MAXULONG) in decimal.
1330      */
1331     WCHAR Value[sizeof("4294967295")];
1332 
1333     Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", GeoId);
1334     ASSERT(NT_SUCCESS(Status));
1335 
1336     RtlInitUnicodeString(&Name,
1337                          L".DEFAULT\\Control Panel\\International\\Geo");
1338     InitializeObjectAttributes(&ObjectAttributes,
1339                                &Name,
1340                                OBJ_CASE_INSENSITIVE,
1341                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
1342                                NULL);
1343     Status = NtOpenKey(&KeyHandle,
1344                        KEY_SET_VALUE,
1345                        &ObjectAttributes);
1346     if (!NT_SUCCESS(Status))
1347     {
1348         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1349         return FALSE;
1350     }
1351 
1352     RtlInitUnicodeString(&Name, L"Nation");
1353     Status = NtSetValueKey(KeyHandle,
1354                            &Name,
1355                            0,
1356                            REG_SZ,
1357                            (PVOID)Value,
1358                            (wcslen(Value) + 1) * sizeof(WCHAR));
1359     NtClose(KeyHandle);
1360     if (!NT_SUCCESS(Status))
1361     {
1362         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1363         return FALSE;
1364     }
1365 
1366     return TRUE;
1367 }
1368 
1369 BOOLEAN
SetDefaultPagefile(_In_ WCHAR Drive)1370 SetDefaultPagefile(
1371     _In_ WCHAR Drive)
1372 {
1373     NTSTATUS Status;
1374     HANDLE KeyHandle;
1375     OBJECT_ATTRIBUTES ObjectAttributes;
1376     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1377     UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1378     WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1379 
1380     InitializeObjectAttributes(&ObjectAttributes,
1381                                &KeyName,
1382                                OBJ_CASE_INSENSITIVE,
1383                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1384                                NULL);
1385     Status = NtOpenKey(&KeyHandle,
1386                        KEY_ALL_ACCESS,
1387                        &ObjectAttributes);
1388     if (!NT_SUCCESS(Status))
1389         return FALSE;
1390 
1391     ValueBuffer[0] = Drive;
1392 
1393     NtSetValueKey(KeyHandle,
1394                   &ValueName,
1395                   0,
1396                   REG_MULTI_SZ,
1397                   (PVOID)&ValueBuffer,
1398                   sizeof(ValueBuffer));
1399 
1400     NtClose(KeyHandle);
1401     return TRUE;
1402 }
1403 
1404 /* EOF */
1405