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