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