bf9a80492995783ca5d49b33c2003b610de85280
[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 IN PCHAR 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 CHAR 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 IN PCHAR 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 sprintf(DisplayText, "%S", 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 wcscpy(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 swprintf(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 swprintf(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 wcscpy(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, "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 wcscpy(SectionName, L"Files.");
768 wcscat(SectionName, (const wchar_t*)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 swprintf(RegPath, L"System\\CurrentControlSet\\Services\\%s", 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 swprintf(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 PWCHAR 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 = (PWCHAR)GetListEntryUserData(Entry);
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 PWCHAR KeyName,
1088 IN PWCHAR KeyValue,
1089 IN PCHAR DisplayText,
1090 IN SIZE_T DisplayTextSize,
1091 OUT PVOID* UserData,
1092 OUT PBOOLEAN Current,
1093 IN PVOID Parameter OPTIONAL)
1094 {
1095 PLANG_ENTRY_PARAM LangEntryParam = (PLANG_ENTRY_PARAM)Parameter;
1096
1097 if (!IsLanguageAvailable(KeyName))
1098 {
1099 /* The specified language is unavailable, skip the entry */
1100 return 2;
1101 }
1102
1103 *UserData = RtlAllocateHeap(ProcessHeap, 0,
1104 (wcslen(KeyName) + 1) * sizeof(WCHAR));
1105 if (*UserData == NULL)
1106 {
1107 /* Failure, stop enumeration */
1108 DPRINT1("RtlAllocateHeap() failed\n");
1109 return 0;
1110 }
1111
1112 wcscpy((PWCHAR)*UserData, KeyName);
1113 sprintf(DisplayText, "%S", KeyValue);
1114
1115 *Current = FALSE;
1116
1117 if (!_wcsicmp(KeyName, LangEntryParam->DefaultLanguage))
1118 DefaultLanguageIndex = LangEntryParam->uIndex;
1119
1120 LangEntryParam->uIndex++;
1121
1122 /* Add the entry */
1123 return 1;
1124 }
1125
1126 PGENERIC_LIST
1127 CreateLanguageList(
1128 IN HINF InfFile,
1129 OUT PWSTR DefaultLanguage)
1130 {
1131 PGENERIC_LIST List;
1132 INFCONTEXT Context;
1133 PWCHAR KeyValue;
1134
1135 LANG_ENTRY_PARAM LangEntryParam;
1136
1137 LangEntryParam.uIndex = 0;
1138 LangEntryParam.DefaultLanguage = DefaultLanguage;
1139
1140 /* Get default language id */
1141 if (!SetupFindFirstLineW(InfFile, L"NLS", L"DefaultLanguage", &Context))
1142 return NULL;
1143
1144 if (!INF_GetData(&Context, NULL, &KeyValue))
1145 return NULL;
1146
1147 wcscpy(DefaultLanguage, KeyValue);
1148
1149 List = CreateGenericList();
1150 if (List == NULL)
1151 return NULL;
1152
1153 if (AddEntriesFromInfSection(List,
1154 InfFile,
1155 L"Language",
1156 &Context,
1157 ProcessLangEntry,
1158 &LangEntryParam) == -1)
1159 {
1160 DestroyGenericList(List, TRUE);
1161 return NULL;
1162 }
1163
1164 /* Only one language available, make it the default one */
1165 if (LangEntryParam.uIndex == 1)
1166 {
1167 DefaultLanguageIndex = 0;
1168 wcscpy(DefaultLanguage,
1169 (PWSTR)GetListEntryUserData(GetFirstListEntry(List)));
1170 }
1171
1172 return List;
1173 }
1174
1175
1176 PGENERIC_LIST
1177 CreateKeyboardLayoutList(
1178 IN HINF InfFile,
1179 IN PCWSTR LanguageId,
1180 OUT PWSTR DefaultKBLayout)
1181 {
1182 PGENERIC_LIST List;
1183 INFCONTEXT Context;
1184 PWCHAR KeyValue;
1185 const MUI_LAYOUTS* LayoutsList;
1186 ULONG uIndex = 0;
1187
1188 /* Get default layout id */
1189 if (!SetupFindFirstLineW(InfFile, L"NLS", L"DefaultLayout", &Context))
1190 return NULL;
1191
1192 if (!INF_GetData(&Context, NULL, &KeyValue))
1193 return NULL;
1194
1195 wcscpy(DefaultKBLayout, KeyValue);
1196
1197 List = CreateGenericList();
1198 if (List == NULL)
1199 return NULL;
1200
1201 LayoutsList = MUIGetLayoutsList(LanguageId);
1202
1203 do
1204 {
1205 // NOTE: See https://svn.reactos.org/svn/reactos?view=revision&revision=68354
1206 if (AddEntriesFromInfSection(List,
1207 InfFile,
1208 L"KeyboardLayout",
1209 &Context,
1210 DefaultProcessEntry,
1211 DefaultKBLayout) == -1)
1212 {
1213 DestroyGenericList(List, TRUE);
1214 return NULL;
1215 }
1216
1217 uIndex++;
1218
1219 } while (LayoutsList[uIndex].LangID != NULL);
1220
1221 /* Check whether some keyboard layouts have been found */
1222 /* FIXME: Handle this case */
1223 if (GetNumberOfListEntries(List) == 0)
1224 {
1225 DPRINT1("No keyboard layouts have been found\n");
1226 DestroyGenericList(List, TRUE);
1227 return NULL;
1228 }
1229
1230 return List;
1231 }
1232
1233
1234 BOOLEAN
1235 ProcessKeyboardLayoutRegistry(
1236 IN PGENERIC_LIST List,
1237 IN PCWSTR LanguageId)
1238 {
1239 PGENERIC_LIST_ENTRY Entry;
1240 PWCHAR LayoutId;
1241 const MUI_LAYOUTS* LayoutsList;
1242 MUI_LAYOUTS NewLayoutsList[20];
1243 ULONG uIndex;
1244 ULONG uOldPos = 0;
1245
1246 Entry = GetCurrentListEntry(List);
1247 if (Entry == NULL)
1248 return FALSE;
1249
1250 LayoutId = (PWCHAR)GetListEntryUserData(Entry);
1251 if (LayoutId == NULL)
1252 return FALSE;
1253
1254 LayoutsList = MUIGetLayoutsList(LanguageId);
1255
1256 if (_wcsicmp(LayoutsList[0].LayoutID, LayoutId) == 0)
1257 return TRUE;
1258
1259 for (uIndex = 1; LayoutsList[uIndex].LangID != NULL; uIndex++)
1260 {
1261 if (_wcsicmp(LayoutsList[uIndex].LayoutID, LayoutId) == 0)
1262 {
1263 uOldPos = uIndex;
1264 continue;
1265 }
1266
1267 NewLayoutsList[uIndex].LangID = LayoutsList[uIndex].LangID;
1268 NewLayoutsList[uIndex].LayoutID = LayoutsList[uIndex].LayoutID;
1269 }
1270
1271 NewLayoutsList[uIndex].LangID = NULL;
1272 NewLayoutsList[uIndex].LayoutID = NULL;
1273 NewLayoutsList[uOldPos].LangID = LayoutsList[0].LangID;
1274 NewLayoutsList[uOldPos].LayoutID = LayoutsList[0].LayoutID;
1275 NewLayoutsList[0].LangID = LayoutsList[uOldPos].LangID;
1276 NewLayoutsList[0].LayoutID = LayoutsList[uOldPos].LayoutID;
1277
1278 return AddKbLayoutsToRegistry(NewLayoutsList);
1279 }
1280
1281 #if 0
1282 BOOLEAN
1283 ProcessKeyboardLayoutFiles(
1284 IN PGENERIC_LIST List)
1285 {
1286 return TRUE;
1287 }
1288 #endif
1289
1290 BOOLEAN
1291 SetGeoID(
1292 IN PCWSTR Id)
1293 {
1294 NTSTATUS Status;
1295 OBJECT_ATTRIBUTES ObjectAttributes;
1296 UNICODE_STRING Name;
1297 HANDLE KeyHandle;
1298
1299 RtlInitUnicodeString(&Name,
1300 L".DEFAULT\\Control Panel\\International\\Geo");
1301 InitializeObjectAttributes(&ObjectAttributes,
1302 &Name,
1303 OBJ_CASE_INSENSITIVE,
1304 GetRootKeyByPredefKey(HKEY_USERS, NULL),
1305 NULL);
1306 Status = NtOpenKey(&KeyHandle,
1307 KEY_SET_VALUE,
1308 &ObjectAttributes);
1309 if (!NT_SUCCESS(Status))
1310 {
1311 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
1312 return FALSE;
1313 }
1314
1315 RtlInitUnicodeString(&Name, L"Nation");
1316 Status = NtSetValueKey(KeyHandle,
1317 &Name,
1318 0,
1319 REG_SZ,
1320 (PVOID)Id,
1321 (wcslen(Id) + 1) * sizeof(WCHAR));
1322 NtClose(KeyHandle);
1323 if (!NT_SUCCESS(Status))
1324 {
1325 DPRINT1("NtSetValueKey() failed (Status = %lx)\n", Status);
1326 return FALSE;
1327 }
1328
1329 return TRUE;
1330 }
1331
1332
1333 BOOLEAN
1334 SetDefaultPagefile(
1335 IN WCHAR Drive)
1336 {
1337 NTSTATUS Status;
1338 HANDLE KeyHandle;
1339 OBJECT_ATTRIBUTES ObjectAttributes;
1340 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1341 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1342 WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1343
1344 InitializeObjectAttributes(&ObjectAttributes,
1345 &KeyName,
1346 OBJ_CASE_INSENSITIVE,
1347 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
1348 NULL);
1349 Status = NtOpenKey(&KeyHandle,
1350 KEY_ALL_ACCESS,
1351 &ObjectAttributes);
1352 if (!NT_SUCCESS(Status))
1353 return FALSE;
1354
1355 ValueBuffer[0] = Drive;
1356
1357 NtSetValueKey(KeyHandle,
1358 &ValueName,
1359 0,
1360 REG_MULTI_SZ,
1361 (PVOID)&ValueBuffer,
1362 sizeof(ValueBuffer));
1363
1364 NtClose(KeyHandle);
1365 return TRUE;
1366 }
1367
1368 /* EOF */