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 (lpClass != NULL) 3722 { 3723 if (*lpcClass > 0) 3724 { 3725 ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 3726 } 3727 else 3728 { 3729 ClassLength = 0; 3730 } 3731 3732 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3); 3733 FullInfo = RtlAllocateHeap(ProcessHeap, 3734 0, 3735 FullInfoSize); 3736 if (FullInfo == NULL) 3737 { 3738 ErrorCode = ERROR_OUTOFMEMORY; 3739 goto Cleanup; 3740 } 3741 } 3742 else 3743 { 3744 FullInfoSize = sizeof(KEY_FULL_INFORMATION); 3745 FullInfo = &FullInfoBuffer; 3746 } 3747 3748 if (lpcbSecurityDescriptor != NULL) 3749 *lpcbSecurityDescriptor = 0; 3750 3751 Status = NtQueryKey(KeyHandle, 3752 KeyFullInformation, 3753 FullInfo, 3754 FullInfoSize, 3755 &Length); 3756 TRACE("NtQueryKey() returned status 0x%X\n", Status); 3757 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 3758 { 3759 ErrorCode = RtlNtStatusToDosError(Status); 3760 goto Cleanup; 3761 } 3762 3763 TRACE("SubKeys %d\n", FullInfo->SubKeys); 3764 if (lpcSubKeys != NULL) 3765 { 3766 *lpcSubKeys = FullInfo->SubKeys; 3767 } 3768 3769 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen); 3770 if (lpcMaxSubKeyLen != NULL) 3771 { 3772 *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR); 3773 } 3774 3775 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen); 3776 if (lpcMaxClassLen != NULL) 3777 { 3778 *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR); 3779 } 3780 3781 TRACE("Values %lu\n", FullInfo->Values); 3782 if (lpcValues != NULL) 3783 { 3784 *lpcValues = FullInfo->Values; 3785 } 3786 3787 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen); 3788 if (lpcMaxValueNameLen != NULL) 3789 { 3790 *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR); 3791 } 3792 3793 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen); 3794 if (lpcMaxValueLen != NULL) 3795 { 3796 *lpcMaxValueLen = FullInfo->MaxValueDataLen; 3797 } 3798 3799 if (lpcbSecurityDescriptor != NULL) 3800 { 3801 Status = NtQuerySecurityObject(KeyHandle, 3802 OWNER_SECURITY_INFORMATION | 3803 GROUP_SECURITY_INFORMATION | 3804 DACL_SECURITY_INFORMATION, 3805 NULL, 3806 0, 3807 lpcbSecurityDescriptor); 3808 TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status); 3809 } 3810 3811 if (lpftLastWriteTime != NULL) 3812 { 3813 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart; 3814 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart; 3815 } 3816 3817 if (lpClass != NULL) 3818 { 3819 if (*lpcClass == 0) 3820 { 3821 goto Cleanup; 3822 } 3823 3824 if (FullInfo->ClassLength > ClassLength) 3825 { 3826 ErrorCode = ERROR_INSUFFICIENT_BUFFER; 3827 } 3828 else 3829 { 3830 RtlCopyMemory(lpClass, 3831 FullInfo->Class, 3832 FullInfo->ClassLength); 3833 lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL; 3834 } 3835 } 3836 3837 if (lpcClass != NULL) 3838 { 3839 *lpcClass = FullInfo->ClassLength / sizeof(WCHAR); 3840 } 3841 3842 Cleanup: 3843 if (lpClass != NULL) 3844 { 3845 RtlFreeHeap(ProcessHeap, 3846 0, 3847 FullInfo); 3848 } 3849 3850 ClosePredefKey(KeyHandle); 3851 3852 return ErrorCode; 3853 } 3854 3855 3856 /************************************************************************ 3857 * RegQueryMultipleValuesA 3858 * 3859 * @implemented 3860 */ 3861 LONG WINAPI 3862 RegQueryMultipleValuesA(HKEY hKey, 3863 PVALENTA val_list, 3864 DWORD num_vals, 3865 LPSTR lpValueBuf, 3866 LPDWORD ldwTotsize) 3867 { 3868 ULONG i; 3869 DWORD maxBytes = *ldwTotsize; 3870 LPSTR bufptr = lpValueBuf; 3871 LONG ErrorCode; 3872 3873 if (maxBytes >= (1024*1024)) 3874 return ERROR_MORE_DATA; 3875 3876 *ldwTotsize = 0; 3877 3878 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n", 3879 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3880 3881 for (i = 0; i < num_vals; i++) 3882 { 3883 val_list[i].ve_valuelen = 0; 3884 ErrorCode = RegQueryValueExA(hKey, 3885 val_list[i].ve_valuename, 3886 NULL, 3887 NULL, 3888 NULL, 3889 &val_list[i].ve_valuelen); 3890 if (ErrorCode != ERROR_SUCCESS) 3891 { 3892 return ErrorCode; 3893 } 3894 3895 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3896 { 3897 ErrorCode = RegQueryValueExA(hKey, 3898 val_list[i].ve_valuename, 3899 NULL, 3900 &val_list[i].ve_type, 3901 (LPBYTE)bufptr, 3902 &val_list[i].ve_valuelen); 3903 if (ErrorCode != ERROR_SUCCESS) 3904 { 3905 return ErrorCode; 3906 } 3907 3908 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3909 3910 bufptr += val_list[i].ve_valuelen; 3911 } 3912 3913 *ldwTotsize += val_list[i].ve_valuelen; 3914 } 3915 3916 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3917 } 3918 3919 3920 /************************************************************************ 3921 * RegQueryMultipleValuesW 3922 * 3923 * @implemented 3924 */ 3925 LONG WINAPI 3926 RegQueryMultipleValuesW(HKEY hKey, 3927 PVALENTW val_list, 3928 DWORD num_vals, 3929 LPWSTR lpValueBuf, 3930 LPDWORD ldwTotsize) 3931 { 3932 ULONG i; 3933 DWORD maxBytes = *ldwTotsize; 3934 LPSTR bufptr = (LPSTR)lpValueBuf; 3935 LONG ErrorCode; 3936 3937 if (maxBytes >= (1024*1024)) 3938 return ERROR_MORE_DATA; 3939 3940 *ldwTotsize = 0; 3941 3942 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n", 3943 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 3944 3945 for (i = 0; i < num_vals; i++) 3946 { 3947 val_list[i].ve_valuelen = 0; 3948 ErrorCode = RegQueryValueExW(hKey, 3949 val_list[i].ve_valuename, 3950 NULL, 3951 NULL, 3952 NULL, 3953 &val_list[i].ve_valuelen); 3954 if (ErrorCode != ERROR_SUCCESS) 3955 { 3956 return ErrorCode; 3957 } 3958 3959 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 3960 { 3961 ErrorCode = RegQueryValueExW(hKey, 3962 val_list[i].ve_valuename, 3963 NULL, 3964 &val_list[i].ve_type, 3965 (LPBYTE)bufptr, 3966 &val_list[i].ve_valuelen); 3967 if (ErrorCode != ERROR_SUCCESS) 3968 { 3969 return ErrorCode; 3970 } 3971 3972 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 3973 3974 bufptr += val_list[i].ve_valuelen; 3975 } 3976 3977 *ldwTotsize += val_list[i].ve_valuelen; 3978 } 3979 3980 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 3981 } 3982 3983 3984 /************************************************************************ 3985 * RegQueryReflectionKey 3986 * 3987 * @unimplemented 3988 */ 3989 LONG WINAPI 3990 RegQueryReflectionKey(IN HKEY hBase, 3991 OUT BOOL* bIsReflectionDisabled) 3992 { 3993 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n", 3994 hBase, bIsReflectionDisabled); 3995 return ERROR_CALL_NOT_IMPLEMENTED; 3996 } 3997 3998 3999 /****************************************************************************** 4000 * RegQueryValueExA [ADVAPI32.@] 4001 * 4002 * Get the type and contents of a specified value under with a key. 4003 * 4004 * PARAMS 4005 * hkey [I] Handle of the key to query 4006 * name [I] Name of value under hkey to query 4007 * reserved [I] Reserved - must be NULL 4008 * type [O] Destination for the value type, or NULL if not required 4009 * data [O] Destination for the values contents, or NULL if not required 4010 * count [I/O] Size of data, updated with the number of bytes returned 4011 * 4012 * RETURNS 4013 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. 4014 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. 4015 * ERROR_INVALID_PARAMETER, if any other parameter is invalid. 4016 * ERROR_MORE_DATA, if on input *count is too small to hold the contents. 4017 * 4018 * NOTES 4019 * MSDN states that if data is too small it is partially filled. In reality 4020 * it remains untouched. 4021 */ 4022 LONG 4023 WINAPI 4024 RegQueryValueExA( 4025 _In_ HKEY hkeyorg, 4026 _In_ LPCSTR name, 4027 _In_ LPDWORD reserved, 4028 _Out_opt_ LPDWORD type, 4029 _Out_opt_ LPBYTE data, 4030 _Inout_opt_ LPDWORD count) 4031 { 4032 UNICODE_STRING nameW; 4033 DWORD DataLength; 4034 DWORD ErrorCode; 4035 DWORD BufferSize = 0; 4036 WCHAR* Buffer; 4037 CHAR* DataStr = (CHAR*)data; 4038 DWORD LocalType; 4039 4040 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */ 4041 if ((data && !count) || reserved) 4042 return ERROR_INVALID_PARAMETER; 4043 4044 if (name) 4045 { 4046 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name)) 4047 return ERROR_NOT_ENOUGH_MEMORY; 4048 } 4049 else 4050 RtlInitEmptyUnicodeString(&nameW, NULL, 0); 4051 4052 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize); 4053 if (ErrorCode != ERROR_SUCCESS) 4054 { 4055 if ((!data) && count) 4056 *count = 0; 4057 RtlFreeUnicodeString(&nameW); 4058 return ErrorCode; 4059 } 4060 4061 /* See if we can directly handle the call without caring for conversion */ 4062 if (!is_string(LocalType) || !count) 4063 { 4064 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count); 4065 RtlFreeUnicodeString(&nameW); 4066 return ErrorCode; 4067 } 4068 4069 /* Allocate a unicode string to get the data */ 4070 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); 4071 if (!Buffer) 4072 { 4073 RtlFreeUnicodeString(&nameW); 4074 return ERROR_NOT_ENOUGH_MEMORY; 4075 } 4076 4077 ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize); 4078 if (ErrorCode != ERROR_SUCCESS) 4079 { 4080 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4081 RtlFreeUnicodeString(&nameW); 4082 return ErrorCode; 4083 } 4084 4085 /* We don't need this anymore */ 4086 RtlFreeUnicodeString(&nameW); 4087 4088 /* Get the length for the multi-byte string (without the terminating NULL!) */ 4089 DataLength = *count; 4090 RtlUnicodeToMultiByteSize(count, Buffer, BufferSize); 4091 4092 if ((!data) || (DataLength < *count)) 4093 { 4094 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4095 return data ? ERROR_MORE_DATA : ERROR_SUCCESS; 4096 } 4097 4098 /* We can finally do the conversion */ 4099 RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize); 4100 4101 /* NULL-terminate if there is enough room */ 4102 if (DataLength > *count) 4103 DataStr[*count] = '\0'; 4104 4105 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 4106 4107 return ERROR_SUCCESS; 4108 } 4109 4110 4111 /************************************************************************ 4112 * RegQueryValueExW 4113 * 4114 * @implemented 4115 */ 4116 LONG 4117 WINAPI 4118 RegQueryValueExW( 4119 _In_ HKEY hkeyorg, 4120 _In_ LPCWSTR name, 4121 _In_ LPDWORD reserved, 4122 _In_ LPDWORD type, 4123 _In_ LPBYTE data, 4124 _In_ LPDWORD count) 4125 { 4126 HANDLE hkey; 4127 NTSTATUS status; 4128 UNICODE_STRING name_str; 4129 DWORD total_size; 4130 char buffer[256], *buf_ptr = buffer; 4131 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 4132 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); 4133 4134 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", 4135 hkeyorg, debugstr_w(name), reserved, type, data, count, 4136 (count && data) ? *count : 0 ); 4137 4138 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 4139 4140 status = MapDefaultKey(&hkey, hkeyorg); 4141 if (!NT_SUCCESS(status)) 4142 { 4143 return RtlNtStatusToDosError(status); 4144 } 4145 4146 if (IsHKCRKey(hkey)) 4147 { 4148 LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count); 4149 ClosePredefKey(hkey); 4150 return ErrorCode; 4151 } 4152 4153 RtlInitUnicodeString( &name_str, name ); 4154 4155 if (data) 4156 total_size = min( sizeof(buffer), *count + info_size ); 4157 else 4158 total_size = info_size; 4159 4160 4161 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4162 buffer, total_size, &total_size ); 4163 4164 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) 4165 { 4166 // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE 4167 // On windows these conditions are likely to be side effects of the implementation... 4168 if (status == STATUS_INVALID_HANDLE && hkey) 4169 { 4170 if (type) *type = REG_NONE; 4171 if (count) *count = 0; 4172 } 4173 else if (status == STATUS_OBJECT_NAME_NOT_FOUND) 4174 { 4175 if (type) *type = REG_NONE; 4176 if (data == NULL && count) *count = 0; 4177 } 4178 goto done; 4179 } 4180 4181 if (data) 4182 { 4183 /* retry with a dynamically allocated buffer */ 4184 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) 4185 { 4186 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4187 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 4188 { 4189 ClosePredefKey(hkey); 4190 return ERROR_NOT_ENOUGH_MEMORY; 4191 } 4192 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; 4193 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 4194 buf_ptr, total_size, &total_size ); 4195 } 4196 4197 if (NT_SUCCESS(status)) 4198 { 4199 memcpy( data, buf_ptr + info_size, total_size - info_size ); 4200 /* if the type is REG_SZ and data is not 0-terminated 4201 * and there is enough space in the buffer NT appends a \0 */ 4202 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR)) 4203 { 4204 WCHAR *ptr = (WCHAR *)(data + total_size - info_size); 4205 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 4206 } 4207 } 4208 else if (status != STATUS_BUFFER_OVERFLOW) goto done; 4209 } 4210 else status = STATUS_SUCCESS; 4211 4212 if (type) *type = info->Type; 4213 if (count) *count = total_size - info_size; 4214 4215 done: 4216 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 4217 ClosePredefKey(hkey); 4218 return RtlNtStatusToDosError(status); 4219 } 4220 4221 4222 /************************************************************************ 4223 * RegQueryValueA 4224 * 4225 * @implemented 4226 */ 4227 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) 4228 { 4229 DWORD ret; 4230 HKEY subkey = hkey; 4231 4232 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); 4233 4234 if (name && name[0]) 4235 { 4236 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; 4237 } 4238 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4239 if (subkey != hkey) RegCloseKey( subkey ); 4240 if (ret == ERROR_FILE_NOT_FOUND) 4241 { 4242 /* return empty string if default value not found */ 4243 if (data) *data = 0; 4244 if (count) *count = 1; 4245 ret = ERROR_SUCCESS; 4246 } 4247 return ret; 4248 } 4249 4250 4251 /************************************************************************ 4252 * RegQueryValueW 4253 * 4254 * @implemented 4255 */ 4256 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) 4257 { 4258 DWORD ret; 4259 HKEY subkey = hkey; 4260 4261 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); 4262 if (hkey == NULL) 4263 { 4264 return ERROR_INVALID_HANDLE; 4265 } 4266 if (name && name[0]) 4267 { 4268 ret = RegOpenKeyW( hkey, name, &subkey); 4269 if (ret != ERROR_SUCCESS) 4270 { 4271 return ret; 4272 } 4273 } 4274 4275 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 4276 4277 if (subkey != hkey) 4278 { 4279 RegCloseKey( subkey ); 4280 } 4281 4282 if (ret == ERROR_FILE_NOT_FOUND) 4283 { 4284 /* return empty string if default value not found */ 4285 if (data) 4286 *data = 0; 4287 if (count) 4288 *count = sizeof(WCHAR); 4289 ret = ERROR_SUCCESS; 4290 } 4291 return ret; 4292 } 4293 4294 4295 /************************************************************************ 4296 * RegReplaceKeyA 4297 * 4298 * @implemented 4299 */ 4300 LONG WINAPI 4301 RegReplaceKeyA(HKEY hKey, 4302 LPCSTR lpSubKey, 4303 LPCSTR lpNewFile, 4304 LPCSTR lpOldFile) 4305 { 4306 UNICODE_STRING SubKey; 4307 UNICODE_STRING NewFile; 4308 UNICODE_STRING OldFile; 4309 LONG ErrorCode; 4310 4311 RtlInitEmptyUnicodeString(&SubKey, NULL, 0); 4312 RtlInitEmptyUnicodeString(&OldFile, NULL, 0); 4313 RtlInitEmptyUnicodeString(&NewFile, NULL, 0); 4314 4315 if (lpSubKey) 4316 { 4317 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey)) 4318 { 4319 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4320 goto Exit; 4321 } 4322 } 4323 4324 if (lpOldFile) 4325 { 4326 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile)) 4327 { 4328 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4329 goto Exit; 4330 } 4331 } 4332 4333 if (lpNewFile) 4334 { 4335 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile)) 4336 { 4337 ErrorCode = ERROR_NOT_ENOUGH_MEMORY; 4338 goto Exit; 4339 } 4340 } 4341 4342 ErrorCode = RegReplaceKeyW(hKey, 4343 SubKey.Buffer, 4344 NewFile.Buffer, 4345 OldFile.Buffer); 4346 4347 Exit: 4348 RtlFreeUnicodeString(&OldFile); 4349 RtlFreeUnicodeString(&NewFile); 4350 RtlFreeUnicodeString(&SubKey); 4351 4352 return ErrorCode; 4353 } 4354 4355 4356 /************************************************************************ 4357 * RegReplaceKeyW 4358 * 4359 * @unimplemented 4360 */ 4361 LONG WINAPI 4362 RegReplaceKeyW(HKEY hKey, 4363 LPCWSTR lpSubKey, 4364 LPCWSTR lpNewFile, 4365 LPCWSTR lpOldFile) 4366 { 4367 OBJECT_ATTRIBUTES KeyObjectAttributes; 4368 OBJECT_ATTRIBUTES NewObjectAttributes; 4369 OBJECT_ATTRIBUTES OldObjectAttributes; 4370 UNICODE_STRING SubKeyName; 4371 UNICODE_STRING NewFileName; 4372 UNICODE_STRING OldFileName; 4373 BOOLEAN CloseRealKey; 4374 HANDLE RealKeyHandle; 4375 HANDLE KeyHandle; 4376 NTSTATUS Status; 4377 LONG ErrorCode = ERROR_SUCCESS; 4378 4379 if (hKey == HKEY_PERFORMANCE_DATA) 4380 { 4381 return ERROR_INVALID_HANDLE; 4382 } 4383 4384 Status = MapDefaultKey(&KeyHandle, 4385 hKey); 4386 if (!NT_SUCCESS(Status)) 4387 { 4388 return RtlNtStatusToDosError(Status); 4389 } 4390 4391 /* Open the real key */ 4392 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0) 4393 { 4394 RtlInitUnicodeString(&SubKeyName, lpSubKey); 4395 InitializeObjectAttributes(&KeyObjectAttributes, 4396 &SubKeyName, 4397 OBJ_CASE_INSENSITIVE, 4398 KeyHandle, 4399 NULL); 4400 Status = NtOpenKey(&RealKeyHandle, 4401 MAXIMUM_ALLOWED, 4402 &KeyObjectAttributes); 4403 if (!NT_SUCCESS(Status)) 4404 { 4405 ErrorCode = RtlNtStatusToDosError(Status); 4406 goto Cleanup; 4407 } 4408 4409 CloseRealKey = TRUE; 4410 } 4411 else 4412 { 4413 RealKeyHandle = KeyHandle; 4414 CloseRealKey = FALSE; 4415 } 4416 4417 /* Convert new file name */ 4418 if (!RtlDosPathNameToNtPathName_U(lpNewFile, 4419 &NewFileName, 4420 NULL, 4421 NULL)) 4422 { 4423 if (CloseRealKey) 4424 { 4425 NtClose(RealKeyHandle); 4426 } 4427 4428 ErrorCode = ERROR_INVALID_PARAMETER; 4429 goto Cleanup; 4430 } 4431 4432 InitializeObjectAttributes(&NewObjectAttributes, 4433 &NewFileName, 4434 OBJ_CASE_INSENSITIVE, 4435 NULL, 4436 NULL); 4437 4438 /* Convert old file name */ 4439 if (!RtlDosPathNameToNtPathName_U(lpOldFile, 4440 &OldFileName, 4441 NULL, 4442 NULL)) 4443 { 4444 RtlFreeHeap(RtlGetProcessHeap (), 4445 0, 4446 NewFileName.Buffer); 4447 if (CloseRealKey) 4448 { 4449 NtClose(RealKeyHandle); 4450 } 4451 4452 ErrorCode = ERROR_INVALID_PARAMETER; 4453 goto Cleanup; 4454 } 4455 4456 InitializeObjectAttributes(&OldObjectAttributes, 4457 &OldFileName, 4458 OBJ_CASE_INSENSITIVE, 4459 NULL, 4460 NULL); 4461 4462 Status = NtReplaceKey(&NewObjectAttributes, 4463 RealKeyHandle, 4464 &OldObjectAttributes); 4465 4466 RtlFreeHeap(RtlGetProcessHeap(), 4467 0, 4468 OldFileName.Buffer); 4469 RtlFreeHeap(RtlGetProcessHeap(), 4470 0, 4471 NewFileName.Buffer); 4472 4473 if (CloseRealKey) 4474 { 4475 NtClose(RealKeyHandle); 4476 } 4477 4478 if (!NT_SUCCESS(Status)) 4479 { 4480 return RtlNtStatusToDosError(Status); 4481 } 4482 4483 Cleanup: 4484 ClosePredefKey(KeyHandle); 4485 4486 return ErrorCode; 4487 } 4488 4489 4490 /************************************************************************ 4491 * RegRestoreKeyA 4492 * 4493 * @implemented 4494 */ 4495 LONG WINAPI 4496 RegRestoreKeyA(HKEY hKey, 4497 LPCSTR lpFile, 4498 DWORD dwFlags) 4499 { 4500 UNICODE_STRING FileName; 4501 LONG ErrorCode; 4502 4503 if (lpFile) 4504 { 4505 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4506 return ERROR_NOT_ENOUGH_MEMORY; 4507 } 4508 else 4509 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4510 4511 ErrorCode = RegRestoreKeyW(hKey, 4512 FileName.Buffer, 4513 dwFlags); 4514 4515 RtlFreeUnicodeString(&FileName); 4516 4517 return ErrorCode; 4518 } 4519 4520 4521 /************************************************************************ 4522 * RegRestoreKeyW 4523 * 4524 * @implemented 4525 */ 4526 LONG WINAPI 4527 RegRestoreKeyW(HKEY hKey, 4528 LPCWSTR lpFile, 4529 DWORD dwFlags) 4530 { 4531 OBJECT_ATTRIBUTES ObjectAttributes; 4532 IO_STATUS_BLOCK IoStatusBlock; 4533 UNICODE_STRING FileName; 4534 HANDLE FileHandle; 4535 HANDLE KeyHandle; 4536 NTSTATUS Status; 4537 4538 if (hKey == HKEY_PERFORMANCE_DATA) 4539 { 4540 return ERROR_INVALID_HANDLE; 4541 } 4542 4543 Status = MapDefaultKey(&KeyHandle, 4544 hKey); 4545 if (!NT_SUCCESS(Status)) 4546 { 4547 return RtlNtStatusToDosError(Status); 4548 } 4549 4550 if (!RtlDosPathNameToNtPathName_U(lpFile, 4551 &FileName, 4552 NULL, 4553 NULL)) 4554 { 4555 Status = STATUS_INVALID_PARAMETER; 4556 goto Cleanup; 4557 } 4558 4559 InitializeObjectAttributes(&ObjectAttributes, 4560 &FileName, 4561 OBJ_CASE_INSENSITIVE, 4562 NULL, 4563 NULL); 4564 4565 Status = NtOpenFile(&FileHandle, 4566 FILE_GENERIC_READ, 4567 &ObjectAttributes, 4568 &IoStatusBlock, 4569 FILE_SHARE_READ, 4570 FILE_SYNCHRONOUS_IO_NONALERT); 4571 RtlFreeHeap(RtlGetProcessHeap(), 4572 0, 4573 FileName.Buffer); 4574 if (!NT_SUCCESS(Status)) 4575 { 4576 goto Cleanup; 4577 } 4578 4579 Status = NtRestoreKey(KeyHandle, 4580 FileHandle, 4581 (ULONG)dwFlags); 4582 NtClose (FileHandle); 4583 4584 Cleanup: 4585 ClosePredefKey(KeyHandle); 4586 4587 if (!NT_SUCCESS(Status)) 4588 { 4589 return RtlNtStatusToDosError(Status); 4590 } 4591 4592 return ERROR_SUCCESS; 4593 } 4594 4595 4596 /************************************************************************ 4597 * RegSaveKeyA 4598 * 4599 * @implemented 4600 */ 4601 LONG WINAPI 4602 RegSaveKeyA(HKEY hKey, 4603 LPCSTR lpFile, 4604 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4605 { 4606 UNICODE_STRING FileName; 4607 LONG ErrorCode; 4608 4609 if (lpFile) 4610 { 4611 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4612 return ERROR_NOT_ENOUGH_MEMORY; 4613 } 4614 else 4615 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4616 4617 ErrorCode = RegSaveKeyW(hKey, 4618 FileName.Buffer, 4619 lpSecurityAttributes); 4620 RtlFreeUnicodeString(&FileName); 4621 4622 return ErrorCode; 4623 } 4624 4625 4626 /************************************************************************ 4627 * RegSaveKeyW 4628 * 4629 * @implemented 4630 */ 4631 LONG WINAPI 4632 RegSaveKeyW(HKEY hKey, 4633 LPCWSTR lpFile, 4634 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 4635 { 4636 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 4637 OBJECT_ATTRIBUTES ObjectAttributes; 4638 UNICODE_STRING FileName; 4639 IO_STATUS_BLOCK IoStatusBlock; 4640 HANDLE FileHandle; 4641 HANDLE KeyHandle; 4642 NTSTATUS Status; 4643 4644 Status = MapDefaultKey(&KeyHandle, 4645 hKey); 4646 if (!NT_SUCCESS(Status)) 4647 { 4648 return RtlNtStatusToDosError(Status); 4649 } 4650 4651 if (!RtlDosPathNameToNtPathName_U(lpFile, 4652 &FileName, 4653 NULL, 4654 NULL)) 4655 { 4656 Status = STATUS_INVALID_PARAMETER; 4657 goto Cleanup; 4658 } 4659 4660 if (lpSecurityAttributes != NULL) 4661 { 4662 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 4663 } 4664 4665 InitializeObjectAttributes(&ObjectAttributes, 4666 &FileName, 4667 OBJ_CASE_INSENSITIVE, 4668 NULL, 4669 SecurityDescriptor); 4670 Status = NtCreateFile(&FileHandle, 4671 GENERIC_WRITE | SYNCHRONIZE, 4672 &ObjectAttributes, 4673 &IoStatusBlock, 4674 NULL, 4675 FILE_ATTRIBUTE_NORMAL, 4676 FILE_SHARE_READ, 4677 FILE_CREATE, 4678 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 4679 NULL, 4680 0); 4681 RtlFreeHeap(RtlGetProcessHeap(), 4682 0, 4683 FileName.Buffer); 4684 if (!NT_SUCCESS(Status)) 4685 { 4686 goto Cleanup; 4687 } 4688 4689 Status = NtSaveKey(KeyHandle, 4690 FileHandle); 4691 NtClose (FileHandle); 4692 4693 Cleanup: 4694 ClosePredefKey(KeyHandle); 4695 4696 if (!NT_SUCCESS(Status)) 4697 { 4698 return RtlNtStatusToDosError(Status); 4699 } 4700 4701 return ERROR_SUCCESS; 4702 } 4703 4704 4705 /************************************************************************ 4706 * RegSaveKeyExA 4707 * 4708 * @implemented 4709 */ 4710 LONG 4711 WINAPI 4712 RegSaveKeyExA(HKEY hKey, 4713 LPCSTR lpFile, 4714 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4715 DWORD Flags) 4716 { 4717 UNICODE_STRING FileName; 4718 LONG ErrorCode; 4719 4720 if (lpFile) 4721 { 4722 if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile)) 4723 return ERROR_NOT_ENOUGH_MEMORY; 4724 } 4725 else 4726 RtlInitEmptyUnicodeString(&FileName, NULL, 0); 4727 4728 ErrorCode = RegSaveKeyExW(hKey, 4729 FileName.Buffer, 4730 lpSecurityAttributes, 4731 Flags); 4732 RtlFreeUnicodeString(&FileName); 4733 4734 return ErrorCode; 4735 } 4736 4737 4738 /************************************************************************ 4739 * RegSaveKeyExW 4740 * 4741 * @unimplemented 4742 */ 4743 LONG 4744 WINAPI 4745 RegSaveKeyExW(HKEY hKey, 4746 LPCWSTR lpFile, 4747 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 4748 DWORD Flags) 4749 { 4750 switch (Flags) 4751 { 4752 case REG_STANDARD_FORMAT: 4753 case REG_LATEST_FORMAT: 4754 case REG_NO_COMPRESSION: 4755 break; 4756 default: 4757 return ERROR_INVALID_PARAMETER; 4758 } 4759 4760 FIXME("RegSaveKeyExW(): Flags ignored!\n"); 4761 4762 return RegSaveKeyW(hKey, 4763 lpFile, 4764 lpSecurityAttributes); 4765 } 4766 4767 4768 /************************************************************************ 4769 * RegSetKeySecurity 4770 * 4771 * @implemented 4772 */ 4773 LONG WINAPI 4774 RegSetKeySecurity(HKEY hKey, 4775 SECURITY_INFORMATION SecurityInformation, 4776 PSECURITY_DESCRIPTOR pSecurityDescriptor) 4777 { 4778 HANDLE KeyHandle; 4779 NTSTATUS Status; 4780 4781 if (hKey == HKEY_PERFORMANCE_DATA) 4782 { 4783 return ERROR_INVALID_HANDLE; 4784 } 4785 4786 Status = MapDefaultKey(&KeyHandle, 4787 hKey); 4788 if (!NT_SUCCESS(Status)) 4789 { 4790 return RtlNtStatusToDosError(Status); 4791 } 4792 4793 Status = NtSetSecurityObject(KeyHandle, 4794 SecurityInformation, 4795 pSecurityDescriptor); 4796 4797 ClosePredefKey(KeyHandle); 4798 4799 if (!NT_SUCCESS(Status)) 4800 { 4801 return RtlNtStatusToDosError(Status); 4802 } 4803 4804 return ERROR_SUCCESS; 4805 } 4806 4807 4808 /************************************************************************ 4809 * RegSetValueExA 4810 * 4811 * @implemented 4812 */ 4813 LONG WINAPI 4814 RegSetValueExA(HKEY hKey, 4815 LPCSTR lpValueName, 4816 DWORD Reserved, 4817 DWORD dwType, 4818 CONST BYTE* lpData, 4819 DWORD cbData) 4820 { 4821 UNICODE_STRING ValueName; 4822 LPWSTR pValueName; 4823 ANSI_STRING AnsiString; 4824 UNICODE_STRING Data; 4825 LONG ErrorCode; 4826 LPBYTE pData; 4827 DWORD DataSize; 4828 NTSTATUS Status; 4829 4830 /* Convert SubKey name to Unicode */ 4831 if (lpValueName != NULL && lpValueName[0] != '\0') 4832 { 4833 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, lpValueName)) 4834 return ERROR_NOT_ENOUGH_MEMORY; 4835 } 4836 else 4837 { 4838 ValueName.Buffer = NULL; 4839 } 4840 4841 pValueName = (LPWSTR)ValueName.Buffer; 4842 4843 4844 if (is_string(dwType) && (cbData != 0)) 4845 { 4846 /* Convert ANSI string Data to Unicode */ 4847 /* If last character NOT zero then increment length */ 4848 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0); 4849 AnsiString.Buffer = (PSTR)lpData; 4850 AnsiString.Length = cbData + bNoNulledStr; 4851 AnsiString.MaximumLength = cbData + bNoNulledStr; 4852 Status = RtlAnsiStringToUnicodeString(&Data, 4853 &AnsiString, 4854 TRUE); 4855 4856 if (!NT_SUCCESS(Status)) 4857 { 4858 if (pValueName != NULL) 4859 RtlFreeUnicodeString(&ValueName); 4860 4861 return RtlNtStatusToDosError(Status); 4862 } 4863 pData = (LPBYTE)Data.Buffer; 4864 DataSize = cbData * sizeof(WCHAR); 4865 } 4866 else 4867 { 4868 Data.Buffer = NULL; 4869 pData = (LPBYTE)lpData; 4870 DataSize = cbData; 4871 } 4872 4873 ErrorCode = RegSetValueExW(hKey, 4874 pValueName, 4875 Reserved, 4876 dwType, 4877 pData, 4878 DataSize); 4879 4880 if (pValueName != NULL) 4881 RtlFreeUnicodeString(&ValueName); 4882 4883 if (Data.Buffer != NULL) 4884 RtlFreeUnicodeString(&Data); 4885 4886 return ErrorCode; 4887 } 4888 4889 4890 /************************************************************************ 4891 * RegSetValueExW 4892 * 4893 * @implemented 4894 */ 4895 LONG 4896 WINAPI 4897 RegSetValueExW( 4898 _In_ HKEY hKey, 4899 _In_ LPCWSTR lpValueName, 4900 _In_ DWORD Reserved, 4901 _In_ DWORD dwType, 4902 _In_ CONST BYTE* lpData, 4903 _In_ DWORD cbData) 4904 { 4905 UNICODE_STRING ValueName; 4906 HANDLE KeyHandle; 4907 NTSTATUS Status; 4908 4909 Status = MapDefaultKey(&KeyHandle, 4910 hKey); 4911 if (!NT_SUCCESS(Status)) 4912 { 4913 return RtlNtStatusToDosError(Status); 4914 } 4915 4916 if (IsHKCRKey(KeyHandle)) 4917 { 4918 LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData); 4919 ClosePredefKey(KeyHandle); 4920 return ErrorCode; 4921 } 4922 4923 if (is_string(dwType) && (cbData != 0)) 4924 { 4925 PWSTR pwsData = (PWSTR)lpData; 4926 4927 _SEH2_TRY 4928 { 4929 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') && 4930 (pwsData[cbData / sizeof(WCHAR)] == L'\0')) 4931 { 4932 /* Increment length if last character is not zero and next is zero */ 4933 cbData += sizeof(WCHAR); 4934 } 4935 } 4936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4937 { 4938 /* Do not fail if we fault where we were told not to go */ 4939 } 4940 _SEH2_END; 4941 } 4942 4943 RtlInitUnicodeString(&ValueName, lpValueName); 4944 4945 Status = NtSetValueKey(KeyHandle, 4946 &ValueName, 4947 0, 4948 dwType, 4949 (PVOID)lpData, 4950 (ULONG)cbData); 4951 4952 ClosePredefKey(KeyHandle); 4953 4954 if (!NT_SUCCESS(Status)) 4955 { 4956 return RtlNtStatusToDosError(Status); 4957 } 4958 4959 return ERROR_SUCCESS; 4960 } 4961 4962 4963 /************************************************************************ 4964 * RegSetValueA 4965 * 4966 * @implemented 4967 */ 4968 LONG WINAPI 4969 RegSetValueA(HKEY hKeyOriginal, 4970 LPCSTR lpSubKey, 4971 DWORD dwType, 4972 LPCSTR lpData, 4973 DWORD cbData) 4974 { 4975 HKEY subkey; 4976 HANDLE hKey; 4977 DWORD ret; 4978 NTSTATUS Status; 4979 4980 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData ); 4981 4982 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER; 4983 4984 Status = MapDefaultKey(&hKey, hKeyOriginal); 4985 if (!NT_SUCCESS(Status)) 4986 { 4987 return RtlNtStatusToDosError (Status); 4988 } 4989 subkey = hKey; 4990 4991 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 4992 { 4993 ret = RegCreateKeyA(hKey, lpSubKey, &subkey); 4994 if (ret != ERROR_SUCCESS) 4995 goto Cleanup; 4996 } 4997 4998 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 ); 4999 if (subkey != hKey) 5000 RegCloseKey(subkey); 5001 5002 Cleanup: 5003 ClosePredefKey(hKey); 5004 5005 return ret; 5006 } 5007 5008 5009 /************************************************************************ 5010 * RegSetValueW 5011 * 5012 * @implemented 5013 */ 5014 LONG WINAPI 5015 RegSetValueW(HKEY hKeyOriginal, 5016 LPCWSTR lpSubKey, 5017 DWORD dwType, 5018 LPCWSTR lpData, 5019 DWORD cbData) 5020 { 5021 HKEY subkey; 5022 HANDLE hKey; 5023 DWORD ret; 5024 NTSTATUS Status; 5025 5026 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData ); 5027 5028 if (dwType != REG_SZ || !lpData) 5029 return ERROR_INVALID_PARAMETER; 5030 5031 Status = MapDefaultKey(&hKey, 5032 hKeyOriginal); 5033 if (!NT_SUCCESS(Status)) 5034 { 5035 return RtlNtStatusToDosError(Status); 5036 } 5037 subkey = hKey; 5038 5039 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 5040 { 5041 ret = RegCreateKeyW(hKey, lpSubKey, &subkey); 5042 if (ret != ERROR_SUCCESS) 5043 goto Cleanup; 5044 } 5045 5046 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, 5047 (wcslen( lpData ) + 1) * sizeof(WCHAR) ); 5048 if (subkey != hKey) 5049 RegCloseKey(subkey); 5050 5051 Cleanup: 5052 ClosePredefKey(hKey); 5053 5054 return ret; 5055 } 5056 5057 5058 /************************************************************************ 5059 * RegUnLoadKeyA 5060 * 5061 * @implemented 5062 */ 5063 LONG WINAPI 5064 RegUnLoadKeyA(HKEY hKey, 5065 LPCSTR lpSubKey) 5066 { 5067 UNICODE_STRING KeyName; 5068 DWORD ErrorCode; 5069 5070 if (lpSubKey) 5071 { 5072 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey)) 5073 return ERROR_NOT_ENOUGH_MEMORY; 5074 } 5075 else 5076 RtlInitEmptyUnicodeString(&KeyName, NULL, 0); 5077 5078 ErrorCode = RegUnLoadKeyW(hKey, 5079 KeyName.Buffer); 5080 5081 RtlFreeUnicodeString (&KeyName); 5082 5083 return ErrorCode; 5084 } 5085 5086 5087 /************************************************************************ 5088 * RegUnLoadKeyW 5089 * 5090 * @implemented 5091 */ 5092 LONG WINAPI 5093 RegUnLoadKeyW(HKEY hKey, 5094 LPCWSTR lpSubKey) 5095 { 5096 OBJECT_ATTRIBUTES ObjectAttributes; 5097 UNICODE_STRING KeyName; 5098 HANDLE KeyHandle; 5099 NTSTATUS Status; 5100 5101 if (hKey == HKEY_PERFORMANCE_DATA) 5102 { 5103 return ERROR_INVALID_HANDLE; 5104 } 5105 5106 Status = MapDefaultKey(&KeyHandle, hKey); 5107 if (!NT_SUCCESS(Status)) 5108 { 5109 return RtlNtStatusToDosError(Status); 5110 } 5111 5112 RtlInitUnicodeString(&KeyName, lpSubKey); 5113 5114 InitializeObjectAttributes(&ObjectAttributes, 5115 &KeyName, 5116 OBJ_CASE_INSENSITIVE, 5117 KeyHandle, 5118 NULL); 5119 5120 Status = NtUnloadKey(&ObjectAttributes); 5121 5122 ClosePredefKey(KeyHandle); 5123 5124 if (!NT_SUCCESS(Status)) 5125 { 5126 return RtlNtStatusToDosError(Status); 5127 } 5128 5129 return ERROR_SUCCESS; 5130 } 5131 5132 /* EOF */ 5133