1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/advapi32/reg/reg.c 5 * PURPOSE: Registry functions 6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) 7 * Thomas Weidenmueller <w3seek@reactos.com> 8 * UPDATE HISTORY: 9 * Created 01/11/98 10 * 19990309 EA Stubs 11 * 20050502 Fireball imported some stuff from WINE 12 */ 13 14 /* INCLUDES *****************************************************************/ 15 16 #include <advapi32.h> 17 18 #include <ndk/cmfuncs.h> 19 #include <pseh/pseh2.h> 20 21 #include "reg.h" 22 23 WINE_DEFAULT_DEBUG_CHANNEL(reg); 24 25 /* DEFINES ******************************************************************/ 26 27 #define MAX_DEFAULT_HANDLES 6 28 #define REG_MAX_NAME_SIZE 256 29 #define REG_MAX_DATA_SIZE 2048 30 31 /* GLOBALS ******************************************************************/ 32 33 static RTL_CRITICAL_SECTION HandleTableCS; 34 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES]; 35 static HANDLE ProcessHeap; 36 static BOOLEAN DefaultHandlesDisabled = FALSE; 37 static BOOLEAN DefaultHandleHKUDisabled = FALSE; 38 static BOOLEAN DllInitialized = FALSE; /* HACK */ 39 40 /* PROTOTYPES ***************************************************************/ 41 42 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key); 43 static VOID CloseDefaultKeys(VOID); 44 #define ClosePredefKey(Handle) \ 45 if ((ULONG_PTR)Handle & 0x1) { \ 46 NtClose(Handle); \ 47 } 48 #define IsPredefKey(HKey) \ 49 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000) 50 #define GetPredefKeyIndex(HKey) \ 51 ((ULONG_PTR)(HKey) & 0x0FFFFFFF) 52 53 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle); 54 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle); 55 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle); 56 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle); 57 58 59 /* FUNCTIONS ****************************************************************/ 60 /* check if value type needs string conversion (Ansi<->Unicode) */ 61 __inline static int is_string( DWORD type ) 62 { 63 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); 64 } 65 66 /************************************************************************ 67 * RegInitDefaultHandles 68 */ 69 BOOL 70 RegInitialize(VOID) 71 { 72 TRACE("RegInitialize()\n"); 73 74 /* Lazy init hack */ 75 if (!DllInitialized) 76 { 77 ProcessHeap = RtlGetProcessHeap(); 78 RtlZeroMemory(DefaultHandleTable, 79 MAX_DEFAULT_HANDLES * sizeof(HANDLE)); 80 RtlInitializeCriticalSection(&HandleTableCS); 81 82 DllInitialized = TRUE; 83 } 84 85 return TRUE; 86 } 87 88 89 /************************************************************************ 90 * RegInit 91 */ 92 BOOL 93 RegCleanup(VOID) 94 { 95 TRACE("RegCleanup()\n"); 96 97 CloseDefaultKeys(); 98 RtlDeleteCriticalSection(&HandleTableCS); 99 100 return TRUE; 101 } 102 103 104 static NTSTATUS 105 OpenPredefinedKey(IN ULONG Index, 106 OUT HANDLE Handle) 107 { 108 NTSTATUS Status; 109 110 switch (Index) 111 { 112 case 0: /* HKEY_CLASSES_ROOT */ 113 Status = OpenClassesRootKey (Handle); 114 break; 115 116 case 1: /* HKEY_CURRENT_USER */ 117 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED, 118 Handle); 119 break; 120 121 case 2: /* HKEY_LOCAL_MACHINE */ 122 Status = OpenLocalMachineKey (Handle); 123 break; 124 125 case 3: /* HKEY_USERS */ 126 Status = OpenUsersKey (Handle); 127 break; 128 #if 0 129 case 4: /* HKEY_PERFORMANCE_DATA */ 130 Status = OpenPerformanceDataKey (Handle); 131 break; 132 #endif 133 134 case 5: /* HKEY_CURRENT_CONFIG */ 135 Status = OpenCurrentConfigKey (Handle); 136 break; 137 138 case 6: /* HKEY_DYN_DATA */ 139 Status = STATUS_NOT_IMPLEMENTED; 140 break; 141 142 default: 143 WARN("MapDefaultHandle() no handle creator\n"); 144 Status = STATUS_INVALID_PARAMETER; 145 break; 146 } 147 148 return Status; 149 } 150 151 152 static NTSTATUS 153 MapDefaultKey(OUT PHANDLE RealKey, 154 IN HKEY Key) 155 { 156 PHANDLE Handle; 157 ULONG Index; 158 BOOLEAN DoOpen, DefDisabled; 159 NTSTATUS Status = STATUS_SUCCESS; 160 161 TRACE("MapDefaultKey (Key %x)\n", Key); 162 163 if (!IsPredefKey(Key)) 164 { 165 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1); 166 return STATUS_SUCCESS; 167 } 168 169 /* Handle special cases here */ 170 Index = GetPredefKeyIndex(Key); 171 if (Index >= MAX_DEFAULT_HANDLES) 172 { 173 return STATUS_INVALID_PARAMETER; 174 } 175 RegInitialize(); /* HACK until delay-loading is implemented */ 176 RtlEnterCriticalSection (&HandleTableCS); 177 178 if (Key == HKEY_CURRENT_USER) 179 DefDisabled = DefaultHandleHKUDisabled; 180 else 181 DefDisabled = DefaultHandlesDisabled; 182 183 if (!DefDisabled) 184 { 185 Handle = &DefaultHandleTable[Index]; 186 DoOpen = (*Handle == NULL); 187 } 188 else 189 { 190 Handle = RealKey; 191 DoOpen = TRUE; 192 } 193 194 if (DoOpen) 195 { 196 /* create/open the default handle */ 197 Status = OpenPredefinedKey(Index, 198 Handle); 199 } 200 201 if (NT_SUCCESS(Status)) 202 { 203 if (!DefDisabled) 204 *RealKey = *Handle; 205 else 206 *(PULONG_PTR)Handle |= 0x1; 207 } 208 209 RtlLeaveCriticalSection (&HandleTableCS); 210 211 return Status; 212 } 213 214 215 static VOID 216 CloseDefaultKeys(VOID) 217 { 218 ULONG i; 219 RegInitialize(); /* HACK until delay-loading is implemented */ 220 RtlEnterCriticalSection(&HandleTableCS); 221 222 for (i = 0; i < MAX_DEFAULT_HANDLES; i++) 223 { 224 if (DefaultHandleTable[i] != NULL) 225 { 226 NtClose(DefaultHandleTable[i]); 227 DefaultHandleTable[i] = NULL; 228 } 229 } 230 231 RtlLeaveCriticalSection(&HandleTableCS); 232 } 233 234 235 static NTSTATUS 236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle) 237 { 238 OBJECT_ATTRIBUTES Attributes; 239 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES"); 240 NTSTATUS Status; 241 242 TRACE("OpenClassesRootKey()\n"); 243 244 InitializeObjectAttributes(&Attributes, 245 &KeyName, 246 OBJ_CASE_INSENSITIVE, 247 NULL, 248 NULL); 249 Status = NtOpenKey(KeyHandle, 250 MAXIMUM_ALLOWED, 251 &Attributes); 252 253 if (!NT_SUCCESS(Status)) 254 return Status; 255 256 /* Mark it as HKCR */ 257 MakeHKCRKey((HKEY*)KeyHandle); 258 259 return Status; 260 } 261 262 263 static NTSTATUS 264 OpenLocalMachineKey(PHANDLE KeyHandle) 265 { 266 OBJECT_ATTRIBUTES Attributes; 267 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine"); 268 NTSTATUS Status; 269 270 TRACE("OpenLocalMachineKey()\n"); 271 272 InitializeObjectAttributes(&Attributes, 273 &KeyName, 274 OBJ_CASE_INSENSITIVE, 275 NULL, 276 NULL); 277 Status = NtOpenKey(KeyHandle, 278 MAXIMUM_ALLOWED, 279 &Attributes); 280 281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status); 282 283 return Status; 284 } 285 286 287 static NTSTATUS 288 OpenUsersKey(PHANDLE KeyHandle) 289 { 290 OBJECT_ATTRIBUTES Attributes; 291 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User"); 292 293 TRACE("OpenUsersKey()\n"); 294 295 InitializeObjectAttributes(&Attributes, 296 &KeyName, 297 OBJ_CASE_INSENSITIVE, 298 NULL, 299 NULL); 300 return NtOpenKey(KeyHandle, 301 MAXIMUM_ALLOWED, 302 &Attributes); 303 } 304 305 306 static NTSTATUS 307 OpenCurrentConfigKey (PHANDLE KeyHandle) 308 { 309 OBJECT_ATTRIBUTES Attributes; 310 UNICODE_STRING KeyName = 311 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current"); 312 313 TRACE("OpenCurrentConfigKey()\n"); 314 315 InitializeObjectAttributes(&Attributes, 316 &KeyName, 317 OBJ_CASE_INSENSITIVE, 318 NULL, 319 NULL); 320 return NtOpenKey(KeyHandle, 321 MAXIMUM_ALLOWED, 322 &Attributes); 323 } 324 325 #ifndef _ADVAPI32_VISTA_ 326 327 /************************************************************************ 328 * RegDisablePredefinedCache 329 * 330 * @implemented 331 */ 332 LONG WINAPI 333 RegDisablePredefinedCache(VOID) 334 { 335 RegInitialize(); /* HACK until delay-loading is implemented */ 336 RtlEnterCriticalSection(&HandleTableCS); 337 DefaultHandleHKUDisabled = TRUE; 338 RtlLeaveCriticalSection(&HandleTableCS); 339 return ERROR_SUCCESS; 340 } 341 342 343 /************************************************************************ 344 * RegDisablePredefinedCacheEx 345 * 346 * @implemented 347 */ 348 LONG WINAPI 349 RegDisablePredefinedCacheEx(VOID) 350 { 351 RegInitialize(); /* HACK until delay-loading is implemented */ 352 RtlEnterCriticalSection(&HandleTableCS); 353 DefaultHandlesDisabled = TRUE; 354 DefaultHandleHKUDisabled = TRUE; 355 RtlLeaveCriticalSection(&HandleTableCS); 356 return ERROR_SUCCESS; 357 } 358 359 360 /************************************************************************ 361 * RegOverridePredefKey 362 * 363 * @implemented 364 */ 365 LONG WINAPI 366 RegOverridePredefKey(IN HKEY hKey, 367 IN HKEY hNewHKey OPTIONAL) 368 { 369 LONG ErrorCode = ERROR_SUCCESS; 370 371 if ((hKey == HKEY_CLASSES_ROOT || 372 hKey == HKEY_CURRENT_CONFIG || 373 hKey == HKEY_CURRENT_USER || 374 hKey == HKEY_LOCAL_MACHINE || 375 hKey == HKEY_PERFORMANCE_DATA || 376 hKey == HKEY_USERS) && 377 !IsPredefKey(hNewHKey)) 378 { 379 PHANDLE Handle; 380 ULONG Index; 381 382 Index = GetPredefKeyIndex(hKey); 383 Handle = &DefaultHandleTable[Index]; 384 385 if (hNewHKey == NULL) 386 { 387 /* restore the default mapping */ 388 NTSTATUS Status = OpenPredefinedKey(Index, 389 &hNewHKey); 390 if (!NT_SUCCESS(Status)) 391 { 392 return RtlNtStatusToDosError(Status); 393 } 394 395 ASSERT(hNewHKey != NULL); 396 } 397 RegInitialize(); /* HACK until delay-loading is implemented */ 398 RtlEnterCriticalSection(&HandleTableCS); 399 400 /* close the currently mapped handle if existing */ 401 if (*Handle != NULL) 402 { 403 NtClose(*Handle); 404 } 405 406 /* update the mapping */ 407 *Handle = hNewHKey; 408 409 RtlLeaveCriticalSection(&HandleTableCS); 410 } 411 else 412 ErrorCode = ERROR_INVALID_HANDLE; 413 414 return ErrorCode; 415 } 416 417 418 /************************************************************************ 419 * RegCloseKey 420 * 421 * @implemented 422 */ 423 LONG WINAPI 424 RegCloseKey(HKEY hKey) 425 { 426 NTSTATUS Status; 427 428 /* don't close null handle or a pseudo handle */ 429 if (!hKey) 430 { 431 return ERROR_INVALID_HANDLE; 432 } 433 434 if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000) 435 { 436 return ERROR_SUCCESS; 437 } 438 439 Status = NtClose(hKey); 440 if (!NT_SUCCESS(Status)) 441 { 442 return RtlNtStatusToDosError(Status); 443 } 444 445 return ERROR_SUCCESS; 446 } 447 448 #endif // _ADVAPI32_VISTA_ 449 450 static NTSTATUS 451 RegpCopyTree(IN HKEY hKeySrc, 452 IN HKEY hKeyDest) 453 { 454 typedef struct 455 { 456 LIST_ENTRY ListEntry; 457 HANDLE hKeySrc; 458 HANDLE hKeyDest; 459 } REGP_COPY_KEYS, *PREGP_COPY_KEYS; 460 461 LIST_ENTRY copyQueueHead; 462 PREGP_COPY_KEYS copyKeys, newCopyKeys; 463 union 464 { 465 KEY_VALUE_FULL_INFORMATION *KeyValue; 466 KEY_NODE_INFORMATION *KeyNode; 467 PVOID Buffer; 468 } Info; 469 ULONG Index, BufferSizeRequired, BufferSize = 0x200; 470 NTSTATUS Status = STATUS_SUCCESS; 471 NTSTATUS Status2 = STATUS_SUCCESS; 472 473 InitializeListHead(©QueueHead); 474 475 Info.Buffer = RtlAllocateHeap(ProcessHeap, 476 0, 477 BufferSize); 478 if (Info.Buffer == NULL) 479 { 480 return STATUS_INSUFFICIENT_RESOURCES; 481 } 482 483 copyKeys = RtlAllocateHeap(ProcessHeap, 484 0, 485 sizeof(REGP_COPY_KEYS)); 486 if (copyKeys != NULL) 487 { 488 copyKeys->hKeySrc = hKeySrc; 489 copyKeys->hKeyDest = hKeyDest; 490 InsertHeadList(©QueueHead, 491 ©Keys->ListEntry); 492 493 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */ 494 495 do 496 { 497 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink, 498 REGP_COPY_KEYS, 499 ListEntry); 500 501 /* enumerate all values and copy them */ 502 Index = 0; 503 for (;;) 504 { 505 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc, 506 Index, 507 KeyValueFullInformation, 508 Info.KeyValue, 509 BufferSize, 510 &BufferSizeRequired); 511 if (NT_SUCCESS(Status2)) 512 { 513 UNICODE_STRING ValueName; 514 PVOID Data; 515 516 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 517 ValueName.Length = Info.KeyValue->NameLength; 518 ValueName.MaximumLength = ValueName.Length; 519 ValueName.Buffer = Info.KeyValue->Name; 520 521 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset); 522 523 Status2 = NtSetValueKey(copyKeys->hKeyDest, 524 &ValueName, 525 Info.KeyValue->TitleIndex, 526 Info.KeyValue->Type, 527 Data, 528 Info.KeyValue->DataLength); 529 530 /* don't break, let's try to copy as many values as possible */ 531 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status)) 532 { 533 Status = Status2; 534 } 535 536 Index++; 537 } 538 else if (Status2 == STATUS_BUFFER_OVERFLOW) 539 { 540 PVOID Buffer; 541 542 ASSERT(BufferSize < BufferSizeRequired); 543 544 Buffer = RtlReAllocateHeap(ProcessHeap, 545 0, 546 Info.Buffer, 547 BufferSizeRequired); 548 if (Buffer != NULL) 549 { 550 Info.Buffer = Buffer; 551 BufferSize = BufferSizeRequired; 552 /* try again */ 553 } 554 else 555 { 556 /* don't break, let's try to copy as many values as possible */ 557 Status2 = STATUS_INSUFFICIENT_RESOURCES; 558 Index++; 559 560 if (NT_SUCCESS(Status)) 561 { 562 Status = Status2; 563 } 564 } 565 } 566 else 567 { 568 /* break to avoid an infinite loop in case of denied access or 569 other errors! */ 570 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status)) 571 { 572 Status = Status2; 573 } 574 575 break; 576 } 577 } 578 579 /* enumerate all subkeys and open and enqueue them */ 580 Index = 0; 581 for (;;) 582 { 583 Status2 = NtEnumerateKey(copyKeys->hKeySrc, 584 Index, 585 KeyNodeInformation, 586 Info.KeyNode, 587 BufferSize, 588 &BufferSizeRequired); 589 if (NT_SUCCESS(Status2)) 590 { 591 HANDLE KeyHandle, NewKeyHandle; 592 OBJECT_ATTRIBUTES ObjectAttributes; 593 UNICODE_STRING SubKeyName, ClassName; 594 595 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 596 SubKeyName.Length = Info.KeyNode->NameLength; 597 SubKeyName.MaximumLength = SubKeyName.Length; 598 SubKeyName.Buffer = Info.KeyNode->Name; 599 ClassName.Length = Info.KeyNode->ClassLength; 600 ClassName.MaximumLength = ClassName.Length; 601 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset); 602 603 /* open the subkey with sufficient rights */ 604 605 InitializeObjectAttributes(&ObjectAttributes, 606 &SubKeyName, 607 OBJ_CASE_INSENSITIVE, 608 copyKeys->hKeySrc, 609 NULL); 610 611 Status2 = NtOpenKey(&KeyHandle, 612 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, 613 &ObjectAttributes); 614 if (NT_SUCCESS(Status2)) 615 { 616 /* FIXME - attempt to query the security information */ 617 618 InitializeObjectAttributes(&ObjectAttributes, 619 &SubKeyName, 620 OBJ_CASE_INSENSITIVE, 621 copyKeys->hKeyDest, 622 NULL); 623 624 Status2 = NtCreateKey(&NewKeyHandle, 625 KEY_ALL_ACCESS, 626 &ObjectAttributes, 627 Info.KeyNode->TitleIndex, 628 &ClassName, 629 0, 630 NULL); 631 if (NT_SUCCESS(Status2)) 632 { 633 newCopyKeys = RtlAllocateHeap(ProcessHeap, 634 0, 635 sizeof(REGP_COPY_KEYS)); 636 if (newCopyKeys != NULL) 637 { 638 /* save the handles and enqueue the subkey */ 639 newCopyKeys->hKeySrc = KeyHandle; 640 newCopyKeys->hKeyDest = NewKeyHandle; 641 InsertTailList(©QueueHead, 642 &newCopyKeys->ListEntry); 643 } 644 else 645 { 646 NtClose(KeyHandle); 647 NtClose(NewKeyHandle); 648 649 Status2 = STATUS_INSUFFICIENT_RESOURCES; 650 } 651 } 652 else 653 { 654 NtClose(KeyHandle); 655 } 656 } 657 658 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status)) 659 { 660 Status = Status2; 661 } 662 663 Index++; 664 } 665 else if (Status2 == STATUS_BUFFER_OVERFLOW) 666 { 667 PVOID Buffer; 668 669 ASSERT(BufferSize < BufferSizeRequired); 670 671 Buffer = RtlReAllocateHeap(ProcessHeap, 672 0, 673 Info.Buffer, 674 BufferSizeRequired); 675 if (Buffer != NULL) 676 { 677 Info.Buffer = Buffer; 678 BufferSize = BufferSizeRequired; 679 /* try again */ 680 } 681 else 682 { 683 /* don't break, let's try to copy as many keys as possible */ 684 Status2 = STATUS_INSUFFICIENT_RESOURCES; 685 Index++; 686 687 if (NT_SUCCESS(Status)) 688 { 689 Status = Status2; 690 } 691 } 692 } 693 else 694 { 695 /* break to avoid an infinite loop in case of denied access or 696 other errors! */ 697 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status)) 698 { 699 Status = Status2; 700 } 701 702 break; 703 } 704 } 705 706 /* close the handles and remove the entry from the list */ 707 if (copyKeys->hKeySrc != hKeySrc) 708 { 709 NtClose(copyKeys->hKeySrc); 710 } 711 if (copyKeys->hKeyDest != hKeyDest) 712 { 713 NtClose(copyKeys->hKeyDest); 714 } 715 716 RemoveEntryList(©Keys->ListEntry); 717 718 RtlFreeHeap(ProcessHeap, 719 0, 720 copyKeys); 721 } while (!IsListEmpty(©QueueHead)); 722 } 723 else 724 Status = STATUS_INSUFFICIENT_RESOURCES; 725 726 RtlFreeHeap(ProcessHeap, 727 0, 728 Info.Buffer); 729 730 return Status; 731 } 732 733 734 /************************************************************************ 735 * RegCopyTreeW 736 * 737 * @implemented 738 */ 739 LONG WINAPI 740 RegCopyTreeW(IN HKEY hKeySrc, 741 IN LPCWSTR lpSubKey OPTIONAL, 742 IN HKEY hKeyDest) 743 { 744 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL; 745 NTSTATUS Status; 746 747 Status = MapDefaultKey(&KeyHandle, 748 hKeySrc); 749 if (!NT_SUCCESS(Status)) 750 { 751 return RtlNtStatusToDosError(Status); 752 } 753 754 Status = MapDefaultKey(&DestKeyHandle, 755 hKeyDest); 756 if (!NT_SUCCESS(Status)) 757 { 758 goto Cleanup2; 759 } 760 761 if (lpSubKey != NULL) 762 { 763 OBJECT_ATTRIBUTES ObjectAttributes; 764 UNICODE_STRING SubKeyName; 765 766 RtlInitUnicodeString(&SubKeyName, lpSubKey); 767 768 InitializeObjectAttributes(&ObjectAttributes, 769 &SubKeyName, 770 OBJ_CASE_INSENSITIVE, 771 KeyHandle, 772 NULL); 773 774 Status = NtOpenKey(&SubKeyHandle, 775 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, 776 &ObjectAttributes); 777 if (!NT_SUCCESS(Status)) 778 { 779 goto Cleanup; 780 } 781 782 CurKey = SubKeyHandle; 783 } 784 else 785 CurKey = KeyHandle; 786 787 Status = RegpCopyTree(CurKey, 788 hKeyDest); 789 790 if (SubKeyHandle != NULL) 791 { 792 NtClose(SubKeyHandle); 793 } 794 795 Cleanup: 796 ClosePredefKey(DestKeyHandle); 797 Cleanup2: 798 ClosePredefKey(KeyHandle); 799 800 if (!NT_SUCCESS(Status)) 801 { 802 return RtlNtStatusToDosError(Status); 803 } 804 805 return ERROR_SUCCESS; 806 } 807 808 #ifndef _ADVAPI32_VISTA_ 809 810 /************************************************************************ 811 * RegCopyTreeA 812 * 813 * @implemented 814 */ 815 LONG WINAPI 816 RegCopyTreeA(IN HKEY hKeySrc, 817 IN LPCSTR lpSubKey OPTIONAL, 818 IN HKEY hKeyDest) 819 { 820 UNICODE_STRING SubKeyName = { 0, 0, NULL }; 821 LONG Ret; 822 823 if (lpSubKey != NULL && 824 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey)) 825 { 826 return ERROR_NOT_ENOUGH_MEMORY; 827 } 828 829 Ret = RegCopyTreeW(hKeySrc, 830 SubKeyName.Buffer, 831 hKeyDest); 832 833 RtlFreeUnicodeString(&SubKeyName); 834 835 return Ret; 836 } 837 838 839 /************************************************************************ 840 * RegConnectRegistryA 841 * 842 * @implemented 843 */ 844 LONG WINAPI 845 RegConnectRegistryA(IN LPCSTR lpMachineName, 846 IN HKEY hKey, 847 OUT PHKEY phkResult) 848 { 849 UNICODE_STRING MachineName = { 0, 0, NULL }; 850 LONG Ret; 851 852 if (lpMachineName != NULL && 853 !RtlCreateUnicodeStringFromAsciiz(&MachineName, lpMachineName)) 854 { 855 return ERROR_NOT_ENOUGH_MEMORY; 856 } 857 858 Ret = RegConnectRegistryW(MachineName.Buffer, 859 hKey, 860 phkResult); 861 862 RtlFreeUnicodeString(&MachineName); 863 864 return Ret; 865 } 866 867 868 /************************************************************************ 869 * RegConnectRegistryW 870 * 871 * @unimplemented 872 */ 873 LONG WINAPI 874 RegConnectRegistryW(LPCWSTR lpMachineName, 875 HKEY hKey, 876 PHKEY phkResult) 877 { 878 LONG ret; 879 880 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult); 881 882 if (!lpMachineName || !*lpMachineName) 883 { 884 /* Use the local machine name */ 885 ret = RegOpenKeyW( hKey, NULL, phkResult ); 886 } 887 else 888 { 889 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1]; 890 DWORD len = sizeof(compName) / sizeof(WCHAR); 891 892 /* MSDN says lpMachineName must start with \\ : not so */ 893 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\') 894 lpMachineName += 2; 895 896 if (GetComputerNameW(compName, &len)) 897 { 898 if (!_wcsicmp(lpMachineName, compName)) 899 ret = RegOpenKeyW(hKey, NULL, phkResult); 900 else 901 { 902 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName)); 903 ret = ERROR_BAD_NETPATH; 904 } 905 } 906 else 907 ret = GetLastError(); 908 } 909 910 return ret; 911 } 912 913 914 /************************************************************************ 915 * CreateNestedKey 916 * 917 * Create key and all necessary intermediate keys 918 */ 919 static NTSTATUS 920 CreateNestedKey(PHKEY KeyHandle, 921 POBJECT_ATTRIBUTES ObjectAttributes, 922 PUNICODE_STRING ClassString, 923 DWORD dwOptions, 924 REGSAM samDesired, 925 DWORD *lpdwDisposition) 926 { 927 OBJECT_ATTRIBUTES LocalObjectAttributes; 928 UNICODE_STRING LocalKeyName; 929 ULONG Disposition; 930 NTSTATUS Status; 931 ULONG FullNameLength; 932 ULONG Length; 933 PWCHAR Ptr; 934 HANDLE LocalKeyHandle; 935 936 Status = NtCreateKey((PHANDLE) KeyHandle, 937 samDesired, 938 ObjectAttributes, 939 0, 940 ClassString, 941 dwOptions, 942 (PULONG)lpdwDisposition); 943 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status); 944 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 945 return Status; 946 947 /* Copy object attributes */ 948 RtlCopyMemory(&LocalObjectAttributes, 949 ObjectAttributes, 950 sizeof(OBJECT_ATTRIBUTES)); 951 RtlCreateUnicodeString(&LocalKeyName, 952 ObjectAttributes->ObjectName->Buffer); 953 LocalObjectAttributes.ObjectName = &LocalKeyName; 954 FullNameLength = LocalKeyName.Length / sizeof(WCHAR); 955 956 LocalKeyHandle = NULL; 957 958 /* Remove the last part of the key name and try to create the key again. */ 959 while (Status == STATUS_OBJECT_NAME_NOT_FOUND) 960 { 961 Ptr = wcsrchr(LocalKeyName.Buffer, '\\'); 962 if (Ptr == NULL || Ptr == LocalKeyName.Buffer) 963 { 964 Status = STATUS_UNSUCCESSFUL; 965 break; 966 } 967 968 *Ptr = (WCHAR)0; 969 LocalKeyName.Length = (USHORT)wcslen(LocalKeyName.Buffer) * sizeof(WCHAR); 970 971 Status = NtCreateKey(&LocalKeyHandle, 972 KEY_CREATE_SUB_KEY, 973 &LocalObjectAttributes, 974 0, 975 NULL, 976 0, 977 &Disposition); 978 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status); 979 } 980 981 if (!NT_SUCCESS(Status)) 982 { 983 RtlFreeUnicodeString(&LocalKeyName); 984 return Status; 985 } 986 987 /* Add removed parts of the key name and create them too. */ 988 Length = wcslen(LocalKeyName.Buffer); 989 while (TRUE) 990 { 991 if (LocalKeyHandle) 992 NtClose (LocalKeyHandle); 993 994 LocalKeyName.Buffer[Length] = L'\\'; 995 Length = wcslen (LocalKeyName.Buffer); 996 LocalKeyName.Length = Length * sizeof(WCHAR); 997 998 if (Length == FullNameLength) 999 { 1000 Status = NtCreateKey((PHANDLE) KeyHandle, 1001 samDesired, 1002 ObjectAttributes, 1003 0, 1004 ClassString, 1005 dwOptions, 1006 (PULONG)lpdwDisposition); 1007 break; 1008 } 1009 1010 Status = NtCreateKey(&LocalKeyHandle, 1011 KEY_CREATE_SUB_KEY, 1012 &LocalObjectAttributes, 1013 0, 1014 NULL, 1015 0, 1016 &Disposition); 1017 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status); 1018 if (!NT_SUCCESS(Status)) 1019 break; 1020 } 1021 1022 RtlFreeUnicodeString(&LocalKeyName); 1023 1024 return Status; 1025 } 1026 1027 1028 /************************************************************************ 1029 * RegCreateKeyExA 1030 * 1031 * @implemented 1032 */ 1033 LONG WINAPI 1034 RegCreateKeyExA( 1035 _In_ HKEY hKey, 1036 _In_ LPCSTR lpSubKey, 1037 _In_ DWORD Reserved, 1038 _In_ LPSTR lpClass, 1039 _In_ DWORD dwOptions, 1040 _In_ REGSAM samDesired, 1041 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, 1042 _Out_ PHKEY phkResult, 1043 _Out_ LPDWORD lpdwDisposition) 1044 { 1045 UNICODE_STRING SubKeyString; 1046 UNICODE_STRING ClassString; 1047 DWORD ErrorCode; 1048 1049 RtlInitEmptyUnicodeString(&ClassString, NULL, 0); 1050 RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0); 1051 1052 if (lpClass) 1053 { 1054 if (!RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass)) 1055 { 1056 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1057 goto Exit; 1058 } 1059 } 1060 1061 if (lpSubKey) 1062 { 1063 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey)) 1064 { 1065 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1066 goto Exit; 1067 } 1068 } 1069 1070 ErrorCode = RegCreateKeyExW( 1071 hKey, 1072 SubKeyString.Buffer, 1073 Reserved, 1074 ClassString.Buffer, 1075 dwOptions, 1076 samDesired, 1077 lpSecurityAttributes, 1078 phkResult, 1079 lpdwDisposition); 1080 1081 Exit: 1082 RtlFreeUnicodeString(&SubKeyString); 1083 RtlFreeUnicodeString(&ClassString); 1084 1085 return ErrorCode; 1086 } 1087 1088 1089 /************************************************************************ 1090 * RegCreateKeyExW 1091 * 1092 * @implemented 1093 */ 1094 LONG 1095 WINAPI 1096 RegCreateKeyExW( 1097 _In_ HKEY hKey, 1098 _In_ LPCWSTR lpSubKey, 1099 _In_ DWORD Reserved, 1100 _In_opt_ LPWSTR lpClass, 1101 _In_ DWORD dwOptions, 1102 _In_ REGSAM samDesired, 1103 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, 1104 _Out_ PHKEY phkResult, 1105 _Out_opt_ LPDWORD lpdwDisposition) 1106 { 1107 UNICODE_STRING SubKeyString; 1108 UNICODE_STRING ClassString; 1109 OBJECT_ATTRIBUTES ObjectAttributes; 1110 HANDLE ParentKey; 1111 ULONG Attributes = OBJ_CASE_INSENSITIVE; 1112 NTSTATUS Status; 1113 1114 TRACE("RegCreateKeyExW() called\n"); 1115 1116 /* get the real parent key */ 1117 Status = MapDefaultKey(&ParentKey, 1118 hKey); 1119 if (!NT_SUCCESS(Status)) 1120 { 1121 return RtlNtStatusToDosError(Status); 1122 } 1123 1124 TRACE("ParentKey %p\n", ParentKey); 1125 1126 if (IsHKCRKey(ParentKey)) 1127 { 1128 LONG ErrorCode = CreateHKCRKey( 1129 ParentKey, 1130 lpSubKey, 1131 Reserved, 1132 lpClass, 1133 dwOptions, 1134 samDesired, 1135 lpSecurityAttributes, 1136 phkResult, 1137 lpdwDisposition); 1138 ClosePredefKey(ParentKey); 1139 return ErrorCode; 1140 } 1141 1142 if (dwOptions & REG_OPTION_OPEN_LINK) 1143 Attributes |= OBJ_OPENLINK; 1144 1145 RtlInitUnicodeString(&ClassString, 1146 lpClass); 1147 RtlInitUnicodeString(&SubKeyString, 1148 lpSubKey); 1149 InitializeObjectAttributes(&ObjectAttributes, 1150 &SubKeyString, 1151 Attributes, 1152 (HANDLE)ParentKey, 1153 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL); 1154 Status = CreateNestedKey(phkResult, 1155 &ObjectAttributes, 1156 (lpClass == NULL)? NULL : &ClassString, 1157 dwOptions, 1158 samDesired, 1159 lpdwDisposition); 1160 1161 ClosePredefKey(ParentKey); 1162 1163 TRACE("Status %x\n", Status); 1164 if (!NT_SUCCESS(Status)) 1165 { 1166 return RtlNtStatusToDosError(Status); 1167 } 1168 1169 return ERROR_SUCCESS; 1170 } 1171 1172 1173 /************************************************************************ 1174 * RegCreateKeyA 1175 * 1176 * @implemented 1177 */ 1178 LONG WINAPI 1179 RegCreateKeyA(HKEY hKey, 1180 LPCSTR lpSubKey, 1181 PHKEY phkResult) 1182 { 1183 return RegCreateKeyExA(hKey, 1184 lpSubKey, 1185 0, 1186 NULL, 1187 0, 1188 MAXIMUM_ALLOWED, 1189 NULL, 1190 phkResult, 1191 NULL); 1192 } 1193 1194 1195 /************************************************************************ 1196 * RegCreateKeyW 1197 * 1198 * @implemented 1199 */ 1200 LONG WINAPI 1201 RegCreateKeyW(HKEY hKey, 1202 LPCWSTR lpSubKey, 1203 PHKEY phkResult) 1204 { 1205 return RegCreateKeyExW(hKey, 1206 lpSubKey, 1207 0, 1208 NULL, 1209 0, 1210 MAXIMUM_ALLOWED, 1211 NULL, 1212 phkResult, 1213 NULL); 1214 } 1215 1216 1217 /************************************************************************ 1218 * RegDeleteKeyA 1219 * 1220 * @implemented 1221 */ 1222 LONG 1223 WINAPI 1224 RegDeleteKeyA( 1225 _In_ HKEY hKey, 1226 _In_ LPCSTR lpSubKey) 1227 { 1228 return RegDeleteKeyExA(hKey, lpSubKey, 0, 0); 1229 } 1230 1231 1232 /************************************************************************ 1233 * RegDeleteKeyW 1234 * 1235 * @implemented 1236 */ 1237 LONG 1238 WINAPI 1239 RegDeleteKeyW( 1240 _In_ HKEY hKey, 1241 _In_ LPCWSTR lpSubKey) 1242 { 1243 return RegDeleteKeyExW(hKey, lpSubKey, 0, 0); 1244 } 1245 1246 1247 /************************************************************************ 1248 * RegDeleteKeyExA 1249 * 1250 * @implemented 1251 */ 1252 LONG 1253 WINAPI 1254 RegDeleteKeyExA( 1255 _In_ HKEY hKey, 1256 _In_ LPCSTR lpSubKey, 1257 _In_ REGSAM samDesired, 1258 _In_ DWORD Reserved) 1259 { 1260 LONG ErrorCode; 1261 UNICODE_STRING SubKeyName; 1262 1263 if (lpSubKey) 1264 { 1265 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey)) 1266 return ERROR_NOT_ENOUGH_MEMORY; 1267 } 1268 else 1269 RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0); 1270 1271 ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved); 1272 1273 RtlFreeUnicodeString(&SubKeyName); 1274 1275 return ErrorCode; 1276 } 1277 1278 1279 /************************************************************************ 1280 * RegDeleteKeyExW 1281 * 1282 * @implemented 1283 */ 1284 LONG 1285 WINAPI 1286 RegDeleteKeyExW( 1287 _In_ HKEY hKey, 1288 _In_ LPCWSTR lpSubKey, 1289 _In_ REGSAM samDesired, 1290 _In_ DWORD Reserved) 1291 { 1292 OBJECT_ATTRIBUTES ObjectAttributes; 1293 UNICODE_STRING SubKeyName; 1294 HANDLE ParentKey; 1295 HANDLE TargetKey; 1296 NTSTATUS Status; 1297 1298 /* Make sure we got a subkey */ 1299 if (!lpSubKey) 1300 { 1301 /* Fail */ 1302 return ERROR_INVALID_PARAMETER; 1303 } 1304 1305 Status = MapDefaultKey(&ParentKey, 1306 hKey); 1307 if (!NT_SUCCESS(Status)) 1308 { 1309 return RtlNtStatusToDosError(Status); 1310 } 1311 1312 if (IsHKCRKey(ParentKey)) 1313 { 1314 LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved); 1315 ClosePredefKey(ParentKey); 1316 return ErrorCode; 1317 } 1318 1319 if (samDesired & KEY_WOW64_32KEY) 1320 ERR("Wow64 not yet supported!\n"); 1321 1322 if (samDesired & KEY_WOW64_64KEY) 1323 ERR("Wow64 not yet supported!\n"); 1324 1325 1326 RtlInitUnicodeString(&SubKeyName, lpSubKey); 1327 InitializeObjectAttributes(&ObjectAttributes, 1328 &SubKeyName, 1329 OBJ_CASE_INSENSITIVE, 1330 ParentKey, 1331 NULL); 1332 Status = NtOpenKey(&TargetKey, 1333 DELETE, 1334 &ObjectAttributes); 1335 if (!NT_SUCCESS(Status)) 1336 { 1337 goto Cleanup; 1338 } 1339 1340 Status = NtDeleteKey(TargetKey); 1341 NtClose(TargetKey); 1342 1343 Cleanup: 1344 ClosePredefKey(ParentKey); 1345 1346 if (!NT_SUCCESS(Status)) 1347 { 1348 return RtlNtStatusToDosError(Status); 1349 } 1350 1351 return ERROR_SUCCESS; 1352 } 1353 1354 1355 /************************************************************************ 1356 * RegDeleteKeyValueW 1357 * 1358 * @implemented 1359 */ 1360 LONG WINAPI 1361 RegDeleteKeyValueW(IN HKEY hKey, 1362 IN LPCWSTR lpSubKey OPTIONAL, 1363 IN LPCWSTR lpValueName OPTIONAL) 1364 { 1365 HKEY hSubKey = hKey; 1366 LONG ErrorCode; 1367 1368 if (lpSubKey) 1369 { 1370 ErrorCode = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey); 1371 if (ErrorCode) 1372 { 1373 return ErrorCode; 1374 } 1375 } 1376 ErrorCode = RegDeleteValueW(hSubKey, lpValueName); 1377 1378 if (hSubKey != hKey) 1379 { 1380 RegCloseKey(hSubKey); 1381 } 1382 return ErrorCode; 1383 } 1384 1385 1386 /************************************************************************ 1387 * RegDeleteKeyValueA 1388 * 1389 * @implemented 1390 */ 1391 LONG WINAPI 1392 RegDeleteKeyValueA(IN HKEY hKey, 1393 IN LPCSTR lpSubKey OPTIONAL, 1394 IN LPCSTR lpValueName OPTIONAL) 1395 { 1396 UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL }; 1397 LONG Ret; 1398 1399 if (lpSubKey != NULL && 1400 !RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey)) 1401 { 1402 return ERROR_NOT_ENOUGH_MEMORY; 1403 } 1404 1405 if (lpValueName != NULL && 1406 !RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName)) 1407 { 1408 RtlFreeUnicodeString(&SubKey); 1409 return ERROR_NOT_ENOUGH_MEMORY; 1410 } 1411 1412 Ret = RegDeleteKeyValueW(hKey, 1413 SubKey.Buffer, 1414 ValueName.Buffer); 1415 1416 RtlFreeUnicodeString(&SubKey); 1417 RtlFreeUnicodeString(&ValueName); 1418 1419 return Ret; 1420 } 1421 1422 #if 0 1423 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing 1424 static NTSTATUS 1425 RegpDeleteTree(IN HKEY hKey) 1426 { 1427 typedef struct 1428 { 1429 LIST_ENTRY ListEntry; 1430 HANDLE KeyHandle; 1431 } REGP_DEL_KEYS, *PREG_DEL_KEYS; 1432 1433 LIST_ENTRY delQueueHead; 1434 PREG_DEL_KEYS delKeys, newDelKeys; 1435 HANDLE ProcessHeap; 1436 ULONG BufferSize; 1437 PKEY_BASIC_INFORMATION BasicInfo; 1438 PREG_DEL_KEYS KeyDelRoot; 1439 NTSTATUS Status = STATUS_SUCCESS; 1440 NTSTATUS Status2 = STATUS_SUCCESS; 1441 1442 InitializeListHead(&delQueueHead); 1443 1444 ProcessHeap = RtlGetProcessHeap(); 1445 1446 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION 1447 structure for the root key, we only do that for subkeys as we need to 1448 allocate REGP_DEL_KEYS structures anyway! */ 1449 KeyDelRoot = RtlAllocateHeap(ProcessHeap, 1450 0, 1451 sizeof(REGP_DEL_KEYS)); 1452 if (KeyDelRoot != NULL) 1453 { 1454 KeyDelRoot->KeyHandle = hKey; 1455 InsertTailList(&delQueueHead, 1456 &KeyDelRoot->ListEntry); 1457 1458 do 1459 { 1460 delKeys = CONTAINING_RECORD(delQueueHead.Flink, 1461 REGP_DEL_KEYS, 1462 ListEntry); 1463 1464 BufferSize = 0; 1465 BasicInfo = NULL; 1466 newDelKeys = NULL; 1467 1468 ReadFirstSubKey: 1469 /* check if this key contains subkeys and delete them first by queuing 1470 them at the head of the list */ 1471 Status2 = NtEnumerateKey(delKeys->KeyHandle, 1472 0, 1473 KeyBasicInformation, 1474 BasicInfo, 1475 BufferSize, 1476 &BufferSize); 1477 1478 if (NT_SUCCESS(Status2)) 1479 { 1480 OBJECT_ATTRIBUTES ObjectAttributes; 1481 UNICODE_STRING SubKeyName; 1482 1483 ASSERT(newDelKeys != NULL); 1484 ASSERT(BasicInfo != NULL); 1485 1486 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 1487 SubKeyName.Length = BasicInfo->NameLength; 1488 SubKeyName.MaximumLength = BasicInfo->NameLength; 1489 SubKeyName.Buffer = BasicInfo->Name; 1490 1491 InitializeObjectAttributes(&ObjectAttributes, 1492 &SubKeyName, 1493 OBJ_CASE_INSENSITIVE, 1494 delKeys->KeyHandle, 1495 NULL); 1496 1497 /* open the subkey */ 1498 Status2 = NtOpenKey(&newDelKeys->KeyHandle, 1499 DELETE | KEY_ENUMERATE_SUB_KEYS, 1500 &ObjectAttributes); 1501 if (!NT_SUCCESS(Status2)) 1502 { 1503 goto SubKeyFailure; 1504 } 1505 1506 /* enqueue this key to the head of the deletion queue */ 1507 InsertHeadList(&delQueueHead, 1508 &newDelKeys->ListEntry); 1509 1510 /* try again from the head of the list */ 1511 continue; 1512 } 1513 else 1514 { 1515 if (Status2 == STATUS_BUFFER_TOO_SMALL) 1516 { 1517 newDelKeys = RtlAllocateHeap(ProcessHeap, 1518 0, 1519 BufferSize + sizeof(REGP_DEL_KEYS)); 1520 if (newDelKeys != NULL) 1521 { 1522 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1); 1523 1524 /* try again */ 1525 goto ReadFirstSubKey; 1526 } 1527 else 1528 { 1529 /* don't break, let's try to delete as many keys as possible */ 1530 Status2 = STATUS_INSUFFICIENT_RESOURCES; 1531 goto SubKeyFailureNoFree; 1532 } 1533 } 1534 else if (Status2 == STATUS_BUFFER_OVERFLOW) 1535 { 1536 PREG_DEL_KEYS newDelKeys2; 1537 1538 ASSERT(newDelKeys != NULL); 1539 1540 /* we need more memory to query the key name */ 1541 newDelKeys2 = RtlReAllocateHeap(ProcessHeap, 1542 0, 1543 newDelKeys, 1544 BufferSize + sizeof(REGP_DEL_KEYS)); 1545 if (newDelKeys2 != NULL) 1546 { 1547 newDelKeys = newDelKeys2; 1548 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1); 1549 1550 /* try again */ 1551 goto ReadFirstSubKey; 1552 } 1553 else 1554 { 1555 /* don't break, let's try to delete as many keys as possible */ 1556 Status2 = STATUS_INSUFFICIENT_RESOURCES; 1557 } 1558 } 1559 else if (Status2 == STATUS_NO_MORE_ENTRIES) 1560 { 1561 /* in some race conditions where another thread would delete 1562 the same tree at the same time, newDelKeys could actually 1563 be != NULL! */ 1564 if (newDelKeys != NULL) 1565 { 1566 RtlFreeHeap(ProcessHeap, 1567 0, 1568 newDelKeys); 1569 } 1570 break; 1571 } 1572 1573 SubKeyFailure: 1574 /* newDelKeys can be NULL here when NtEnumerateKey returned an 1575 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */ 1576 if (newDelKeys != NULL) 1577 { 1578 RtlFreeHeap(ProcessHeap, 1579 0, 1580 newDelKeys); 1581 } 1582 1583 SubKeyFailureNoFree: 1584 /* don't break, let's try to delete as many keys as possible */ 1585 if (NT_SUCCESS(Status)) 1586 { 1587 Status = Status2; 1588 } 1589 } 1590 1591 Status2 = NtDeleteKey(delKeys->KeyHandle); 1592 1593 /* NOTE: do NOT close the handle anymore, it's invalid already! */ 1594 1595 if (!NT_SUCCESS(Status2)) 1596 { 1597 /* close the key handle so we don't leak handles for keys we were 1598 unable to delete. But only do this for handles not supplied 1599 by the caller! */ 1600 1601 if (delKeys->KeyHandle != hKey) 1602 { 1603 NtClose(delKeys->KeyHandle); 1604 } 1605 1606 if (NT_SUCCESS(Status)) 1607 { 1608 /* don't break, let's try to delete as many keys as possible */ 1609 Status = Status2; 1610 } 1611 } 1612 1613 /* remove the entry from the list */ 1614 RemoveEntryList(&delKeys->ListEntry); 1615 1616 RtlFreeHeap(ProcessHeap, 1617 0, 1618 delKeys); 1619 } while (!IsListEmpty(&delQueueHead)); 1620 } 1621 else 1622 Status = STATUS_INSUFFICIENT_RESOURCES; 1623 1624 return Status; 1625 } 1626 1627 1628 /************************************************************************ 1629 * RegDeleteTreeW 1630 * 1631 * @implemented 1632 */ 1633 LONG WINAPI 1634 RegDeleteTreeW(IN HKEY hKey, 1635 IN LPCWSTR lpSubKey OPTIONAL) 1636 { 1637 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 1638 NTSTATUS Status; 1639 1640 Status = MapDefaultKey(&KeyHandle, 1641 hKey); 1642 if (!NT_SUCCESS(Status)) 1643 { 1644 return RtlNtStatusToDosError(Status); 1645 } 1646 1647 if (lpSubKey != NULL) 1648 { 1649 OBJECT_ATTRIBUTES ObjectAttributes; 1650 UNICODE_STRING SubKeyName; 1651 1652 RtlInitUnicodeString(&SubKeyName, lpSubKey); 1653 1654 InitializeObjectAttributes(&ObjectAttributes, 1655 &SubKeyName, 1656 OBJ_CASE_INSENSITIVE, 1657 KeyHandle, 1658 NULL); 1659 1660 Status = NtOpenKey(&SubKeyHandle, 1661 DELETE | KEY_ENUMERATE_SUB_KEYS, 1662 &ObjectAttributes); 1663 if (!NT_SUCCESS(Status)) 1664 { 1665 goto Cleanup; 1666 } 1667 1668 CurKey = SubKeyHandle; 1669 } 1670 else 1671 CurKey = KeyHandle; 1672 1673 Status = RegpDeleteTree(CurKey); 1674 1675 if (NT_SUCCESS(Status)) 1676 { 1677 /* make sure we only close hKey (KeyHandle) when the caller specified a 1678 subkey, because the handle would be invalid already! */ 1679 if (CurKey != KeyHandle) 1680 { 1681 ClosePredefKey(KeyHandle); 1682 } 1683 1684 return ERROR_SUCCESS; 1685 } 1686 else 1687 { 1688 /* make sure we close all handles we created! */ 1689 if (SubKeyHandle != NULL) 1690 { 1691 NtClose(SubKeyHandle); 1692 } 1693 1694 Cleanup: 1695 ClosePredefKey(KeyHandle); 1696 1697 return RtlNtStatusToDosError(Status); 1698 } 1699 } 1700 #endif 1701 1702 #endif // _ADVAPI32_VISTA_ 1703 1704 /************************************************************************ 1705 * RegDeleteTreeW 1706 * 1707 * @implemented 1708 */ 1709 LSTATUS 1710 WINAPI 1711 RegDeleteTreeW(HKEY hKey, 1712 LPCWSTR lpszSubKey) 1713 { 1714 LONG ret; 1715 DWORD dwMaxSubkeyLen, dwMaxValueLen; 1716 DWORD dwMaxLen, dwSize; 1717 NTSTATUS Status; 1718 HANDLE KeyHandle; 1719 HKEY hSubKey; 1720 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; 1721 1722 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey)); 1723 1724 Status = MapDefaultKey(&KeyHandle, 1725 hKey); 1726 if (!NT_SUCCESS(Status)) 1727 { 1728 return RtlNtStatusToDosError(Status); 1729 } 1730 1731 hSubKey = KeyHandle; 1732 1733 if(lpszSubKey) 1734 { 1735 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey); 1736 if (ret) 1737 { 1738 ClosePredefKey(KeyHandle); 1739 return ret; 1740 } 1741 } 1742 1743 /* Get highest length for keys, values */ 1744 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, 1745 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); 1746 if (ret) goto cleanup; 1747 1748 dwMaxSubkeyLen++; 1749 dwMaxValueLen++; 1750 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); 1751 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR)) 1752 { 1753 /* Name too big: alloc a buffer for it */ 1754 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR)))) 1755 { 1756 ret = ERROR_NOT_ENOUGH_MEMORY; 1757 goto cleanup; 1758 } 1759 } 1760 1761 1762 /* Recursively delete all the subkeys */ 1763 while (TRUE) 1764 { 1765 dwSize = dwMaxLen; 1766 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, 1767 NULL, NULL, NULL)) break; 1768 1769 ret = RegDeleteTreeW(hSubKey, lpszName); 1770 if (ret) goto cleanup; 1771 } 1772 1773 if (lpszSubKey) 1774 ret = RegDeleteKeyW(KeyHandle, lpszSubKey); 1775 else 1776 while (TRUE) 1777 { 1778 dwSize = dwMaxLen; 1779 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize, 1780 NULL, NULL, NULL, NULL)) break; 1781 1782 ret = RegDeleteValueW(KeyHandle, lpszName); 1783 if (ret) goto cleanup; 1784 } 1785 1786 cleanup: 1787 /* Free buffer if allocated */ 1788 if (lpszName != szNameBuf) 1789 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName); 1790 if(lpszSubKey) 1791 RegCloseKey(hSubKey); 1792 1793 ClosePredefKey(KeyHandle); 1794 1795 return ret; 1796 } 1797 1798 1799 /************************************************************************ 1800 * RegDeleteTreeA 1801 * 1802 * @implemented 1803 */ 1804 LONG WINAPI 1805 RegDeleteTreeA(IN HKEY hKey, 1806 IN LPCSTR lpSubKey OPTIONAL) 1807 { 1808 UNICODE_STRING SubKeyName = { 0, 0, NULL }; 1809 LONG Ret; 1810 1811 if (lpSubKey != NULL && 1812 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey)) 1813 { 1814 return ERROR_NOT_ENOUGH_MEMORY; 1815 } 1816 1817 Ret = RegDeleteTreeW(hKey, 1818 SubKeyName.Buffer); 1819 1820 RtlFreeUnicodeString(&SubKeyName); 1821 1822 return Ret; 1823 } 1824 1825 #ifndef _ADVAPI32_VISTA_ 1826 1827 /************************************************************************ 1828 * RegDisableReflectionKey 1829 * 1830 * @unimplemented 1831 */ 1832 LONG WINAPI 1833 RegDisableReflectionKey(IN HKEY hBase) 1834 { 1835 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase); 1836 return ERROR_CALL_NOT_IMPLEMENTED; 1837 } 1838 1839 1840 /************************************************************************ 1841 * RegEnableReflectionKey 1842 * 1843 * @unimplemented 1844 */ 1845 LONG WINAPI 1846 RegEnableReflectionKey(IN HKEY hBase) 1847 { 1848 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase); 1849 return ERROR_CALL_NOT_IMPLEMENTED; 1850 } 1851 1852 1853 /****************************************************************************** 1854 * RegpApplyRestrictions [internal] 1855 * 1856 * Helper function for RegGetValueA/W. 1857 */ 1858 static VOID 1859 RegpApplyRestrictions(DWORD dwFlags, 1860 DWORD dwType, 1861 DWORD cbData, 1862 PLONG ret) 1863 { 1864 /* Check if the type is restricted by the passed flags */ 1865 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA) 1866 { 1867 DWORD dwMask = 0; 1868 1869 switch (dwType) 1870 { 1871 case REG_NONE: dwMask = RRF_RT_REG_NONE; break; 1872 case REG_SZ: dwMask = RRF_RT_REG_SZ; break; 1873 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break; 1874 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break; 1875 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break; 1876 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break; 1877 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break; 1878 } 1879 1880 if (dwFlags & dwMask) 1881 { 1882 /* Type is not restricted, check for size mismatch */ 1883 if (dwType == REG_BINARY) 1884 { 1885 DWORD cbExpect = 0; 1886 1887 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) 1888 cbExpect = 4; 1889 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) 1890 cbExpect = 8; 1891 1892 if (cbExpect && cbData != cbExpect) 1893 *ret = ERROR_DATATYPE_MISMATCH; 1894 } 1895 } 1896 else *ret = ERROR_UNSUPPORTED_TYPE; 1897 } 1898 } 1899 1900 1901 /****************************************************************************** 1902 * RegGetValueW [ADVAPI32.@] 1903 * 1904 * Retrieves the type and data for a value name associated with a key, 1905 * optionally expanding its content and restricting its type. 1906 * 1907 * PARAMS 1908 * hKey [I] Handle to an open key. 1909 * pszSubKey [I] Name of the subkey of hKey. 1910 * pszValue [I] Name of value under hKey/szSubKey to query. 1911 * dwFlags [I] Flags restricting the value type to retrieve. 1912 * pdwType [O] Destination for the values type, may be NULL. 1913 * pvData [O] Destination for the values content, may be NULL. 1914 * pcbData [I/O] Size of pvData, updated with the size in bytes required to 1915 * retrieve the whole content, including the trailing '\0' 1916 * for strings. 1917 * 1918 * RETURNS 1919 * Success: ERROR_SUCCESS 1920 * Failure: nonzero error code from Winerror.h 1921 * 1922 * NOTES 1923 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically 1924 * expanded and pdwType is set to REG_SZ instead. 1925 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 1926 * without RRF_NOEXPAND is thus not allowed. 1927 * An exception is the case where RRF_RT_ANY is specified, because then 1928 * RRF_NOEXPAND is allowed. 1929 */ 1930 LSTATUS WINAPI 1931 RegGetValueW(HKEY hKey, 1932 LPCWSTR pszSubKey, 1933 LPCWSTR pszValue, 1934 DWORD dwFlags, 1935 LPDWORD pdwType, 1936 PVOID pvData, 1937 LPDWORD pcbData) 1938 { 1939 DWORD dwType, cbData = pcbData ? *pcbData : 0; 1940 PVOID pvBuf = NULL; 1941 LONG ret; 1942 1943 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 1944 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, 1945 pvData, pcbData, cbData); 1946 1947 if (pvData && !pcbData) 1948 return ERROR_INVALID_PARAMETER; 1949 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && 1950 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) 1951 return ERROR_INVALID_PARAMETER; 1952 1953 if (pszSubKey && pszSubKey[0]) 1954 { 1955 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); 1956 if (ret != ERROR_SUCCESS) return ret; 1957 } 1958 1959 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData); 1960 1961 /* If we are going to expand we need to read in the whole the value even 1962 * if the passed buffer was too small as the expanded string might be 1963 * smaller than the unexpanded one and could fit into cbData bytes. */ 1964 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && 1965 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) 1966 { 1967 do 1968 { 1969 HeapFree(GetProcessHeap(), 0, pvBuf); 1970 1971 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); 1972 if (!pvBuf) 1973 { 1974 ret = ERROR_NOT_ENOUGH_MEMORY; 1975 break; 1976 } 1977 1978 if (ret == ERROR_MORE_DATA || !pvData) 1979 ret = RegQueryValueExW(hKey, pszValue, NULL, 1980 &dwType, pvBuf, &cbData); 1981 else 1982 { 1983 /* Even if cbData was large enough we have to copy the 1984 * string since ExpandEnvironmentStrings can't handle 1985 * overlapping buffers. */ 1986 CopyMemory(pvBuf, pvData, cbData); 1987 } 1988 1989 /* Both the type or the value itself could have been modified in 1990 * between so we have to keep retrying until the buffer is large 1991 * enough or we no longer have to expand the value. */ 1992 } 1993 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); 1994 1995 if (ret == ERROR_SUCCESS) 1996 { 1997 /* Recheck dwType in case it changed since the first call */ 1998 if (dwType == REG_EXPAND_SZ) 1999 { 2000 cbData = ExpandEnvironmentStringsW(pvBuf, pvData, 2001 pcbData ? *pcbData : 0) * sizeof(WCHAR); 2002 dwType = REG_SZ; 2003 if (pvData && pcbData && cbData > *pcbData) 2004 ret = ERROR_MORE_DATA; 2005 } 2006 else if (pvData) 2007 CopyMemory(pvData, pvBuf, *pcbData); 2008 } 2009 2010 HeapFree(GetProcessHeap(), 0, pvBuf); 2011 } 2012 2013 if (pszSubKey && pszSubKey[0]) 2014 RegCloseKey(hKey); 2015 2016 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); 2017 2018 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) 2019 ZeroMemory(pvData, *pcbData); 2020 2021 if (pdwType) 2022 *pdwType = dwType; 2023 2024 if (pcbData) 2025 *pcbData = cbData; 2026 2027 return ret; 2028 } 2029 2030 2031 /****************************************************************************** 2032 * RegGetValueA [ADVAPI32.@] 2033 * 2034 * See RegGetValueW. 2035 */ 2036 LSTATUS WINAPI 2037 RegGetValueA(HKEY hKey, 2038 LPCSTR pszSubKey, 2039 LPCSTR pszValue, 2040 DWORD dwFlags, 2041 LPDWORD pdwType, 2042 PVOID pvData, 2043 LPDWORD pcbData) 2044 { 2045 DWORD dwType, cbData = pcbData ? *pcbData : 0; 2046 PVOID pvBuf = NULL; 2047 LONG ret; 2048 2049 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 2050 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData, 2051 cbData); 2052 2053 if (pvData && !pcbData) 2054 return ERROR_INVALID_PARAMETER; 2055 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && 2056 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) 2057 return ERROR_INVALID_PARAMETER; 2058 2059 if (pszSubKey && pszSubKey[0]) 2060 { 2061 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); 2062 if (ret != ERROR_SUCCESS) return ret; 2063 } 2064 2065 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData); 2066 2067 /* If we are going to expand we need to read in the whole the value even 2068 * if the passed buffer was too small as the expanded string might be 2069 * smaller than the unexpanded one and could fit into cbData bytes. */ 2070 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && 2071 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))) 2072 { 2073 do { 2074 HeapFree(GetProcessHeap(), 0, pvBuf); 2075 2076 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); 2077 if (!pvBuf) 2078 { 2079 ret = ERROR_NOT_ENOUGH_MEMORY; 2080 break; 2081 } 2082 2083 if (ret == ERROR_MORE_DATA || !pvData) 2084 ret = RegQueryValueExA(hKey, pszValue, NULL, 2085 &dwType, pvBuf, &cbData); 2086 else 2087 { 2088 /* Even if cbData was large enough we have to copy the 2089 * string since ExpandEnvironmentStrings can't handle 2090 * overlapping buffers. */ 2091 CopyMemory(pvBuf, pvData, cbData); 2092 } 2093 2094 /* Both the type or the value itself could have been modified in 2095 * between so we have to keep retrying until the buffer is large 2096 * enough or we no longer have to expand the value. */ 2097 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); 2098 2099 if (ret == ERROR_SUCCESS) 2100 { 2101 /* Recheck dwType in case it changed since the first call */ 2102 if (dwType == REG_EXPAND_SZ) 2103 { 2104 cbData = ExpandEnvironmentStringsA(pvBuf, pvData, 2105 pcbData ? *pcbData : 0); 2106 dwType = REG_SZ; 2107 if(pvData && pcbData && cbData > *pcbData) 2108 ret = ERROR_MORE_DATA; 2109 } 2110 else if (pvData) 2111 CopyMemory(pvData, pvBuf, *pcbData); 2112 } 2113 2114 HeapFree(GetProcessHeap(), 0, pvBuf); 2115 } 2116 2117 if (pszSubKey && pszSubKey[0]) 2118 RegCloseKey(hKey); 2119 2120 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); 2121 2122 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) 2123 ZeroMemory(pvData, *pcbData); 2124 2125 if (pdwType) *pdwType = dwType; 2126 if (pcbData) *pcbData = cbData; 2127 2128 return ret; 2129 } 2130 2131 #endif // _ADVAPI32_VISTA_ 2132 2133 /************************************************************************ 2134 * RegSetKeyValueW 2135 * 2136 * @implemented 2137 */ 2138 LONG WINAPI 2139 RegSetKeyValueW(IN HKEY hKey, 2140 IN LPCWSTR lpSubKey OPTIONAL, 2141 IN LPCWSTR lpValueName OPTIONAL, 2142 IN DWORD dwType, 2143 IN LPCVOID lpData OPTIONAL, 2144 IN DWORD cbData) 2145 { 2146 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 2147 NTSTATUS Status; 2148 LONG Ret; 2149 2150 Status = MapDefaultKey(&KeyHandle, 2151 hKey); 2152 if (!NT_SUCCESS(Status)) 2153 { 2154 return RtlNtStatusToDosError(Status); 2155 } 2156 2157 if (lpSubKey != NULL) 2158 { 2159 OBJECT_ATTRIBUTES ObjectAttributes; 2160 UNICODE_STRING SubKeyName; 2161 2162 RtlInitUnicodeString(&SubKeyName, lpSubKey); 2163 2164 InitializeObjectAttributes(&ObjectAttributes, 2165 &SubKeyName, 2166 OBJ_CASE_INSENSITIVE, 2167 KeyHandle, 2168 NULL); 2169 2170 Status = NtOpenKey(&SubKeyHandle, 2171 KEY_SET_VALUE, 2172 &ObjectAttributes); 2173 if (!NT_SUCCESS(Status)) 2174 { 2175 Ret = RtlNtStatusToDosError(Status); 2176 goto Cleanup; 2177 } 2178 2179 CurKey = SubKeyHandle; 2180 } 2181 else 2182 CurKey = KeyHandle; 2183 2184 Ret = RegSetValueExW(CurKey, 2185 lpValueName, 2186 0, 2187 dwType, 2188 lpData, 2189 cbData); 2190 2191 if (SubKeyHandle != NULL) 2192 { 2193 NtClose(SubKeyHandle); 2194 } 2195 2196 Cleanup: 2197 ClosePredefKey(KeyHandle); 2198 2199 return Ret; 2200 } 2201 2202 #ifndef _ADVAPI32_VISTA_ 2203 2204 /************************************************************************ 2205 * RegSetKeyValueA 2206 * 2207 * @implemented 2208 */ 2209 LONG WINAPI 2210 RegSetKeyValueA(IN HKEY hKey, 2211 IN LPCSTR lpSubKey OPTIONAL, 2212 IN LPCSTR lpValueName OPTIONAL, 2213 IN DWORD dwType, 2214 IN LPCVOID lpData OPTIONAL, 2215 IN DWORD cbData) 2216 { 2217 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 2218 NTSTATUS Status; 2219 LONG Ret; 2220 2221 Status = MapDefaultKey(&KeyHandle, 2222 hKey); 2223 if (!NT_SUCCESS(Status)) 2224 { 2225 return RtlNtStatusToDosError(Status); 2226 } 2227 2228 if (lpSubKey != NULL) 2229 { 2230 OBJECT_ATTRIBUTES ObjectAttributes; 2231 UNICODE_STRING SubKeyName; 2232 2233 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey)) 2234 { 2235 Ret = ERROR_NOT_ENOUGH_MEMORY; 2236 goto Cleanup; 2237 } 2238 2239 InitializeObjectAttributes(&ObjectAttributes, 2240 &SubKeyName, 2241 OBJ_CASE_INSENSITIVE, 2242 KeyHandle, 2243 NULL); 2244 2245 Status = NtOpenKey(&SubKeyHandle, 2246 KEY_SET_VALUE, 2247 &ObjectAttributes); 2248 2249 RtlFreeUnicodeString(&SubKeyName); 2250 2251 if (!NT_SUCCESS(Status)) 2252 { 2253 Ret = RtlNtStatusToDosError(Status); 2254 goto Cleanup; 2255 } 2256 2257 CurKey = SubKeyHandle; 2258 } 2259 else 2260 CurKey = KeyHandle; 2261 2262 Ret = RegSetValueExA(CurKey, 2263 lpValueName, 2264 0, 2265 dwType, 2266 lpData, 2267 cbData); 2268 2269 if (SubKeyHandle != NULL) 2270 { 2271 NtClose(SubKeyHandle); 2272 } 2273 2274 Cleanup: 2275 ClosePredefKey(KeyHandle); 2276 2277 return Ret; 2278 } 2279 2280 2281 /************************************************************************ 2282 * RegDeleteValueA 2283 * 2284 * @implemented 2285 */ 2286 LONG WINAPI 2287 RegDeleteValueA(HKEY hKey, 2288 LPCSTR lpValueName) 2289 { 2290 UNICODE_STRING ValueName; 2291 HANDLE KeyHandle; 2292 NTSTATUS Status; 2293 LONG ErrorCode = ERROR_SUCCESS; 2294 2295 Status = MapDefaultKey(&KeyHandle, 2296 hKey); 2297 if (!NT_SUCCESS(Status)) 2298 { 2299 return RtlNtStatusToDosError(Status); 2300 } 2301 2302 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName)) 2303 { 2304 ClosePredefKey(KeyHandle); 2305 return ERROR_NOT_ENOUGH_MEMORY; 2306 } 2307 2308 if (IsHKCRKey(KeyHandle)) 2309 { 2310 ErrorCode = DeleteHKCRValue(KeyHandle, &ValueName); 2311 } 2312 else 2313 { 2314 Status = NtDeleteValueKey(KeyHandle, &ValueName); 2315 if (!NT_SUCCESS(Status)) 2316 ErrorCode = RtlNtStatusToDosError(Status); 2317 } 2318 RtlFreeUnicodeString(&ValueName); 2319 ClosePredefKey(KeyHandle); 2320 return ErrorCode; 2321 } 2322 2323 2324 /************************************************************************ 2325 * RegDeleteValueW 2326 * 2327 * @implemented 2328 */ 2329 LONG WINAPI 2330 RegDeleteValueW(HKEY hKey, 2331 LPCWSTR lpValueName) 2332 { 2333 UNICODE_STRING ValueName; 2334 NTSTATUS Status; 2335 HANDLE KeyHandle; 2336 LONG ErrorCode = ERROR_SUCCESS; 2337 2338 Status = MapDefaultKey(&KeyHandle, 2339 hKey); 2340 if (!NT_SUCCESS(Status)) 2341 { 2342 return RtlNtStatusToDosError(Status); 2343 } 2344 2345 RtlInitUnicodeString(&ValueName, lpValueName); 2346 2347 if (IsHKCRKey(KeyHandle)) 2348 { 2349 ErrorCode = DeleteHKCRValue(KeyHandle, &ValueName); 2350 } 2351 else 2352 { 2353 Status = NtDeleteValueKey(KeyHandle, &ValueName); 2354 if (!NT_SUCCESS(Status)) 2355 ErrorCode = RtlNtStatusToDosError(Status); 2356 } 2357 ClosePredefKey(KeyHandle); 2358 return ErrorCode; 2359 } 2360 2361 2362 /************************************************************************ 2363 * RegEnumKeyA 2364 * 2365 * @implemented 2366 */ 2367 LONG WINAPI 2368 RegEnumKeyA(HKEY hKey, 2369 DWORD dwIndex, 2370 LPSTR lpName, 2371 DWORD cbName) 2372 { 2373 DWORD dwLength; 2374 2375 dwLength = cbName; 2376 return RegEnumKeyExA(hKey, 2377 dwIndex, 2378 lpName, 2379 &dwLength, 2380 NULL, 2381 NULL, 2382 NULL, 2383 NULL); 2384 } 2385 2386 2387 /************************************************************************ 2388 * RegEnumKeyW 2389 * 2390 * @implemented 2391 */ 2392 LONG WINAPI 2393 RegEnumKeyW(HKEY hKey, 2394 DWORD dwIndex, 2395 LPWSTR lpName, 2396 DWORD cbName) 2397 { 2398 DWORD dwLength; 2399 2400 dwLength = cbName; 2401 return RegEnumKeyExW(hKey, 2402 dwIndex, 2403 lpName, 2404 &dwLength, 2405 NULL, 2406 NULL, 2407 NULL, 2408 NULL); 2409 } 2410 2411 2412 /************************************************************************ 2413 * RegEnumKeyExA 2414 * 2415 * @implemented 2416 */ 2417 LONG 2418 WINAPI 2419 RegEnumKeyExA( 2420 _In_ HKEY hKey, 2421 _In_ DWORD dwIndex, 2422 _Out_ LPSTR lpName, 2423 _Inout_ LPDWORD lpcbName, 2424 _Reserved_ LPDWORD lpReserved, 2425 _Out_opt_ LPSTR lpClass, 2426 _Inout_opt_ LPDWORD lpcbClass, 2427 _Out_opt_ PFILETIME lpftLastWriteTime) 2428 { 2429 WCHAR* NameBuffer = NULL; 2430 WCHAR* ClassBuffer = NULL; 2431 DWORD NameLength, ClassLength; 2432 LONG ErrorCode; 2433 2434 /* Allocate our buffers */ 2435 if (*lpcbName > 0) 2436 { 2437 NameLength = *lpcbName; 2438 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR)); 2439 if (NameBuffer == NULL) 2440 { 2441 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2442 goto Exit; 2443 } 2444 } 2445 2446 if (lpClass) 2447 { 2448 if (*lpcbClass > 0) 2449 { 2450 ClassLength = *lpcbClass; 2451 ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR)); 2452 if (ClassBuffer == NULL) 2453 { 2454 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2455 goto Exit; 2456 } 2457 } 2458 } 2459 2460 /* Do the actual call */ 2461 ErrorCode = RegEnumKeyExW( 2462 hKey, 2463 dwIndex, 2464 NameBuffer, 2465 lpcbName, 2466 lpReserved, 2467 ClassBuffer, 2468 lpcbClass, 2469 lpftLastWriteTime); 2470 2471 if (ErrorCode != ERROR_SUCCESS) 2472 goto Exit; 2473 2474 /* Convert the strings */ 2475 RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR)); 2476 /* NULL terminate if we can */ 2477 if (NameLength > *lpcbName) 2478 lpName[*lpcbName] = '\0'; 2479 2480 if (lpClass) 2481 { 2482 RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR)); 2483 if (ClassLength > *lpcbClass) 2484 lpClass[*lpcbClass] = '\0'; 2485 } 2486 2487 Exit: 2488 if (NameBuffer) 2489 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 2490 if (ClassBuffer) 2491 RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer); 2492 2493 return ErrorCode; 2494 } 2495 2496 2497 /************************************************************************ 2498 * RegEnumKeyExW 2499 * 2500 * @implemented 2501 */ 2502 LONG 2503 WINAPI 2504 RegEnumKeyExW( 2505 _In_ HKEY hKey, 2506 _In_ DWORD dwIndex, 2507 _Out_ LPWSTR lpName, 2508 _Inout_ LPDWORD lpcbName, 2509 _Reserved_ LPDWORD lpReserved, 2510 _Out_opt_ LPWSTR lpClass, 2511 _Inout_opt_ LPDWORD lpcbClass, 2512 _Out_opt_ PFILETIME lpftLastWriteTime) 2513 { 2514 union 2515 { 2516 KEY_NODE_INFORMATION Node; 2517 KEY_BASIC_INFORMATION Basic; 2518 } *KeyInfo; 2519 2520 ULONG BufferSize; 2521 ULONG ResultSize; 2522 ULONG NameLength; 2523 ULONG ClassLength = 0; 2524 HANDLE KeyHandle; 2525 LONG ErrorCode = ERROR_SUCCESS; 2526 NTSTATUS Status; 2527 2528 Status = MapDefaultKey(&KeyHandle, 2529 hKey); 2530 if (!NT_SUCCESS(Status)) 2531 { 2532 return RtlNtStatusToDosError(Status); 2533 } 2534 2535 if (IsHKCRKey(KeyHandle)) 2536 { 2537 ErrorCode = EnumHKCRKey( 2538 KeyHandle, 2539 dwIndex, 2540 lpName, 2541 lpcbName, 2542 lpReserved, 2543 lpClass, 2544 lpcbClass, 2545 lpftLastWriteTime); 2546 ClosePredefKey(KeyHandle); 2547 return ErrorCode; 2548 } 2549 2550 if (*lpcbName > 0) 2551 { 2552 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR); 2553 } 2554 else 2555 { 2556 NameLength = 0; 2557 } 2558 2559 if (lpClass) 2560 { 2561 if (*lpcbClass > 0) 2562 { 2563 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 2564 } 2565 else 2566 { 2567 ClassLength = 0; 2568 } 2569 2570 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength; 2571 } 2572 else 2573 { 2574 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength; 2575 } 2576 2577 KeyInfo = RtlAllocateHeap(ProcessHeap, 2578 0, 2579 BufferSize); 2580 if (KeyInfo == NULL) 2581 { 2582 ErrorCode = ERROR_OUTOFMEMORY; 2583 goto Cleanup; 2584 } 2585 2586 Status = NtEnumerateKey(KeyHandle, 2587 (ULONG)dwIndex, 2588 lpClass ? KeyNodeInformation : KeyBasicInformation, 2589 KeyInfo, 2590 BufferSize, 2591 &ResultSize); 2592 TRACE("NtEnumerateKey() returned status 0x%X\n", Status); 2593 if (!NT_SUCCESS(Status)) 2594 { 2595 ErrorCode = RtlNtStatusToDosError (Status); 2596 } 2597 else 2598 { 2599 if (lpClass == NULL) 2600 { 2601 if (KeyInfo->Basic.NameLength > NameLength) 2602 { 2603 ErrorCode = ERROR_MORE_DATA; 2604 } 2605 else 2606 { 2607 RtlCopyMemory(lpName, 2608 KeyInfo->Basic.Name, 2609 KeyInfo->Basic.NameLength); 2610 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR)); 2611 lpName[*lpcbName] = 0; 2612 } 2613 } 2614 else 2615 { 2616 if (KeyInfo->Node.NameLength > NameLength || 2617 KeyInfo->Node.ClassLength > ClassLength) 2618 { 2619 ErrorCode = ERROR_MORE_DATA; 2620 } 2621 else 2622 { 2623 RtlCopyMemory(lpName, 2624 KeyInfo->Node.Name, 2625 KeyInfo->Node.NameLength); 2626 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR); 2627 lpName[*lpcbName] = 0; 2628 RtlCopyMemory(lpClass, 2629 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset), 2630 KeyInfo->Node.ClassLength); 2631 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR)); 2632 lpClass[*lpcbClass] = 0; 2633 } 2634 } 2635 2636 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL) 2637 { 2638 if (lpClass == NULL) 2639 { 2640 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart; 2641 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart; 2642 } 2643 else 2644 { 2645 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart; 2646 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart; 2647 } 2648 } 2649 } 2650 2651 RtlFreeHeap(ProcessHeap, 2652 0, 2653 KeyInfo); 2654 2655 Cleanup: 2656 ClosePredefKey(KeyHandle); 2657 2658 return ErrorCode; 2659 } 2660 2661 2662 /************************************************************************ 2663 * RegEnumValueA 2664 * 2665 * @implemented 2666 */ 2667 LONG WINAPI 2668 RegEnumValueA( 2669 _In_ HKEY hKey, 2670 _In_ DWORD dwIndex, 2671 _Out_ LPSTR lpName, 2672 _Inout_ LPDWORD lpcbName, 2673 _Reserved_ LPDWORD lpdwReserved, 2674 _Out_opt_ LPDWORD lpdwType, 2675 _Out_opt_ LPBYTE lpData, 2676 _Inout_opt_ LPDWORD lpcbData) 2677 { 2678 WCHAR* NameBuffer; 2679 DWORD NameBufferSize, NameLength; 2680 LONG ErrorCode; 2681 DWORD LocalType = REG_NONE; 2682 BOOL NameOverflow = FALSE; 2683 2684 /* Do parameter checks now, once and for all. */ 2685 if (!lpName || !lpcbName) 2686 return ERROR_INVALID_PARAMETER; 2687 2688 if ((lpData && !lpcbData) || lpdwReserved) 2689 return ERROR_INVALID_PARAMETER; 2690 2691 /* Get the size of the buffer we must use for the first call to RegEnumValueW */ 2692 ErrorCode = RegQueryInfoKeyW( 2693 hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL); 2694 if (ErrorCode != ERROR_SUCCESS) 2695 return ErrorCode; 2696 2697 /* Add space for the null terminator */ 2698 NameBufferSize++; 2699 2700 /* Allocate the buffer for the unicode name */ 2701 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR)); 2702 if (NameBuffer == NULL) 2703 { 2704 return ERROR_NOT_ENOUGH_MEMORY; 2705 } 2706 2707 /* 2708 * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value. 2709 * So for the first call, we check if we overflow on the name, as we have no way of knowing if this 2710 * is an overflow on the data or on the name during the the second call. So the first time, we make the 2711 * call with the supplied value. This is merdique, but this is how it is. 2712 */ 2713 NameLength = *lpcbName; 2714 ErrorCode = RegEnumValueW( 2715 hKey, 2716 dwIndex, 2717 NameBuffer, 2718 &NameLength, 2719 NULL, 2720 &LocalType, 2721 NULL, 2722 NULL); 2723 if (ErrorCode != ERROR_SUCCESS) 2724 { 2725 if (ErrorCode == ERROR_MORE_DATA) 2726 NameOverflow = TRUE; 2727 else 2728 goto Exit; 2729 } 2730 2731 if (is_string(LocalType) && lpcbData) 2732 { 2733 /* We must allocate a buffer to get the unicode data */ 2734 DWORD DataBufferSize = *lpcbData * sizeof(WCHAR); 2735 WCHAR* DataBuffer = NULL; 2736 DWORD DataLength = *lpcbData; 2737 LPSTR DataStr = (LPSTR)lpData; 2738 2739 if (lpData) 2740 DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR)); 2741 2742 /* Do the real call */ 2743 ErrorCode = RegEnumValueW( 2744 hKey, 2745 dwIndex, 2746 NameBuffer, 2747 &NameBufferSize, 2748 lpdwReserved, 2749 lpdwType, 2750 (LPBYTE)DataBuffer, 2751 &DataBufferSize); 2752 2753 *lpcbData = DataBufferSize / sizeof(WCHAR); 2754 2755 if (ErrorCode != ERROR_SUCCESS) 2756 { 2757 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer); 2758 goto Exit; 2759 } 2760 2761 /* Copy the data whatever the error code is */ 2762 if (lpData) 2763 { 2764 /* Do the data conversion */ 2765 RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize); 2766 /* NULL-terminate if there is enough room */ 2767 if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0')) 2768 DataStr[*lpcbData] = '\0'; 2769 } 2770 2771 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer); 2772 } 2773 else 2774 { 2775 /* No data conversion needed. Do the call with provided buffers */ 2776 ErrorCode = RegEnumValueW( 2777 hKey, 2778 dwIndex, 2779 NameBuffer, 2780 &NameBufferSize, 2781 lpdwReserved, 2782 lpdwType, 2783 lpData, 2784 lpcbData); 2785 2786 if (ErrorCode != ERROR_SUCCESS) 2787 { 2788 goto Exit; 2789 } 2790 } 2791 2792 if (NameOverflow) 2793 { 2794 ErrorCode = ERROR_MORE_DATA; 2795 goto Exit; 2796 } 2797 2798 /* Convert the name string */ 2799 RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR)); 2800 lpName[*lpcbName] = ANSI_NULL; 2801 2802 Exit: 2803 if (NameBuffer) 2804 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 2805 2806 return ErrorCode; 2807 } 2808 2809 2810 /****************************************************************************** 2811 * RegEnumValueW [ADVAPI32.@] 2812 * @implemented 2813 * 2814 * PARAMS 2815 * hkey [I] Handle to key to query 2816 * index [I] Index of value to query 2817 * value [O] Value string 2818 * val_count [I/O] Size of value buffer (in wchars) 2819 * reserved [I] Reserved 2820 * type [O] Type code 2821 * data [O] Value data 2822 * count [I/O] Size of data buffer (in bytes) 2823 * 2824 * RETURNS 2825 * Success: ERROR_SUCCESS 2826 * Failure: nonzero error code from Winerror.h 2827 */ 2828 LONG 2829 WINAPI 2830 RegEnumValueW( 2831 _In_ HKEY hKey, 2832 _In_ DWORD index, 2833 _Out_ LPWSTR value, 2834 _Inout_ PDWORD val_count, 2835 _Reserved_ PDWORD reserved, 2836 _Out_opt_ PDWORD type, 2837 _Out_opt_ LPBYTE data, 2838 _Inout_opt_ PDWORD count) 2839 { 2840 HANDLE KeyHandle; 2841 NTSTATUS status; 2842 ULONG total_size; 2843 char buffer[256], *buf_ptr = buffer; 2844 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; 2845 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name ); 2846 2847 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n", 2848 hKey, index, value, val_count, reserved, type, data, count ); 2849 2850 if (!value || !val_count) 2851 return ERROR_INVALID_PARAMETER; 2852 2853 if ((data && !count) || reserved) 2854 return ERROR_INVALID_PARAMETER; 2855 2856 status = MapDefaultKey(&KeyHandle, hKey); 2857 if (!NT_SUCCESS(status)) 2858 { 2859 return RtlNtStatusToDosError(status); 2860 } 2861 2862 if (IsHKCRKey(KeyHandle)) 2863 { 2864 LONG ErrorCode = EnumHKCRValue( 2865 KeyHandle, 2866 index, 2867 value, 2868 val_count, 2869 reserved, 2870 type, 2871 data, 2872 count); 2873 ClosePredefKey(KeyHandle); 2874 return ErrorCode; 2875 } 2876 2877 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); 2878 if (data) total_size += *count; 2879 total_size = min( sizeof(buffer), total_size ); 2880 2881 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 2882 buffer, total_size, &total_size ); 2883 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done; 2884 2885 if (value || data) 2886 { 2887 /* retry with a dynamically allocated buffer */ 2888 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL)) 2889 { 2890 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 2891 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 2892 { 2893 status = ERROR_NOT_ENOUGH_MEMORY; 2894 goto done; 2895 } 2896 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr; 2897 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 2898 buf_ptr, total_size, &total_size ); 2899 } 2900 2901 if (status) goto done; 2902 2903 if (value) 2904 { 2905 if (info->NameLength/sizeof(WCHAR) >= *val_count) 2906 { 2907 status = STATUS_BUFFER_OVERFLOW; 2908 goto overflow; 2909 } 2910 memcpy( value, info->Name, info->NameLength ); 2911 *val_count = info->NameLength / sizeof(WCHAR); 2912 value[*val_count] = 0; 2913 } 2914 2915 if (data) 2916 { 2917 if (info->DataLength > *count) 2918 { 2919 status = STATUS_BUFFER_OVERFLOW; 2920 goto overflow; 2921 } 2922 memcpy( data, buf_ptr + info->DataOffset, info->DataLength ); 2923 if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR)) 2924 { 2925 /* if the type is REG_SZ and data is not 0-terminated 2926 * and there is enough space in the buffer NT appends a \0 */ 2927 WCHAR *ptr = (WCHAR *)(data + info->DataLength); 2928 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 2929 } 2930 } 2931 } 2932 else status = STATUS_SUCCESS; 2933 2934 overflow: 2935 if (type) *type = info->Type; 2936 if (count) *count = info->DataLength; 2937 2938 done: 2939 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 2940 ClosePredefKey(KeyHandle); 2941 return RtlNtStatusToDosError(status); 2942 } 2943 2944 2945 /************************************************************************ 2946 * RegFlushKey 2947 * 2948 * @implemented 2949 */ 2950 LONG WINAPI 2951 RegFlushKey(HKEY hKey) 2952 { 2953 HANDLE KeyHandle; 2954 NTSTATUS Status; 2955 2956 if (hKey == HKEY_PERFORMANCE_DATA) 2957 { 2958 return ERROR_SUCCESS; 2959 } 2960 2961 Status = MapDefaultKey(&KeyHandle, 2962 hKey); 2963 if (!NT_SUCCESS(Status)) 2964 { 2965 return RtlNtStatusToDosError(Status); 2966 } 2967 2968 Status = NtFlushKey(KeyHandle); 2969 2970 ClosePredefKey(KeyHandle); 2971 2972 if (!NT_SUCCESS(Status)) 2973 { 2974 return RtlNtStatusToDosError(Status); 2975 } 2976 2977 return ERROR_SUCCESS; 2978 } 2979 2980 2981 /************************************************************************ 2982 * RegGetKeySecurity 2983 * 2984 * @implemented 2985 */ 2986 LONG WINAPI 2987 RegGetKeySecurity(HKEY hKey, 2988 SECURITY_INFORMATION SecurityInformation, 2989 PSECURITY_DESCRIPTOR pSecurityDescriptor, 2990 LPDWORD lpcbSecurityDescriptor) 2991 { 2992 HANDLE KeyHandle; 2993 NTSTATUS Status; 2994 2995 if (hKey == HKEY_PERFORMANCE_DATA) 2996 { 2997 return ERROR_INVALID_HANDLE; 2998 } 2999 3000 Status = MapDefaultKey(&KeyHandle, 3001 hKey); 3002 if (!NT_SUCCESS(Status)) 3003 { 3004 TRACE("MapDefaultKey() failed (Status %lx)\n", Status); 3005 return RtlNtStatusToDosError(Status); 3006 } 3007 3008 Status = NtQuerySecurityObject(KeyHandle, 3009 SecurityInformation, 3010 pSecurityDescriptor, 3011 *lpcbSecurityDescriptor, 3012 lpcbSecurityDescriptor); 3013 3014 ClosePredefKey(KeyHandle); 3015 3016 if (!NT_SUCCESS(Status)) 3017 { 3018 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status); 3019 return RtlNtStatusToDosError(Status); 3020 } 3021 3022 return ERROR_SUCCESS; 3023 } 3024 3025 3026 /************************************************************************ 3027 * RegLoadKeyA 3028 * 3029 * @implemented 3030 */ 3031 LONG WINAPI 3032 RegLoadKeyA(HKEY hKey, 3033 LPCSTR lpSubKey, 3034 LPCSTR lpFile) 3035 { 3036 UNICODE_STRING FileName; 3037 UNICODE_STRING KeyName; 3038 LONG ErrorCode; 3039 3040 RtlInitEmptyUnicodeString(&KeyName, NULL, 0); 3041 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 3042 3043 if (lpSubKey) 3044 { 3045 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey)) 3046 { 3047 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3048 goto Exit; 3049 } 3050 } 3051 3052 if (lpFile) 3053 { 3054 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 3055 { 3056 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3057 goto Exit; 3058 } 3059 } 3060 3061 ErrorCode = RegLoadKeyW(hKey, 3062 KeyName.Buffer, 3063 FileName.Buffer); 3064 3065 Exit: 3066 RtlFreeUnicodeString(&FileName); 3067 RtlFreeUnicodeString(&KeyName); 3068 3069 return ErrorCode; 3070 } 3071 3072 3073 /************************************************************************ 3074 * RegLoadKeyW 3075 * 3076 * @implemented 3077 */ 3078 LONG WINAPI 3079 RegLoadKeyW(HKEY hKey, 3080 LPCWSTR lpSubKey, 3081 LPCWSTR lpFile) 3082 { 3083 OBJECT_ATTRIBUTES FileObjectAttributes; 3084 OBJECT_ATTRIBUTES KeyObjectAttributes; 3085 UNICODE_STRING FileName; 3086 UNICODE_STRING KeyName; 3087 HANDLE KeyHandle; 3088 NTSTATUS Status; 3089 LONG ErrorCode = ERROR_SUCCESS; 3090 3091 if (hKey == HKEY_PERFORMANCE_DATA) 3092 { 3093 return ERROR_INVALID_HANDLE; 3094 } 3095 3096 Status = MapDefaultKey(&KeyHandle, 3097 hKey); 3098 if (!NT_SUCCESS(Status)) 3099 { 3100 return RtlNtStatusToDosError(Status); 3101 } 3102 3103 if (!RtlDosPathNameToNtPathName_U(lpFile, 3104 &FileName, 3105 NULL, 3106 NULL)) 3107 { 3108 ErrorCode = ERROR_BAD_PATHNAME; 3109 goto Cleanup; 3110 } 3111 3112 InitializeObjectAttributes(&FileObjectAttributes, 3113 &FileName, 3114 OBJ_CASE_INSENSITIVE, 3115 NULL, 3116 NULL); 3117 3118 RtlInitUnicodeString(&KeyName, lpSubKey); 3119 3120 InitializeObjectAttributes(&KeyObjectAttributes, 3121 &KeyName, 3122 OBJ_CASE_INSENSITIVE, 3123 KeyHandle, 3124 NULL); 3125 3126 Status = NtLoadKey(&KeyObjectAttributes, 3127 &FileObjectAttributes); 3128 3129 RtlFreeHeap(RtlGetProcessHeap(), 3130 0, 3131 FileName.Buffer); 3132 3133 if (!NT_SUCCESS(Status)) 3134 { 3135 ErrorCode = RtlNtStatusToDosError(Status); 3136 goto Cleanup; 3137 } 3138 3139 Cleanup: 3140 ClosePredefKey(KeyHandle); 3141 3142 return ErrorCode; 3143 } 3144 3145 3146 /************************************************************************ 3147 * RegNotifyChangeKeyValue 3148 * 3149 * @unimplemented 3150 */ 3151 LONG WINAPI 3152 RegNotifyChangeKeyValue(HKEY hKey, 3153 BOOL bWatchSubtree, 3154 DWORD dwNotifyFilter, 3155 HANDLE hEvent, 3156 BOOL fAsynchronous) 3157 { 3158 IO_STATUS_BLOCK IoStatusBlock; 3159 HANDLE KeyHandle; 3160 NTSTATUS Status; 3161 LONG ErrorCode = ERROR_SUCCESS; 3162 3163 if (hKey == HKEY_PERFORMANCE_DATA) 3164 { 3165 return ERROR_INVALID_HANDLE; 3166 } 3167 3168 if ((fAsynchronous != FALSE) && (hEvent == NULL)) 3169 { 3170 return ERROR_INVALID_PARAMETER; 3171 } 3172 3173 Status = MapDefaultKey(&KeyHandle, 3174 hKey); 3175 if (!NT_SUCCESS(Status)) 3176 { 3177 return RtlNtStatusToDosError(Status); 3178 } 3179 3180 /* FIXME: Remote key handles must fail */ 3181 3182 Status = NtNotifyChangeKey(KeyHandle, 3183 hEvent, 3184 0, 3185 0, 3186 &IoStatusBlock, 3187 dwNotifyFilter, 3188 bWatchSubtree, 3189 0, 3190 0, 3191 fAsynchronous); 3192 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT) 3193 { 3194 ErrorCode = RtlNtStatusToDosError(Status); 3195 } 3196 3197 ClosePredefKey(KeyHandle); 3198 3199 return ErrorCode; 3200 } 3201 3202 3203 /************************************************************************ 3204 * RegOpenCurrentUser 3205 * 3206 * @implemented 3207 */ 3208 LONG WINAPI 3209 RegOpenCurrentUser(IN REGSAM samDesired, 3210 OUT PHKEY phkResult) 3211 { 3212 NTSTATUS Status; 3213 3214 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired, 3215 (PHANDLE)phkResult); 3216 if (!NT_SUCCESS(Status)) 3217 { 3218 /* NOTE - don't set the last error code! just return the error! */ 3219 return RtlNtStatusToDosError(Status); 3220 } 3221 3222 return ERROR_SUCCESS; 3223 } 3224 3225 3226 /************************************************************************ 3227 * RegOpenKeyA 3228 * 3229 * 20050503 Fireball - imported from WINE 3230 * 3231 * @implemented 3232 */ 3233 LONG WINAPI 3234 RegOpenKeyA(HKEY hKey, 3235 LPCSTR lpSubKey, 3236 PHKEY phkResult) 3237 { 3238 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", 3239 hKey, lpSubKey, phkResult); 3240 3241 if (!phkResult) 3242 return ERROR_INVALID_PARAMETER; 3243 3244 if (!hKey && !lpSubKey) 3245 { 3246 *phkResult = hKey; 3247 return ERROR_SUCCESS; 3248 } 3249 3250 return RegOpenKeyExA(hKey, 3251 lpSubKey, 3252 0, 3253 MAXIMUM_ALLOWED, 3254 phkResult); 3255 } 3256 3257 3258 /************************************************************************ 3259 * RegOpenKeyW 3260 * 3261 * 19981101 Ariadne 3262 * 19990525 EA 3263 * 20050503 Fireball - imported from WINE 3264 * 3265 * @implemented 3266 */ 3267 LONG WINAPI 3268 RegOpenKeyW(HKEY hKey, 3269 LPCWSTR lpSubKey, 3270 PHKEY phkResult) 3271 { 3272 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", 3273 hKey, lpSubKey, phkResult); 3274 3275 if (!phkResult) 3276 return ERROR_INVALID_PARAMETER; 3277 3278 if (!hKey && !lpSubKey) 3279 { 3280 *phkResult = hKey; 3281 return ERROR_SUCCESS; 3282 } 3283 3284 return RegOpenKeyExW(hKey, 3285 lpSubKey, 3286 0, 3287 MAXIMUM_ALLOWED, 3288 phkResult); 3289 } 3290 3291 3292 /************************************************************************ 3293 * RegOpenKeyExA 3294 * 3295 * @implemented 3296 */ 3297 LONG WINAPI 3298 RegOpenKeyExA( 3299 _In_ HKEY hKey, 3300 _In_ LPCSTR lpSubKey, 3301 _In_ DWORD ulOptions, 3302 _In_ REGSAM samDesired, 3303 _Out_ PHKEY phkResult) 3304 { 3305 UNICODE_STRING SubKeyString; 3306 LONG ErrorCode; 3307 3308 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n", 3309 hKey, lpSubKey, ulOptions, samDesired, phkResult); 3310 3311 if (lpSubKey) 3312 { 3313 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey)) 3314 return ERROR_NOT_ENOUGH_MEMORY; 3315 } 3316 else 3317 RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0); 3318 3319 ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult); 3320 3321 RtlFreeUnicodeString(&SubKeyString); 3322 3323 return ErrorCode; 3324 } 3325 3326 3327 /************************************************************************ 3328 * RegOpenKeyExW 3329 * 3330 * @implemented 3331 */ 3332 LONG WINAPI 3333 RegOpenKeyExW(HKEY hKey, 3334 LPCWSTR lpSubKey, 3335 DWORD ulOptions, 3336 REGSAM samDesired, 3337 PHKEY phkResult) 3338 { 3339 OBJECT_ATTRIBUTES ObjectAttributes; 3340 UNICODE_STRING SubKeyString; 3341 HANDLE KeyHandle; 3342 NTSTATUS Status; 3343 ULONG Attributes = OBJ_CASE_INSENSITIVE; 3344 LONG ErrorCode = ERROR_SUCCESS; 3345 BOOLEAN SubKeyStringAllocated = FALSE; 3346 3347 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n", 3348 hKey, lpSubKey, ulOptions, samDesired, phkResult); 3349 if (!phkResult) 3350 { 3351 return ERROR_INVALID_PARAMETER; 3352 } 3353 3354 if (!hKey && lpSubKey && phkResult) 3355 { 3356 return ERROR_INVALID_HANDLE; 3357 } 3358 3359 if (IsPredefKey(hKey) && (!lpSubKey || !*lpSubKey)) 3360 { 3361 *phkResult = hKey; 3362 return ERROR_SUCCESS; 3363 } 3364 3365 Status = MapDefaultKey(&KeyHandle, hKey); 3366 if (!NT_SUCCESS(Status)) 3367 { 3368 return RtlNtStatusToDosError(Status); 3369 } 3370 3371 if (IsHKCRKey(KeyHandle)) 3372 { 3373 ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult); 3374 ClosePredefKey(KeyHandle); 3375 return ErrorCode; 3376 } 3377 3378 if (ulOptions & REG_OPTION_OPEN_LINK) 3379 Attributes |= OBJ_OPENLINK; 3380 3381 if (lpSubKey == NULL || wcscmp(lpSubKey, L"\\") == 0) 3382 { 3383 RtlInitUnicodeString(&SubKeyString, L""); 3384 } 3385 else 3386 { 3387 RtlInitUnicodeString(&SubKeyString, lpSubKey); 3388 3389 /* Handle unaligned lpSubKey */ 3390 if ((ULONG_PTR)lpSubKey & 1) 3391 { 3392 UNICODE_STRING AlignedString; 3393 3394 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 3395 &SubKeyString, 3396 &AlignedString); 3397 if (!NT_SUCCESS(Status)) 3398 { 3399 goto Exit; 3400 } 3401 3402 SubKeyString = AlignedString; 3403 SubKeyStringAllocated = TRUE; 3404 } 3405 } 3406 3407 InitializeObjectAttributes(&ObjectAttributes, 3408 &SubKeyString, 3409 Attributes, 3410 KeyHandle, 3411 NULL); 3412 3413 Status = NtOpenKey((PHANDLE)phkResult, 3414 samDesired, 3415 &ObjectAttributes); 3416 3417 Exit: 3418 3419 if (SubKeyStringAllocated) 3420 { 3421 RtlFreeUnicodeString(&SubKeyString); 3422 } 3423 3424 if (!NT_SUCCESS(Status)) 3425 { 3426 ErrorCode = RtlNtStatusToDosError(Status); 3427 } 3428 3429 ClosePredefKey(KeyHandle); 3430 3431 return ErrorCode; 3432 } 3433 3434 3435 /************************************************************************ 3436 * RegOpenUserClassesRoot 3437 * 3438 * @implemented 3439 */ 3440 LONG WINAPI 3441 RegOpenUserClassesRoot(IN HANDLE hToken, 3442 IN DWORD dwOptions, 3443 IN REGSAM samDesired, 3444 OUT PHKEY phkResult) 3445 { 3446 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\"; 3447 const WCHAR UserClassesKeySuffix[] = L"_Classes"; 3448 PTOKEN_USER TokenUserData; 3449 ULONG RequiredLength; 3450 UNICODE_STRING UserSidString, UserClassesKeyRoot; 3451 OBJECT_ATTRIBUTES ObjectAttributes; 3452 NTSTATUS Status; 3453 3454 /* check parameters */ 3455 if (hToken == NULL || dwOptions != 0 || phkResult == NULL) 3456 { 3457 return ERROR_INVALID_PARAMETER; 3458 } 3459 3460 /* 3461 * Get the user sid from the token 3462 */ 3463 3464 ReadTokenSid: 3465 /* determine how much memory we need */ 3466 Status = NtQueryInformationToken(hToken, 3467 TokenUser, 3468 NULL, 3469 0, 3470 &RequiredLength); 3471 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL)) 3472 { 3473 /* NOTE - as opposed to all other registry functions windows does indeed 3474 change the last error code in case the caller supplied a invalid 3475 handle for example! */ 3476 return RtlNtStatusToDosError(Status); 3477 } 3478 RegInitialize(); /* HACK until delay-loading is implemented */ 3479 TokenUserData = RtlAllocateHeap(ProcessHeap, 3480 0, 3481 RequiredLength); 3482 if (TokenUserData == NULL) 3483 { 3484 return ERROR_NOT_ENOUGH_MEMORY; 3485 } 3486 3487 /* attempt to read the information */ 3488 Status = NtQueryInformationToken(hToken, 3489 TokenUser, 3490 TokenUserData, 3491 RequiredLength, 3492 &RequiredLength); 3493 if (!NT_SUCCESS(Status)) 3494 { 3495 RtlFreeHeap(ProcessHeap, 3496 0, 3497 TokenUserData); 3498 if (Status == STATUS_BUFFER_TOO_SMALL) 3499 { 3500 /* the information appears to have changed?! try again */ 3501 goto ReadTokenSid; 3502 } 3503 3504 /* NOTE - as opposed to all other registry functions windows does indeed 3505 change the last error code in case the caller supplied a invalid 3506 handle for example! */ 3507 return RtlNtStatusToDosError(Status); 3508 } 3509 3510 /* 3511 * Build the absolute path for the user's registry in the form 3512 * "\Registry\User\<SID>_Classes" 3513 */ 3514 Status = RtlConvertSidToUnicodeString(&UserSidString, 3515 TokenUserData->User.Sid, 3516 TRUE); 3517 3518 /* we don't need the user data anymore, free it */ 3519 RtlFreeHeap(ProcessHeap, 3520 0, 3521 TokenUserData); 3522 3523 if (!NT_SUCCESS(Status)) 3524 { 3525 return RtlNtStatusToDosError(Status); 3526 } 3527 3528 /* allocate enough memory for the entire key string */ 3529 UserClassesKeyRoot.Length = 0; 3530 UserClassesKeyRoot.MaximumLength = UserSidString.Length + 3531 sizeof(UserClassesKeyPrefix) + 3532 sizeof(UserClassesKeySuffix); 3533 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap, 3534 0, 3535 UserClassesKeyRoot.MaximumLength); 3536 if (UserClassesKeyRoot.Buffer == NULL) 3537 { 3538 RtlFreeUnicodeString(&UserSidString); 3539 return RtlNtStatusToDosError(Status); 3540 } 3541 3542 /* build the string */ 3543 RtlAppendUnicodeToString(&UserClassesKeyRoot, 3544 UserClassesKeyPrefix); 3545 RtlAppendUnicodeStringToString(&UserClassesKeyRoot, 3546 &UserSidString); 3547 RtlAppendUnicodeToString(&UserClassesKeyRoot, 3548 UserClassesKeySuffix); 3549 3550 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot); 3551 3552 /* 3553 * Open the key 3554 */ 3555 InitializeObjectAttributes(&ObjectAttributes, 3556 &UserClassesKeyRoot, 3557 OBJ_CASE_INSENSITIVE, 3558 NULL, 3559 NULL); 3560 3561 Status = NtOpenKey((PHANDLE)phkResult, 3562 samDesired, 3563 &ObjectAttributes); 3564 3565 RtlFreeUnicodeString(&UserSidString); 3566 RtlFreeUnicodeString(&UserClassesKeyRoot); 3567 3568 if (!NT_SUCCESS(Status)) 3569 { 3570 return RtlNtStatusToDosError(Status); 3571 } 3572 3573 return ERROR_SUCCESS; 3574 } 3575 3576 3577 /************************************************************************ 3578 * RegQueryInfoKeyA 3579 * 3580 * @implemented 3581 */ 3582 LONG WINAPI 3583 RegQueryInfoKeyA(HKEY hKey, 3584 LPSTR lpClass, 3585 LPDWORD lpcClass, 3586 LPDWORD lpReserved, 3587 LPDWORD lpcSubKeys, 3588 LPDWORD lpcMaxSubKeyLen, 3589 LPDWORD lpcMaxClassLen, 3590 LPDWORD lpcValues, 3591 LPDWORD lpcMaxValueNameLen, 3592 LPDWORD lpcMaxValueLen, 3593 LPDWORD lpcbSecurityDescriptor, 3594 PFILETIME lpftLastWriteTime) 3595 { 3596 WCHAR ClassName[MAX_PATH]; 3597 UNICODE_STRING UnicodeString; 3598 ANSI_STRING AnsiString; 3599 LONG ErrorCode; 3600 NTSTATUS Status; 3601 DWORD cClass = 0; 3602 3603 if ((lpClass) && (!lpcClass)) 3604 { 3605 return ERROR_INVALID_PARAMETER; 3606 } 3607 3608 RtlInitUnicodeString(&UnicodeString, 3609 NULL); 3610 if (lpClass != NULL) 3611 { 3612 RtlInitEmptyUnicodeString(&UnicodeString, 3613 ClassName, 3614 sizeof(ClassName)); 3615 cClass = sizeof(ClassName) / sizeof(WCHAR); 3616 } 3617 3618 ErrorCode = RegQueryInfoKeyW(hKey, 3619 UnicodeString.Buffer, 3620 &cClass, 3621 lpReserved, 3622 lpcSubKeys, 3623 lpcMaxSubKeyLen, 3624 lpcMaxClassLen, 3625 lpcValues, 3626 lpcMaxValueNameLen, 3627 lpcMaxValueLen, 3628 lpcbSecurityDescriptor, 3629 lpftLastWriteTime); 3630 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL)) 3631 { 3632 if (*lpcClass == 0) 3633 { 3634 return ErrorCode; 3635 } 3636 3637 RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass); 3638 UnicodeString.Length = cClass * sizeof(WCHAR); 3639 Status = RtlUnicodeStringToAnsiString(&AnsiString, 3640 &UnicodeString, 3641 FALSE); 3642 ErrorCode = RtlNtStatusToDosError(Status); 3643 cClass = AnsiString.Length; 3644 lpClass[cClass] = ANSI_NULL; 3645 } 3646 3647 if (lpcClass != NULL) 3648 { 3649 *lpcClass = cClass; 3650 } 3651 3652 return ErrorCode; 3653 } 3654 3655 3656 /************************************************************************ 3657 * RegQueryInfoKeyW 3658 * 3659 * @implemented 3660 */ 3661 LONG WINAPI 3662 RegQueryInfoKeyW(HKEY hKey, 3663 LPWSTR lpClass, 3664 LPDWORD lpcClass, 3665 LPDWORD lpReserved, 3666 LPDWORD lpcSubKeys, 3667 LPDWORD lpcMaxSubKeyLen, 3668 LPDWORD lpcMaxClassLen, 3669 LPDWORD lpcValues, 3670 LPDWORD lpcMaxValueNameLen, 3671 LPDWORD lpcMaxValueLen, 3672 LPDWORD lpcbSecurityDescriptor, 3673 PFILETIME lpftLastWriteTime) 3674 { 3675 KEY_FULL_INFORMATION FullInfoBuffer; 3676 PKEY_FULL_INFORMATION FullInfo; 3677 ULONG FullInfoSize; 3678 ULONG ClassLength = 0; 3679 HANDLE KeyHandle; 3680 NTSTATUS Status; 3681 ULONG Length; 3682 LONG ErrorCode = ERROR_SUCCESS; 3683 3684 if ((lpClass) && (!lpcClass)) 3685 { 3686 return ERROR_INVALID_PARAMETER; 3687 } 3688 3689 Status = MapDefaultKey(&KeyHandle, 3690 hKey); 3691 if (!NT_SUCCESS(Status)) 3692 { 3693 return RtlNtStatusToDosError(Status); 3694 } 3695 3696 if (IsHKCRKey(KeyHandle)) 3697 { 3698 ErrorCode = QueryInfoHKCRKey(KeyHandle, lpClass, lpcClass, lpReserved, 3699 lpcSubKeys, lpcMaxSubKeyLen, lpcMaxClassLen, 3700 lpcValues, lpcMaxValueNameLen, lpcMaxValueLen, 3701 lpcbSecurityDescriptor, lpftLastWriteTime); 3702 ClosePredefKey(KeyHandle); 3703 return ErrorCode; 3704 } 3705 3706 if (lpClass != NULL) 3707 { 3708 if (*lpcClass > 0) 3709 { 3710 ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 3711 } 3712 else 3713 { 3714 ClassLength = 0; 3715 } 3716 3717 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3); 3718 FullInfo = RtlAllocateHeap(ProcessHeap, 3719 0, 3720 FullInfoSize); 3721 if (FullInfo == NULL) 3722 { 3723 ErrorCode = ERROR_OUTOFMEMORY; 3724 goto Cleanup; 3725 } 3726 } 3727 else 3728 { 3729 FullInfoSize = sizeof(KEY_FULL_INFORMATION); 3730 FullInfo = &FullInfoBuffer; 3731 } 3732 3733 if (lpcbSecurityDescriptor != NULL) 3734 *lpcbSecurityDescriptor = 0; 3735 3736 Status = NtQueryKey(KeyHandle, 3737 KeyFullInformation, 3738 FullInfo, 3739 FullInfoSize, 3740 &Length); 3741 TRACE("NtQueryKey() returned status 0x%X\n", Status); 3742 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 3743 { 3744 ErrorCode = RtlNtStatusToDosError(Status); 3745 goto Cleanup; 3746 } 3747 3748 TRACE("SubKeys %d\n", FullInfo->SubKeys); 3749 if (lpcSubKeys != NULL) 3750 { 3751 *lpcSubKeys = FullInfo->SubKeys; 3752 } 3753 3754 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen); 3755 if (lpcMaxSubKeyLen != NULL) 3756 { 3757 *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR); 3758 } 3759 3760 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen); 3761 if (lpcMaxClassLen != NULL) 3762 { 3763 *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR); 3764 } 3765 3766 TRACE("Values %lu\n", FullInfo->Values); 3767 if (lpcValues != NULL) 3768 { 3769 *lpcValues = FullInfo->Values; 3770 } 3771 3772 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen); 3773 if (lpcMaxValueNameLen != NULL) 3774 { 3775 *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR); 3776 } 3777 3778 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen); 3779 if (lpcMaxValueLen != NULL) 3780 { 3781 *lpcMaxValueLen = FullInfo->MaxValueDataLen; 3782 } 3783 3784 if (lpcbSecurityDescriptor != NULL) 3785 { 3786 Status = NtQuerySecurityObject(KeyHandle, 3787 OWNER_SECURITY_INFORMATION | 3788 GROUP_SECURITY_INFORMATION | 3789 DACL_SECURITY_INFORMATION, 3790 NULL, 3791 0, 3792 lpcbSecurityDescriptor); 3793 TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status); 3794 } 3795 3796 if (lpftLastWriteTime != NULL) 3797 { 3798 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart; 3799 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart; 3800 } 3801 3802 if (lpClass != NULL) 3803 { 3804 if (*lpcClass == 0) 3805 { 3806 goto Cleanup; 3807 } 3808 3809 if (FullInfo->ClassLength > ClassLength) 3810 { 3811 ErrorCode = ERROR_INSUFFICIENT_BUFFER; 3812 } 3813 else 3814 { 3815 RtlCopyMemory(lpClass, 3816 FullInfo->Class, 3817 FullInfo->ClassLength); 3818 lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL; 3819 } 3820 } 3821 3822 if (lpcClass != NULL) 3823 { 3824 *lpcClass = FullInfo->ClassLength / sizeof(WCHAR); 3825 } 3826 3827 Cleanup: 3828 if (lpClass != NULL) 3829 { 3830 RtlFreeHeap(ProcessHeap, 3831 0, 3832 FullInfo); 3833 } 3834 3835 ClosePredefKey(KeyHandle); 3836 3837 return ErrorCode; 3838 } 3839 3840 3841 /************************************************************************ 3842 * RegQueryMultipleValuesA 3843 * 3844 * @implemented 3845 */ 3846 LONG WINAPI 3847 RegQueryMultipleValuesA(HKEY hKey, 3848 PVALENTA val_list, 3849 DWORD num_vals, 3850 LPSTR lpValueBuf, 3851 LPDWORD ldwTotsize) 3852 { 3853 ULONG i; 3854 DWORD maxBytes = *ldwTotsize; 3855 LPSTR bufptr = lpValueBuf; 3856 LONG ErrorCode; 3857 3858 if (maxBytes >= (1024*1024)) 3859 return ERROR_MORE_DATA; 3860 3861 *ldwTotsize = 0; 3862 3863 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n", 3864 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3865 3866 for (i = 0; i < num_vals; i++) 3867 { 3868 val_list[i].ve_valuelen = 0; 3869 ErrorCode = RegQueryValueExA(hKey, 3870 val_list[i].ve_valuename, 3871 NULL, 3872 NULL, 3873 NULL, 3874 &val_list[i].ve_valuelen); 3875 if (ErrorCode != ERROR_SUCCESS) 3876 { 3877 return ErrorCode; 3878 } 3879 3880 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3881 { 3882 ErrorCode = RegQueryValueExA(hKey, 3883 val_list[i].ve_valuename, 3884 NULL, 3885 &val_list[i].ve_type, 3886 (LPBYTE)bufptr, 3887 &val_list[i].ve_valuelen); 3888 if (ErrorCode != ERROR_SUCCESS) 3889 { 3890 return ErrorCode; 3891 } 3892 3893 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3894 3895 bufptr += val_list[i].ve_valuelen; 3896 } 3897 3898 *ldwTotsize += val_list[i].ve_valuelen; 3899 } 3900 3901 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3902 } 3903 3904 3905 /************************************************************************ 3906 * RegQueryMultipleValuesW 3907 * 3908 * @implemented 3909 */ 3910 LONG WINAPI 3911 RegQueryMultipleValuesW(HKEY hKey, 3912 PVALENTW val_list, 3913 DWORD num_vals, 3914 LPWSTR lpValueBuf, 3915 LPDWORD ldwTotsize) 3916 { 3917 ULONG i; 3918 DWORD maxBytes = *ldwTotsize; 3919 LPSTR bufptr = (LPSTR)lpValueBuf; 3920 LONG ErrorCode; 3921 3922 if (maxBytes >= (1024*1024)) 3923 return ERROR_MORE_DATA; 3924 3925 *ldwTotsize = 0; 3926 3927 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n", 3928 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3929 3930 for (i = 0; i < num_vals; i++) 3931 { 3932 val_list[i].ve_valuelen = 0; 3933 ErrorCode = RegQueryValueExW(hKey, 3934 val_list[i].ve_valuename, 3935 NULL, 3936 NULL, 3937 NULL, 3938 &val_list[i].ve_valuelen); 3939 if (ErrorCode != ERROR_SUCCESS) 3940 { 3941 return ErrorCode; 3942 } 3943 3944 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3945 { 3946 ErrorCode = RegQueryValueExW(hKey, 3947 val_list[i].ve_valuename, 3948 NULL, 3949 &val_list[i].ve_type, 3950 (LPBYTE)bufptr, 3951 &val_list[i].ve_valuelen); 3952 if (ErrorCode != ERROR_SUCCESS) 3953 { 3954 return ErrorCode; 3955 } 3956 3957 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3958 3959 bufptr += val_list[i].ve_valuelen; 3960 } 3961 3962 *ldwTotsize += val_list[i].ve_valuelen; 3963 } 3964 3965 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3966 } 3967 3968 3969 /************************************************************************ 3970 * RegQueryReflectionKey 3971 * 3972 * @unimplemented 3973 */ 3974 LONG WINAPI 3975 RegQueryReflectionKey(IN HKEY hBase, 3976 OUT BOOL* bIsReflectionDisabled) 3977 { 3978 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n", 3979 hBase, bIsReflectionDisabled); 3980 return ERROR_CALL_NOT_IMPLEMENTED; 3981 } 3982 3983 3984 /****************************************************************************** 3985 * RegQueryValueExA [ADVAPI32.@] 3986 * 3987 * Get the type and contents of a specified value under with a key. 3988 * 3989 * PARAMS 3990 * hkey [I] Handle of the key to query 3991 * name [I] Name of value under hkey to query 3992 * reserved [I] Reserved - must be NULL 3993 * type [O] Destination for the value type, or NULL if not required 3994 * data [O] Destination for the values contents, or NULL if not required 3995 * count [I/O] Size of data, updated with the number of bytes returned 3996 * 3997 * RETURNS 3998 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. 3999 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. 4000 * ERROR_INVALID_PARAMETER, if any other parameter is invalid. 4001 * ERROR_MORE_DATA, if on input *count is too small to hold the contents. 4002 * 4003 * NOTES 4004 * MSDN states that if data is too small it is partially filled. In reality 4005 * it remains untouched. 4006 */ 4007 LONG 4008 WINAPI 4009 RegQueryValueExA( 4010 _In_ HKEY hkeyorg, 4011 _In_ LPCSTR name, 4012 _In_ LPDWORD reserved, 4013 _Out_opt_ LPDWORD type, 4014 _Out_opt_ LPBYTE data, 4015 _Inout_opt_ LPDWORD count) 4016 { 4017 UNICODE_STRING nameW; 4018 DWORD DataLength; 4019 DWORD ErrorCode; 4020 DWORD BufferSize = 0; 4021 WCHAR* Buffer; 4022 CHAR* DataStr = (CHAR*)data; 4023 DWORD LocalType; 4024 4025 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */ 4026 if ((data && !count) || reserved) 4027 return ERROR_INVALID_PARAMETER; 4028 4029 if (name) 4030 { 4031 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name)) 4032 return ERROR_NOT_ENOUGH_MEMORY; 4033 } 4034 else 4035 RtlInitEmptyUnicodeString(&nameW, NULL, 0); 4036 4037 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize); 4038 if (ErrorCode != ERROR_SUCCESS) 4039 { 4040 if ((!data) && count) 4041 *count = 0; 4042 RtlFreeUnicodeString(&nameW); 4043 return ErrorCode; 4044 } 4045 4046 /* See if we can directly handle the call without caring for conversion */ 4047 if (!is_string(LocalType) || !count) 4048 { 4049 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count); 4050 RtlFreeUnicodeString(&nameW); 4051 return ErrorCode; 4052 } 4053 4054 /* Allocate a unicode string to get the data */ 4055 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); 4056 if (!Buffer) 4057 { 4058 RtlFreeUnicodeString(&nameW); 4059 return ERROR_NOT_ENOUGH_MEMORY; 4060 } 4061 4062 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize); 4063 if (ErrorCode != ERROR_SUCCESS) 4064 { 4065 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4066 RtlFreeUnicodeString(&nameW); 4067 return ErrorCode; 4068 } 4069 4070 /* We don't need this anymore */ 4071 RtlFreeUnicodeString(&nameW); 4072 4073 /* Get the length for the multi-byte string (without the terminating NULL!) */ 4074 DataLength = *count; 4075 RtlUnicodeToMultiByteSize(count, Buffer, BufferSize); 4076 4077 if ((!data) || (DataLength < *count)) 4078 { 4079 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4080 return data ? ERROR_MORE_DATA : ERROR_SUCCESS; 4081 } 4082 4083 /* We can finally do the conversion */ 4084 RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize); 4085 4086 /* NULL-terminate if there is enough room */ 4087 if (DataLength > *count) 4088 DataStr[*count] = '\0'; 4089 4090 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4091 4092 return ERROR_SUCCESS; 4093 } 4094 4095 4096 /************************************************************************ 4097 * RegQueryValueExW 4098 * 4099 * @implemented 4100 */ 4101 LONG 4102 WINAPI 4103 RegQueryValueExW( 4104 _In_ HKEY hkeyorg, 4105 _In_ LPCWSTR name, 4106 _In_ LPDWORD reserved, 4107 _In_ LPDWORD type, 4108 _In_ LPBYTE data, 4109 _In_ LPDWORD count) 4110 { 4111 HANDLE hkey; 4112 NTSTATUS status; 4113 UNICODE_STRING name_str; 4114 DWORD total_size; 4115 char buffer[256], *buf_ptr = buffer; 4116 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 4117 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); 4118 4119 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", 4120 hkeyorg, debugstr_w(name), reserved, type, data, count, 4121 (count && data) ? *count : 0 ); 4122 4123 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 4124 4125 status = MapDefaultKey(&hkey, hkeyorg); 4126 if (!NT_SUCCESS(status)) 4127 { 4128 return RtlNtStatusToDosError(status); 4129 } 4130 4131 if (IsHKCRKey(hkey)) 4132 { 4133 LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count); 4134 ClosePredefKey(hkey); 4135 return ErrorCode; 4136 } 4137 4138 RtlInitUnicodeString( &name_str, name ); 4139 4140 if (data) 4141 total_size = min( sizeof(buffer), *count + info_size ); 4142 else 4143 total_size = info_size; 4144 4145 4146 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4147 buffer, total_size, &total_size ); 4148 4149 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) 4150 { 4151 // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE 4152 // On windows these conditions are likely to be side effects of the implementation... 4153 if (status == STATUS_INVALID_HANDLE && hkey) 4154 { 4155 if (type) *type = REG_NONE; 4156 if (count) *count = 0; 4157 } 4158 else if (status == STATUS_OBJECT_NAME_NOT_FOUND) 4159 { 4160 if (type) *type = REG_NONE; 4161 if (data == NULL && count) *count = 0; 4162 } 4163 goto done; 4164 } 4165 4166 if (data) 4167 { 4168 /* retry with a dynamically allocated buffer */ 4169 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) 4170 { 4171 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4172 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 4173 { 4174 ClosePredefKey(hkey); 4175 return ERROR_NOT_ENOUGH_MEMORY; 4176 } 4177 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; 4178 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4179 buf_ptr, total_size, &total_size ); 4180 } 4181 4182 if (NT_SUCCESS(status)) 4183 { 4184 memcpy( data, buf_ptr + info_size, total_size - info_size ); 4185 /* if the type is REG_SZ and data is not 0-terminated 4186 * and there is enough space in the buffer NT appends a \0 */ 4187 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR)) 4188 { 4189 WCHAR *ptr = (WCHAR *)(data + total_size - info_size); 4190 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 4191 } 4192 } 4193 else if (status != STATUS_BUFFER_OVERFLOW) goto done; 4194 } 4195 else status = STATUS_SUCCESS; 4196 4197 if (type) *type = info->Type; 4198 if (count) *count = total_size - info_size; 4199 4200 done: 4201 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4202 ClosePredefKey(hkey); 4203 return RtlNtStatusToDosError(status); 4204 } 4205 4206 4207 /************************************************************************ 4208 * RegQueryValueA 4209 * 4210 * @implemented 4211 */ 4212 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) 4213 { 4214 DWORD ret; 4215 HKEY subkey = hkey; 4216 4217 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); 4218 4219 if (name && name[0]) 4220 { 4221 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; 4222 } 4223 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4224 if (subkey != hkey) RegCloseKey( subkey ); 4225 if (ret == ERROR_FILE_NOT_FOUND) 4226 { 4227 /* return empty string if default value not found */ 4228 if (data) *data = 0; 4229 if (count) *count = 1; 4230 ret = ERROR_SUCCESS; 4231 } 4232 return ret; 4233 } 4234 4235 4236 /************************************************************************ 4237 * RegQueryValueW 4238 * 4239 * @implemented 4240 */ 4241 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) 4242 { 4243 DWORD ret; 4244 HKEY subkey = hkey; 4245 4246 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); 4247 if (hkey == NULL) 4248 { 4249 return ERROR_INVALID_HANDLE; 4250 } 4251 if (name && name[0]) 4252 { 4253 ret = RegOpenKeyW( hkey, name, &subkey); 4254 if (ret != ERROR_SUCCESS) 4255 { 4256 return ret; 4257 } 4258 } 4259 4260 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4261 4262 if (subkey != hkey) 4263 { 4264 RegCloseKey( subkey ); 4265 } 4266 4267 if (ret == ERROR_FILE_NOT_FOUND) 4268 { 4269 /* return empty string if default value not found */ 4270 if (data) 4271 *data = 0; 4272 if (count) 4273 *count = sizeof(WCHAR); 4274 ret = ERROR_SUCCESS; 4275 } 4276 return ret; 4277 } 4278 4279 4280 /************************************************************************ 4281 * RegReplaceKeyA 4282 * 4283 * @implemented 4284 */ 4285 LONG WINAPI 4286 RegReplaceKeyA(HKEY hKey, 4287 LPCSTR lpSubKey, 4288 LPCSTR lpNewFile, 4289 LPCSTR lpOldFile) 4290 { 4291 UNICODE_STRING SubKey; 4292 UNICODE_STRING NewFile; 4293 UNICODE_STRING OldFile; 4294 LONG ErrorCode; 4295 4296 RtlInitEmptyUnicodeString(&SubKey, NULL, 0); 4297 RtlInitEmptyUnicodeString(&OldFile, NULL, 0); 4298 RtlInitEmptyUnicodeString(&NewFile, NULL, 0); 4299 4300 if (lpSubKey) 4301 { 4302 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey)) 4303 { 4304 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4305 goto Exit; 4306 } 4307 } 4308 4309 if (lpOldFile) 4310 { 4311 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile)) 4312 { 4313 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4314 goto Exit; 4315 } 4316 } 4317 4318 if (lpNewFile) 4319 { 4320 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile)) 4321 { 4322 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4323 goto Exit; 4324 } 4325 } 4326 4327 ErrorCode = RegReplaceKeyW(hKey, 4328 SubKey.Buffer, 4329 NewFile.Buffer, 4330 OldFile.Buffer); 4331 4332 Exit: 4333 RtlFreeUnicodeString(&OldFile); 4334 RtlFreeUnicodeString(&NewFile); 4335 RtlFreeUnicodeString(&SubKey); 4336 4337 return ErrorCode; 4338 } 4339 4340 4341 /************************************************************************ 4342 * RegReplaceKeyW 4343 * 4344 * @unimplemented 4345 */ 4346 LONG WINAPI 4347 RegReplaceKeyW(HKEY hKey, 4348 LPCWSTR lpSubKey, 4349 LPCWSTR lpNewFile, 4350 LPCWSTR lpOldFile) 4351 { 4352 OBJECT_ATTRIBUTES KeyObjectAttributes; 4353 OBJECT_ATTRIBUTES NewObjectAttributes; 4354 OBJECT_ATTRIBUTES OldObjectAttributes; 4355 UNICODE_STRING SubKeyName; 4356 UNICODE_STRING NewFileName; 4357 UNICODE_STRING OldFileName; 4358 BOOLEAN CloseRealKey; 4359 HANDLE RealKeyHandle; 4360 HANDLE KeyHandle; 4361 NTSTATUS Status; 4362 LONG ErrorCode = ERROR_SUCCESS; 4363 4364 if (hKey == HKEY_PERFORMANCE_DATA) 4365 { 4366 return ERROR_INVALID_HANDLE; 4367 } 4368 4369 Status = MapDefaultKey(&KeyHandle, 4370 hKey); 4371 if (!NT_SUCCESS(Status)) 4372 { 4373 return RtlNtStatusToDosError(Status); 4374 } 4375 4376 /* Open the real key */ 4377 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0) 4378 { 4379 RtlInitUnicodeString(&SubKeyName, lpSubKey); 4380 InitializeObjectAttributes(&KeyObjectAttributes, 4381 &SubKeyName, 4382 OBJ_CASE_INSENSITIVE, 4383 KeyHandle, 4384 NULL); 4385 Status = NtOpenKey(&RealKeyHandle, 4386 MAXIMUM_ALLOWED, 4387 &KeyObjectAttributes); 4388 if (!NT_SUCCESS(Status)) 4389 { 4390 ErrorCode = RtlNtStatusToDosError(Status); 4391 goto Cleanup; 4392 } 4393 4394 CloseRealKey = TRUE; 4395 } 4396 else 4397 { 4398 RealKeyHandle = KeyHandle; 4399 CloseRealKey = FALSE; 4400 } 4401 4402 /* Convert new file name */ 4403 if (!RtlDosPathNameToNtPathName_U(lpNewFile, 4404 &NewFileName, 4405 NULL, 4406 NULL)) 4407 { 4408 if (CloseRealKey) 4409 { 4410 NtClose(RealKeyHandle); 4411 } 4412 4413 ErrorCode = ERROR_INVALID_PARAMETER; 4414 goto Cleanup; 4415 } 4416 4417 InitializeObjectAttributes(&NewObjectAttributes, 4418 &NewFileName, 4419 OBJ_CASE_INSENSITIVE, 4420 NULL, 4421 NULL); 4422 4423 /* Convert old file name */ 4424 if (!RtlDosPathNameToNtPathName_U(lpOldFile, 4425 &OldFileName, 4426 NULL, 4427 NULL)) 4428 { 4429 RtlFreeHeap(RtlGetProcessHeap (), 4430 0, 4431 NewFileName.Buffer); 4432 if (CloseRealKey) 4433 { 4434 NtClose(RealKeyHandle); 4435 } 4436 4437 ErrorCode = ERROR_INVALID_PARAMETER; 4438 goto Cleanup; 4439 } 4440 4441 InitializeObjectAttributes(&OldObjectAttributes, 4442 &OldFileName, 4443 OBJ_CASE_INSENSITIVE, 4444 NULL, 4445 NULL); 4446 4447 Status = NtReplaceKey(&NewObjectAttributes, 4448 RealKeyHandle, 4449 &OldObjectAttributes); 4450 4451 RtlFreeHeap(RtlGetProcessHeap(), 4452 0, 4453 OldFileName.Buffer); 4454 RtlFreeHeap(RtlGetProcessHeap(), 4455 0, 4456 NewFileName.Buffer); 4457 4458 if (CloseRealKey) 4459 { 4460 NtClose(RealKeyHandle); 4461 } 4462 4463 if (!NT_SUCCESS(Status)) 4464 { 4465 return RtlNtStatusToDosError(Status); 4466 } 4467 4468 Cleanup: 4469 ClosePredefKey(KeyHandle); 4470 4471 return ErrorCode; 4472 } 4473 4474 4475 /************************************************************************ 4476 * RegRestoreKeyA 4477 * 4478 * @implemented 4479 */ 4480 LONG WINAPI 4481 RegRestoreKeyA(HKEY hKey, 4482 LPCSTR lpFile, 4483 DWORD dwFlags) 4484 { 4485 UNICODE_STRING FileName; 4486 LONG ErrorCode; 4487 4488 if (lpFile) 4489 { 4490 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4491 return ERROR_NOT_ENOUGH_MEMORY; 4492 } 4493 else 4494 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4495 4496 ErrorCode = RegRestoreKeyW(hKey, 4497 FileName.Buffer, 4498 dwFlags); 4499 4500 RtlFreeUnicodeString(&FileName); 4501 4502 return ErrorCode; 4503 } 4504 4505 4506 /************************************************************************ 4507 * RegRestoreKeyW 4508 * 4509 * @implemented 4510 */ 4511 LONG WINAPI 4512 RegRestoreKeyW(HKEY hKey, 4513 LPCWSTR lpFile, 4514 DWORD dwFlags) 4515 { 4516 OBJECT_ATTRIBUTES ObjectAttributes; 4517 IO_STATUS_BLOCK IoStatusBlock; 4518 UNICODE_STRING FileName; 4519 HANDLE FileHandle; 4520 HANDLE KeyHandle; 4521 NTSTATUS Status; 4522 4523 if (hKey == HKEY_PERFORMANCE_DATA) 4524 { 4525 return ERROR_INVALID_HANDLE; 4526 } 4527 4528 Status = MapDefaultKey(&KeyHandle, 4529 hKey); 4530 if (!NT_SUCCESS(Status)) 4531 { 4532 return RtlNtStatusToDosError(Status); 4533 } 4534 4535 if (!RtlDosPathNameToNtPathName_U(lpFile, 4536 &FileName, 4537 NULL, 4538 NULL)) 4539 { 4540 Status = STATUS_INVALID_PARAMETER; 4541 goto Cleanup; 4542 } 4543 4544 InitializeObjectAttributes(&ObjectAttributes, 4545 &FileName, 4546 OBJ_CASE_INSENSITIVE, 4547 NULL, 4548 NULL); 4549 4550 Status = NtOpenFile(&FileHandle, 4551 FILE_GENERIC_READ, 4552 &ObjectAttributes, 4553 &IoStatusBlock, 4554 FILE_SHARE_READ, 4555 FILE_SYNCHRONOUS_IO_NONALERT); 4556 RtlFreeHeap(RtlGetProcessHeap(), 4557 0, 4558 FileName.Buffer); 4559 if (!NT_SUCCESS(Status)) 4560 { 4561 goto Cleanup; 4562 } 4563 4564 Status = NtRestoreKey(KeyHandle, 4565 FileHandle, 4566 (ULONG)dwFlags); 4567 NtClose (FileHandle); 4568 4569 Cleanup: 4570 ClosePredefKey(KeyHandle); 4571 4572 if (!NT_SUCCESS(Status)) 4573 { 4574 return RtlNtStatusToDosError(Status); 4575 } 4576 4577 return ERROR_SUCCESS; 4578 } 4579 4580 4581 /************************************************************************ 4582 * RegSaveKeyA 4583 * 4584 * @implemented 4585 */ 4586 LONG WINAPI 4587 RegSaveKeyA(HKEY hKey, 4588 LPCSTR lpFile, 4589 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4590 { 4591 UNICODE_STRING FileName; 4592 LONG ErrorCode; 4593 4594 if (lpFile) 4595 { 4596 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4597 return ERROR_NOT_ENOUGH_MEMORY; 4598 } 4599 else 4600 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4601 4602 ErrorCode = RegSaveKeyW(hKey, 4603 FileName.Buffer, 4604 lpSecurityAttributes); 4605 RtlFreeUnicodeString(&FileName); 4606 4607 return ErrorCode; 4608 } 4609 4610 4611 /************************************************************************ 4612 * RegSaveKeyW 4613 * 4614 * @implemented 4615 */ 4616 LONG WINAPI 4617 RegSaveKeyW(HKEY hKey, 4618 LPCWSTR lpFile, 4619 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4620 { 4621 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 4622 OBJECT_ATTRIBUTES ObjectAttributes; 4623 UNICODE_STRING FileName; 4624 IO_STATUS_BLOCK IoStatusBlock; 4625 HANDLE FileHandle; 4626 HANDLE KeyHandle; 4627 NTSTATUS Status; 4628 4629 Status = MapDefaultKey(&KeyHandle, 4630 hKey); 4631 if (!NT_SUCCESS(Status)) 4632 { 4633 return RtlNtStatusToDosError(Status); 4634 } 4635 4636 if (!RtlDosPathNameToNtPathName_U(lpFile, 4637 &FileName, 4638 NULL, 4639 NULL)) 4640 { 4641 Status = STATUS_INVALID_PARAMETER; 4642 goto Cleanup; 4643 } 4644 4645 if (lpSecurityAttributes != NULL) 4646 { 4647 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 4648 } 4649 4650 InitializeObjectAttributes(&ObjectAttributes, 4651 &FileName, 4652 OBJ_CASE_INSENSITIVE, 4653 NULL, 4654 SecurityDescriptor); 4655 Status = NtCreateFile(&FileHandle, 4656 GENERIC_WRITE | SYNCHRONIZE, 4657 &ObjectAttributes, 4658 &IoStatusBlock, 4659 NULL, 4660 FILE_ATTRIBUTE_NORMAL, 4661 FILE_SHARE_READ, 4662 FILE_CREATE, 4663 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 4664 NULL, 4665 0); 4666 RtlFreeHeap(RtlGetProcessHeap(), 4667 0, 4668 FileName.Buffer); 4669 if (!NT_SUCCESS(Status)) 4670 { 4671 goto Cleanup; 4672 } 4673 4674 Status = NtSaveKey(KeyHandle, 4675 FileHandle); 4676 NtClose (FileHandle); 4677 4678 Cleanup: 4679 ClosePredefKey(KeyHandle); 4680 4681 if (!NT_SUCCESS(Status)) 4682 { 4683 return RtlNtStatusToDosError(Status); 4684 } 4685 4686 return ERROR_SUCCESS; 4687 } 4688 4689 4690 /************************************************************************ 4691 * RegSaveKeyExA 4692 * 4693 * @implemented 4694 */ 4695 LONG 4696 WINAPI 4697 RegSaveKeyExA(HKEY hKey, 4698 LPCSTR lpFile, 4699 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4700 DWORD Flags) 4701 { 4702 UNICODE_STRING FileName; 4703 LONG ErrorCode; 4704 4705 if (lpFile) 4706 { 4707 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4708 return ERROR_NOT_ENOUGH_MEMORY; 4709 } 4710 else 4711 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4712 4713 ErrorCode = RegSaveKeyExW(hKey, 4714 FileName.Buffer, 4715 lpSecurityAttributes, 4716 Flags); 4717 RtlFreeUnicodeString(&FileName); 4718 4719 return ErrorCode; 4720 } 4721 4722 4723 /************************************************************************ 4724 * RegSaveKeyExW 4725 * 4726 * @unimplemented 4727 */ 4728 LONG 4729 WINAPI 4730 RegSaveKeyExW(HKEY hKey, 4731 LPCWSTR lpFile, 4732 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4733 DWORD Flags) 4734 { 4735 switch (Flags) 4736 { 4737 case REG_STANDARD_FORMAT: 4738 case REG_LATEST_FORMAT: 4739 case REG_NO_COMPRESSION: 4740 break; 4741 default: 4742 return ERROR_INVALID_PARAMETER; 4743 } 4744 4745 FIXME("RegSaveKeyExW(): Flags ignored!\n"); 4746 4747 return RegSaveKeyW(hKey, 4748 lpFile, 4749 lpSecurityAttributes); 4750 } 4751 4752 4753 /************************************************************************ 4754 * RegSetKeySecurity 4755 * 4756 * @implemented 4757 */ 4758 LONG WINAPI 4759 RegSetKeySecurity(HKEY hKey, 4760 SECURITY_INFORMATION SecurityInformation, 4761 PSECURITY_DESCRIPTOR pSecurityDescriptor) 4762 { 4763 HANDLE KeyHandle; 4764 NTSTATUS Status; 4765 4766 if (hKey == HKEY_PERFORMANCE_DATA) 4767 { 4768 return ERROR_INVALID_HANDLE; 4769 } 4770 4771 Status = MapDefaultKey(&KeyHandle, 4772 hKey); 4773 if (!NT_SUCCESS(Status)) 4774 { 4775 return RtlNtStatusToDosError(Status); 4776 } 4777 4778 Status = NtSetSecurityObject(KeyHandle, 4779 SecurityInformation, 4780 pSecurityDescriptor); 4781 4782 ClosePredefKey(KeyHandle); 4783 4784 if (!NT_SUCCESS(Status)) 4785 { 4786 return RtlNtStatusToDosError(Status); 4787 } 4788 4789 return ERROR_SUCCESS; 4790 } 4791 4792 4793 /************************************************************************ 4794 * RegSetValueExA 4795 * 4796 * @implemented 4797 */ 4798 LONG WINAPI 4799 RegSetValueExA(HKEY hKey, 4800 LPCSTR lpValueName, 4801 DWORD Reserved, 4802 DWORD dwType, 4803 CONST BYTE* lpData, 4804 DWORD cbData) 4805 { 4806 UNICODE_STRING ValueName; 4807 LPWSTR pValueName; 4808 ANSI_STRING AnsiString; 4809 UNICODE_STRING Data; 4810 LONG ErrorCode; 4811 LPBYTE pData; 4812 DWORD DataSize; 4813 NTSTATUS Status; 4814 4815 /* Convert SubKey name to Unicode */ 4816 if (lpValueName != NULL && lpValueName[0] != '\0') 4817 { 4818 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName)) 4819 return ERROR_NOT_ENOUGH_MEMORY; 4820 } 4821 else 4822 { 4823 ValueName.Buffer = NULL; 4824 } 4825 4826 pValueName = (LPWSTR)ValueName.Buffer; 4827 4828 4829 if (is_string(dwType) && (cbData != 0)) 4830 { 4831 /* Convert ANSI string Data to Unicode */ 4832 /* If last character NOT zero then increment length */ 4833 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0); 4834 AnsiString.Buffer = (PSTR)lpData; 4835 AnsiString.Length = cbData + bNoNulledStr; 4836 AnsiString.MaximumLength = cbData + bNoNulledStr; 4837 Status = RtlAnsiStringToUnicodeString(&Data, 4838 &AnsiString, 4839 TRUE); 4840 4841 if (!NT_SUCCESS(Status)) 4842 { 4843 if (pValueName != NULL) 4844 RtlFreeUnicodeString(&ValueName); 4845 4846 return RtlNtStatusToDosError(Status); 4847 } 4848 pData = (LPBYTE)Data.Buffer; 4849 DataSize = cbData * sizeof(WCHAR); 4850 } 4851 else 4852 { 4853 Data.Buffer = NULL; 4854 pData = (LPBYTE)lpData; 4855 DataSize = cbData; 4856 } 4857 4858 ErrorCode = RegSetValueExW(hKey, 4859 pValueName, 4860 Reserved, 4861 dwType, 4862 pData, 4863 DataSize); 4864 4865 if (pValueName != NULL) 4866 RtlFreeUnicodeString(&ValueName); 4867 4868 if (Data.Buffer != NULL) 4869 RtlFreeUnicodeString(&Data); 4870 4871 return ErrorCode; 4872 } 4873 4874 4875 /************************************************************************ 4876 * RegSetValueExW 4877 * 4878 * @implemented 4879 */ 4880 LONG 4881 WINAPI 4882 RegSetValueExW( 4883 _In_ HKEY hKey, 4884 _In_ LPCWSTR lpValueName, 4885 _In_ DWORD Reserved, 4886 _In_ DWORD dwType, 4887 _In_ CONST BYTE* lpData, 4888 _In_ DWORD cbData) 4889 { 4890 UNICODE_STRING ValueName; 4891 HANDLE KeyHandle; 4892 NTSTATUS Status; 4893 4894 Status = MapDefaultKey(&KeyHandle, 4895 hKey); 4896 if (!NT_SUCCESS(Status)) 4897 { 4898 return RtlNtStatusToDosError(Status); 4899 } 4900 4901 if (IsHKCRKey(KeyHandle)) 4902 { 4903 LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData); 4904 ClosePredefKey(KeyHandle); 4905 return ErrorCode; 4906 } 4907 4908 if (is_string(dwType) && (cbData != 0)) 4909 { 4910 PWSTR pwsData = (PWSTR)lpData; 4911 4912 _SEH2_TRY 4913 { 4914 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') && 4915 (pwsData[cbData / sizeof(WCHAR)] == L'\0')) 4916 { 4917 /* Increment length if last character is not zero and next is zero */ 4918 cbData += sizeof(WCHAR); 4919 } 4920 } 4921 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4922 { 4923 /* Do not fail if we fault where we were told not to go */ 4924 } 4925 _SEH2_END; 4926 } 4927 4928 RtlInitUnicodeString(&ValueName, lpValueName); 4929 4930 Status = NtSetValueKey(KeyHandle, 4931 &ValueName, 4932 0, 4933 dwType, 4934 (PVOID)lpData, 4935 (ULONG)cbData); 4936 4937 ClosePredefKey(KeyHandle); 4938 4939 if (!NT_SUCCESS(Status)) 4940 { 4941 return RtlNtStatusToDosError(Status); 4942 } 4943 4944 return ERROR_SUCCESS; 4945 } 4946 4947 4948 /************************************************************************ 4949 * RegSetValueA 4950 * 4951 * @implemented 4952 */ 4953 LONG WINAPI 4954 RegSetValueA(HKEY hKeyOriginal, 4955 LPCSTR lpSubKey, 4956 DWORD dwType, 4957 LPCSTR lpData, 4958 DWORD cbData) 4959 { 4960 HKEY subkey; 4961 HANDLE hKey; 4962 DWORD ret; 4963 NTSTATUS Status; 4964 4965 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData ); 4966 4967 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER; 4968 4969 Status = MapDefaultKey(&hKey, hKeyOriginal); 4970 if (!NT_SUCCESS(Status)) 4971 { 4972 return RtlNtStatusToDosError (Status); 4973 } 4974 subkey = hKey; 4975 4976 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 4977 { 4978 ret = RegCreateKeyA(hKey, lpSubKey, &subkey); 4979 if (ret != ERROR_SUCCESS) 4980 goto Cleanup; 4981 } 4982 4983 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 ); 4984 if (subkey != hKey) 4985 RegCloseKey(subkey); 4986 4987 Cleanup: 4988 ClosePredefKey(hKey); 4989 4990 return ret; 4991 } 4992 4993 4994 /************************************************************************ 4995 * RegSetValueW 4996 * 4997 * @implemented 4998 */ 4999 LONG WINAPI 5000 RegSetValueW(HKEY hKeyOriginal, 5001 LPCWSTR lpSubKey, 5002 DWORD dwType, 5003 LPCWSTR lpData, 5004 DWORD cbData) 5005 { 5006 HKEY subkey; 5007 HANDLE hKey; 5008 DWORD ret; 5009 NTSTATUS Status; 5010 5011 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData ); 5012 5013 if (dwType != REG_SZ || !lpData) 5014 return ERROR_INVALID_PARAMETER; 5015 5016 Status = MapDefaultKey(&hKey, 5017 hKeyOriginal); 5018 if (!NT_SUCCESS(Status)) 5019 { 5020 return RtlNtStatusToDosError(Status); 5021 } 5022 subkey = hKey; 5023 5024 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 5025 { 5026 ret = RegCreateKeyW(hKey, lpSubKey, &subkey); 5027 if (ret != ERROR_SUCCESS) 5028 goto Cleanup; 5029 } 5030 5031 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, 5032 (wcslen( lpData ) + 1) * sizeof(WCHAR) ); 5033 if (subkey != hKey) 5034 RegCloseKey(subkey); 5035 5036 Cleanup: 5037 ClosePredefKey(hKey); 5038 5039 return ret; 5040 } 5041 5042 5043 /************************************************************************ 5044 * RegUnLoadKeyA 5045 * 5046 * @implemented 5047 */ 5048 LONG WINAPI 5049 RegUnLoadKeyA(HKEY hKey, 5050 LPCSTR lpSubKey) 5051 { 5052 UNICODE_STRING KeyName; 5053 DWORD ErrorCode; 5054 5055 if (lpSubKey) 5056 { 5057 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey)) 5058 return ERROR_NOT_ENOUGH_MEMORY; 5059 } 5060 else 5061 RtlInitEmptyUnicodeString(&KeyName, NULL, 0); 5062 5063 ErrorCode = RegUnLoadKeyW(hKey, 5064 KeyName.Buffer); 5065 5066 RtlFreeUnicodeString (&KeyName); 5067 5068 return ErrorCode; 5069 } 5070 5071 5072 /************************************************************************ 5073 * RegUnLoadKeyW 5074 * 5075 * @implemented 5076 */ 5077 LONG WINAPI 5078 RegUnLoadKeyW(HKEY hKey, 5079 LPCWSTR lpSubKey) 5080 { 5081 OBJECT_ATTRIBUTES ObjectAttributes; 5082 UNICODE_STRING KeyName; 5083 HANDLE KeyHandle; 5084 NTSTATUS Status; 5085 5086 if (hKey == HKEY_PERFORMANCE_DATA) 5087 { 5088 return ERROR_INVALID_HANDLE; 5089 } 5090 5091 Status = MapDefaultKey(&KeyHandle, hKey); 5092 if (!NT_SUCCESS(Status)) 5093 { 5094 return RtlNtStatusToDosError(Status); 5095 } 5096 5097 RtlInitUnicodeString(&KeyName, lpSubKey); 5098 5099 InitializeObjectAttributes(&ObjectAttributes, 5100 &KeyName, 5101 OBJ_CASE_INSENSITIVE, 5102 KeyHandle, 5103 NULL); 5104 5105 Status = NtUnloadKey(&ObjectAttributes); 5106 5107 ClosePredefKey(KeyHandle); 5108 5109 if (!NT_SUCCESS(Status)) 5110 { 5111 return RtlNtStatusToDosError(Status); 5112 } 5113 5114 return ERROR_SUCCESS; 5115 } 5116 5117 #endif // _ADVAPI32_VISTA_ 5118 5119 /****************************************************************************** 5120 * load_string [Internal] 5121 * 5122 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to 5123 * avoid importing user32, which is higher level than advapi32. Helper for 5124 * RegLoadMUIString. 5125 */ 5126 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) 5127 { 5128 HGLOBAL hMemory; 5129 HRSRC hResource; 5130 WCHAR* pString; 5131 int idxString; 5132 5133 /* Negative values have to be inverted. */ 5134 if (HIWORD(resId) == 0xffff) 5135 resId = (UINT)(-((INT)resId)); 5136 5137 /* Load the resource into memory and get a pointer to it. */ 5138 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); 5139 if (!hResource) return 0; 5140 hMemory = LoadResource(hModule, hResource); 5141 if (!hMemory) return 0; 5142 pString = LockResource(hMemory); 5143 5144 /* Strings are length-prefixed. Lowest nibble of resId is an index. */ 5145 idxString = resId & 0xf; 5146 while (idxString--) pString += *pString + 1; 5147 5148 /* If no buffer is given, return length of the string. */ 5149 if (!pwszBuffer) return *pString; 5150 5151 /* Else copy over the string, respecting the buffer size. */ 5152 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); 5153 if (cMaxChars >= 0) 5154 { 5155 memcpy(pwszBuffer, pString + 1, cMaxChars * sizeof(WCHAR)); 5156 pwszBuffer[cMaxChars] = L'\0'; 5157 } 5158 5159 return cMaxChars; 5160 } 5161 5162 /************************************************************************ 5163 * RegLoadMUIStringW 5164 * 5165 * @implemented 5166 */ 5167 LONG WINAPI 5168 RegLoadMUIStringW( 5169 IN HKEY hKey, 5170 IN LPCWSTR pszValue OPTIONAL, 5171 OUT LPWSTR pszOutBuf, 5172 IN DWORD cbOutBuf, 5173 OUT LPDWORD pcbData OPTIONAL, 5174 IN DWORD Flags, 5175 IN LPCWSTR pszDirectory OPTIONAL) 5176 { 5177 DWORD dwValueType, cbData; 5178 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; 5179 LONG result; 5180 5181 /* Parameter sanity checks. */ 5182 if (!hKey || !pszOutBuf) 5183 return ERROR_INVALID_PARAMETER; 5184 5185 if (pszDirectory && *pszDirectory) 5186 { 5187 FIXME("BaseDir parameter not yet supported!\n"); 5188 return ERROR_INVALID_PARAMETER; 5189 } 5190 5191 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ 5192 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); 5193 if (result != ERROR_SUCCESS) goto cleanup; 5194 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) 5195 { 5196 result = ERROR_FILE_NOT_FOUND; 5197 goto cleanup; 5198 } 5199 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 5200 if (!pwszTempBuffer) 5201 { 5202 result = ERROR_NOT_ENOUGH_MEMORY; 5203 goto cleanup; 5204 } 5205 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); 5206 if (result != ERROR_SUCCESS) goto cleanup; 5207 5208 /* Expand environment variables, if appropriate, or copy the original string over. */ 5209 if (dwValueType == REG_EXPAND_SZ) 5210 { 5211 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); 5212 if (!cbData) goto cleanup; 5213 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 5214 if (!pwszExpandedBuffer) 5215 { 5216 result = ERROR_NOT_ENOUGH_MEMORY; 5217 goto cleanup; 5218 } 5219 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); 5220 } 5221 else 5222 { 5223 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 5224 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); 5225 } 5226 5227 /* If the value references a resource based string, parse the value and load the string. 5228 * Else just copy over the original value. */ 5229 result = ERROR_SUCCESS; 5230 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ 5231 { 5232 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); 5233 } 5234 else 5235 { 5236 WCHAR* pComma = wcsrchr(pwszExpandedBuffer, L','); 5237 UINT uiStringId; 5238 HMODULE hModule; 5239 5240 /* Format of the expanded value is 'path_to_dll,-resId' */ 5241 if (!pComma || pComma[1] != L'-') 5242 { 5243 result = ERROR_BADKEY; 5244 goto cleanup; 5245 } 5246 5247 uiStringId = _wtoi(pComma + 2); 5248 *pComma = L'\0'; 5249 5250 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); 5251 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) 5252 result = ERROR_BADKEY; 5253 FreeLibrary(hModule); 5254 } 5255 5256 cleanup: 5257 HeapFree(GetProcessHeap(), 0, pwszTempBuffer); 5258 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); 5259 return result; 5260 } 5261 5262 /************************************************************************ 5263 * RegLoadMUIStringA 5264 * 5265 * @implemented 5266 */ 5267 LONG WINAPI 5268 RegLoadMUIStringA( 5269 IN HKEY hKey, 5270 IN LPCSTR pszValue OPTIONAL, 5271 OUT LPSTR pszOutBuf, 5272 IN DWORD cbOutBuf, 5273 OUT LPDWORD pcbData OPTIONAL, 5274 IN DWORD Flags, 5275 IN LPCSTR pszDirectory OPTIONAL) 5276 { 5277 UNICODE_STRING valueW, baseDirW; 5278 WCHAR* pwszBuffer; 5279 DWORD cbData = cbOutBuf * sizeof(WCHAR); 5280 LONG result; 5281 5282 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL; 5283 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) || 5284 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) || 5285 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData))) 5286 { 5287 result = ERROR_NOT_ENOUGH_MEMORY; 5288 goto cleanup; 5289 } 5290 5291 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags, 5292 baseDirW.Buffer); 5293 5294 if (result == ERROR_SUCCESS) 5295 { 5296 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL); 5297 if (pcbData) 5298 *pcbData = cbData; 5299 } 5300 5301 cleanup: 5302 HeapFree(GetProcessHeap(), 0, pwszBuffer); 5303 RtlFreeUnicodeString(&baseDirW); 5304 RtlFreeUnicodeString(&valueW); 5305 5306 return result; 5307 } 5308 5309 /* EOF */ 5310