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