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 PGENERIC_LIST 437 CreateComputerTypeList( 438 IN HINF InfFile) 439 { 440 PGENERIC_LIST List; 441 INFCONTEXT Context; 442 PCWSTR KeyName; 443 PCWSTR 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 (!SpInfFindFirstLine(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 (SpInfFindNextLine(&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 PCWSTR KeyName; 679 PCWSTR 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 (!SpInfFindFirstLine(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 (SpInfFindNextLine(&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 PCWSTR Buffer; 782 PCWSTR 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 (!SpInfFindFirstLine(InfFile, L"Display", 797 ((PGENENTRY)GetListEntryData(Entry))->Id, 798 &Context)) 799 { 800 DPRINT1("SpInfFindFirstLine() 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 DPRINT("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 DPRINT("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 PCWSTR KeyValue; 1141 1142 LANG_ENTRY_PARAM LangEntryParam; 1143 1144 LangEntryParam.uIndex = 0; 1145 LangEntryParam.DefaultLanguage = DefaultLanguage; 1146 1147 /* Get default language id */ 1148 if (!SpInfFindFirstLine(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 PCWSTR KeyValue; 1192 const MUI_LAYOUTS* LayoutsList; 1193 ULONG uIndex = 0; 1194 1195 /* Get default layout id */ 1196 if (!SpInfFindFirstLine(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 */ 1376