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