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