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