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