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 && phkResult) 3268 { 3269 return ERROR_INVALID_HANDLE; 3270 } 3271 3272 if (!lpSubKey || !*lpSubKey) 3273 { 3274 *phkResult = hKey; 3275 return ERROR_SUCCESS; 3276 } 3277 3278 return RegOpenKeyExA(hKey, 3279 lpSubKey, 3280 0, 3281 MAXIMUM_ALLOWED, 3282 phkResult); 3283 } 3284 3285 3286 /************************************************************************ 3287 * RegOpenKeyW 3288 * 3289 * 19981101 Ariadne 3290 * 19990525 EA 3291 * 20050503 Fireball - imported from WINE 3292 * 3293 * @implemented 3294 */ 3295 LONG WINAPI 3296 RegOpenKeyW(HKEY hKey, 3297 LPCWSTR lpSubKey, 3298 PHKEY phkResult) 3299 { 3300 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", 3301 hKey, lpSubKey, phkResult); 3302 3303 if (!phkResult) 3304 return ERROR_INVALID_PARAMETER; 3305 3306 if (!hKey && lpSubKey && phkResult) 3307 { 3308 return ERROR_INVALID_HANDLE; 3309 } 3310 3311 if (!lpSubKey || !*lpSubKey) 3312 { 3313 *phkResult = hKey; 3314 return ERROR_SUCCESS; 3315 } 3316 3317 return RegOpenKeyExW(hKey, 3318 lpSubKey, 3319 0, 3320 MAXIMUM_ALLOWED, 3321 phkResult); 3322 } 3323 3324 3325 /************************************************************************ 3326 * RegOpenKeyExA 3327 * 3328 * @implemented 3329 */ 3330 LONG WINAPI 3331 RegOpenKeyExA( 3332 _In_ HKEY hKey, 3333 _In_ LPCSTR lpSubKey, 3334 _In_ DWORD ulOptions, 3335 _In_ REGSAM samDesired, 3336 _Out_ PHKEY phkResult) 3337 { 3338 UNICODE_STRING SubKeyString; 3339 LONG ErrorCode; 3340 3341 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n", 3342 hKey, lpSubKey, ulOptions, samDesired, phkResult); 3343 3344 if (lpSubKey) 3345 { 3346 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey)) 3347 return ERROR_NOT_ENOUGH_MEMORY; 3348 } 3349 else 3350 RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0); 3351 3352 ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult); 3353 3354 RtlFreeUnicodeString(&SubKeyString); 3355 3356 return ErrorCode; 3357 } 3358 3359 3360 /************************************************************************ 3361 * RegOpenKeyExW 3362 * 3363 * @implemented 3364 */ 3365 LONG WINAPI 3366 RegOpenKeyExW(HKEY hKey, 3367 LPCWSTR lpSubKey, 3368 DWORD ulOptions, 3369 REGSAM samDesired, 3370 PHKEY phkResult) 3371 { 3372 OBJECT_ATTRIBUTES ObjectAttributes; 3373 UNICODE_STRING SubKeyString; 3374 HANDLE KeyHandle; 3375 NTSTATUS Status; 3376 ULONG Attributes = OBJ_CASE_INSENSITIVE; 3377 LONG ErrorCode = ERROR_SUCCESS; 3378 3379 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n", 3380 hKey, lpSubKey, ulOptions, samDesired, phkResult); 3381 if (!phkResult) 3382 { 3383 return ERROR_INVALID_PARAMETER; 3384 } 3385 3386 Status = MapDefaultKey(&KeyHandle, hKey); 3387 if (!NT_SUCCESS(Status)) 3388 { 3389 return RtlNtStatusToDosError(Status); 3390 } 3391 3392 if (IsHKCRKey(KeyHandle)) 3393 { 3394 ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult); 3395 ClosePredefKey(KeyHandle); 3396 return ErrorCode; 3397 } 3398 3399 if (ulOptions & REG_OPTION_OPEN_LINK) 3400 Attributes |= OBJ_OPENLINK; 3401 3402 RtlInitUnicodeString(&SubKeyString, lpSubKey ? lpSubKey : L""); 3403 3404 InitializeObjectAttributes(&ObjectAttributes, 3405 &SubKeyString, 3406 Attributes, 3407 KeyHandle, 3408 NULL); 3409 3410 Status = NtOpenKey((PHANDLE)phkResult, 3411 samDesired, 3412 &ObjectAttributes); 3413 3414 if (Status == STATUS_DATATYPE_MISALIGNMENT) 3415 { 3416 HANDLE hAligned; 3417 UNICODE_STRING AlignedString; 3418 3419 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 3420 &SubKeyString, 3421 &AlignedString); 3422 if (NT_SUCCESS(Status)) 3423 { 3424 /* Try again with aligned parameters */ 3425 InitializeObjectAttributes(&ObjectAttributes, 3426 &AlignedString, 3427 Attributes, 3428 KeyHandle, 3429 NULL); 3430 3431 Status = NtOpenKey(&hAligned, 3432 samDesired, 3433 &ObjectAttributes); 3434 3435 RtlFreeUnicodeString(&AlignedString); 3436 3437 if (NT_SUCCESS(Status)) 3438 *phkResult = hAligned; 3439 } 3440 else 3441 { 3442 /* Restore the original error */ 3443 Status = STATUS_DATATYPE_MISALIGNMENT; 3444 } 3445 } 3446 3447 if (!NT_SUCCESS(Status)) 3448 { 3449 ErrorCode = RtlNtStatusToDosError(Status); 3450 } 3451 3452 3453 ClosePredefKey(KeyHandle); 3454 3455 return ErrorCode; 3456 } 3457 3458 3459 /************************************************************************ 3460 * RegOpenUserClassesRoot 3461 * 3462 * @implemented 3463 */ 3464 LONG WINAPI 3465 RegOpenUserClassesRoot(IN HANDLE hToken, 3466 IN DWORD dwOptions, 3467 IN REGSAM samDesired, 3468 OUT PHKEY phkResult) 3469 { 3470 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\"; 3471 const WCHAR UserClassesKeySuffix[] = L"_Classes"; 3472 PTOKEN_USER TokenUserData; 3473 ULONG RequiredLength; 3474 UNICODE_STRING UserSidString, UserClassesKeyRoot; 3475 OBJECT_ATTRIBUTES ObjectAttributes; 3476 NTSTATUS Status; 3477 3478 /* check parameters */ 3479 if (hToken == NULL || dwOptions != 0 || phkResult == NULL) 3480 { 3481 return ERROR_INVALID_PARAMETER; 3482 } 3483 3484 /* 3485 * Get the user sid from the token 3486 */ 3487 3488 ReadTokenSid: 3489 /* determine how much memory we need */ 3490 Status = NtQueryInformationToken(hToken, 3491 TokenUser, 3492 NULL, 3493 0, 3494 &RequiredLength); 3495 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL)) 3496 { 3497 /* NOTE - as opposed to all other registry functions windows does indeed 3498 change the last error code in case the caller supplied a invalid 3499 handle for example! */ 3500 return RtlNtStatusToDosError(Status); 3501 } 3502 RegInitialize(); /* HACK until delay-loading is implemented */ 3503 TokenUserData = RtlAllocateHeap(ProcessHeap, 3504 0, 3505 RequiredLength); 3506 if (TokenUserData == NULL) 3507 { 3508 return ERROR_NOT_ENOUGH_MEMORY; 3509 } 3510 3511 /* attempt to read the information */ 3512 Status = NtQueryInformationToken(hToken, 3513 TokenUser, 3514 TokenUserData, 3515 RequiredLength, 3516 &RequiredLength); 3517 if (!NT_SUCCESS(Status)) 3518 { 3519 RtlFreeHeap(ProcessHeap, 3520 0, 3521 TokenUserData); 3522 if (Status == STATUS_BUFFER_TOO_SMALL) 3523 { 3524 /* the information appears to have changed?! try again */ 3525 goto ReadTokenSid; 3526 } 3527 3528 /* NOTE - as opposed to all other registry functions windows does indeed 3529 change the last error code in case the caller supplied a invalid 3530 handle for example! */ 3531 return RtlNtStatusToDosError(Status); 3532 } 3533 3534 /* 3535 * Build the absolute path for the user's registry in the form 3536 * "\Registry\User\<SID>_Classes" 3537 */ 3538 Status = RtlConvertSidToUnicodeString(&UserSidString, 3539 TokenUserData->User.Sid, 3540 TRUE); 3541 3542 /* we don't need the user data anymore, free it */ 3543 RtlFreeHeap(ProcessHeap, 3544 0, 3545 TokenUserData); 3546 3547 if (!NT_SUCCESS(Status)) 3548 { 3549 return RtlNtStatusToDosError(Status); 3550 } 3551 3552 /* allocate enough memory for the entire key string */ 3553 UserClassesKeyRoot.Length = 0; 3554 UserClassesKeyRoot.MaximumLength = UserSidString.Length + 3555 sizeof(UserClassesKeyPrefix) + 3556 sizeof(UserClassesKeySuffix); 3557 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap, 3558 0, 3559 UserClassesKeyRoot.MaximumLength); 3560 if (UserClassesKeyRoot.Buffer == NULL) 3561 { 3562 RtlFreeUnicodeString(&UserSidString); 3563 return RtlNtStatusToDosError(Status); 3564 } 3565 3566 /* build the string */ 3567 RtlAppendUnicodeToString(&UserClassesKeyRoot, 3568 UserClassesKeyPrefix); 3569 RtlAppendUnicodeStringToString(&UserClassesKeyRoot, 3570 &UserSidString); 3571 RtlAppendUnicodeToString(&UserClassesKeyRoot, 3572 UserClassesKeySuffix); 3573 3574 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot); 3575 3576 /* 3577 * Open the key 3578 */ 3579 InitializeObjectAttributes(&ObjectAttributes, 3580 &UserClassesKeyRoot, 3581 OBJ_CASE_INSENSITIVE, 3582 NULL, 3583 NULL); 3584 3585 Status = NtOpenKey((PHANDLE)phkResult, 3586 samDesired, 3587 &ObjectAttributes); 3588 3589 RtlFreeUnicodeString(&UserSidString); 3590 RtlFreeUnicodeString(&UserClassesKeyRoot); 3591 3592 if (!NT_SUCCESS(Status)) 3593 { 3594 return RtlNtStatusToDosError(Status); 3595 } 3596 3597 return ERROR_SUCCESS; 3598 } 3599 3600 3601 /************************************************************************ 3602 * RegQueryInfoKeyA 3603 * 3604 * @implemented 3605 */ 3606 LONG WINAPI 3607 RegQueryInfoKeyA(HKEY hKey, 3608 LPSTR lpClass, 3609 LPDWORD lpcClass, 3610 LPDWORD lpReserved, 3611 LPDWORD lpcSubKeys, 3612 LPDWORD lpcMaxSubKeyLen, 3613 LPDWORD lpcMaxClassLen, 3614 LPDWORD lpcValues, 3615 LPDWORD lpcMaxValueNameLen, 3616 LPDWORD lpcMaxValueLen, 3617 LPDWORD lpcbSecurityDescriptor, 3618 PFILETIME lpftLastWriteTime) 3619 { 3620 WCHAR ClassName[MAX_PATH]; 3621 UNICODE_STRING UnicodeString; 3622 ANSI_STRING AnsiString; 3623 LONG ErrorCode; 3624 NTSTATUS Status; 3625 DWORD cClass = 0; 3626 3627 if ((lpClass) && (!lpcClass)) 3628 { 3629 return ERROR_INVALID_PARAMETER; 3630 } 3631 3632 RtlInitUnicodeString(&UnicodeString, 3633 NULL); 3634 if (lpClass != NULL) 3635 { 3636 RtlInitEmptyUnicodeString(&UnicodeString, 3637 ClassName, 3638 sizeof(ClassName)); 3639 cClass = sizeof(ClassName) / sizeof(WCHAR); 3640 } 3641 3642 ErrorCode = RegQueryInfoKeyW(hKey, 3643 UnicodeString.Buffer, 3644 &cClass, 3645 lpReserved, 3646 lpcSubKeys, 3647 lpcMaxSubKeyLen, 3648 lpcMaxClassLen, 3649 lpcValues, 3650 lpcMaxValueNameLen, 3651 lpcMaxValueLen, 3652 lpcbSecurityDescriptor, 3653 lpftLastWriteTime); 3654 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL)) 3655 { 3656 if (*lpcClass == 0) 3657 { 3658 return ErrorCode; 3659 } 3660 3661 RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass); 3662 UnicodeString.Length = cClass * sizeof(WCHAR); 3663 Status = RtlUnicodeStringToAnsiString(&AnsiString, 3664 &UnicodeString, 3665 FALSE); 3666 ErrorCode = RtlNtStatusToDosError(Status); 3667 cClass = AnsiString.Length; 3668 lpClass[cClass] = ANSI_NULL; 3669 } 3670 3671 if (lpcClass != NULL) 3672 { 3673 *lpcClass = cClass; 3674 } 3675 3676 return ErrorCode; 3677 } 3678 3679 3680 /************************************************************************ 3681 * RegQueryInfoKeyW 3682 * 3683 * @implemented 3684 */ 3685 LONG WINAPI 3686 RegQueryInfoKeyW(HKEY hKey, 3687 LPWSTR lpClass, 3688 LPDWORD lpcClass, 3689 LPDWORD lpReserved, 3690 LPDWORD lpcSubKeys, 3691 LPDWORD lpcMaxSubKeyLen, 3692 LPDWORD lpcMaxClassLen, 3693 LPDWORD lpcValues, 3694 LPDWORD lpcMaxValueNameLen, 3695 LPDWORD lpcMaxValueLen, 3696 LPDWORD lpcbSecurityDescriptor, 3697 PFILETIME lpftLastWriteTime) 3698 { 3699 KEY_FULL_INFORMATION FullInfoBuffer; 3700 PKEY_FULL_INFORMATION FullInfo; 3701 ULONG FullInfoSize; 3702 ULONG ClassLength = 0; 3703 HANDLE KeyHandle; 3704 NTSTATUS Status; 3705 ULONG Length; 3706 LONG ErrorCode = ERROR_SUCCESS; 3707 3708 if ((lpClass) && (!lpcClass)) 3709 { 3710 return ERROR_INVALID_PARAMETER; 3711 } 3712 3713 Status = MapDefaultKey(&KeyHandle, 3714 hKey); 3715 if (!NT_SUCCESS(Status)) 3716 { 3717 return RtlNtStatusToDosError(Status); 3718 } 3719 3720 if (lpClass != NULL) 3721 { 3722 if (*lpcClass > 0) 3723 { 3724 ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 3725 } 3726 else 3727 { 3728 ClassLength = 0; 3729 } 3730 3731 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3); 3732 FullInfo = RtlAllocateHeap(ProcessHeap, 3733 0, 3734 FullInfoSize); 3735 if (FullInfo == NULL) 3736 { 3737 ErrorCode = ERROR_OUTOFMEMORY; 3738 goto Cleanup; 3739 } 3740 } 3741 else 3742 { 3743 FullInfoSize = sizeof(KEY_FULL_INFORMATION); 3744 FullInfo = &FullInfoBuffer; 3745 } 3746 3747 if (lpcbSecurityDescriptor != NULL) 3748 *lpcbSecurityDescriptor = 0; 3749 3750 Status = NtQueryKey(KeyHandle, 3751 KeyFullInformation, 3752 FullInfo, 3753 FullInfoSize, 3754 &Length); 3755 TRACE("NtQueryKey() returned status 0x%X\n", Status); 3756 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 3757 { 3758 ErrorCode = RtlNtStatusToDosError(Status); 3759 goto Cleanup; 3760 } 3761 3762 TRACE("SubKeys %d\n", FullInfo->SubKeys); 3763 if (lpcSubKeys != NULL) 3764 { 3765 *lpcSubKeys = FullInfo->SubKeys; 3766 } 3767 3768 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen); 3769 if (lpcMaxSubKeyLen != NULL) 3770 { 3771 *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR); 3772 } 3773 3774 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen); 3775 if (lpcMaxClassLen != NULL) 3776 { 3777 *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR); 3778 } 3779 3780 TRACE("Values %lu\n", FullInfo->Values); 3781 if (lpcValues != NULL) 3782 { 3783 *lpcValues = FullInfo->Values; 3784 } 3785 3786 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen); 3787 if (lpcMaxValueNameLen != NULL) 3788 { 3789 *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR); 3790 } 3791 3792 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen); 3793 if (lpcMaxValueLen != NULL) 3794 { 3795 *lpcMaxValueLen = FullInfo->MaxValueDataLen; 3796 } 3797 3798 if (lpcbSecurityDescriptor != NULL) 3799 { 3800 Status = NtQuerySecurityObject(KeyHandle, 3801 OWNER_SECURITY_INFORMATION | 3802 GROUP_SECURITY_INFORMATION | 3803 DACL_SECURITY_INFORMATION, 3804 NULL, 3805 0, 3806 lpcbSecurityDescriptor); 3807 TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status); 3808 } 3809 3810 if (lpftLastWriteTime != NULL) 3811 { 3812 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart; 3813 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart; 3814 } 3815 3816 if (lpClass != NULL) 3817 { 3818 if (*lpcClass == 0) 3819 { 3820 goto Cleanup; 3821 } 3822 3823 if (FullInfo->ClassLength > ClassLength) 3824 { 3825 ErrorCode = ERROR_INSUFFICIENT_BUFFER; 3826 } 3827 else 3828 { 3829 RtlCopyMemory(lpClass, 3830 FullInfo->Class, 3831 FullInfo->ClassLength); 3832 lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL; 3833 } 3834 } 3835 3836 if (lpcClass != NULL) 3837 { 3838 *lpcClass = FullInfo->ClassLength / sizeof(WCHAR); 3839 } 3840 3841 Cleanup: 3842 if (lpClass != NULL) 3843 { 3844 RtlFreeHeap(ProcessHeap, 3845 0, 3846 FullInfo); 3847 } 3848 3849 ClosePredefKey(KeyHandle); 3850 3851 return ErrorCode; 3852 } 3853 3854 3855 /************************************************************************ 3856 * RegQueryMultipleValuesA 3857 * 3858 * @implemented 3859 */ 3860 LONG WINAPI 3861 RegQueryMultipleValuesA(HKEY hKey, 3862 PVALENTA val_list, 3863 DWORD num_vals, 3864 LPSTR lpValueBuf, 3865 LPDWORD ldwTotsize) 3866 { 3867 ULONG i; 3868 DWORD maxBytes = *ldwTotsize; 3869 LPSTR bufptr = lpValueBuf; 3870 LONG ErrorCode; 3871 3872 if (maxBytes >= (1024*1024)) 3873 return ERROR_MORE_DATA; 3874 3875 *ldwTotsize = 0; 3876 3877 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n", 3878 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3879 3880 for (i = 0; i < num_vals; i++) 3881 { 3882 val_list[i].ve_valuelen = 0; 3883 ErrorCode = RegQueryValueExA(hKey, 3884 val_list[i].ve_valuename, 3885 NULL, 3886 NULL, 3887 NULL, 3888 &val_list[i].ve_valuelen); 3889 if (ErrorCode != ERROR_SUCCESS) 3890 { 3891 return ErrorCode; 3892 } 3893 3894 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3895 { 3896 ErrorCode = RegQueryValueExA(hKey, 3897 val_list[i].ve_valuename, 3898 NULL, 3899 &val_list[i].ve_type, 3900 (LPBYTE)bufptr, 3901 &val_list[i].ve_valuelen); 3902 if (ErrorCode != ERROR_SUCCESS) 3903 { 3904 return ErrorCode; 3905 } 3906 3907 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3908 3909 bufptr += val_list[i].ve_valuelen; 3910 } 3911 3912 *ldwTotsize += val_list[i].ve_valuelen; 3913 } 3914 3915 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3916 } 3917 3918 3919 /************************************************************************ 3920 * RegQueryMultipleValuesW 3921 * 3922 * @implemented 3923 */ 3924 LONG WINAPI 3925 RegQueryMultipleValuesW(HKEY hKey, 3926 PVALENTW val_list, 3927 DWORD num_vals, 3928 LPWSTR lpValueBuf, 3929 LPDWORD ldwTotsize) 3930 { 3931 ULONG i; 3932 DWORD maxBytes = *ldwTotsize; 3933 LPSTR bufptr = (LPSTR)lpValueBuf; 3934 LONG ErrorCode; 3935 3936 if (maxBytes >= (1024*1024)) 3937 return ERROR_MORE_DATA; 3938 3939 *ldwTotsize = 0; 3940 3941 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n", 3942 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3943 3944 for (i = 0; i < num_vals; i++) 3945 { 3946 val_list[i].ve_valuelen = 0; 3947 ErrorCode = RegQueryValueExW(hKey, 3948 val_list[i].ve_valuename, 3949 NULL, 3950 NULL, 3951 NULL, 3952 &val_list[i].ve_valuelen); 3953 if (ErrorCode != ERROR_SUCCESS) 3954 { 3955 return ErrorCode; 3956 } 3957 3958 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3959 { 3960 ErrorCode = RegQueryValueExW(hKey, 3961 val_list[i].ve_valuename, 3962 NULL, 3963 &val_list[i].ve_type, 3964 (LPBYTE)bufptr, 3965 &val_list[i].ve_valuelen); 3966 if (ErrorCode != ERROR_SUCCESS) 3967 { 3968 return ErrorCode; 3969 } 3970 3971 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3972 3973 bufptr += val_list[i].ve_valuelen; 3974 } 3975 3976 *ldwTotsize += val_list[i].ve_valuelen; 3977 } 3978 3979 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3980 } 3981 3982 3983 /************************************************************************ 3984 * RegQueryReflectionKey 3985 * 3986 * @unimplemented 3987 */ 3988 LONG WINAPI 3989 RegQueryReflectionKey(IN HKEY hBase, 3990 OUT BOOL* bIsReflectionDisabled) 3991 { 3992 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n", 3993 hBase, bIsReflectionDisabled); 3994 return ERROR_CALL_NOT_IMPLEMENTED; 3995 } 3996 3997 3998 /****************************************************************************** 3999 * RegQueryValueExA [ADVAPI32.@] 4000 * 4001 * Get the type and contents of a specified value under with a key. 4002 * 4003 * PARAMS 4004 * hkey [I] Handle of the key to query 4005 * name [I] Name of value under hkey to query 4006 * reserved [I] Reserved - must be NULL 4007 * type [O] Destination for the value type, or NULL if not required 4008 * data [O] Destination for the values contents, or NULL if not required 4009 * count [I/O] Size of data, updated with the number of bytes returned 4010 * 4011 * RETURNS 4012 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. 4013 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. 4014 * ERROR_INVALID_PARAMETER, if any other parameter is invalid. 4015 * ERROR_MORE_DATA, if on input *count is too small to hold the contents. 4016 * 4017 * NOTES 4018 * MSDN states that if data is too small it is partially filled. In reality 4019 * it remains untouched. 4020 */ 4021 LONG 4022 WINAPI 4023 RegQueryValueExA( 4024 _In_ HKEY hkeyorg, 4025 _In_ LPCSTR name, 4026 _In_ LPDWORD reserved, 4027 _Out_opt_ LPDWORD type, 4028 _Out_opt_ LPBYTE data, 4029 _Inout_opt_ LPDWORD count) 4030 { 4031 UNICODE_STRING nameW; 4032 DWORD DataLength; 4033 DWORD ErrorCode; 4034 DWORD BufferSize = 0; 4035 WCHAR* Buffer; 4036 CHAR* DataStr = (CHAR*)data; 4037 DWORD LocalType; 4038 4039 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */ 4040 if ((data && !count) || reserved) 4041 return ERROR_INVALID_PARAMETER; 4042 4043 if (name) 4044 { 4045 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name)) 4046 return ERROR_NOT_ENOUGH_MEMORY; 4047 } 4048 else 4049 RtlInitEmptyUnicodeString(&nameW, NULL, 0); 4050 4051 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize); 4052 if (ErrorCode != ERROR_SUCCESS) 4053 { 4054 if ((!data) && count) 4055 *count = 0; 4056 RtlFreeUnicodeString(&nameW); 4057 return ErrorCode; 4058 } 4059 4060 /* See if we can directly handle the call without caring for conversion */ 4061 if (!is_string(LocalType) || !count) 4062 { 4063 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count); 4064 RtlFreeUnicodeString(&nameW); 4065 return ErrorCode; 4066 } 4067 4068 /* Allocate a unicode string to get the data */ 4069 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); 4070 if (!Buffer) 4071 { 4072 RtlFreeUnicodeString(&nameW); 4073 return ERROR_NOT_ENOUGH_MEMORY; 4074 } 4075 4076 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize); 4077 if (ErrorCode != ERROR_SUCCESS) 4078 { 4079 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4080 RtlFreeUnicodeString(&nameW); 4081 return ErrorCode; 4082 } 4083 4084 /* We don't need this anymore */ 4085 RtlFreeUnicodeString(&nameW); 4086 4087 DataLength = *count; 4088 RtlUnicodeToMultiByteSize(count, Buffer, BufferSize); 4089 4090 if ((!data) || (DataLength < *count)) 4091 { 4092 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4093 return data ? ERROR_MORE_DATA : ERROR_SUCCESS; 4094 } 4095 4096 /* We can finally do the conversion */ 4097 RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize); 4098 4099 /* NULL-terminate if there is enough room */ 4100 if ((DataLength > *count) && (DataStr[*count - 1] != '\0')) 4101 DataStr[*count] = '\0'; 4102 4103 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4104 4105 return ERROR_SUCCESS; 4106 } 4107 4108 4109 /************************************************************************ 4110 * RegQueryValueExW 4111 * 4112 * @implemented 4113 */ 4114 LONG 4115 WINAPI 4116 RegQueryValueExW( 4117 _In_ HKEY hkeyorg, 4118 _In_ LPCWSTR name, 4119 _In_ LPDWORD reserved, 4120 _In_ LPDWORD type, 4121 _In_ LPBYTE data, 4122 _In_ LPDWORD count) 4123 { 4124 HANDLE hkey; 4125 NTSTATUS status; 4126 UNICODE_STRING name_str; 4127 DWORD total_size; 4128 char buffer[256], *buf_ptr = buffer; 4129 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 4130 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); 4131 4132 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", 4133 hkeyorg, debugstr_w(name), reserved, type, data, count, 4134 (count && data) ? *count : 0 ); 4135 4136 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 4137 4138 status = MapDefaultKey(&hkey, hkeyorg); 4139 if (!NT_SUCCESS(status)) 4140 { 4141 return RtlNtStatusToDosError(status); 4142 } 4143 4144 if (IsHKCRKey(hkey)) 4145 { 4146 LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count); 4147 ClosePredefKey(hkey); 4148 return ErrorCode; 4149 } 4150 4151 RtlInitUnicodeString( &name_str, name ); 4152 4153 if (data) 4154 total_size = min( sizeof(buffer), *count + info_size ); 4155 else 4156 total_size = info_size; 4157 4158 4159 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4160 buffer, total_size, &total_size ); 4161 4162 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) 4163 { 4164 // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE 4165 // On windows these conditions are likely to be side effects of the implementation... 4166 if (status == STATUS_INVALID_HANDLE && hkey) 4167 { 4168 if (type) *type = REG_NONE; 4169 if (count) *count = 0; 4170 } 4171 else if (status == STATUS_OBJECT_NAME_NOT_FOUND) 4172 { 4173 if (type) *type = REG_NONE; 4174 if (data == NULL && count) *count = 0; 4175 } 4176 goto done; 4177 } 4178 4179 if (data) 4180 { 4181 /* retry with a dynamically allocated buffer */ 4182 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) 4183 { 4184 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4185 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 4186 { 4187 ClosePredefKey(hkey); 4188 return ERROR_NOT_ENOUGH_MEMORY; 4189 } 4190 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; 4191 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4192 buf_ptr, total_size, &total_size ); 4193 } 4194 4195 if (NT_SUCCESS(status)) 4196 { 4197 memcpy( data, buf_ptr + info_size, total_size - info_size ); 4198 /* if the type is REG_SZ and data is not 0-terminated 4199 * and there is enough space in the buffer NT appends a \0 */ 4200 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR)) 4201 { 4202 WCHAR *ptr = (WCHAR *)(data + total_size - info_size); 4203 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 4204 } 4205 } 4206 else if (status != STATUS_BUFFER_OVERFLOW) goto done; 4207 } 4208 else status = STATUS_SUCCESS; 4209 4210 if (type) *type = info->Type; 4211 if (count) *count = total_size - info_size; 4212 4213 done: 4214 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4215 ClosePredefKey(hkey); 4216 return RtlNtStatusToDosError(status); 4217 } 4218 4219 4220 /************************************************************************ 4221 * RegQueryValueA 4222 * 4223 * @implemented 4224 */ 4225 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) 4226 { 4227 DWORD ret; 4228 HKEY subkey = hkey; 4229 4230 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); 4231 4232 if (name && name[0]) 4233 { 4234 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; 4235 } 4236 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4237 if (subkey != hkey) RegCloseKey( subkey ); 4238 if (ret == ERROR_FILE_NOT_FOUND) 4239 { 4240 /* return empty string if default value not found */ 4241 if (data) *data = 0; 4242 if (count) *count = 1; 4243 ret = ERROR_SUCCESS; 4244 } 4245 return ret; 4246 } 4247 4248 4249 /************************************************************************ 4250 * RegQueryValueW 4251 * 4252 * @implemented 4253 */ 4254 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) 4255 { 4256 DWORD ret; 4257 HKEY subkey = hkey; 4258 4259 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); 4260 if (hkey == NULL) 4261 { 4262 return ERROR_INVALID_HANDLE; 4263 } 4264 if (name && name[0]) 4265 { 4266 ret = RegOpenKeyW( hkey, name, &subkey); 4267 if (ret != ERROR_SUCCESS) 4268 { 4269 return ret; 4270 } 4271 } 4272 4273 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4274 4275 if (subkey != hkey) 4276 { 4277 RegCloseKey( subkey ); 4278 } 4279 4280 if (ret == ERROR_FILE_NOT_FOUND) 4281 { 4282 /* return empty string if default value not found */ 4283 if (data) 4284 *data = 0; 4285 if (count) 4286 *count = sizeof(WCHAR); 4287 ret = ERROR_SUCCESS; 4288 } 4289 return ret; 4290 } 4291 4292 4293 /************************************************************************ 4294 * RegReplaceKeyA 4295 * 4296 * @implemented 4297 */ 4298 LONG WINAPI 4299 RegReplaceKeyA(HKEY hKey, 4300 LPCSTR lpSubKey, 4301 LPCSTR lpNewFile, 4302 LPCSTR lpOldFile) 4303 { 4304 UNICODE_STRING SubKey; 4305 UNICODE_STRING NewFile; 4306 UNICODE_STRING OldFile; 4307 LONG ErrorCode; 4308 4309 RtlInitEmptyUnicodeString(&SubKey, NULL, 0); 4310 RtlInitEmptyUnicodeString(&OldFile, NULL, 0); 4311 RtlInitEmptyUnicodeString(&NewFile, NULL, 0); 4312 4313 if (lpSubKey) 4314 { 4315 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey)) 4316 { 4317 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4318 goto Exit; 4319 } 4320 } 4321 4322 if (lpOldFile) 4323 { 4324 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile)) 4325 { 4326 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4327 goto Exit; 4328 } 4329 } 4330 4331 if (lpNewFile) 4332 { 4333 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile)) 4334 { 4335 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4336 goto Exit; 4337 } 4338 } 4339 4340 ErrorCode = RegReplaceKeyW(hKey, 4341 SubKey.Buffer, 4342 NewFile.Buffer, 4343 OldFile.Buffer); 4344 4345 Exit: 4346 RtlFreeUnicodeString(&OldFile); 4347 RtlFreeUnicodeString(&NewFile); 4348 RtlFreeUnicodeString(&SubKey); 4349 4350 return ErrorCode; 4351 } 4352 4353 4354 /************************************************************************ 4355 * RegReplaceKeyW 4356 * 4357 * @unimplemented 4358 */ 4359 LONG WINAPI 4360 RegReplaceKeyW(HKEY hKey, 4361 LPCWSTR lpSubKey, 4362 LPCWSTR lpNewFile, 4363 LPCWSTR lpOldFile) 4364 { 4365 OBJECT_ATTRIBUTES KeyObjectAttributes; 4366 OBJECT_ATTRIBUTES NewObjectAttributes; 4367 OBJECT_ATTRIBUTES OldObjectAttributes; 4368 UNICODE_STRING SubKeyName; 4369 UNICODE_STRING NewFileName; 4370 UNICODE_STRING OldFileName; 4371 BOOLEAN CloseRealKey; 4372 HANDLE RealKeyHandle; 4373 HANDLE KeyHandle; 4374 NTSTATUS Status; 4375 LONG ErrorCode = ERROR_SUCCESS; 4376 4377 if (hKey == HKEY_PERFORMANCE_DATA) 4378 { 4379 return ERROR_INVALID_HANDLE; 4380 } 4381 4382 Status = MapDefaultKey(&KeyHandle, 4383 hKey); 4384 if (!NT_SUCCESS(Status)) 4385 { 4386 return RtlNtStatusToDosError(Status); 4387 } 4388 4389 /* Open the real key */ 4390 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0) 4391 { 4392 RtlInitUnicodeString(&SubKeyName, lpSubKey); 4393 InitializeObjectAttributes(&KeyObjectAttributes, 4394 &SubKeyName, 4395 OBJ_CASE_INSENSITIVE, 4396 KeyHandle, 4397 NULL); 4398 Status = NtOpenKey(&RealKeyHandle, 4399 MAXIMUM_ALLOWED, 4400 &KeyObjectAttributes); 4401 if (!NT_SUCCESS(Status)) 4402 { 4403 ErrorCode = RtlNtStatusToDosError(Status); 4404 goto Cleanup; 4405 } 4406 4407 CloseRealKey = TRUE; 4408 } 4409 else 4410 { 4411 RealKeyHandle = KeyHandle; 4412 CloseRealKey = FALSE; 4413 } 4414 4415 /* Convert new file name */ 4416 if (!RtlDosPathNameToNtPathName_U(lpNewFile, 4417 &NewFileName, 4418 NULL, 4419 NULL)) 4420 { 4421 if (CloseRealKey) 4422 { 4423 NtClose(RealKeyHandle); 4424 } 4425 4426 ErrorCode = ERROR_INVALID_PARAMETER; 4427 goto Cleanup; 4428 } 4429 4430 InitializeObjectAttributes(&NewObjectAttributes, 4431 &NewFileName, 4432 OBJ_CASE_INSENSITIVE, 4433 NULL, 4434 NULL); 4435 4436 /* Convert old file name */ 4437 if (!RtlDosPathNameToNtPathName_U(lpOldFile, 4438 &OldFileName, 4439 NULL, 4440 NULL)) 4441 { 4442 RtlFreeHeap(RtlGetProcessHeap (), 4443 0, 4444 NewFileName.Buffer); 4445 if (CloseRealKey) 4446 { 4447 NtClose(RealKeyHandle); 4448 } 4449 4450 ErrorCode = ERROR_INVALID_PARAMETER; 4451 goto Cleanup; 4452 } 4453 4454 InitializeObjectAttributes(&OldObjectAttributes, 4455 &OldFileName, 4456 OBJ_CASE_INSENSITIVE, 4457 NULL, 4458 NULL); 4459 4460 Status = NtReplaceKey(&NewObjectAttributes, 4461 RealKeyHandle, 4462 &OldObjectAttributes); 4463 4464 RtlFreeHeap(RtlGetProcessHeap(), 4465 0, 4466 OldFileName.Buffer); 4467 RtlFreeHeap(RtlGetProcessHeap(), 4468 0, 4469 NewFileName.Buffer); 4470 4471 if (CloseRealKey) 4472 { 4473 NtClose(RealKeyHandle); 4474 } 4475 4476 if (!NT_SUCCESS(Status)) 4477 { 4478 return RtlNtStatusToDosError(Status); 4479 } 4480 4481 Cleanup: 4482 ClosePredefKey(KeyHandle); 4483 4484 return ErrorCode; 4485 } 4486 4487 4488 /************************************************************************ 4489 * RegRestoreKeyA 4490 * 4491 * @implemented 4492 */ 4493 LONG WINAPI 4494 RegRestoreKeyA(HKEY hKey, 4495 LPCSTR lpFile, 4496 DWORD dwFlags) 4497 { 4498 UNICODE_STRING FileName; 4499 LONG ErrorCode; 4500 4501 if (lpFile) 4502 { 4503 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4504 return ERROR_NOT_ENOUGH_MEMORY; 4505 } 4506 else 4507 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4508 4509 ErrorCode = RegRestoreKeyW(hKey, 4510 FileName.Buffer, 4511 dwFlags); 4512 4513 RtlFreeUnicodeString(&FileName); 4514 4515 return ErrorCode; 4516 } 4517 4518 4519 /************************************************************************ 4520 * RegRestoreKeyW 4521 * 4522 * @implemented 4523 */ 4524 LONG WINAPI 4525 RegRestoreKeyW(HKEY hKey, 4526 LPCWSTR lpFile, 4527 DWORD dwFlags) 4528 { 4529 OBJECT_ATTRIBUTES ObjectAttributes; 4530 IO_STATUS_BLOCK IoStatusBlock; 4531 UNICODE_STRING FileName; 4532 HANDLE FileHandle; 4533 HANDLE KeyHandle; 4534 NTSTATUS Status; 4535 4536 if (hKey == HKEY_PERFORMANCE_DATA) 4537 { 4538 return ERROR_INVALID_HANDLE; 4539 } 4540 4541 Status = MapDefaultKey(&KeyHandle, 4542 hKey); 4543 if (!NT_SUCCESS(Status)) 4544 { 4545 return RtlNtStatusToDosError(Status); 4546 } 4547 4548 if (!RtlDosPathNameToNtPathName_U(lpFile, 4549 &FileName, 4550 NULL, 4551 NULL)) 4552 { 4553 Status = STATUS_INVALID_PARAMETER; 4554 goto Cleanup; 4555 } 4556 4557 InitializeObjectAttributes(&ObjectAttributes, 4558 &FileName, 4559 OBJ_CASE_INSENSITIVE, 4560 NULL, 4561 NULL); 4562 4563 Status = NtOpenFile(&FileHandle, 4564 FILE_GENERIC_READ, 4565 &ObjectAttributes, 4566 &IoStatusBlock, 4567 FILE_SHARE_READ, 4568 FILE_SYNCHRONOUS_IO_NONALERT); 4569 RtlFreeHeap(RtlGetProcessHeap(), 4570 0, 4571 FileName.Buffer); 4572 if (!NT_SUCCESS(Status)) 4573 { 4574 goto Cleanup; 4575 } 4576 4577 Status = NtRestoreKey(KeyHandle, 4578 FileHandle, 4579 (ULONG)dwFlags); 4580 NtClose (FileHandle); 4581 4582 Cleanup: 4583 ClosePredefKey(KeyHandle); 4584 4585 if (!NT_SUCCESS(Status)) 4586 { 4587 return RtlNtStatusToDosError(Status); 4588 } 4589 4590 return ERROR_SUCCESS; 4591 } 4592 4593 4594 /************************************************************************ 4595 * RegSaveKeyA 4596 * 4597 * @implemented 4598 */ 4599 LONG WINAPI 4600 RegSaveKeyA(HKEY hKey, 4601 LPCSTR lpFile, 4602 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4603 { 4604 UNICODE_STRING FileName; 4605 LONG ErrorCode; 4606 4607 if (lpFile) 4608 { 4609 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4610 return ERROR_NOT_ENOUGH_MEMORY; 4611 } 4612 else 4613 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4614 4615 ErrorCode = RegSaveKeyW(hKey, 4616 FileName.Buffer, 4617 lpSecurityAttributes); 4618 RtlFreeUnicodeString(&FileName); 4619 4620 return ErrorCode; 4621 } 4622 4623 4624 /************************************************************************ 4625 * RegSaveKeyW 4626 * 4627 * @implemented 4628 */ 4629 LONG WINAPI 4630 RegSaveKeyW(HKEY hKey, 4631 LPCWSTR lpFile, 4632 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4633 { 4634 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 4635 OBJECT_ATTRIBUTES ObjectAttributes; 4636 UNICODE_STRING FileName; 4637 IO_STATUS_BLOCK IoStatusBlock; 4638 HANDLE FileHandle; 4639 HANDLE KeyHandle; 4640 NTSTATUS Status; 4641 4642 Status = MapDefaultKey(&KeyHandle, 4643 hKey); 4644 if (!NT_SUCCESS(Status)) 4645 { 4646 return RtlNtStatusToDosError(Status); 4647 } 4648 4649 if (!RtlDosPathNameToNtPathName_U(lpFile, 4650 &FileName, 4651 NULL, 4652 NULL)) 4653 { 4654 Status = STATUS_INVALID_PARAMETER; 4655 goto Cleanup; 4656 } 4657 4658 if (lpSecurityAttributes != NULL) 4659 { 4660 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 4661 } 4662 4663 InitializeObjectAttributes(&ObjectAttributes, 4664 &FileName, 4665 OBJ_CASE_INSENSITIVE, 4666 NULL, 4667 SecurityDescriptor); 4668 Status = NtCreateFile(&FileHandle, 4669 GENERIC_WRITE | SYNCHRONIZE, 4670 &ObjectAttributes, 4671 &IoStatusBlock, 4672 NULL, 4673 FILE_ATTRIBUTE_NORMAL, 4674 FILE_SHARE_READ, 4675 FILE_CREATE, 4676 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 4677 NULL, 4678 0); 4679 RtlFreeHeap(RtlGetProcessHeap(), 4680 0, 4681 FileName.Buffer); 4682 if (!NT_SUCCESS(Status)) 4683 { 4684 goto Cleanup; 4685 } 4686 4687 Status = NtSaveKey(KeyHandle, 4688 FileHandle); 4689 NtClose (FileHandle); 4690 4691 Cleanup: 4692 ClosePredefKey(KeyHandle); 4693 4694 if (!NT_SUCCESS(Status)) 4695 { 4696 return RtlNtStatusToDosError(Status); 4697 } 4698 4699 return ERROR_SUCCESS; 4700 } 4701 4702 4703 /************************************************************************ 4704 * RegSaveKeyExA 4705 * 4706 * @implemented 4707 */ 4708 LONG 4709 WINAPI 4710 RegSaveKeyExA(HKEY hKey, 4711 LPCSTR lpFile, 4712 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4713 DWORD Flags) 4714 { 4715 UNICODE_STRING FileName; 4716 LONG ErrorCode; 4717 4718 if (lpFile) 4719 { 4720 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4721 return ERROR_NOT_ENOUGH_MEMORY; 4722 } 4723 else 4724 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4725 4726 ErrorCode = RegSaveKeyExW(hKey, 4727 FileName.Buffer, 4728 lpSecurityAttributes, 4729 Flags); 4730 RtlFreeUnicodeString(&FileName); 4731 4732 return ErrorCode; 4733 } 4734 4735 4736 /************************************************************************ 4737 * RegSaveKeyExW 4738 * 4739 * @unimplemented 4740 */ 4741 LONG 4742 WINAPI 4743 RegSaveKeyExW(HKEY hKey, 4744 LPCWSTR lpFile, 4745 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4746 DWORD Flags) 4747 { 4748 switch (Flags) 4749 { 4750 case REG_STANDARD_FORMAT: 4751 case REG_LATEST_FORMAT: 4752 case REG_NO_COMPRESSION: 4753 break; 4754 default: 4755 return ERROR_INVALID_PARAMETER; 4756 } 4757 4758 FIXME("RegSaveKeyExW(): Flags ignored!\n"); 4759 4760 return RegSaveKeyW(hKey, 4761 lpFile, 4762 lpSecurityAttributes); 4763 } 4764 4765 4766 /************************************************************************ 4767 * RegSetKeySecurity 4768 * 4769 * @implemented 4770 */ 4771 LONG WINAPI 4772 RegSetKeySecurity(HKEY hKey, 4773 SECURITY_INFORMATION SecurityInformation, 4774 PSECURITY_DESCRIPTOR pSecurityDescriptor) 4775 { 4776 HANDLE KeyHandle; 4777 NTSTATUS Status; 4778 4779 if (hKey == HKEY_PERFORMANCE_DATA) 4780 { 4781 return ERROR_INVALID_HANDLE; 4782 } 4783 4784 Status = MapDefaultKey(&KeyHandle, 4785 hKey); 4786 if (!NT_SUCCESS(Status)) 4787 { 4788 return RtlNtStatusToDosError(Status); 4789 } 4790 4791 Status = NtSetSecurityObject(KeyHandle, 4792 SecurityInformation, 4793 pSecurityDescriptor); 4794 4795 ClosePredefKey(KeyHandle); 4796 4797 if (!NT_SUCCESS(Status)) 4798 { 4799 return RtlNtStatusToDosError(Status); 4800 } 4801 4802 return ERROR_SUCCESS; 4803 } 4804 4805 4806 /************************************************************************ 4807 * RegSetValueExA 4808 * 4809 * @implemented 4810 */ 4811 LONG WINAPI 4812 RegSetValueExA(HKEY hKey, 4813 LPCSTR lpValueName, 4814 DWORD Reserved, 4815 DWORD dwType, 4816 CONST BYTE* lpData, 4817 DWORD cbData) 4818 { 4819 UNICODE_STRING ValueName; 4820 LPWSTR pValueName; 4821 ANSI_STRING AnsiString; 4822 UNICODE_STRING Data; 4823 LONG ErrorCode; 4824 LPBYTE pData; 4825 DWORD DataSize; 4826 NTSTATUS Status; 4827 4828 /* Convert SubKey name to Unicode */ 4829 if (lpValueName != NULL && lpValueName[0] != '\0') 4830 { 4831 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName)) 4832 return ERROR_NOT_ENOUGH_MEMORY; 4833 } 4834 else 4835 { 4836 ValueName.Buffer = NULL; 4837 } 4838 4839 pValueName = (LPWSTR)ValueName.Buffer; 4840 4841 4842 if (is_string(dwType) && (cbData != 0)) 4843 { 4844 /* Convert ANSI string Data to Unicode */ 4845 /* If last character NOT zero then increment length */ 4846 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0); 4847 AnsiString.Buffer = (PSTR)lpData; 4848 AnsiString.Length = cbData + bNoNulledStr; 4849 AnsiString.MaximumLength = cbData + bNoNulledStr; 4850 Status = RtlAnsiStringToUnicodeString(&Data, 4851 &AnsiString, 4852 TRUE); 4853 4854 if (!NT_SUCCESS(Status)) 4855 { 4856 if (pValueName != NULL) 4857 RtlFreeUnicodeString(&ValueName); 4858 4859 return RtlNtStatusToDosError(Status); 4860 } 4861 pData = (LPBYTE)Data.Buffer; 4862 DataSize = cbData * sizeof(WCHAR); 4863 } 4864 else 4865 { 4866 Data.Buffer = NULL; 4867 pData = (LPBYTE)lpData; 4868 DataSize = cbData; 4869 } 4870 4871 ErrorCode = RegSetValueExW(hKey, 4872 pValueName, 4873 Reserved, 4874 dwType, 4875 pData, 4876 DataSize); 4877 4878 if (pValueName != NULL) 4879 RtlFreeUnicodeString(&ValueName); 4880 4881 if (Data.Buffer != NULL) 4882 RtlFreeUnicodeString(&Data); 4883 4884 return ErrorCode; 4885 } 4886 4887 4888 /************************************************************************ 4889 * RegSetValueExW 4890 * 4891 * @implemented 4892 */ 4893 LONG 4894 WINAPI 4895 RegSetValueExW( 4896 _In_ HKEY hKey, 4897 _In_ LPCWSTR lpValueName, 4898 _In_ DWORD Reserved, 4899 _In_ DWORD dwType, 4900 _In_ CONST BYTE* lpData, 4901 _In_ DWORD cbData) 4902 { 4903 UNICODE_STRING ValueName; 4904 HANDLE KeyHandle; 4905 NTSTATUS Status; 4906 4907 Status = MapDefaultKey(&KeyHandle, 4908 hKey); 4909 if (!NT_SUCCESS(Status)) 4910 { 4911 return RtlNtStatusToDosError(Status); 4912 } 4913 4914 if (IsHKCRKey(KeyHandle)) 4915 { 4916 LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData); 4917 ClosePredefKey(KeyHandle); 4918 return ErrorCode; 4919 } 4920 4921 if (is_string(dwType) && (cbData != 0)) 4922 { 4923 PWSTR pwsData = (PWSTR)lpData; 4924 4925 _SEH2_TRY 4926 { 4927 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') && 4928 (pwsData[cbData / sizeof(WCHAR)] == L'\0')) 4929 { 4930 /* Increment length if last character is not zero and next is zero */ 4931 cbData += sizeof(WCHAR); 4932 } 4933 } 4934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4935 { 4936 /* Do not fail if we fault where we were told not to go */ 4937 } 4938 _SEH2_END; 4939 } 4940 4941 RtlInitUnicodeString(&ValueName, lpValueName); 4942 4943 Status = NtSetValueKey(KeyHandle, 4944 &ValueName, 4945 0, 4946 dwType, 4947 (PVOID)lpData, 4948 (ULONG)cbData); 4949 4950 ClosePredefKey(KeyHandle); 4951 4952 if (!NT_SUCCESS(Status)) 4953 { 4954 return RtlNtStatusToDosError(Status); 4955 } 4956 4957 return ERROR_SUCCESS; 4958 } 4959 4960 4961 /************************************************************************ 4962 * RegSetValueA 4963 * 4964 * @implemented 4965 */ 4966 LONG WINAPI 4967 RegSetValueA(HKEY hKeyOriginal, 4968 LPCSTR lpSubKey, 4969 DWORD dwType, 4970 LPCSTR lpData, 4971 DWORD cbData) 4972 { 4973 HKEY subkey; 4974 HANDLE hKey; 4975 DWORD ret; 4976 NTSTATUS Status; 4977 4978 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData ); 4979 4980 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER; 4981 4982 Status = MapDefaultKey(&hKey, hKeyOriginal); 4983 if (!NT_SUCCESS(Status)) 4984 { 4985 return RtlNtStatusToDosError (Status); 4986 } 4987 subkey = hKey; 4988 4989 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 4990 { 4991 ret = RegCreateKeyA(hKey, lpSubKey, &subkey); 4992 if (ret != ERROR_SUCCESS) 4993 goto Cleanup; 4994 } 4995 4996 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 ); 4997 if (subkey != hKey) 4998 RegCloseKey(subkey); 4999 5000 Cleanup: 5001 ClosePredefKey(hKey); 5002 5003 return ret; 5004 } 5005 5006 5007 /************************************************************************ 5008 * RegSetValueW 5009 * 5010 * @implemented 5011 */ 5012 LONG WINAPI 5013 RegSetValueW(HKEY hKeyOriginal, 5014 LPCWSTR lpSubKey, 5015 DWORD dwType, 5016 LPCWSTR lpData, 5017 DWORD cbData) 5018 { 5019 HKEY subkey; 5020 HANDLE hKey; 5021 DWORD ret; 5022 NTSTATUS Status; 5023 5024 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData ); 5025 5026 if (dwType != REG_SZ || !lpData) 5027 return ERROR_INVALID_PARAMETER; 5028 5029 Status = MapDefaultKey(&hKey, 5030 hKeyOriginal); 5031 if (!NT_SUCCESS(Status)) 5032 { 5033 return RtlNtStatusToDosError(Status); 5034 } 5035 subkey = hKey; 5036 5037 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 5038 { 5039 ret = RegCreateKeyW(hKey, lpSubKey, &subkey); 5040 if (ret != ERROR_SUCCESS) 5041 goto Cleanup; 5042 } 5043 5044 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, 5045 (wcslen( lpData ) + 1) * sizeof(WCHAR) ); 5046 if (subkey != hKey) 5047 RegCloseKey(subkey); 5048 5049 Cleanup: 5050 ClosePredefKey(hKey); 5051 5052 return ret; 5053 } 5054 5055 5056 /************************************************************************ 5057 * RegUnLoadKeyA 5058 * 5059 * @implemented 5060 */ 5061 LONG WINAPI 5062 RegUnLoadKeyA(HKEY hKey, 5063 LPCSTR lpSubKey) 5064 { 5065 UNICODE_STRING KeyName; 5066 DWORD ErrorCode; 5067 5068 if (lpSubKey) 5069 { 5070 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey)) 5071 return ERROR_NOT_ENOUGH_MEMORY; 5072 } 5073 else 5074 RtlInitEmptyUnicodeString(&KeyName, NULL, 0); 5075 5076 ErrorCode = RegUnLoadKeyW(hKey, 5077 KeyName.Buffer); 5078 5079 RtlFreeUnicodeString (&KeyName); 5080 5081 return ErrorCode; 5082 } 5083 5084 5085 /************************************************************************ 5086 * RegUnLoadKeyW 5087 * 5088 * @implemented 5089 */ 5090 LONG WINAPI 5091 RegUnLoadKeyW(HKEY hKey, 5092 LPCWSTR lpSubKey) 5093 { 5094 OBJECT_ATTRIBUTES ObjectAttributes; 5095 UNICODE_STRING KeyName; 5096 HANDLE KeyHandle; 5097 NTSTATUS Status; 5098 5099 if (hKey == HKEY_PERFORMANCE_DATA) 5100 { 5101 return ERROR_INVALID_HANDLE; 5102 } 5103 5104 Status = MapDefaultKey(&KeyHandle, hKey); 5105 if (!NT_SUCCESS(Status)) 5106 { 5107 return RtlNtStatusToDosError(Status); 5108 } 5109 5110 RtlInitUnicodeString(&KeyName, lpSubKey); 5111 5112 InitializeObjectAttributes(&ObjectAttributes, 5113 &KeyName, 5114 OBJ_CASE_INSENSITIVE, 5115 KeyHandle, 5116 NULL); 5117 5118 Status = NtUnloadKey(&ObjectAttributes); 5119 5120 ClosePredefKey(KeyHandle); 5121 5122 if (!NT_SUCCESS(Status)) 5123 { 5124 return RtlNtStatusToDosError(Status); 5125 } 5126 5127 return ERROR_SUCCESS; 5128 } 5129 5130 /* EOF */ 5131