[SETUPLIB] Improve the bootloader 'validity' checks -- Addendum to f06734e5 (r74512).
[reactos.git] / base / setup / lib / settings.c
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 if (IsAcpiComputer())
277 {
278 if (pFullInfo->SubKeys == 1)
279 {
280 /* Computer is mono-CPU */
281 ComputerIdentifier = L"ACPI UP";
282 }
283 else
284 {
285 /* Computer is multi-CPUs */
286 ComputerIdentifier = L"ACPI MP";
287 }
288 }
289 else
290 {
291 if (pFullInfo->SubKeys == 1)
292 {
293 /* Computer is mono-CPU */
294 ComputerIdentifier = L"PC UP";
295 }
296 else
297 {
298 /* Computer is multi-CPUs */
299 ComputerIdentifier = L"PC MP";
300 }
301 }
302
303 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
304
305 /* Copy computer identifier to return buffer */
306 SizeNeeded = (wcslen(ComputerIdentifier) + 1) * sizeof(WCHAR);
307 if (SizeNeeded > IdentifierLength)
308 return FALSE;
309
310 RtlCopyMemory(Identifier, ComputerIdentifier, SizeNeeded);
311
312 return TRUE;
313 }
314
315
316 /*
317 * Return values:
318 * 0x00: Failure, stop the enumeration;
319 * 0x01: Add the entry and continue the enumeration;
320 * 0x02: Skip the entry but continue the enumeration.
321 */
322 typedef UCHAR
323 (NTAPI *PPROCESS_ENTRY_ROUTINE)(
324 IN PWCHAR KeyName,
325 IN PWCHAR KeyValue,
326 OUT PWCHAR DisplayText,
327 IN SIZE_T DisplayTextSize,
328 OUT PVOID* UserData,
329 OUT PBOOLEAN Current,
330 IN PVOID Parameter OPTIONAL);
331
332 static LONG
333 AddEntriesFromInfSection(
334 IN OUT PGENERIC_LIST List,
335 IN HINF InfFile,
336 IN PCWSTR SectionName,
337 IN PINFCONTEXT pContext,
338 IN PPROCESS_ENTRY_ROUTINE ProcessEntry,
339 IN PVOID Parameter OPTIONAL)
340 {
341 LONG TotalCount = 0;
342 PWCHAR KeyName;
343 PWCHAR KeyValue;
344 PVOID UserData;
345 BOOLEAN Current;
346 UCHAR RetVal;
347 WCHAR DisplayText[128];
348
349 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, pContext))
350 return -1;
351
352 do
353 {
354 /*
355 * NOTE: Do not use INF_GetData() as it expects INF entries of exactly
356 * two fields ("key = value"); however we expect to be able to deal with
357 * entries having more than two fields, the only requirement being that
358 * the second field (field number 1) contains the field description.
359 */
360 if (!INF_GetDataField(pContext, 0, &KeyName))
361 {
362 DPRINT("INF_GetDataField() failed\n");
363 return -1;
364 }
365
366 if (!INF_GetDataField(pContext, 1, &KeyValue))
367 {
368 DPRINT("INF_GetDataField() failed\n");
369 INF_FreeData(KeyName);
370 return -1;
371 }
372
373 UserData = NULL;
374 Current = FALSE;
375 RetVal = ProcessEntry(KeyName,
376 KeyValue,
377 DisplayText,
378 sizeof(DisplayText),
379 &UserData,
380 &Current,
381 Parameter);
382 INF_FreeData(KeyName);
383 INF_FreeData(KeyValue);
384
385 if (RetVal == 0)
386 {
387 DPRINT("ProcessEntry() failed\n");
388 return -1;
389 }
390 else if (RetVal == 1)
391 {
392 AppendGenericListEntry(List, DisplayText, UserData, Current);
393 ++TotalCount;
394 }
395 // else if (RetVal == 2), skip the entry.
396
397 } while (SetupFindNextLine(pContext, pContext));
398
399 return TotalCount;
400 }
401
402 static UCHAR
403 NTAPI
404 DefaultProcessEntry(
405 IN PWCHAR KeyName,
406 IN PWCHAR KeyValue,
407 OUT PWCHAR DisplayText,
408 IN SIZE_T DisplayTextSize,
409 OUT PVOID* UserData,
410 OUT PBOOLEAN Current,
411 IN PVOID Parameter OPTIONAL)
412 {
413 PWSTR CompareKey = (PWSTR)Parameter;
414
415 *UserData = RtlAllocateHeap(ProcessHeap, 0,
416 (wcslen(KeyName) + 1) * sizeof(WCHAR));
417 if (*UserData == NULL)
418 {
419 /* Failure, stop enumeration */
420 DPRINT1("RtlAllocateHeap() failed\n");
421 return 0;
422 }
423
424 wcscpy((PWCHAR)*UserData, KeyName);
425 RtlStringCbCopyW(DisplayText, DisplayTextSize, KeyValue);
426
427 *Current = (CompareKey ? !_wcsicmp(KeyName, CompareKey) : FALSE);
428
429 /* Add the entry */
430 return 1;
431 }
432
433
434 PGENERIC_LIST
435 CreateComputerTypeList(
436 IN HINF InfFile)
437 {
438 PGENERIC_LIST List;
439 INFCONTEXT Context;
440 PWCHAR KeyName;
441 PWCHAR KeyValue;
442 WCHAR ComputerIdentifier[128];
443 WCHAR ComputerKey[32];
444
445 /* Get the computer identification */
446 if (!GetComputerIdentifier(ComputerIdentifier, 128))
447 {
448 ComputerIdentifier[0] = 0;
449 }
450
451 DPRINT("Computer identifier: '%S'\n", ComputerIdentifier);
452
453 /* Search for matching device identifier */
454 if (!SetupFindFirstLineW(InfFile, L"Map.Computer", NULL, &Context))
455 {
456 /* FIXME: error message */
457 return NULL;
458 }
459
460 do
461 {
462 BOOLEAN FoundId;
463
464 if (!INF_GetDataField(&Context, 1, &KeyValue))
465 {
466 /* FIXME: Handle error! */
467 DPRINT("INF_GetDataField() failed\n");
468 return NULL;
469 }
470
471 DPRINT("KeyValue: %S\n", KeyValue);
472 FoundId = !!wcsstr(ComputerIdentifier, KeyValue);
473 INF_FreeData(KeyValue);
474
475 if (!FoundId)
476 continue;
477
478 if (!INF_GetDataField(&Context, 0, &KeyName))
479 {
480 /* FIXME: Handle error! */
481 DPRINT("INF_GetDataField() failed\n");
482 return NULL;
483 }
484
485 DPRINT("Computer key: %S\n", KeyName);
486 RtlStringCchCopyW(ComputerKey, ARRAYSIZE(ComputerKey), KeyName);
487 INF_FreeData(KeyName);
488 } while (SetupFindNextLine(&Context, &Context));
489
490 List = CreateGenericList();
491 if (List == NULL)
492 return NULL;
493
494 if (AddEntriesFromInfSection(List,
495 InfFile,
496 L"Computer",
497 &Context,
498 DefaultProcessEntry,
499 ComputerKey) == -1)
500 {
501 DestroyGenericList(List, TRUE);
502 return NULL;
503 }
504
505 return List;
506 }
507
508 static
509 BOOLEAN
510 GetDisplayIdentifier(
511 OUT PWSTR Identifier,
512 IN ULONG IdentifierLength)
513 {
514 OBJECT_ATTRIBUTES ObjectAttributes;
515 UNICODE_STRING KeyName;
516 WCHAR Buffer[32];
517 HANDLE BusKey;
518 HANDLE BusInstanceKey;
519 HANDLE ControllerKey;
520 HANDLE ControllerInstanceKey;
521 ULONG BusInstance;
522 ULONG ControllerInstance;
523 ULONG BufferLength;
524 ULONG ReturnedLength;
525 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
526 NTSTATUS Status;
527
528 DPRINT("GetDisplayIdentifier() called\n");
529
530 /* Open the bus key */
531 RtlInitUnicodeString(&KeyName,
532 L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter");
533 InitializeObjectAttributes(&ObjectAttributes,
534 &KeyName,
535 OBJ_CASE_INSENSITIVE,
536 NULL,
537 NULL);
538
539 Status = NtOpenKey(&BusKey,
540 KEY_ENUMERATE_SUB_KEYS,
541 &ObjectAttributes);
542 if (!NT_SUCCESS(Status))
543 {
544 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
545 return FALSE;
546 }
547
548 BusInstance = 0;
549 while (TRUE)
550 {
551 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", BusInstance);
552 RtlInitUnicodeString(&KeyName, Buffer);
553 InitializeObjectAttributes(&ObjectAttributes,
554 &KeyName,
555 OBJ_CASE_INSENSITIVE,
556 BusKey,
557 NULL);
558
559 Status = NtOpenKey(&BusInstanceKey,
560 KEY_ENUMERATE_SUB_KEYS,
561 &ObjectAttributes);
562 if (!NT_SUCCESS(Status))
563 {
564 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
565 NtClose(BusKey);
566 return FALSE;
567 }
568
569 /* Open the controller type key */
570 RtlInitUnicodeString(&KeyName, L"DisplayController");
571 InitializeObjectAttributes(&ObjectAttributes,
572 &KeyName,
573 OBJ_CASE_INSENSITIVE,
574 BusInstanceKey,
575 NULL);
576
577 Status = NtOpenKey(&ControllerKey,
578 KEY_ENUMERATE_SUB_KEYS,
579 &ObjectAttributes);
580 if (NT_SUCCESS(Status))
581 {
582 ControllerInstance = 0;
583
584 while (TRUE)
585 {
586 /* Open the pointer controller instance key */
587 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer), L"%lu", ControllerInstance);
588 RtlInitUnicodeString(&KeyName, Buffer);
589 InitializeObjectAttributes(&ObjectAttributes,
590 &KeyName,
591 OBJ_CASE_INSENSITIVE,
592 ControllerKey,
593 NULL);
594
595 Status = NtOpenKey(&ControllerInstanceKey,
596 KEY_QUERY_VALUE,
597 &ObjectAttributes);
598 if (!NT_SUCCESS(Status))
599 {
600 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
601 NtClose(ControllerKey);
602 NtClose(BusInstanceKey);
603 NtClose(BusKey);
604 return FALSE;
605 }
606
607 /* Get controller identifier */
608 RtlInitUnicodeString(&KeyName, L"Identifier");
609
610 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
611 256 * sizeof(WCHAR);
612 ValueInfo = (KEY_VALUE_PARTIAL_INFORMATION*) RtlAllocateHeap(RtlGetProcessHeap(),
613 0,
614 BufferLength);
615 if (ValueInfo == NULL)
616 {
617 DPRINT("RtlAllocateHeap() failed\n");
618 NtClose(ControllerInstanceKey);
619 NtClose(ControllerKey);
620 NtClose(BusInstanceKey);
621 NtClose(BusKey);
622 return FALSE;
623 }
624
625 Status = NtQueryValueKey(ControllerInstanceKey,
626 &KeyName,
627 KeyValuePartialInformation,
628 ValueInfo,
629 BufferLength,
630 &ReturnedLength);
631 if (NT_SUCCESS(Status))
632 {
633 DPRINT("Identifier: %S\n", (PWSTR)ValueInfo->Data);
634
635 BufferLength = min(ValueInfo->DataLength / sizeof(WCHAR), IdentifierLength);
636 RtlCopyMemory(Identifier,
637 ValueInfo->Data,
638 BufferLength * sizeof(WCHAR));
639 Identifier[BufferLength] = 0;
640
641 RtlFreeHeap(RtlGetProcessHeap(),
642 0,
643 ValueInfo);
644
645 NtClose(ControllerInstanceKey);
646 NtClose(ControllerKey);
647 NtClose(BusInstanceKey);
648 NtClose(BusKey);
649 return TRUE;
650 }
651
652 NtClose(ControllerInstanceKey);
653
654 ControllerInstance++;
655 }
656
657 NtClose(ControllerKey);
658 }
659
660 NtClose(BusInstanceKey);
661
662 BusInstance++;
663 }
664
665 NtClose(BusKey);
666
667 return FALSE;
668 }
669
670 PGENERIC_LIST
671 CreateDisplayDriverList(
672 IN HINF InfFile)
673 {
674 PGENERIC_LIST List;
675 INFCONTEXT Context;
676 PWCHAR KeyName;
677 PWCHAR KeyValue;
678 WCHAR DisplayIdentifier[128];
679 WCHAR DisplayKey[32];
680
681 /* Get the display identification */
682 if (!GetDisplayIdentifier(DisplayIdentifier, 128))
683 {
684 DisplayIdentifier[0] = 0;
685 }
686
687 DPRINT("Display identifier: '%S'\n", DisplayIdentifier);
688
689 /* Search for matching device identifier */
690 if (!SetupFindFirstLineW(InfFile, L"Map.Display", NULL, &Context))
691 {
692 /* FIXME: error message */
693 return NULL;
694 }
695
696 do
697 {
698 BOOLEAN FoundId;
699
700 if (!INF_GetDataField(&Context, 1, &KeyValue))
701 {
702 /* FIXME: Handle error! */
703 DPRINT("INF_GetDataField() failed\n");
704 return NULL;
705 }
706
707 DPRINT("KeyValue: %S\n", KeyValue);
708 FoundId = !!wcsstr(DisplayIdentifier, KeyValue);
709 INF_FreeData(KeyValue);
710
711 if (!FoundId)
712 continue;
713
714 if (!INF_GetDataField(&Context, 0, &KeyName))
715 {
716 /* FIXME: Handle error! */
717 DPRINT("INF_GetDataField() failed\n");
718 return NULL;
719 }
720
721 DPRINT("Display key: %S\n", KeyName);
722 RtlStringCchCopyW(DisplayKey, ARRAYSIZE(DisplayKey), KeyName);
723 INF_FreeData(KeyName);
724 } while (SetupFindNextLine(&Context, &Context));
725
726 List = CreateGenericList();
727 if (List == NULL)
728 return NULL;
729
730 if (AddEntriesFromInfSection(List,
731 InfFile,
732 L"Display",
733 &Context,
734 DefaultProcessEntry,
735 DisplayKey) == -1)
736 {
737 DestroyGenericList(List, TRUE);
738 return NULL;
739 }
740
741 #if 0
742 AppendGenericListEntry(List, L"Other display driver", NULL, TRUE);
743 #endif
744
745 return List;
746 }
747
748
749 BOOLEAN
750 ProcessComputerFiles(
751 IN HINF InfFile,
752 IN PGENERIC_LIST List,
753 OUT PWSTR* AdditionalSectionName)
754 {
755 PGENERIC_LIST_ENTRY Entry;
756 static WCHAR SectionName[128];
757
758 DPRINT("ProcessComputerFiles() called\n");
759
760 Entry = GetCurrentListEntry(List);
761 if (Entry == NULL)
762 {
763 DPRINT("GetCurrentListEntry() failed\n");
764 return FALSE;
765 }
766
767 RtlStringCchPrintfW(SectionName, ARRAYSIZE(SectionName),
768 L"Files.%s", (PCWSTR)GetListEntryUserData(Entry));
769 *AdditionalSectionName = SectionName;
770
771 return TRUE;
772 }
773
774 BOOLEAN
775 ProcessDisplayRegistry(
776 IN HINF InfFile,
777 IN PGENERIC_LIST List)
778 {
779 NTSTATUS Status;
780 PGENERIC_LIST_ENTRY Entry;
781 INFCONTEXT Context;
782 PWCHAR Buffer;
783 PWCHAR ServiceName;
784 ULONG StartValue;
785 ULONG Width, Height, Bpp;
786 OBJECT_ATTRIBUTES ObjectAttributes;
787 UNICODE_STRING KeyName;
788 HANDLE KeyHandle;
789 WCHAR RegPath[255];
790
791 DPRINT("ProcessDisplayRegistry() called\n");
792
793 Entry = GetCurrentListEntry(List);
794 if (Entry == NULL)
795 {
796 DPRINT1("GetCurrentListEntry() failed\n");
797 return FALSE;
798 }
799
800 if (!SetupFindFirstLineW(InfFile, L"Display", (WCHAR*)GetListEntryUserData(Entry), &Context))
801 {
802 DPRINT1("SetupFindFirstLineW() failed\n");
803 return FALSE;
804 }
805
806 /* Enable the correct driver */
807 if (!INF_GetDataField(&Context, 3, &ServiceName))
808 {
809 DPRINT1("INF_GetDataField() failed\n");
810 return FALSE;
811 }
812
813 ASSERT(wcslen(ServiceName) < 10);
814 DPRINT1("Service name: '%S'\n", ServiceName);
815
816 RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
817 L"System\\CurrentControlSet\\Services\\%s",
818 ServiceName);
819 RtlInitUnicodeString(&KeyName, RegPath);
820 InitializeObjectAttributes(&ObjectAttributes,
821 &KeyName,
822 OBJ_CASE_INSENSITIVE,
823 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
824 NULL);
825 Status = NtOpenKey(&KeyHandle,
826 KEY_SET_VALUE,
827 &ObjectAttributes);
828 if (!NT_SUCCESS(Status))
829 {
830 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
831 return FALSE;
832 }
833
834 StartValue = 1;
835 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
836 L"Start",
837 REG_DWORD,
838 &StartValue,
839 sizeof(StartValue));
840 NtClose(KeyHandle);
841 if (!NT_SUCCESS(Status))
842 {
843 DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
844 return FALSE;
845 }
846
847 /* Set the resolution */
848
849 if (!INF_GetDataField(&Context, 4, &Buffer))
850 {
851 DPRINT1("INF_GetDataField() failed\n");
852 return FALSE;
853 }
854
855 RtlStringCchPrintfW(RegPath, ARRAYSIZE(RegPath),
856 L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\%s\\Device0",
857 ServiceName);
858 DPRINT1("RegPath: '%S'\n", RegPath);
859 RtlInitUnicodeString(&KeyName, RegPath);
860 InitializeObjectAttributes(&ObjectAttributes,
861 &KeyName,
862 OBJ_CASE_INSENSITIVE,
863 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
864 NULL);
865 Status = NtOpenKey(&KeyHandle,
866 KEY_SET_VALUE,
867 &ObjectAttributes);
868 if (!NT_SUCCESS(Status))
869 {
870 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
871 return FALSE;
872 }
873
874 Width = wcstoul(Buffer, NULL, 10);
875 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
876 L"DefaultSettings.XResolution",
877 REG_DWORD,
878 &Width,
879 sizeof(Width));
880 if (!NT_SUCCESS(Status))
881 {
882 DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
883 NtClose(KeyHandle);
884 return FALSE;
885 }
886
887 if (!INF_GetDataField(&Context, 5, &Buffer))
888 {
889 DPRINT1("INF_GetDataField() failed\n");
890 NtClose(KeyHandle);
891 return FALSE;
892 }
893
894 Height = wcstoul(Buffer, 0, 0);
895 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
896 L"DefaultSettings.YResolution",
897 REG_DWORD,
898 &Height,
899 sizeof(Height));
900 if (!NT_SUCCESS(Status))
901 {
902 DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
903 NtClose(KeyHandle);
904 return FALSE;
905 }
906
907 if (!INF_GetDataField(&Context, 6, &Buffer))
908 {
909 DPRINT1("INF_GetDataField() failed\n");
910 NtClose(KeyHandle);
911 return FALSE;
912 }
913
914 Bpp = wcstoul(Buffer, 0, 0);
915 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, KeyHandle,
916 L"DefaultSettings.BitsPerPel",
917 REG_DWORD,
918 &Bpp,
919 sizeof(Bpp));
920 if (!NT_SUCCESS(Status))
921 {
922 DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
923 NtClose(KeyHandle);
924 return FALSE;
925 }
926
927 NtClose(KeyHandle);
928
929 DPRINT("ProcessDisplayRegistry() done\n");
930
931 return TRUE;
932 }
933
934 BOOLEAN
935 ProcessLocaleRegistry(
936 IN PGENERIC_LIST List)
937 {
938 PGENERIC_LIST_ENTRY Entry;
939 PWCHAR LanguageId;
940 OBJECT_ATTRIBUTES ObjectAttributes;
941 UNICODE_STRING KeyName;
942 UNICODE_STRING ValueName;
943
944 HANDLE KeyHandle;
945 NTSTATUS Status;
946
947 Entry = GetCurrentListEntry(List);
948 if (Entry == NULL)
949 return FALSE;
950
951 LanguageId = (PWCHAR)GetListEntryUserData(Entry);
952 if (LanguageId == NULL)
953 return FALSE;
954
955 DPRINT("LanguageId: %S\n", LanguageId);
956
957 /* Open the default users locale key */
958 RtlInitUnicodeString(&KeyName,
959 L".DEFAULT\\Control Panel\\International");
960
961 InitializeObjectAttributes(&ObjectAttributes,
962 &KeyName,
963 OBJ_CASE_INSENSITIVE,
964 GetRootKeyByPredefKey(HKEY_USERS, NULL),
965 NULL);
966
967 Status = NtOpenKey(&KeyHandle,
968 KEY_SET_VALUE,
969 &ObjectAttributes);
970 if (!NT_SUCCESS(Status))
971 {
972 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
973 return FALSE;
974 }
975
976 /* Set default user locale */
977 RtlInitUnicodeString(&ValueName, L"Locale");
978 Status = NtSetValueKey(KeyHandle,
979 &ValueName,
980 0,
981 REG_SZ,
982 (PVOID)LanguageId,
983 (wcslen(LanguageId) + 1) * sizeof(WCHAR));
984 NtClose(KeyHandle);
985 if (!NT_SUCCESS(Status))
986 {
987 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
988 return FALSE;
989 }
990
991 /* Skip first 4 zeroes */
992 if (wcslen(LanguageId) >= 4)
993 LanguageId += 4;
994
995 /* Open the NLS language key */
996 RtlInitUnicodeString(&KeyName,
997 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
998
999 InitializeObjectAttributes(&ObjectAttributes,
1000 &KeyName,
1001 OBJ_CASE_INSENSITIVE,
1002 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1003 NULL);
1004
1005 Status = NtOpenKey(&KeyHandle,
1006 KEY_SET_VALUE,
1007 &ObjectAttributes);
1008 if (!NT_SUCCESS(Status))
1009 {
1010 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1011 return FALSE;
1012 }
1013
1014 /* Set default language */
1015 RtlInitUnicodeString(&ValueName, L"Default");
1016 Status = NtSetValueKey(KeyHandle,
1017 &ValueName,
1018 0,
1019 REG_SZ,
1020 (PVOID)LanguageId,
1021 (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1022 if (!NT_SUCCESS(Status))
1023 {
1024 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1025 NtClose(KeyHandle);
1026 return FALSE;
1027 }
1028
1029 /* Set install language */
1030 RtlInitUnicodeString(&ValueName, L"InstallLanguage");
1031 Status = NtSetValueKey(KeyHandle,
1032 &ValueName,
1033 0,
1034 REG_SZ,
1035 (PVOID)LanguageId,
1036 (wcslen(LanguageId) + 1) * sizeof(WCHAR));
1037 NtClose(KeyHandle);
1038 if (!NT_SUCCESS(Status))
1039 {
1040 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1041 return FALSE;
1042 }
1043
1044 return TRUE;
1045 }
1046
1047
1048 PGENERIC_LIST
1049 CreateKeyboardDriverList(
1050 IN HINF InfFile)
1051 {
1052 PGENERIC_LIST List;
1053 INFCONTEXT Context;
1054
1055 List = CreateGenericList();
1056 if (List == NULL)
1057 return NULL;
1058
1059 if (AddEntriesFromInfSection(List,
1060 InfFile,
1061 L"Keyboard",
1062 &Context,
1063 DefaultProcessEntry,
1064 NULL) == -1)
1065 {
1066 DestroyGenericList(List, TRUE);
1067 return NULL;
1068 }
1069
1070 return List;
1071 }
1072
1073
1074 ULONG
1075 GetDefaultLanguageIndex(VOID)
1076 {
1077 return DefaultLanguageIndex;
1078 }
1079
1080 typedef struct _LANG_ENTRY_PARAM
1081 {
1082 ULONG uIndex;
1083 PWCHAR DefaultLanguage;
1084 } LANG_ENTRY_PARAM, *PLANG_ENTRY_PARAM;
1085
1086 static UCHAR
1087 NTAPI
1088 ProcessLangEntry(
1089 IN PWCHAR KeyName,
1090 IN PWCHAR KeyValue,
1091 OUT PWCHAR DisplayText,
1092 IN SIZE_T DisplayTextSize,
1093 OUT PVOID* UserData,
1094 OUT PBOOLEAN Current,
1095 IN PVOID Parameter OPTIONAL)
1096 {
1097 PLANG_ENTRY_PARAM LangEntryParam = (PLANG_ENTRY_PARAM)Parameter;
1098
1099 if (!IsLanguageAvailable(KeyName))
1100 {
1101 /* The specified language is unavailable, skip the entry */
1102 return 2;
1103 }
1104
1105 *UserData = RtlAllocateHeap(ProcessHeap, 0,
1106 (wcslen(KeyName) + 1) * sizeof(WCHAR));
1107 if (*UserData == NULL)
1108 {
1109 /* Failure, stop enumeration */
1110 DPRINT1("RtlAllocateHeap() failed\n");
1111 return 0;
1112 }
1113
1114 wcscpy((PWCHAR)*UserData, KeyName);
1115 RtlStringCbCopyW(DisplayText, DisplayTextSize, KeyValue);
1116
1117 *Current = FALSE;
1118
1119 if (!_wcsicmp(KeyName, LangEntryParam->DefaultLanguage))
1120 DefaultLanguageIndex = LangEntryParam->uIndex;
1121
1122 LangEntryParam->uIndex++;
1123
1124 /* Add the entry */
1125 return 1;
1126 }
1127
1128 PGENERIC_LIST
1129 CreateLanguageList(
1130 IN HINF InfFile,
1131 OUT PWSTR DefaultLanguage)
1132 {
1133 PGENERIC_LIST List;
1134 INFCONTEXT Context;
1135 PWCHAR KeyValue;
1136
1137 LANG_ENTRY_PARAM LangEntryParam;
1138
1139 LangEntryParam.uIndex = 0;
1140 LangEntryParam.DefaultLanguage = DefaultLanguage;
1141
1142 /* Get default language id */
1143 if (!SetupFindFirstLineW(InfFile, L"NLS", L"DefaultLanguage", &Context))
1144 return NULL;
1145
1146 if (!INF_GetData(&Context, NULL, &KeyValue))
1147 return NULL;
1148
1149 wcscpy(DefaultLanguage, KeyValue);
1150
1151 List = CreateGenericList();
1152 if (List == NULL)
1153 return NULL;
1154
1155 if (AddEntriesFromInfSection(List,
1156 InfFile,
1157 L"Language",
1158 &Context,
1159 ProcessLangEntry,
1160 &LangEntryParam) == -1)
1161 {
1162 DestroyGenericList(List, TRUE);
1163 return NULL;
1164 }
1165
1166 /* Only one language available, make it the default one */
1167 if (LangEntryParam.uIndex == 1)
1168 {
1169 DefaultLanguageIndex = 0;
1170 wcscpy(DefaultLanguage,
1171 (PWSTR)GetListEntryUserData(GetFirstListEntry(List)));
1172 }
1173
1174 return List;
1175 }
1176
1177
1178 PGENERIC_LIST
1179 CreateKeyboardLayoutList(
1180 IN HINF InfFile,
1181 IN PCWSTR LanguageId,
1182 OUT PWSTR DefaultKBLayout)
1183 {
1184 PGENERIC_LIST List;
1185 INFCONTEXT Context;
1186 PWCHAR KeyValue;
1187 const MUI_LAYOUTS* LayoutsList;
1188 ULONG uIndex = 0;
1189
1190 /* Get default layout id */
1191 if (!SetupFindFirstLineW(InfFile, L"NLS", L"DefaultLayout", &Context))
1192 return NULL;
1193
1194 if (!INF_GetData(&Context, NULL, &KeyValue))
1195 return NULL;
1196
1197 wcscpy(DefaultKBLayout, KeyValue);
1198
1199 List = CreateGenericList();
1200 if (List == NULL)
1201 return NULL;
1202
1203 LayoutsList = MUIGetLayoutsList(LanguageId);
1204
1205 do
1206 {
1207 // NOTE: See https://svn.reactos.org/svn/reactos?view=revision&revision=68354
1208 if (AddEntriesFromInfSection(List,
1209 InfFile,
1210 L"KeyboardLayout",
1211 &Context,
1212 DefaultProcessEntry,
1213 DefaultKBLayout) == -1)
1214 {
1215 DestroyGenericList(List, TRUE);
1216 return NULL;
1217 }
1218
1219 uIndex++;
1220
1221 } while (LayoutsList[uIndex].LangID != NULL);
1222
1223 /* Check whether some keyboard layouts have been found */
1224 /* FIXME: Handle this case */
1225 if (GetNumberOfListEntries(List) == 0)
1226 {
1227 DPRINT1("No keyboard layouts have been found\n");
1228 DestroyGenericList(List, TRUE);
1229 return NULL;
1230 }
1231
1232 return List;
1233 }
1234
1235
1236 BOOLEAN
1237 ProcessKeyboardLayoutRegistry(
1238 IN PGENERIC_LIST List,
1239 IN PCWSTR LanguageId)
1240 {
1241 PGENERIC_LIST_ENTRY Entry;
1242 PWCHAR LayoutId;
1243 const MUI_LAYOUTS* LayoutsList;
1244 MUI_LAYOUTS NewLayoutsList[20];
1245 ULONG uIndex;
1246 ULONG uOldPos = 0;
1247
1248 Entry = GetCurrentListEntry(List);
1249 if (Entry == NULL)
1250 return FALSE;
1251
1252 LayoutId = (PWCHAR)GetListEntryUserData(Entry);
1253 if (LayoutId == NULL)
1254 return FALSE;
1255
1256 LayoutsList = MUIGetLayoutsList(LanguageId);
1257
1258 if (_wcsicmp(LayoutsList[0].LayoutID, LayoutId) == 0)
1259 return TRUE;
1260
1261 for (uIndex = 1; LayoutsList[uIndex].LangID != NULL; uIndex++)
1262 {
1263 if (_wcsicmp(LayoutsList[uIndex].LayoutID, LayoutId) == 0)
1264 {
1265 uOldPos = uIndex;
1266 continue;
1267 }
1268
1269 NewLayoutsList[uIndex].LangID = LayoutsList[uIndex].LangID;
1270 NewLayoutsList[uIndex].LayoutID = LayoutsList[uIndex].LayoutID;
1271 }
1272
1273 NewLayoutsList[uIndex].LangID = NULL;
1274 NewLayoutsList[uIndex].LayoutID = NULL;
1275 NewLayoutsList[uOldPos].LangID = LayoutsList[0].LangID;
1276 NewLayoutsList[uOldPos].LayoutID = LayoutsList[0].LayoutID;
1277 NewLayoutsList[0].LangID = LayoutsList[uOldPos].LangID;
1278 NewLayoutsList[0].LayoutID = LayoutsList[uOldPos].LayoutID;
1279
1280 return AddKbLayoutsToRegistry(NewLayoutsList);
1281 }
1282
1283 #if 0
1284 BOOLEAN
1285 ProcessKeyboardLayoutFiles(
1286 IN PGENERIC_LIST List)
1287 {
1288 return TRUE;
1289 }
1290 #endif
1291
1292 BOOLEAN
1293 SetGeoID(
1294 IN PCWSTR Id)
1295 {
1296 NTSTATUS Status;
1297 OBJECT_ATTRIBUTES ObjectAttributes;
1298 UNICODE_STRING Name;
1299 HANDLE KeyHandle;
1300
1301 RtlInitUnicodeString(&Name,
1302 L".DEFAULT\\Control Panel\\International\\Geo");
1303 InitializeObjectAttributes(&ObjectAttributes,
1304 &Name,
1305 OBJ_CASE_INSENSITIVE,
1306 GetRootKeyByPredefKey(HKEY_USERS, NULL),
1307 NULL);
1308 Status = NtOpenKey(&KeyHandle,
1309 KEY_SET_VALUE,
1310 &ObjectAttributes);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1314 return FALSE;
1315 }
1316
1317 RtlInitUnicodeString(&Name, L"Nation");
1318 Status = NtSetValueKey(KeyHandle,
1319 &Name,
1320 0,
1321 REG_SZ,
1322 (PVOID)Id,
1323 (wcslen(Id) + 1) * sizeof(WCHAR));
1324 NtClose(KeyHandle);
1325 if (!NT_SUCCESS(Status))
1326 {
1327 DPRINT1("NtSetValueKey() failed (Status = %lx)\n", Status);
1328 return FALSE;
1329 }
1330
1331 return TRUE;
1332 }
1333
1334
1335 BOOLEAN
1336 SetDefaultPagefile(
1337 IN WCHAR Drive)
1338 {
1339 NTSTATUS Status;
1340 HANDLE KeyHandle;
1341 OBJECT_ATTRIBUTES ObjectAttributes;
1342 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1343 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1344 WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1345
1346 InitializeObjectAttributes(&ObjectAttributes,
1347 &KeyName,
1348 OBJ_CASE_INSENSITIVE,
1349 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1350 NULL);
1351 Status = NtOpenKey(&KeyHandle,
1352 KEY_ALL_ACCESS,
1353 &ObjectAttributes);
1354 if (!NT_SUCCESS(Status))
1355 return FALSE;
1356
1357 ValueBuffer[0] = Drive;
1358
1359 NtSetValueKey(KeyHandle,
1360 &ValueName,
1361 0,
1362 REG_MULTI_SZ,
1363 (PVOID)&ValueBuffer,
1364 sizeof(ValueBuffer));
1365
1366 NtClose(KeyHandle);
1367 return TRUE;
1368 }
1369
1370 /* EOF */