Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenreg.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS system libraries 00004 * FILE: lib/advapi32/reg/reg.c 00005 * PURPOSE: Registry functions 00006 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) 00007 * Thomas Weidenmueller <w3seek@reactos.com> 00008 * UPDATE HISTORY: 00009 * Created 01/11/98 00010 * 19990309 EA Stubs 00011 * 20050502 Fireball imported some stuff from WINE 00012 */ 00013 00014 /* INCLUDES *****************************************************************/ 00015 00016 #include <advapi32.h> 00017 WINE_DEFAULT_DEBUG_CHANNEL(reg); 00018 00019 /* DEFINES ******************************************************************/ 00020 00021 #define MAX_DEFAULT_HANDLES 6 00022 #define REG_MAX_NAME_SIZE 256 00023 #define REG_MAX_DATA_SIZE 2048 00024 00025 /* GLOBALS ******************************************************************/ 00026 00027 static RTL_CRITICAL_SECTION HandleTableCS; 00028 static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES]; 00029 static HANDLE ProcessHeap; 00030 static BOOLEAN DefaultHandlesDisabled = FALSE; 00031 static BOOLEAN DefaultHandleHKUDisabled = FALSE; 00032 static BOOLEAN DllInitialized = FALSE; /* HACK */ 00033 00034 /* PROTOTYPES ***************************************************************/ 00035 00036 static NTSTATUS MapDefaultKey (PHANDLE ParentKey, HKEY Key); 00037 static VOID CloseDefaultKeys(VOID); 00038 #define ClosePredefKey(Handle) \ 00039 if ((ULONG_PTR)Handle & 0x1) { \ 00040 NtClose(Handle); \ 00041 } 00042 #define IsPredefKey(HKey) \ 00043 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000) 00044 #define GetPredefKeyIndex(HKey) \ 00045 ((ULONG_PTR)(HKey) & 0x0FFFFFFF) 00046 00047 static NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle); 00048 static NTSTATUS OpenLocalMachineKey (PHANDLE KeyHandle); 00049 static NTSTATUS OpenUsersKey (PHANDLE KeyHandle); 00050 static NTSTATUS OpenCurrentConfigKey(PHANDLE KeyHandle); 00051 00052 00053 /* FUNCTIONS ****************************************************************/ 00054 /* check if value type needs string conversion (Ansi<->Unicode) */ 00055 __inline static int is_string( DWORD type ) 00056 { 00057 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); 00058 } 00059 00060 /************************************************************************ 00061 * RegInitDefaultHandles 00062 */ 00063 BOOL 00064 RegInitialize(VOID) 00065 { 00066 TRACE("RegInitialize()\n"); 00067 00068 /* Lazy init hack */ 00069 if (!DllInitialized) 00070 { 00071 ProcessHeap = RtlGetProcessHeap(); 00072 RtlZeroMemory(DefaultHandleTable, 00073 MAX_DEFAULT_HANDLES * sizeof(HANDLE)); 00074 RtlInitializeCriticalSection(&HandleTableCS); 00075 00076 DllInitialized = TRUE; 00077 } 00078 00079 return TRUE; 00080 } 00081 00082 00083 /************************************************************************ 00084 * RegInit 00085 */ 00086 BOOL 00087 RegCleanup(VOID) 00088 { 00089 TRACE("RegCleanup()\n"); 00090 00091 CloseDefaultKeys(); 00092 RtlDeleteCriticalSection(&HandleTableCS); 00093 00094 return TRUE; 00095 } 00096 00097 00098 static NTSTATUS 00099 OpenPredefinedKey(IN ULONG Index, 00100 OUT HANDLE Handle) 00101 { 00102 NTSTATUS Status; 00103 00104 switch (Index) 00105 { 00106 case 0: /* HKEY_CLASSES_ROOT */ 00107 Status = OpenClassesRootKey (Handle); 00108 break; 00109 00110 case 1: /* HKEY_CURRENT_USER */ 00111 Status = RtlOpenCurrentUser (MAXIMUM_ALLOWED, 00112 Handle); 00113 break; 00114 00115 case 2: /* HKEY_LOCAL_MACHINE */ 00116 Status = OpenLocalMachineKey (Handle); 00117 break; 00118 00119 case 3: /* HKEY_USERS */ 00120 Status = OpenUsersKey (Handle); 00121 break; 00122 #if 0 00123 case 4: /* HKEY_PERFORMANCE_DATA */ 00124 Status = OpenPerformanceDataKey (Handle); 00125 break; 00126 #endif 00127 00128 case 5: /* HKEY_CURRENT_CONFIG */ 00129 Status = OpenCurrentConfigKey (Handle); 00130 break; 00131 00132 case 6: /* HKEY_DYN_DATA */ 00133 Status = STATUS_NOT_IMPLEMENTED; 00134 break; 00135 00136 default: 00137 WARN("MapDefaultHandle() no handle creator\n"); 00138 Status = STATUS_INVALID_PARAMETER; 00139 break; 00140 } 00141 00142 return Status; 00143 } 00144 00145 00146 static NTSTATUS 00147 MapDefaultKey(OUT PHANDLE RealKey, 00148 IN HKEY Key) 00149 { 00150 PHANDLE Handle; 00151 ULONG Index; 00152 BOOLEAN DoOpen, DefDisabled; 00153 NTSTATUS Status = STATUS_SUCCESS; 00154 00155 TRACE("MapDefaultKey (Key %x)\n", Key); 00156 00157 if (!IsPredefKey(Key)) 00158 { 00159 *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1); 00160 return STATUS_SUCCESS; 00161 } 00162 00163 /* Handle special cases here */ 00164 Index = GetPredefKeyIndex(Key); 00165 if (Index >= MAX_DEFAULT_HANDLES) 00166 { 00167 return STATUS_INVALID_PARAMETER; 00168 } 00169 RegInitialize(); /* HACK until delay-loading is implemented */ 00170 RtlEnterCriticalSection (&HandleTableCS); 00171 00172 if (Key == HKEY_CURRENT_USER) 00173 DefDisabled = DefaultHandleHKUDisabled; 00174 else 00175 DefDisabled = DefaultHandlesDisabled; 00176 00177 if (!DefDisabled) 00178 { 00179 Handle = &DefaultHandleTable[Index]; 00180 DoOpen = (*Handle == NULL); 00181 } 00182 else 00183 { 00184 Handle = RealKey; 00185 DoOpen = TRUE; 00186 } 00187 00188 if (DoOpen) 00189 { 00190 /* create/open the default handle */ 00191 Status = OpenPredefinedKey(Index, 00192 Handle); 00193 } 00194 00195 if (NT_SUCCESS(Status)) 00196 { 00197 if (!DefDisabled) 00198 *RealKey = *Handle; 00199 else 00200 *(PULONG_PTR)Handle |= 0x1; 00201 } 00202 00203 RtlLeaveCriticalSection (&HandleTableCS); 00204 00205 return Status; 00206 } 00207 00208 00209 static VOID 00210 CloseDefaultKeys(VOID) 00211 { 00212 ULONG i; 00213 RegInitialize(); /* HACK until delay-loading is implemented */ 00214 RtlEnterCriticalSection(&HandleTableCS); 00215 00216 for (i = 0; i < MAX_DEFAULT_HANDLES; i++) 00217 { 00218 if (DefaultHandleTable[i] != NULL) 00219 { 00220 NtClose(DefaultHandleTable[i]); 00221 DefaultHandleTable[i] = NULL; 00222 } 00223 } 00224 00225 RtlLeaveCriticalSection(&HandleTableCS); 00226 } 00227 00228 00229 static NTSTATUS 00230 OpenClassesRootKey(PHANDLE KeyHandle) 00231 { 00232 OBJECT_ATTRIBUTES Attributes; 00233 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES"); 00234 00235 TRACE("OpenClassesRootKey()\n"); 00236 00237 InitializeObjectAttributes(&Attributes, 00238 &KeyName, 00239 OBJ_CASE_INSENSITIVE, 00240 NULL, 00241 NULL); 00242 return NtOpenKey(KeyHandle, 00243 MAXIMUM_ALLOWED, 00244 &Attributes); 00245 } 00246 00247 00248 static NTSTATUS 00249 OpenLocalMachineKey(PHANDLE KeyHandle) 00250 { 00251 OBJECT_ATTRIBUTES Attributes; 00252 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine"); 00253 NTSTATUS Status; 00254 00255 TRACE("OpenLocalMachineKey()\n"); 00256 00257 InitializeObjectAttributes(&Attributes, 00258 &KeyName, 00259 OBJ_CASE_INSENSITIVE, 00260 NULL, 00261 NULL); 00262 Status = NtOpenKey(KeyHandle, 00263 MAXIMUM_ALLOWED, 00264 &Attributes); 00265 00266 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName, Status); 00267 00268 return Status; 00269 } 00270 00271 00272 static NTSTATUS 00273 OpenUsersKey(PHANDLE KeyHandle) 00274 { 00275 OBJECT_ATTRIBUTES Attributes; 00276 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\User"); 00277 00278 TRACE("OpenUsersKey()\n"); 00279 00280 InitializeObjectAttributes(&Attributes, 00281 &KeyName, 00282 OBJ_CASE_INSENSITIVE, 00283 NULL, 00284 NULL); 00285 return NtOpenKey(KeyHandle, 00286 MAXIMUM_ALLOWED, 00287 &Attributes); 00288 } 00289 00290 00291 static NTSTATUS 00292 OpenCurrentConfigKey (PHANDLE KeyHandle) 00293 { 00294 OBJECT_ATTRIBUTES Attributes; 00295 UNICODE_STRING KeyName = 00296 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current"); 00297 00298 TRACE("OpenCurrentConfigKey()\n"); 00299 00300 InitializeObjectAttributes(&Attributes, 00301 &KeyName, 00302 OBJ_CASE_INSENSITIVE, 00303 NULL, 00304 NULL); 00305 return NtOpenKey(KeyHandle, 00306 MAXIMUM_ALLOWED, 00307 &Attributes); 00308 } 00309 00310 00311 /************************************************************************ 00312 * RegDisablePredefinedCache 00313 * 00314 * @implemented 00315 */ 00316 LONG WINAPI 00317 RegDisablePredefinedCache(VOID) 00318 { 00319 RegInitialize(); /* HACK until delay-loading is implemented */ 00320 RtlEnterCriticalSection(&HandleTableCS); 00321 DefaultHandleHKUDisabled = TRUE; 00322 RtlLeaveCriticalSection(&HandleTableCS); 00323 return ERROR_SUCCESS; 00324 } 00325 00326 00327 /************************************************************************ 00328 * RegDisablePredefinedCacheEx 00329 * 00330 * @implemented 00331 */ 00332 LONG WINAPI 00333 RegDisablePredefinedCacheEx(VOID) 00334 { 00335 RegInitialize(); /* HACK until delay-loading is implemented */ 00336 RtlEnterCriticalSection(&HandleTableCS); 00337 DefaultHandlesDisabled = TRUE; 00338 DefaultHandleHKUDisabled = TRUE; 00339 RtlLeaveCriticalSection(&HandleTableCS); 00340 return ERROR_SUCCESS; 00341 } 00342 00343 00344 /************************************************************************ 00345 * RegOverridePredefKey 00346 * 00347 * @implemented 00348 */ 00349 LONG WINAPI 00350 RegOverridePredefKey(IN HKEY hKey, 00351 IN HKEY hNewHKey OPTIONAL) 00352 { 00353 LONG ErrorCode = ERROR_SUCCESS; 00354 00355 if ((hKey == HKEY_CLASSES_ROOT || 00356 hKey == HKEY_CURRENT_CONFIG || 00357 hKey == HKEY_CURRENT_USER || 00358 hKey == HKEY_LOCAL_MACHINE || 00359 hKey == HKEY_PERFORMANCE_DATA || 00360 hKey == HKEY_USERS) && 00361 !IsPredefKey(hNewHKey)) 00362 { 00363 PHANDLE Handle; 00364 ULONG Index; 00365 00366 Index = GetPredefKeyIndex(hKey); 00367 Handle = &DefaultHandleTable[Index]; 00368 00369 if (hNewHKey == NULL) 00370 { 00371 /* restore the default mapping */ 00372 NTSTATUS Status = OpenPredefinedKey(Index, 00373 &hNewHKey); 00374 if (!NT_SUCCESS(Status)) 00375 { 00376 return RtlNtStatusToDosError(Status); 00377 } 00378 00379 ASSERT(hNewHKey != NULL); 00380 } 00381 RegInitialize(); /* HACK until delay-loading is implemented */ 00382 RtlEnterCriticalSection(&HandleTableCS); 00383 00384 /* close the currently mapped handle if existing */ 00385 if (*Handle != NULL) 00386 { 00387 NtClose(*Handle); 00388 } 00389 00390 /* update the mapping */ 00391 *Handle = hNewHKey; 00392 00393 RtlLeaveCriticalSection(&HandleTableCS); 00394 } 00395 else 00396 ErrorCode = ERROR_INVALID_HANDLE; 00397 00398 return ErrorCode; 00399 } 00400 00401 00402 /************************************************************************ 00403 * RegCloseKey 00404 * 00405 * @implemented 00406 */ 00407 LONG WINAPI 00408 RegCloseKey(HKEY hKey) 00409 { 00410 NTSTATUS Status; 00411 00412 /* don't close null handle or a pseudo handle */ 00413 if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)) 00414 { 00415 return ERROR_INVALID_HANDLE; 00416 } 00417 00418 Status = NtClose(hKey); 00419 if (!NT_SUCCESS(Status)) 00420 { 00421 return RtlNtStatusToDosError(Status); 00422 } 00423 00424 return ERROR_SUCCESS; 00425 } 00426 00427 00428 static NTSTATUS 00429 RegpCopyTree(IN HKEY hKeySrc, 00430 IN HKEY hKeyDest) 00431 { 00432 typedef struct 00433 { 00434 LIST_ENTRY ListEntry; 00435 HANDLE hKeySrc; 00436 HANDLE hKeyDest; 00437 } REGP_COPY_KEYS, *PREGP_COPY_KEYS; 00438 00439 LIST_ENTRY copyQueueHead; 00440 PREGP_COPY_KEYS copyKeys, newCopyKeys; 00441 union 00442 { 00443 KEY_VALUE_FULL_INFORMATION *KeyValue; 00444 KEY_NODE_INFORMATION *KeyNode; 00445 PVOID Buffer; 00446 } Info; 00447 ULONG Index, BufferSizeRequired, BufferSize = 0x200; 00448 NTSTATUS Status = STATUS_SUCCESS; 00449 NTSTATUS Status2 = STATUS_SUCCESS; 00450 00451 InitializeListHead(©QueueHead); 00452 00453 Info.Buffer = RtlAllocateHeap(ProcessHeap, 00454 0, 00455 BufferSize); 00456 if (Info.Buffer == NULL) 00457 { 00458 return STATUS_INSUFFICIENT_RESOURCES; 00459 } 00460 00461 copyKeys = RtlAllocateHeap(ProcessHeap, 00462 0, 00463 sizeof(REGP_COPY_KEYS)); 00464 if (copyKeys != NULL) 00465 { 00466 copyKeys->hKeySrc = hKeySrc; 00467 copyKeys->hKeyDest = hKeyDest; 00468 InsertHeadList(©QueueHead, 00469 ©Keys->ListEntry); 00470 00471 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */ 00472 00473 do 00474 { 00475 copyKeys = CONTAINING_RECORD(copyQueueHead.Flink, 00476 REGP_COPY_KEYS, 00477 ListEntry); 00478 00479 /* enumerate all values and copy them */ 00480 Index = 0; 00481 for (;;) 00482 { 00483 Status2 = NtEnumerateValueKey(copyKeys->hKeySrc, 00484 Index, 00485 KeyValueFullInformation, 00486 Info.KeyValue, 00487 BufferSize, 00488 &BufferSizeRequired); 00489 if (NT_SUCCESS(Status2)) 00490 { 00491 UNICODE_STRING ValueName; 00492 PVOID Data; 00493 00494 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 00495 ValueName.Length = Info.KeyValue->NameLength; 00496 ValueName.MaximumLength = ValueName.Length; 00497 ValueName.Buffer = Info.KeyValue->Name; 00498 00499 Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset); 00500 00501 Status2 = NtSetValueKey(copyKeys->hKeyDest, 00502 &ValueName, 00503 Info.KeyValue->TitleIndex, 00504 Info.KeyValue->Type, 00505 Data, 00506 Info.KeyValue->DataLength); 00507 00508 /* don't break, let's try to copy as many values as possible */ 00509 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status)) 00510 { 00511 Status = Status2; 00512 } 00513 00514 Index++; 00515 } 00516 else if (Status2 == STATUS_BUFFER_OVERFLOW) 00517 { 00518 PVOID Buffer; 00519 00520 ASSERT(BufferSize < BufferSizeRequired); 00521 00522 Buffer = RtlReAllocateHeap(ProcessHeap, 00523 0, 00524 Info.Buffer, 00525 BufferSizeRequired); 00526 if (Buffer != NULL) 00527 { 00528 Info.Buffer = Buffer; 00529 /* try again */ 00530 } 00531 else 00532 { 00533 /* don't break, let's try to copy as many values as possible */ 00534 Status2 = STATUS_INSUFFICIENT_RESOURCES; 00535 Index++; 00536 00537 if (NT_SUCCESS(Status)) 00538 { 00539 Status = Status2; 00540 } 00541 } 00542 } 00543 else 00544 { 00545 /* break to avoid an infinite loop in case of denied access or 00546 other errors! */ 00547 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status)) 00548 { 00549 Status = Status2; 00550 } 00551 00552 break; 00553 } 00554 } 00555 00556 /* enumerate all subkeys and open and enqueue them */ 00557 Index = 0; 00558 for (;;) 00559 { 00560 Status2 = NtEnumerateKey(copyKeys->hKeySrc, 00561 Index, 00562 KeyNodeInformation, 00563 Info.KeyNode, 00564 BufferSize, 00565 &BufferSizeRequired); 00566 if (NT_SUCCESS(Status2)) 00567 { 00568 HANDLE KeyHandle, NewKeyHandle; 00569 OBJECT_ATTRIBUTES ObjectAttributes; 00570 UNICODE_STRING SubKeyName, ClassName; 00571 00572 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 00573 SubKeyName.Length = Info.KeyNode->NameLength; 00574 SubKeyName.MaximumLength = SubKeyName.Length; 00575 SubKeyName.Buffer = Info.KeyNode->Name; 00576 ClassName.Length = Info.KeyNode->ClassLength; 00577 ClassName.MaximumLength = ClassName.Length; 00578 ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset); 00579 00580 /* open the subkey with sufficient rights */ 00581 00582 InitializeObjectAttributes(&ObjectAttributes, 00583 &SubKeyName, 00584 OBJ_CASE_INSENSITIVE, 00585 copyKeys->hKeySrc, 00586 NULL); 00587 00588 Status2 = NtOpenKey(&KeyHandle, 00589 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, 00590 &ObjectAttributes); 00591 if (NT_SUCCESS(Status2)) 00592 { 00593 /* FIXME - attempt to query the security information */ 00594 00595 InitializeObjectAttributes(&ObjectAttributes, 00596 &SubKeyName, 00597 OBJ_CASE_INSENSITIVE, 00598 copyKeys->hKeyDest, 00599 NULL); 00600 00601 Status2 = NtCreateKey(&NewKeyHandle, 00602 KEY_ALL_ACCESS, 00603 &ObjectAttributes, 00604 Info.KeyNode->TitleIndex, 00605 &ClassName, 00606 0, 00607 NULL); 00608 if (NT_SUCCESS(Status2)) 00609 { 00610 newCopyKeys = RtlAllocateHeap(ProcessHeap, 00611 0, 00612 sizeof(REGP_COPY_KEYS)); 00613 if (newCopyKeys != NULL) 00614 { 00615 /* save the handles and enqueue the subkey */ 00616 newCopyKeys->hKeySrc = KeyHandle; 00617 newCopyKeys->hKeyDest = NewKeyHandle; 00618 InsertTailList(©QueueHead, 00619 &newCopyKeys->ListEntry); 00620 } 00621 else 00622 { 00623 NtClose(KeyHandle); 00624 NtClose(NewKeyHandle); 00625 00626 Status2 = STATUS_INSUFFICIENT_RESOURCES; 00627 } 00628 } 00629 else 00630 { 00631 NtClose(KeyHandle); 00632 } 00633 } 00634 00635 if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status)) 00636 { 00637 Status = Status2; 00638 } 00639 00640 Index++; 00641 } 00642 else if (Status2 == STATUS_BUFFER_OVERFLOW) 00643 { 00644 PVOID Buffer; 00645 00646 ASSERT(BufferSize < BufferSizeRequired); 00647 00648 Buffer = RtlReAllocateHeap(ProcessHeap, 00649 0, 00650 Info.Buffer, 00651 BufferSizeRequired); 00652 if (Buffer != NULL) 00653 { 00654 Info.Buffer = Buffer; 00655 /* try again */ 00656 } 00657 else 00658 { 00659 /* don't break, let's try to copy as many keys as possible */ 00660 Status2 = STATUS_INSUFFICIENT_RESOURCES; 00661 Index++; 00662 00663 if (NT_SUCCESS(Status)) 00664 { 00665 Status = Status2; 00666 } 00667 } 00668 } 00669 else 00670 { 00671 /* break to avoid an infinite loop in case of denied access or 00672 other errors! */ 00673 if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status)) 00674 { 00675 Status = Status2; 00676 } 00677 00678 break; 00679 } 00680 } 00681 00682 /* close the handles and remove the entry from the list */ 00683 if (copyKeys->hKeySrc != hKeySrc) 00684 { 00685 NtClose(copyKeys->hKeySrc); 00686 } 00687 if (copyKeys->hKeyDest != hKeyDest) 00688 { 00689 NtClose(copyKeys->hKeyDest); 00690 } 00691 00692 RemoveEntryList(©Keys->ListEntry); 00693 00694 RtlFreeHeap(ProcessHeap, 00695 0, 00696 copyKeys); 00697 } while (!IsListEmpty(©QueueHead)); 00698 } 00699 else 00700 Status = STATUS_INSUFFICIENT_RESOURCES; 00701 00702 RtlFreeHeap(ProcessHeap, 00703 0, 00704 Info.Buffer); 00705 00706 return Status; 00707 } 00708 00709 00710 /************************************************************************ 00711 * RegCopyTreeW 00712 * 00713 * @implemented 00714 */ 00715 LONG WINAPI 00716 RegCopyTreeW(IN HKEY hKeySrc, 00717 IN LPCWSTR lpSubKey OPTIONAL, 00718 IN HKEY hKeyDest) 00719 { 00720 HANDLE DestKeyHandle, KeyHandle, CurKey, SubKeyHandle = NULL; 00721 NTSTATUS Status; 00722 00723 Status = MapDefaultKey(&KeyHandle, 00724 hKeySrc); 00725 if (!NT_SUCCESS(Status)) 00726 { 00727 return RtlNtStatusToDosError(Status); 00728 } 00729 00730 Status = MapDefaultKey(&DestKeyHandle, 00731 hKeyDest); 00732 if (!NT_SUCCESS(Status)) 00733 { 00734 goto Cleanup2; 00735 } 00736 00737 if (lpSubKey != NULL) 00738 { 00739 OBJECT_ATTRIBUTES ObjectAttributes; 00740 UNICODE_STRING SubKeyName; 00741 00742 RtlInitUnicodeString(&SubKeyName, 00743 (LPWSTR)lpSubKey); 00744 00745 InitializeObjectAttributes(&ObjectAttributes, 00746 &SubKeyName, 00747 OBJ_CASE_INSENSITIVE, 00748 KeyHandle, 00749 NULL); 00750 00751 Status = NtOpenKey(&SubKeyHandle, 00752 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, 00753 &ObjectAttributes); 00754 if (!NT_SUCCESS(Status)) 00755 { 00756 goto Cleanup; 00757 } 00758 00759 CurKey = SubKeyHandle; 00760 } 00761 else 00762 CurKey = KeyHandle; 00763 00764 Status = RegpCopyTree(CurKey, 00765 hKeyDest); 00766 00767 if (SubKeyHandle != NULL) 00768 { 00769 NtClose(SubKeyHandle); 00770 } 00771 00772 Cleanup: 00773 ClosePredefKey(DestKeyHandle); 00774 Cleanup2: 00775 ClosePredefKey(KeyHandle); 00776 00777 if (!NT_SUCCESS(Status)) 00778 { 00779 return RtlNtStatusToDosError(Status); 00780 } 00781 00782 return ERROR_SUCCESS; 00783 } 00784 00785 00786 /************************************************************************ 00787 * RegCopyTreeA 00788 * 00789 * @implemented 00790 */ 00791 LONG WINAPI 00792 RegCopyTreeA(IN HKEY hKeySrc, 00793 IN LPCSTR lpSubKey OPTIONAL, 00794 IN HKEY hKeyDest) 00795 { 00796 UNICODE_STRING SubKeyName = { 0, 0, NULL }; 00797 LONG Ret; 00798 00799 if (lpSubKey != NULL && 00800 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, 00801 (LPSTR)lpSubKey)) 00802 { 00803 return ERROR_NOT_ENOUGH_MEMORY; 00804 } 00805 00806 Ret = RegCopyTreeW(hKeySrc, 00807 SubKeyName.Buffer, 00808 hKeyDest); 00809 00810 RtlFreeUnicodeString(&SubKeyName); 00811 00812 return Ret; 00813 } 00814 00815 00816 /************************************************************************ 00817 * RegConnectRegistryA 00818 * 00819 * @implemented 00820 */ 00821 LONG WINAPI 00822 RegConnectRegistryA(IN LPCSTR lpMachineName, 00823 IN HKEY hKey, 00824 OUT PHKEY phkResult) 00825 { 00826 UNICODE_STRING MachineName = { 0, 0, NULL }; 00827 LONG Ret; 00828 00829 if (lpMachineName != NULL && 00830 !RtlCreateUnicodeStringFromAsciiz(&MachineName, 00831 (LPSTR)lpMachineName)) 00832 { 00833 return ERROR_NOT_ENOUGH_MEMORY; 00834 } 00835 00836 Ret = RegConnectRegistryW(MachineName.Buffer, 00837 hKey, 00838 phkResult); 00839 00840 RtlFreeUnicodeString(&MachineName); 00841 00842 return Ret; 00843 } 00844 00845 00846 /************************************************************************ 00847 * RegConnectRegistryW 00848 * 00849 * @unimplemented 00850 */ 00851 LONG WINAPI 00852 RegConnectRegistryW(LPCWSTR lpMachineName, 00853 HKEY hKey, 00854 PHKEY phkResult) 00855 { 00856 LONG ret; 00857 00858 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult); 00859 00860 if (!lpMachineName || !*lpMachineName) 00861 { 00862 /* Use the local machine name */ 00863 ret = RegOpenKeyW( hKey, NULL, phkResult ); 00864 } 00865 else 00866 { 00867 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1]; 00868 DWORD len = sizeof(compName) / sizeof(WCHAR); 00869 00870 /* MSDN says lpMachineName must start with \\ : not so */ 00871 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\') 00872 lpMachineName += 2; 00873 00874 if (GetComputerNameW(compName, &len)) 00875 { 00876 if (!_wcsicmp(lpMachineName, compName)) 00877 ret = RegOpenKeyW(hKey, NULL, phkResult); 00878 else 00879 { 00880 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName)); 00881 ret = ERROR_BAD_NETPATH; 00882 } 00883 } 00884 else 00885 ret = GetLastError(); 00886 } 00887 00888 return ret; 00889 } 00890 00891 00892 /************************************************************************ 00893 * CreateNestedKey 00894 * 00895 * Create key and all necessary intermediate keys 00896 */ 00897 static NTSTATUS 00898 CreateNestedKey(PHKEY KeyHandle, 00899 POBJECT_ATTRIBUTES ObjectAttributes, 00900 PUNICODE_STRING ClassString, 00901 DWORD dwOptions, 00902 REGSAM samDesired, 00903 DWORD *lpdwDisposition) 00904 { 00905 OBJECT_ATTRIBUTES LocalObjectAttributes; 00906 UNICODE_STRING LocalKeyName; 00907 ULONG Disposition; 00908 NTSTATUS Status; 00909 ULONG FullNameLength; 00910 ULONG Length; 00911 PWCHAR Ptr; 00912 HANDLE LocalKeyHandle; 00913 00914 Status = NtCreateKey((PHANDLE) KeyHandle, 00915 samDesired, 00916 ObjectAttributes, 00917 0, 00918 ClassString, 00919 dwOptions, 00920 (PULONG)lpdwDisposition); 00921 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status); 00922 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 00923 return Status; 00924 00925 /* Copy object attributes */ 00926 RtlCopyMemory(&LocalObjectAttributes, 00927 ObjectAttributes, 00928 sizeof(OBJECT_ATTRIBUTES)); 00929 RtlCreateUnicodeString(&LocalKeyName, 00930 ObjectAttributes->ObjectName->Buffer); 00931 LocalObjectAttributes.ObjectName = &LocalKeyName; 00932 FullNameLength = LocalKeyName.Length / sizeof(WCHAR); 00933 00934 LocalKeyHandle = NULL; 00935 00936 /* Remove the last part of the key name and try to create the key again. */ 00937 while (Status == STATUS_OBJECT_NAME_NOT_FOUND) 00938 { 00939 Ptr = wcsrchr(LocalKeyName.Buffer, '\\'); 00940 if (Ptr == NULL || Ptr == LocalKeyName.Buffer) 00941 { 00942 Status = STATUS_UNSUCCESSFUL; 00943 break; 00944 } 00945 00946 *Ptr = (WCHAR)0; 00947 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR); 00948 00949 Status = NtCreateKey(&LocalKeyHandle, 00950 KEY_CREATE_SUB_KEY, 00951 &LocalObjectAttributes, 00952 0, 00953 NULL, 00954 0, 00955 &Disposition); 00956 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status); 00957 } 00958 00959 if (!NT_SUCCESS(Status)) 00960 { 00961 RtlFreeUnicodeString(&LocalKeyName); 00962 return Status; 00963 } 00964 00965 /* Add removed parts of the key name and create them too. */ 00966 Length = wcslen(LocalKeyName.Buffer); 00967 while (TRUE) 00968 { 00969 if (LocalKeyHandle) 00970 NtClose (LocalKeyHandle); 00971 00972 LocalKeyName.Buffer[Length] = L'\\'; 00973 Length = wcslen (LocalKeyName.Buffer); 00974 LocalKeyName.Length = Length * sizeof(WCHAR); 00975 00976 if (Length == FullNameLength) 00977 { 00978 Status = NtCreateKey((PHANDLE) KeyHandle, 00979 samDesired, 00980 ObjectAttributes, 00981 0, 00982 ClassString, 00983 dwOptions, 00984 (PULONG)lpdwDisposition); 00985 break; 00986 } 00987 00988 Status = NtCreateKey(&LocalKeyHandle, 00989 KEY_CREATE_SUB_KEY, 00990 &LocalObjectAttributes, 00991 0, 00992 NULL, 00993 0, 00994 &Disposition); 00995 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status); 00996 if (!NT_SUCCESS(Status)) 00997 break; 00998 } 00999 01000 RtlFreeUnicodeString(&LocalKeyName); 01001 01002 return Status; 01003 } 01004 01005 01006 /************************************************************************ 01007 * RegCreateKeyExA 01008 * 01009 * @implemented 01010 */ 01011 LONG WINAPI 01012 RegCreateKeyExA(HKEY hKey, 01013 LPCSTR lpSubKey, 01014 DWORD Reserved, 01015 LPSTR lpClass, 01016 DWORD dwOptions, 01017 REGSAM samDesired, 01018 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 01019 PHKEY phkResult, 01020 LPDWORD lpdwDisposition) 01021 { 01022 UNICODE_STRING SubKeyString; 01023 UNICODE_STRING ClassString; 01024 OBJECT_ATTRIBUTES Attributes; 01025 HANDLE ParentKey; 01026 NTSTATUS Status; 01027 01028 TRACE("RegCreateKeyExA() called\n"); 01029 01030 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES)) 01031 return ERROR_INVALID_USER_BUFFER; 01032 01033 /* get the real parent key */ 01034 Status = MapDefaultKey(&ParentKey, 01035 hKey); 01036 if (!NT_SUCCESS(Status)) 01037 { 01038 return RtlNtStatusToDosError(Status); 01039 } 01040 01041 TRACE("ParentKey %p\n", ParentKey); 01042 01043 if (lpClass != NULL) 01044 { 01045 RtlCreateUnicodeStringFromAsciiz(&ClassString, 01046 lpClass); 01047 } 01048 01049 RtlCreateUnicodeStringFromAsciiz(&SubKeyString, 01050 (LPSTR)lpSubKey); 01051 InitializeObjectAttributes(&Attributes, 01052 &SubKeyString, 01053 OBJ_CASE_INSENSITIVE, 01054 (HANDLE)ParentKey, 01055 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL); 01056 Status = CreateNestedKey(phkResult, 01057 &Attributes, 01058 (lpClass == NULL)? NULL : &ClassString, 01059 dwOptions, 01060 samDesired, 01061 lpdwDisposition); 01062 RtlFreeUnicodeString(&SubKeyString); 01063 if (lpClass != NULL) 01064 { 01065 RtlFreeUnicodeString(&ClassString); 01066 } 01067 01068 ClosePredefKey(ParentKey); 01069 01070 TRACE("Status %x\n", Status); 01071 if (!NT_SUCCESS(Status)) 01072 { 01073 return RtlNtStatusToDosError(Status); 01074 } 01075 01076 return ERROR_SUCCESS; 01077 } 01078 01079 01080 /************************************************************************ 01081 * RegCreateKeyExW 01082 * 01083 * @implemented 01084 */ 01085 LONG WINAPI 01086 RegCreateKeyExW(HKEY hKey, 01087 LPCWSTR lpSubKey, 01088 DWORD Reserved, 01089 LPWSTR lpClass, 01090 DWORD dwOptions, 01091 REGSAM samDesired, 01092 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 01093 PHKEY phkResult, 01094 LPDWORD lpdwDisposition) 01095 { 01096 UNICODE_STRING SubKeyString; 01097 UNICODE_STRING ClassString; 01098 OBJECT_ATTRIBUTES Attributes; 01099 HANDLE ParentKey; 01100 NTSTATUS Status; 01101 01102 TRACE("RegCreateKeyExW() called\n"); 01103 01104 if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES)) 01105 return ERROR_INVALID_USER_BUFFER; 01106 01107 /* get the real parent key */ 01108 Status = MapDefaultKey(&ParentKey, 01109 hKey); 01110 if (!NT_SUCCESS(Status)) 01111 { 01112 return RtlNtStatusToDosError(Status); 01113 } 01114 01115 TRACE("ParentKey %p\n", ParentKey); 01116 01117 RtlInitUnicodeString(&ClassString, 01118 lpClass); 01119 RtlInitUnicodeString(&SubKeyString, 01120 lpSubKey); 01121 InitializeObjectAttributes(&Attributes, 01122 &SubKeyString, 01123 OBJ_CASE_INSENSITIVE, 01124 (HANDLE)ParentKey, 01125 lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL); 01126 Status = CreateNestedKey(phkResult, 01127 &Attributes, 01128 (lpClass == NULL)? NULL : &ClassString, 01129 dwOptions, 01130 samDesired, 01131 lpdwDisposition); 01132 01133 ClosePredefKey(ParentKey); 01134 01135 TRACE("Status %x\n", Status); 01136 if (!NT_SUCCESS(Status)) 01137 { 01138 return RtlNtStatusToDosError(Status); 01139 } 01140 01141 return ERROR_SUCCESS; 01142 } 01143 01144 01145 /************************************************************************ 01146 * RegCreateKeyA 01147 * 01148 * @implemented 01149 */ 01150 LONG WINAPI 01151 RegCreateKeyA(HKEY hKey, 01152 LPCSTR lpSubKey, 01153 PHKEY phkResult) 01154 { 01155 return RegCreateKeyExA(hKey, 01156 lpSubKey, 01157 0, 01158 NULL, 01159 0, 01160 MAXIMUM_ALLOWED, 01161 NULL, 01162 phkResult, 01163 NULL); 01164 } 01165 01166 01167 /************************************************************************ 01168 * RegCreateKeyW 01169 * 01170 * @implemented 01171 */ 01172 LONG WINAPI 01173 RegCreateKeyW(HKEY hKey, 01174 LPCWSTR lpSubKey, 01175 PHKEY phkResult) 01176 { 01177 return RegCreateKeyExW(hKey, 01178 lpSubKey, 01179 0, 01180 NULL, 01181 0, 01182 MAXIMUM_ALLOWED, 01183 NULL, 01184 phkResult, 01185 NULL); 01186 } 01187 01188 01189 /************************************************************************ 01190 * RegDeleteKeyA 01191 * 01192 * @implemented 01193 */ 01194 LONG WINAPI 01195 RegDeleteKeyA(HKEY hKey, 01196 LPCSTR lpSubKey) 01197 { 01198 OBJECT_ATTRIBUTES ObjectAttributes; 01199 UNICODE_STRING SubKeyName; 01200 HANDLE ParentKey; 01201 HANDLE TargetKey; 01202 NTSTATUS Status; 01203 01204 /* Make sure we got a subkey */ 01205 if (!lpSubKey) 01206 { 01207 /* Fail */ 01208 return ERROR_INVALID_PARAMETER; 01209 } 01210 01211 Status = MapDefaultKey(&ParentKey, 01212 hKey); 01213 if (!NT_SUCCESS(Status)) 01214 { 01215 return RtlNtStatusToDosError(Status); 01216 } 01217 01218 RtlCreateUnicodeStringFromAsciiz(&SubKeyName, 01219 (LPSTR)lpSubKey); 01220 InitializeObjectAttributes(&ObjectAttributes, 01221 &SubKeyName, 01222 OBJ_CASE_INSENSITIVE, 01223 ParentKey, 01224 NULL); 01225 01226 Status = NtOpenKey(&TargetKey, 01227 DELETE, 01228 &ObjectAttributes); 01229 RtlFreeUnicodeString(&SubKeyName); 01230 if (!NT_SUCCESS(Status)) 01231 { 01232 goto Cleanup; 01233 } 01234 01235 Status = NtDeleteKey(TargetKey); 01236 NtClose (TargetKey); 01237 01238 Cleanup: 01239 ClosePredefKey(ParentKey); 01240 01241 if (!NT_SUCCESS(Status)) 01242 { 01243 return RtlNtStatusToDosError(Status); 01244 } 01245 01246 return ERROR_SUCCESS; 01247 } 01248 01249 01250 /************************************************************************ 01251 * RegDeleteKeyW 01252 * 01253 * @implemented 01254 */ 01255 LONG WINAPI 01256 RegDeleteKeyW(HKEY hKey, 01257 LPCWSTR lpSubKey) 01258 { 01259 OBJECT_ATTRIBUTES ObjectAttributes; 01260 UNICODE_STRING SubKeyName; 01261 HANDLE ParentKey; 01262 HANDLE TargetKey; 01263 NTSTATUS Status; 01264 01265 /* Make sure we got a subkey */ 01266 if (!lpSubKey) 01267 { 01268 /* Fail */ 01269 return ERROR_INVALID_PARAMETER; 01270 } 01271 01272 Status = MapDefaultKey(&ParentKey, 01273 hKey); 01274 if (!NT_SUCCESS(Status)) 01275 { 01276 return RtlNtStatusToDosError(Status); 01277 } 01278 01279 RtlInitUnicodeString(&SubKeyName, 01280 (LPWSTR)lpSubKey); 01281 InitializeObjectAttributes(&ObjectAttributes, 01282 &SubKeyName, 01283 OBJ_CASE_INSENSITIVE, 01284 ParentKey, 01285 NULL); 01286 Status = NtOpenKey(&TargetKey, 01287 DELETE, 01288 &ObjectAttributes); 01289 if (!NT_SUCCESS(Status)) 01290 { 01291 goto Cleanup; 01292 } 01293 01294 Status = NtDeleteKey(TargetKey); 01295 NtClose(TargetKey); 01296 01297 Cleanup: 01298 ClosePredefKey(ParentKey); 01299 01300 if (!NT_SUCCESS(Status)) 01301 { 01302 return RtlNtStatusToDosError(Status); 01303 } 01304 01305 return ERROR_SUCCESS; 01306 } 01307 01308 01309 /************************************************************************ 01310 * RegDeleteKeyExA 01311 * 01312 * @unimplemented 01313 */ 01314 LONG 01315 WINAPI 01316 RegDeleteKeyExA(HKEY hKey, 01317 LPCSTR lpSubKey, 01318 REGSAM samDesired, 01319 DWORD Reserved) 01320 { 01321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 01322 return ERROR_CALL_NOT_IMPLEMENTED; 01323 } 01324 01325 01326 /************************************************************************ 01327 * RegDeleteKeyExW 01328 * 01329 * @unimplemented 01330 */ 01331 LONG 01332 WINAPI 01333 RegDeleteKeyExW(HKEY hKey, 01334 LPCWSTR lpSubKey, 01335 REGSAM samDesired, 01336 DWORD Reserved) 01337 { 01338 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 01339 return ERROR_CALL_NOT_IMPLEMENTED; 01340 } 01341 01342 01343 /************************************************************************ 01344 * RegDeleteKeyValueW 01345 * 01346 * @implemented 01347 */ 01348 LONG WINAPI 01349 RegDeleteKeyValueW(IN HKEY hKey, 01350 IN LPCWSTR lpSubKey OPTIONAL, 01351 IN LPCWSTR lpValueName OPTIONAL) 01352 { 01353 UNICODE_STRING ValueName; 01354 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 01355 NTSTATUS Status; 01356 01357 Status = MapDefaultKey(&KeyHandle, 01358 hKey); 01359 if (!NT_SUCCESS(Status)) 01360 { 01361 return RtlNtStatusToDosError(Status); 01362 } 01363 01364 if (lpSubKey != NULL) 01365 { 01366 OBJECT_ATTRIBUTES ObjectAttributes; 01367 UNICODE_STRING SubKeyName; 01368 01369 RtlInitUnicodeString(&SubKeyName, 01370 (LPWSTR)lpSubKey); 01371 01372 InitializeObjectAttributes(&ObjectAttributes, 01373 &SubKeyName, 01374 OBJ_CASE_INSENSITIVE, 01375 KeyHandle, 01376 NULL); 01377 01378 Status = NtOpenKey(&SubKeyHandle, 01379 KEY_SET_VALUE, 01380 &ObjectAttributes); 01381 if (!NT_SUCCESS(Status)) 01382 { 01383 goto Cleanup; 01384 } 01385 01386 CurKey = SubKeyHandle; 01387 } 01388 else 01389 CurKey = KeyHandle; 01390 01391 RtlInitUnicodeString(&ValueName, 01392 (LPWSTR)lpValueName); 01393 01394 Status = NtDeleteValueKey(CurKey, 01395 &ValueName); 01396 01397 if (SubKeyHandle != NULL) 01398 { 01399 NtClose(SubKeyHandle); 01400 } 01401 01402 Cleanup: 01403 ClosePredefKey(KeyHandle); 01404 01405 if (!NT_SUCCESS(Status)) 01406 { 01407 return RtlNtStatusToDosError(Status); 01408 } 01409 01410 return ERROR_SUCCESS; 01411 } 01412 01413 01414 /************************************************************************ 01415 * RegDeleteKeyValueA 01416 * 01417 * @implemented 01418 */ 01419 LONG WINAPI 01420 RegDeleteKeyValueA(IN HKEY hKey, 01421 IN LPCSTR lpSubKey OPTIONAL, 01422 IN LPCSTR lpValueName OPTIONAL) 01423 { 01424 UNICODE_STRING SubKey = { 0, 0, NULL }, ValueName = { 0, 0, NULL }; 01425 LONG Ret; 01426 01427 if (lpSubKey != NULL && 01428 !RtlCreateUnicodeStringFromAsciiz(&SubKey, 01429 (LPSTR)lpSubKey)) 01430 { 01431 return ERROR_NOT_ENOUGH_MEMORY; 01432 } 01433 01434 if (lpValueName != NULL && 01435 !RtlCreateUnicodeStringFromAsciiz(&ValueName, 01436 (LPSTR)lpValueName)) 01437 { 01438 RtlFreeUnicodeString(&SubKey); 01439 return ERROR_NOT_ENOUGH_MEMORY; 01440 } 01441 01442 Ret = RegDeleteKeyValueW(hKey, 01443 SubKey.Buffer, 01444 SubKey.Buffer); 01445 01446 RtlFreeUnicodeString(&SubKey); 01447 RtlFreeUnicodeString(&ValueName); 01448 01449 return Ret; 01450 } 01451 01452 #if 0 01453 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing 01454 static NTSTATUS 01455 RegpDeleteTree(IN HKEY hKey) 01456 { 01457 typedef struct 01458 { 01459 LIST_ENTRY ListEntry; 01460 HANDLE KeyHandle; 01461 } REGP_DEL_KEYS, *PREG_DEL_KEYS; 01462 01463 LIST_ENTRY delQueueHead; 01464 PREG_DEL_KEYS delKeys, newDelKeys; 01465 HANDLE ProcessHeap; 01466 ULONG BufferSize; 01467 PKEY_BASIC_INFORMATION BasicInfo; 01468 PREG_DEL_KEYS KeyDelRoot; 01469 NTSTATUS Status = STATUS_SUCCESS; 01470 NTSTATUS Status2 = STATUS_SUCCESS; 01471 01472 InitializeListHead(&delQueueHead); 01473 01474 ProcessHeap = RtlGetProcessHeap(); 01475 01476 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION 01477 structure for the root key, we only do that for subkeys as we need to 01478 allocate REGP_DEL_KEYS structures anyway! */ 01479 KeyDelRoot = RtlAllocateHeap(ProcessHeap, 01480 0, 01481 sizeof(REGP_DEL_KEYS)); 01482 if (KeyDelRoot != NULL) 01483 { 01484 KeyDelRoot->KeyHandle = hKey; 01485 InsertTailList(&delQueueHead, 01486 &KeyDelRoot->ListEntry); 01487 01488 do 01489 { 01490 delKeys = CONTAINING_RECORD(delQueueHead.Flink, 01491 REGP_DEL_KEYS, 01492 ListEntry); 01493 01494 BufferSize = 0; 01495 BasicInfo = NULL; 01496 newDelKeys = NULL; 01497 01498 ReadFirstSubKey: 01499 /* check if this key contains subkeys and delete them first by queuing 01500 them at the head of the list */ 01501 Status2 = NtEnumerateKey(delKeys->KeyHandle, 01502 0, 01503 KeyBasicInformation, 01504 BasicInfo, 01505 BufferSize, 01506 &BufferSize); 01507 01508 if (NT_SUCCESS(Status2)) 01509 { 01510 OBJECT_ATTRIBUTES ObjectAttributes; 01511 UNICODE_STRING SubKeyName; 01512 01513 ASSERT(newDelKeys != NULL); 01514 ASSERT(BasicInfo != NULL); 01515 01516 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */ 01517 SubKeyName.Length = BasicInfo->NameLength; 01518 SubKeyName.MaximumLength = BasicInfo->NameLength; 01519 SubKeyName.Buffer = BasicInfo->Name; 01520 01521 InitializeObjectAttributes(&ObjectAttributes, 01522 &SubKeyName, 01523 OBJ_CASE_INSENSITIVE, 01524 delKeys->KeyHandle, 01525 NULL); 01526 01527 /* open the subkey */ 01528 Status2 = NtOpenKey(&newDelKeys->KeyHandle, 01529 DELETE | KEY_ENUMERATE_SUB_KEYS, 01530 &ObjectAttributes); 01531 if (!NT_SUCCESS(Status2)) 01532 { 01533 goto SubKeyFailure; 01534 } 01535 01536 /* enqueue this key to the head of the deletion queue */ 01537 InsertHeadList(&delQueueHead, 01538 &newDelKeys->ListEntry); 01539 01540 /* try again from the head of the list */ 01541 continue; 01542 } 01543 else 01544 { 01545 if (Status2 == STATUS_BUFFER_TOO_SMALL) 01546 { 01547 newDelKeys = RtlAllocateHeap(ProcessHeap, 01548 0, 01549 BufferSize + sizeof(REGP_DEL_KEYS)); 01550 if (newDelKeys != NULL) 01551 { 01552 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1); 01553 01554 /* try again */ 01555 goto ReadFirstSubKey; 01556 } 01557 else 01558 { 01559 /* don't break, let's try to delete as many keys as possible */ 01560 Status2 = STATUS_INSUFFICIENT_RESOURCES; 01561 goto SubKeyFailureNoFree; 01562 } 01563 } 01564 else if (Status2 == STATUS_BUFFER_OVERFLOW) 01565 { 01566 PREG_DEL_KEYS newDelKeys2; 01567 01568 ASSERT(newDelKeys != NULL); 01569 01570 /* we need more memory to query the key name */ 01571 newDelKeys2 = RtlReAllocateHeap(ProcessHeap, 01572 0, 01573 newDelKeys, 01574 BufferSize + sizeof(REGP_DEL_KEYS)); 01575 if (newDelKeys2 != NULL) 01576 { 01577 newDelKeys = newDelKeys2; 01578 BasicInfo = (PKEY_BASIC_INFORMATION)(newDelKeys + 1); 01579 01580 /* try again */ 01581 goto ReadFirstSubKey; 01582 } 01583 else 01584 { 01585 /* don't break, let's try to delete as many keys as possible */ 01586 Status2 = STATUS_INSUFFICIENT_RESOURCES; 01587 } 01588 } 01589 else if (Status2 == STATUS_NO_MORE_ENTRIES) 01590 { 01591 /* in some race conditions where another thread would delete 01592 the same tree at the same time, newDelKeys could actually 01593 be != NULL! */ 01594 if (newDelKeys != NULL) 01595 { 01596 RtlFreeHeap(ProcessHeap, 01597 0, 01598 newDelKeys); 01599 } 01600 break; 01601 } 01602 01603 SubKeyFailure: 01604 /* newDelKeys can be NULL here when NtEnumerateKey returned an 01605 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */ 01606 if (newDelKeys != NULL) 01607 { 01608 RtlFreeHeap(ProcessHeap, 01609 0, 01610 newDelKeys); 01611 } 01612 01613 SubKeyFailureNoFree: 01614 /* don't break, let's try to delete as many keys as possible */ 01615 if (NT_SUCCESS(Status)) 01616 { 01617 Status = Status2; 01618 } 01619 } 01620 01621 Status2 = NtDeleteKey(delKeys->KeyHandle); 01622 01623 /* NOTE: do NOT close the handle anymore, it's invalid already! */ 01624 01625 if (!NT_SUCCESS(Status2)) 01626 { 01627 /* close the key handle so we don't leak handles for keys we were 01628 unable to delete. But only do this for handles not supplied 01629 by the caller! */ 01630 01631 if (delKeys->KeyHandle != hKey) 01632 { 01633 NtClose(delKeys->KeyHandle); 01634 } 01635 01636 if (NT_SUCCESS(Status)) 01637 { 01638 /* don't break, let's try to delete as many keys as possible */ 01639 Status = Status2; 01640 } 01641 } 01642 01643 /* remove the entry from the list */ 01644 RemoveEntryList(&delKeys->ListEntry); 01645 01646 RtlFreeHeap(ProcessHeap, 01647 0, 01648 delKeys); 01649 } while (!IsListEmpty(&delQueueHead)); 01650 } 01651 else 01652 Status = STATUS_INSUFFICIENT_RESOURCES; 01653 01654 return Status; 01655 } 01656 01657 01658 /************************************************************************ 01659 * RegDeleteTreeW 01660 * 01661 * @implemented 01662 */ 01663 LONG WINAPI 01664 RegDeleteTreeW(IN HKEY hKey, 01665 IN LPCWSTR lpSubKey OPTIONAL) 01666 { 01667 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 01668 NTSTATUS Status; 01669 01670 Status = MapDefaultKey(&KeyHandle, 01671 hKey); 01672 if (!NT_SUCCESS(Status)) 01673 { 01674 return RtlNtStatusToDosError(Status); 01675 } 01676 01677 if (lpSubKey != NULL) 01678 { 01679 OBJECT_ATTRIBUTES ObjectAttributes; 01680 UNICODE_STRING SubKeyName; 01681 01682 RtlInitUnicodeString(&SubKeyName, 01683 (LPWSTR)lpSubKey); 01684 01685 InitializeObjectAttributes(&ObjectAttributes, 01686 &SubKeyName, 01687 OBJ_CASE_INSENSITIVE, 01688 KeyHandle, 01689 NULL); 01690 01691 Status = NtOpenKey(&SubKeyHandle, 01692 DELETE | KEY_ENUMERATE_SUB_KEYS, 01693 &ObjectAttributes); 01694 if (!NT_SUCCESS(Status)) 01695 { 01696 goto Cleanup; 01697 } 01698 01699 CurKey = SubKeyHandle; 01700 } 01701 else 01702 CurKey = KeyHandle; 01703 01704 Status = RegpDeleteTree(CurKey); 01705 01706 if (NT_SUCCESS(Status)) 01707 { 01708 /* make sure we only close hKey (KeyHandle) when the caller specified a 01709 subkey, because the handle would be invalid already! */ 01710 if (CurKey != KeyHandle) 01711 { 01712 ClosePredefKey(KeyHandle); 01713 } 01714 01715 return ERROR_SUCCESS; 01716 } 01717 else 01718 { 01719 /* make sure we close all handles we created! */ 01720 if (SubKeyHandle != NULL) 01721 { 01722 NtClose(SubKeyHandle); 01723 } 01724 01725 Cleanup: 01726 ClosePredefKey(KeyHandle); 01727 01728 return RtlNtStatusToDosError(Status); 01729 } 01730 } 01731 #endif 01732 01733 01734 /************************************************************************ 01735 * RegDeleteTreeW 01736 * 01737 * @implemented 01738 */ 01739 LSTATUS 01740 WINAPI 01741 RegDeleteTreeW(HKEY hKey, 01742 LPCWSTR lpszSubKey) 01743 { 01744 LONG ret; 01745 DWORD dwMaxSubkeyLen, dwMaxValueLen; 01746 DWORD dwMaxLen, dwSize; 01747 NTSTATUS Status; 01748 HANDLE KeyHandle; 01749 HKEY hSubKey; 01750 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; 01751 01752 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey)); 01753 01754 Status = MapDefaultKey(&KeyHandle, 01755 hKey); 01756 if (!NT_SUCCESS(Status)) 01757 { 01758 return RtlNtStatusToDosError(Status); 01759 } 01760 01761 hSubKey = KeyHandle; 01762 01763 if(lpszSubKey) 01764 { 01765 ret = RegOpenKeyExW(KeyHandle, lpszSubKey, 0, KEY_READ, &hSubKey); 01766 if (ret) 01767 { 01768 ClosePredefKey(KeyHandle); 01769 return ret; 01770 } 01771 } 01772 01773 /* Get highest length for keys, values */ 01774 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, 01775 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); 01776 if (ret) goto cleanup; 01777 01778 dwMaxSubkeyLen++; 01779 dwMaxValueLen++; 01780 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); 01781 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR)) 01782 { 01783 /* Name too big: alloc a buffer for it */ 01784 if (!(lpszName = RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR)))) 01785 { 01786 ret = ERROR_NOT_ENOUGH_MEMORY; 01787 goto cleanup; 01788 } 01789 } 01790 01791 01792 /* Recursively delete all the subkeys */ 01793 while (TRUE) 01794 { 01795 dwSize = dwMaxLen; 01796 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, 01797 NULL, NULL, NULL)) break; 01798 01799 ret = RegDeleteTreeW(hSubKey, lpszName); 01800 if (ret) goto cleanup; 01801 } 01802 01803 if (lpszSubKey) 01804 ret = RegDeleteKeyW(KeyHandle, lpszSubKey); 01805 else 01806 while (TRUE) 01807 { 01808 dwSize = dwMaxLen; 01809 if (RegEnumValueW(KeyHandle, 0, lpszName, &dwSize, 01810 NULL, NULL, NULL, NULL)) break; 01811 01812 ret = RegDeleteValueW(KeyHandle, lpszName); 01813 if (ret) goto cleanup; 01814 } 01815 01816 cleanup: 01817 /* Free buffer if allocated */ 01818 if (lpszName != szNameBuf) 01819 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName); 01820 if(lpszSubKey) 01821 RegCloseKey(hSubKey); 01822 01823 ClosePredefKey(KeyHandle); 01824 01825 return ret; 01826 } 01827 01828 01829 /************************************************************************ 01830 * RegDeleteTreeA 01831 * 01832 * @implemented 01833 */ 01834 LONG WINAPI 01835 RegDeleteTreeA(IN HKEY hKey, 01836 IN LPCSTR lpSubKey OPTIONAL) 01837 { 01838 UNICODE_STRING SubKeyName = { 0, 0, NULL }; 01839 LONG Ret; 01840 01841 if (lpSubKey != NULL && 01842 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName, 01843 (LPSTR)lpSubKey)) 01844 { 01845 return ERROR_NOT_ENOUGH_MEMORY; 01846 } 01847 01848 Ret = RegDeleteTreeW(hKey, 01849 SubKeyName.Buffer); 01850 01851 RtlFreeUnicodeString(&SubKeyName); 01852 01853 return Ret; 01854 } 01855 01856 01857 /************************************************************************ 01858 * RegDisableReflectionKey 01859 * 01860 * @unimplemented 01861 */ 01862 LONG WINAPI 01863 RegDisableReflectionKey(IN HKEY hBase) 01864 { 01865 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase); 01866 return ERROR_CALL_NOT_IMPLEMENTED; 01867 } 01868 01869 01870 /************************************************************************ 01871 * RegEnableReflectionKey 01872 * 01873 * @unimplemented 01874 */ 01875 LONG WINAPI 01876 RegEnableReflectionKey(IN HKEY hBase) 01877 { 01878 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase); 01879 return ERROR_CALL_NOT_IMPLEMENTED; 01880 } 01881 01882 01883 /****************************************************************************** 01884 * RegpApplyRestrictions [internal] 01885 * 01886 * Helper function for RegGetValueA/W. 01887 */ 01888 static VOID 01889 RegpApplyRestrictions(DWORD dwFlags, 01890 DWORD dwType, 01891 DWORD cbData, 01892 PLONG ret) 01893 { 01894 /* Check if the type is restricted by the passed flags */ 01895 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA) 01896 { 01897 DWORD dwMask = 0; 01898 01899 switch (dwType) 01900 { 01901 case REG_NONE: dwMask = RRF_RT_REG_NONE; break; 01902 case REG_SZ: dwMask = RRF_RT_REG_SZ; break; 01903 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break; 01904 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break; 01905 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break; 01906 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break; 01907 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break; 01908 } 01909 01910 if (dwFlags & dwMask) 01911 { 01912 /* Type is not restricted, check for size mismatch */ 01913 if (dwType == REG_BINARY) 01914 { 01915 DWORD cbExpect = 0; 01916 01917 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD) 01918 cbExpect = 4; 01919 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD) 01920 cbExpect = 8; 01921 01922 if (cbExpect && cbData != cbExpect) 01923 *ret = ERROR_DATATYPE_MISMATCH; 01924 } 01925 } 01926 else *ret = ERROR_UNSUPPORTED_TYPE; 01927 } 01928 } 01929 01930 01931 /****************************************************************************** 01932 * RegGetValueW [ADVAPI32.@] 01933 * 01934 * Retrieves the type and data for a value name associated with a key, 01935 * optionally expanding its content and restricting its type. 01936 * 01937 * PARAMS 01938 * hKey [I] Handle to an open key. 01939 * pszSubKey [I] Name of the subkey of hKey. 01940 * pszValue [I] Name of value under hKey/szSubKey to query. 01941 * dwFlags [I] Flags restricting the value type to retrieve. 01942 * pdwType [O] Destination for the values type, may be NULL. 01943 * pvData [O] Destination for the values content, may be NULL. 01944 * pcbData [I/O] Size of pvData, updated with the size in bytes required to 01945 * retrieve the whole content, including the trailing '\0' 01946 * for strings. 01947 * 01948 * RETURNS 01949 * Success: ERROR_SUCCESS 01950 * Failure: nonzero error code from Winerror.h 01951 * 01952 * NOTES 01953 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically 01954 * expanded and pdwType is set to REG_SZ instead. 01955 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 01956 * without RRF_NOEXPAND is thus not allowed. 01957 * An exception is the case where RRF_RT_ANY is specified, because then 01958 * RRF_NOEXPAND is allowed. 01959 */ 01960 LSTATUS WINAPI 01961 RegGetValueW(HKEY hKey, 01962 LPCWSTR pszSubKey, 01963 LPCWSTR pszValue, 01964 DWORD dwFlags, 01965 LPDWORD pdwType, 01966 PVOID pvData, 01967 LPDWORD pcbData) 01968 { 01969 DWORD dwType, cbData = pcbData ? *pcbData : 0; 01970 PVOID pvBuf = NULL; 01971 LONG ret; 01972 01973 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 01974 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType, 01975 pvData, pcbData, cbData); 01976 01977 if (pvData && !pcbData) 01978 return ERROR_INVALID_PARAMETER; 01979 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && 01980 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) 01981 return ERROR_INVALID_PARAMETER; 01982 01983 if (pszSubKey && pszSubKey[0]) 01984 { 01985 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); 01986 if (ret != ERROR_SUCCESS) return ret; 01987 } 01988 01989 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData); 01990 01991 /* If we are going to expand we need to read in the whole the value even 01992 * if the passed buffer was too small as the expanded string might be 01993 * smaller than the unexpanded one and could fit into cbData bytes. */ 01994 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && 01995 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) 01996 { 01997 do 01998 { 01999 HeapFree(GetProcessHeap(), 0, pvBuf); 02000 02001 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); 02002 if (!pvBuf) 02003 { 02004 ret = ERROR_NOT_ENOUGH_MEMORY; 02005 break; 02006 } 02007 02008 if (ret == ERROR_MORE_DATA || !pvData) 02009 ret = RegQueryValueExW(hKey, pszValue, NULL, 02010 &dwType, pvBuf, &cbData); 02011 else 02012 { 02013 /* Even if cbData was large enough we have to copy the 02014 * string since ExpandEnvironmentStrings can't handle 02015 * overlapping buffers. */ 02016 CopyMemory(pvBuf, pvData, cbData); 02017 } 02018 02019 /* Both the type or the value itself could have been modified in 02020 * between so we have to keep retrying until the buffer is large 02021 * enough or we no longer have to expand the value. */ 02022 } 02023 while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); 02024 02025 if (ret == ERROR_SUCCESS) 02026 { 02027 /* Recheck dwType in case it changed since the first call */ 02028 if (dwType == REG_EXPAND_SZ) 02029 { 02030 cbData = ExpandEnvironmentStringsW(pvBuf, pvData, 02031 pcbData ? *pcbData : 0) * sizeof(WCHAR); 02032 dwType = REG_SZ; 02033 if (pvData && pcbData && cbData > *pcbData) 02034 ret = ERROR_MORE_DATA; 02035 } 02036 else if (pvData) 02037 CopyMemory(pvData, pvBuf, *pcbData); 02038 } 02039 02040 HeapFree(GetProcessHeap(), 0, pvBuf); 02041 } 02042 02043 if (pszSubKey && pszSubKey[0]) 02044 RegCloseKey(hKey); 02045 02046 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); 02047 02048 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) 02049 ZeroMemory(pvData, *pcbData); 02050 02051 if (pdwType) 02052 *pdwType = dwType; 02053 02054 if (pcbData) 02055 *pcbData = cbData; 02056 02057 return ret; 02058 } 02059 02060 02061 /****************************************************************************** 02062 * RegGetValueA [ADVAPI32.@] 02063 * 02064 * See RegGetValueW. 02065 */ 02066 LSTATUS WINAPI 02067 RegGetValueA(HKEY hKey, 02068 LPCSTR pszSubKey, 02069 LPCSTR pszValue, 02070 DWORD dwFlags, 02071 LPDWORD pdwType, 02072 PVOID pvData, 02073 LPDWORD pcbData) 02074 { 02075 DWORD dwType, cbData = pcbData ? *pcbData : 0; 02076 PVOID pvBuf = NULL; 02077 LONG ret; 02078 02079 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 02080 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData, 02081 cbData); 02082 02083 if (pvData && !pcbData) 02084 return ERROR_INVALID_PARAMETER; 02085 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && 02086 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) 02087 return ERROR_INVALID_PARAMETER; 02088 02089 if (pszSubKey && pszSubKey[0]) 02090 { 02091 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); 02092 if (ret != ERROR_SUCCESS) return ret; 02093 } 02094 02095 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData); 02096 02097 /* If we are going to expand we need to read in the whole the value even 02098 * if the passed buffer was too small as the expanded string might be 02099 * smaller than the unexpanded one and could fit into cbData bytes. */ 02100 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && 02101 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))) 02102 { 02103 do { 02104 HeapFree(GetProcessHeap(), 0, pvBuf); 02105 02106 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); 02107 if (!pvBuf) 02108 { 02109 ret = ERROR_NOT_ENOUGH_MEMORY; 02110 break; 02111 } 02112 02113 if (ret == ERROR_MORE_DATA || !pvData) 02114 ret = RegQueryValueExA(hKey, pszValue, NULL, 02115 &dwType, pvBuf, &cbData); 02116 else 02117 { 02118 /* Even if cbData was large enough we have to copy the 02119 * string since ExpandEnvironmentStrings can't handle 02120 * overlapping buffers. */ 02121 CopyMemory(pvBuf, pvData, cbData); 02122 } 02123 02124 /* Both the type or the value itself could have been modified in 02125 * between so we have to keep retrying until the buffer is large 02126 * enough or we no longer have to expand the value. */ 02127 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); 02128 02129 if (ret == ERROR_SUCCESS) 02130 { 02131 /* Recheck dwType in case it changed since the first call */ 02132 if (dwType == REG_EXPAND_SZ) 02133 { 02134 cbData = ExpandEnvironmentStringsA(pvBuf, pvData, 02135 pcbData ? *pcbData : 0); 02136 dwType = REG_SZ; 02137 if(pvData && pcbData && cbData > *pcbData) 02138 ret = ERROR_MORE_DATA; 02139 } 02140 else if (pvData) 02141 CopyMemory(pvData, pvBuf, *pcbData); 02142 } 02143 02144 HeapFree(GetProcessHeap(), 0, pvBuf); 02145 } 02146 02147 if (pszSubKey && pszSubKey[0]) 02148 RegCloseKey(hKey); 02149 02150 RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); 02151 02152 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) 02153 ZeroMemory(pvData, *pcbData); 02154 02155 if (pdwType) *pdwType = dwType; 02156 if (pcbData) *pcbData = cbData; 02157 02158 return ret; 02159 } 02160 02161 02162 /************************************************************************ 02163 * RegSetKeyValueW 02164 * 02165 * @implemented 02166 */ 02167 LONG WINAPI 02168 RegSetKeyValueW(IN HKEY hKey, 02169 IN LPCWSTR lpSubKey OPTIONAL, 02170 IN LPCWSTR lpValueName OPTIONAL, 02171 IN DWORD dwType, 02172 IN LPCVOID lpData OPTIONAL, 02173 IN DWORD cbData) 02174 { 02175 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 02176 NTSTATUS Status; 02177 LONG Ret; 02178 02179 Status = MapDefaultKey(&KeyHandle, 02180 hKey); 02181 if (!NT_SUCCESS(Status)) 02182 { 02183 return RtlNtStatusToDosError(Status); 02184 } 02185 02186 if (lpSubKey != NULL) 02187 { 02188 OBJECT_ATTRIBUTES ObjectAttributes; 02189 UNICODE_STRING SubKeyName; 02190 02191 RtlInitUnicodeString(&SubKeyName, 02192 (LPWSTR)lpSubKey); 02193 02194 InitializeObjectAttributes(&ObjectAttributes, 02195 &SubKeyName, 02196 OBJ_CASE_INSENSITIVE, 02197 KeyHandle, 02198 NULL); 02199 02200 Status = NtOpenKey(&SubKeyHandle, 02201 KEY_SET_VALUE, 02202 &ObjectAttributes); 02203 if (!NT_SUCCESS(Status)) 02204 { 02205 Ret = RtlNtStatusToDosError(Status); 02206 goto Cleanup; 02207 } 02208 02209 CurKey = SubKeyHandle; 02210 } 02211 else 02212 CurKey = KeyHandle; 02213 02214 Ret = RegSetValueExW(CurKey, 02215 lpValueName, 02216 0, 02217 dwType, 02218 lpData, 02219 cbData); 02220 02221 if (SubKeyHandle != NULL) 02222 { 02223 NtClose(SubKeyHandle); 02224 } 02225 02226 Cleanup: 02227 ClosePredefKey(KeyHandle); 02228 02229 return Ret; 02230 } 02231 02232 02233 /************************************************************************ 02234 * RegSetKeyValueA 02235 * 02236 * @implemented 02237 */ 02238 LONG WINAPI 02239 RegSetKeyValueA(IN HKEY hKey, 02240 IN LPCSTR lpSubKey OPTIONAL, 02241 IN LPCSTR lpValueName OPTIONAL, 02242 IN DWORD dwType, 02243 IN LPCVOID lpData OPTIONAL, 02244 IN DWORD cbData) 02245 { 02246 HANDLE KeyHandle, CurKey, SubKeyHandle = NULL; 02247 NTSTATUS Status; 02248 LONG Ret; 02249 02250 Status = MapDefaultKey(&KeyHandle, 02251 hKey); 02252 if (!NT_SUCCESS(Status)) 02253 { 02254 return RtlNtStatusToDosError(Status); 02255 } 02256 02257 if (lpSubKey != NULL) 02258 { 02259 OBJECT_ATTRIBUTES ObjectAttributes; 02260 UNICODE_STRING SubKeyName; 02261 02262 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, 02263 (LPSTR)lpSubKey)) 02264 { 02265 Ret = ERROR_NOT_ENOUGH_MEMORY; 02266 goto Cleanup; 02267 } 02268 02269 InitializeObjectAttributes(&ObjectAttributes, 02270 &SubKeyName, 02271 OBJ_CASE_INSENSITIVE, 02272 KeyHandle, 02273 NULL); 02274 02275 Status = NtOpenKey(&SubKeyHandle, 02276 KEY_SET_VALUE, 02277 &ObjectAttributes); 02278 02279 RtlFreeUnicodeString(&SubKeyName); 02280 02281 if (!NT_SUCCESS(Status)) 02282 { 02283 Ret = RtlNtStatusToDosError(Status); 02284 goto Cleanup; 02285 } 02286 02287 CurKey = SubKeyHandle; 02288 } 02289 else 02290 CurKey = KeyHandle; 02291 02292 Ret = RegSetValueExA(CurKey, 02293 lpValueName, 02294 0, 02295 dwType, 02296 lpData, 02297 cbData); 02298 02299 if (SubKeyHandle != NULL) 02300 { 02301 NtClose(SubKeyHandle); 02302 } 02303 02304 Cleanup: 02305 ClosePredefKey(KeyHandle); 02306 02307 return Ret; 02308 } 02309 02310 02311 /************************************************************************ 02312 * RegDeleteValueA 02313 * 02314 * @implemented 02315 */ 02316 LONG WINAPI 02317 RegDeleteValueA(HKEY hKey, 02318 LPCSTR lpValueName) 02319 { 02320 UNICODE_STRING ValueName; 02321 HANDLE KeyHandle; 02322 NTSTATUS Status; 02323 02324 Status = MapDefaultKey(&KeyHandle, 02325 hKey); 02326 if (!NT_SUCCESS(Status)) 02327 { 02328 return RtlNtStatusToDosError(Status); 02329 } 02330 02331 RtlCreateUnicodeStringFromAsciiz(&ValueName, 02332 (LPSTR)lpValueName); 02333 Status = NtDeleteValueKey(KeyHandle, 02334 &ValueName); 02335 RtlFreeUnicodeString (&ValueName); 02336 02337 ClosePredefKey(KeyHandle); 02338 02339 if (!NT_SUCCESS(Status)) 02340 { 02341 return RtlNtStatusToDosError(Status); 02342 } 02343 02344 return ERROR_SUCCESS; 02345 } 02346 02347 02348 /************************************************************************ 02349 * RegDeleteValueW 02350 * 02351 * @implemented 02352 */ 02353 LONG WINAPI 02354 RegDeleteValueW(HKEY hKey, 02355 LPCWSTR lpValueName) 02356 { 02357 UNICODE_STRING ValueName; 02358 NTSTATUS Status; 02359 HANDLE KeyHandle; 02360 02361 Status = MapDefaultKey(&KeyHandle, 02362 hKey); 02363 if (!NT_SUCCESS(Status)) 02364 { 02365 return RtlNtStatusToDosError(Status); 02366 } 02367 02368 RtlInitUnicodeString(&ValueName, 02369 (LPWSTR)lpValueName); 02370 02371 Status = NtDeleteValueKey(KeyHandle, 02372 &ValueName); 02373 02374 ClosePredefKey(KeyHandle); 02375 02376 if (!NT_SUCCESS(Status)) 02377 { 02378 return RtlNtStatusToDosError(Status); 02379 } 02380 02381 return ERROR_SUCCESS; 02382 } 02383 02384 02385 /************************************************************************ 02386 * RegEnumKeyA 02387 * 02388 * @implemented 02389 */ 02390 LONG WINAPI 02391 RegEnumKeyA(HKEY hKey, 02392 DWORD dwIndex, 02393 LPSTR lpName, 02394 DWORD cbName) 02395 { 02396 DWORD dwLength; 02397 02398 dwLength = cbName; 02399 return RegEnumKeyExA(hKey, 02400 dwIndex, 02401 lpName, 02402 &dwLength, 02403 NULL, 02404 NULL, 02405 NULL, 02406 NULL); 02407 } 02408 02409 02410 /************************************************************************ 02411 * RegEnumKeyW 02412 * 02413 * @implemented 02414 */ 02415 LONG WINAPI 02416 RegEnumKeyW(HKEY hKey, 02417 DWORD dwIndex, 02418 LPWSTR lpName, 02419 DWORD cbName) 02420 { 02421 DWORD dwLength; 02422 02423 dwLength = cbName; 02424 return RegEnumKeyExW(hKey, 02425 dwIndex, 02426 lpName, 02427 &dwLength, 02428 NULL, 02429 NULL, 02430 NULL, 02431 NULL); 02432 } 02433 02434 02435 /************************************************************************ 02436 * RegEnumKeyExA 02437 * 02438 * @implemented 02439 */ 02440 LONG WINAPI 02441 RegEnumKeyExA(HKEY hKey, 02442 DWORD dwIndex, 02443 LPSTR lpName, 02444 LPDWORD lpcbName, 02445 LPDWORD lpReserved, 02446 LPSTR lpClass, 02447 LPDWORD lpcbClass, 02448 PFILETIME lpftLastWriteTime) 02449 { 02450 union 02451 { 02452 KEY_NODE_INFORMATION Node; 02453 KEY_BASIC_INFORMATION Basic; 02454 } *KeyInfo; 02455 02456 UNICODE_STRING StringU; 02457 ANSI_STRING StringA; 02458 LONG ErrorCode = ERROR_SUCCESS; 02459 DWORD NameLength; 02460 DWORD ClassLength = 0; 02461 DWORD BufferSize; 02462 ULONG ResultSize; 02463 HANDLE KeyHandle; 02464 NTSTATUS Status; 02465 02466 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n", 02467 hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0); 02468 02469 if ((lpClass) && (!lpcbClass)) 02470 { 02471 return ERROR_INVALID_PARAMETER; 02472 } 02473 02474 Status = MapDefaultKey(&KeyHandle, hKey); 02475 if (!NT_SUCCESS(Status)) 02476 { 02477 return RtlNtStatusToDosError(Status); 02478 } 02479 02480 if (*lpcbName > 0) 02481 { 02482 NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR); 02483 } 02484 else 02485 { 02486 NameLength = 0; 02487 } 02488 02489 if (lpClass) 02490 { 02491 if (*lpcbClass > 0) 02492 { 02493 ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 02494 } 02495 else 02496 { 02497 ClassLength = 0; 02498 } 02499 02500 /* The class name should start at a dword boundary */ 02501 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength; 02502 } 02503 else 02504 { 02505 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength; 02506 } 02507 02508 KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize); 02509 if (KeyInfo == NULL) 02510 { 02511 ErrorCode = ERROR_OUTOFMEMORY; 02512 goto Cleanup; 02513 } 02514 02515 Status = NtEnumerateKey(KeyHandle, 02516 (ULONG)dwIndex, 02517 lpClass == NULL ? KeyBasicInformation : KeyNodeInformation, 02518 KeyInfo, 02519 BufferSize, 02520 &ResultSize); 02521 TRACE("NtEnumerateKey() returned status 0x%X\n", Status); 02522 if (!NT_SUCCESS(Status)) 02523 { 02524 ErrorCode = RtlNtStatusToDosError (Status); 02525 } 02526 else 02527 { 02528 if (lpClass == NULL) 02529 { 02530 if (KeyInfo->Basic.NameLength > NameLength) 02531 { 02532 ErrorCode = ERROR_BUFFER_OVERFLOW; 02533 } 02534 else 02535 { 02536 StringU.Buffer = KeyInfo->Basic.Name; 02537 StringU.Length = KeyInfo->Basic.NameLength; 02538 StringU.MaximumLength = KeyInfo->Basic.NameLength; 02539 } 02540 } 02541 else 02542 { 02543 if (KeyInfo->Node.NameLength > NameLength || 02544 KeyInfo->Node.ClassLength > ClassLength) 02545 { 02546 ErrorCode = ERROR_BUFFER_OVERFLOW; 02547 } 02548 else 02549 { 02550 StringA.Buffer = lpClass; 02551 StringA.Length = 0; 02552 StringA.MaximumLength = *lpcbClass; 02553 StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset); 02554 StringU.Length = KeyInfo->Node.ClassLength; 02555 StringU.MaximumLength = KeyInfo->Node.ClassLength; 02556 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE); 02557 lpClass[StringA.Length] = 0; 02558 *lpcbClass = StringA.Length; 02559 StringU.Buffer = KeyInfo->Node.Name; 02560 StringU.Length = KeyInfo->Node.NameLength; 02561 StringU.MaximumLength = KeyInfo->Node.NameLength; 02562 } 02563 } 02564 02565 if (ErrorCode == ERROR_SUCCESS) 02566 { 02567 StringA.Buffer = lpName; 02568 StringA.Length = 0; 02569 StringA.MaximumLength = *lpcbName; 02570 RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE); 02571 lpName[StringA.Length] = 0; 02572 *lpcbName = StringA.Length; 02573 if (lpftLastWriteTime != NULL) 02574 { 02575 if (lpClass == NULL) 02576 { 02577 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart; 02578 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart; 02579 } 02580 else 02581 { 02582 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart; 02583 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart; 02584 } 02585 } 02586 } 02587 } 02588 02589 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */ 02590 TRACE("Key Name1 Length %d\n", NameLength); 02591 TRACE("Key Name Length %d\n", *lpcbName); 02592 TRACE("Key Name %s\n", lpName); 02593 02594 RtlFreeHeap(ProcessHeap, 02595 0, 02596 KeyInfo); 02597 02598 Cleanup: 02599 ClosePredefKey(KeyHandle); 02600 02601 return ErrorCode; 02602 } 02603 02604 02605 /************************************************************************ 02606 * RegEnumKeyExW 02607 * 02608 * @implemented 02609 */ 02610 LONG WINAPI 02611 RegEnumKeyExW(HKEY hKey, 02612 DWORD dwIndex, 02613 LPWSTR lpName, 02614 LPDWORD lpcbName, 02615 LPDWORD lpReserved, 02616 LPWSTR lpClass, 02617 LPDWORD lpcbClass, 02618 PFILETIME lpftLastWriteTime) 02619 { 02620 union 02621 { 02622 KEY_NODE_INFORMATION Node; 02623 KEY_BASIC_INFORMATION Basic; 02624 } *KeyInfo; 02625 02626 ULONG BufferSize; 02627 ULONG ResultSize; 02628 ULONG NameLength; 02629 ULONG ClassLength = 0; 02630 HANDLE KeyHandle; 02631 LONG ErrorCode = ERROR_SUCCESS; 02632 NTSTATUS Status; 02633 02634 Status = MapDefaultKey(&KeyHandle, 02635 hKey); 02636 if (!NT_SUCCESS(Status)) 02637 { 02638 return RtlNtStatusToDosError(Status); 02639 } 02640 02641 if (*lpcbName > 0) 02642 { 02643 NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR); 02644 } 02645 else 02646 { 02647 NameLength = 0; 02648 } 02649 02650 if (lpClass) 02651 { 02652 if (*lpcbClass > 0) 02653 { 02654 ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 02655 } 02656 else 02657 { 02658 ClassLength = 0; 02659 } 02660 02661 BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength; 02662 } 02663 else 02664 { 02665 BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength; 02666 } 02667 02668 KeyInfo = RtlAllocateHeap(ProcessHeap, 02669 0, 02670 BufferSize); 02671 if (KeyInfo == NULL) 02672 { 02673 ErrorCode = ERROR_OUTOFMEMORY; 02674 goto Cleanup; 02675 } 02676 02677 Status = NtEnumerateKey(KeyHandle, 02678 (ULONG)dwIndex, 02679 lpClass ? KeyNodeInformation : KeyBasicInformation, 02680 KeyInfo, 02681 BufferSize, 02682 &ResultSize); 02683 TRACE("NtEnumerateKey() returned status 0x%X\n", Status); 02684 if (!NT_SUCCESS(Status)) 02685 { 02686 ErrorCode = RtlNtStatusToDosError (Status); 02687 } 02688 else 02689 { 02690 if (lpClass == NULL) 02691 { 02692 if (KeyInfo->Basic.NameLength > NameLength) 02693 { 02694 ErrorCode = ERROR_BUFFER_OVERFLOW; 02695 } 02696 else 02697 { 02698 RtlCopyMemory(lpName, 02699 KeyInfo->Basic.Name, 02700 KeyInfo->Basic.NameLength); 02701 *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR)); 02702 lpName[*lpcbName] = 0; 02703 } 02704 } 02705 else 02706 { 02707 if (KeyInfo->Node.NameLength > NameLength || 02708 KeyInfo->Node.ClassLength > ClassLength) 02709 { 02710 ErrorCode = ERROR_BUFFER_OVERFLOW; 02711 } 02712 else 02713 { 02714 RtlCopyMemory(lpName, 02715 KeyInfo->Node.Name, 02716 KeyInfo->Node.NameLength); 02717 *lpcbName = KeyInfo->Node.NameLength / sizeof(WCHAR); 02718 lpName[*lpcbName] = 0; 02719 RtlCopyMemory(lpClass, 02720 (PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset), 02721 KeyInfo->Node.ClassLength); 02722 *lpcbClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR)); 02723 lpClass[*lpcbClass] = 0; 02724 } 02725 } 02726 02727 if (ErrorCode == ERROR_SUCCESS && lpftLastWriteTime != NULL) 02728 { 02729 if (lpClass == NULL) 02730 { 02731 lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart; 02732 lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart; 02733 } 02734 else 02735 { 02736 lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart; 02737 lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart; 02738 } 02739 } 02740 } 02741 02742 RtlFreeHeap(ProcessHeap, 02743 0, 02744 KeyInfo); 02745 02746 Cleanup: 02747 ClosePredefKey(KeyHandle); 02748 02749 return ErrorCode; 02750 } 02751 02752 02753 /************************************************************************ 02754 * RegEnumValueA 02755 * 02756 * @implemented 02757 */ 02758 LONG WINAPI 02759 RegEnumValueA(HKEY hKey, 02760 DWORD index, 02761 LPSTR value, 02762 LPDWORD val_count, 02763 LPDWORD reserved, 02764 LPDWORD type, 02765 LPBYTE data, 02766 LPDWORD count) 02767 { 02768 HANDLE KeyHandle; 02769 NTSTATUS status; 02770 ULONG total_size; 02771 char buffer[256], *buf_ptr = buffer; 02772 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; 02773 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name ); 02774 02775 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n", 02776 // hkey, index, value, val_count, reserved, type, data, count ); 02777 02778 /* NT only checks count, not val_count */ 02779 if ((data && !count) || reserved) 02780 return ERROR_INVALID_PARAMETER; 02781 02782 status = MapDefaultKey(&KeyHandle, hKey); 02783 if (!NT_SUCCESS(status)) 02784 { 02785 return RtlNtStatusToDosError(status); 02786 } 02787 02788 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); 02789 if (data) total_size += *count; 02790 total_size = min( sizeof(buffer), total_size ); 02791 02792 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 02793 buffer, total_size, &total_size ); 02794 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done; 02795 02796 /* we need to fetch the contents for a string type even if not requested, 02797 * because we need to compute the length of the ASCII string. */ 02798 if (value || data || is_string(info->Type)) 02799 { 02800 /* retry with a dynamically allocated buffer */ 02801 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL)) 02802 { 02803 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 02804 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 02805 { 02806 status = STATUS_INSUFFICIENT_RESOURCES; 02807 goto done; 02808 } 02809 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr; 02810 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 02811 buf_ptr, total_size, &total_size ); 02812 } 02813 02814 if (status) goto done; 02815 02816 if (is_string(info->Type)) 02817 { 02818 ULONG len; 02819 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset), 02820 info->DataLength ); 02821 if (data && len) 02822 { 02823 if (len > *count) status = STATUS_BUFFER_OVERFLOW; 02824 else 02825 { 02826 RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset), 02827 info->DataLength ); 02828 /* if the type is REG_SZ and data is not 0-terminated 02829 * and there is enough space in the buffer NT appends a \0 */ 02830 if (len < *count && data[len-1]) data[len] = 0; 02831 } 02832 } 02833 info->DataLength = len; 02834 } 02835 else if (data) 02836 { 02837 if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW; 02838 else memcpy( data, buf_ptr + info->DataOffset, info->DataLength ); 02839 } 02840 02841 if (value && !status) 02842 { 02843 ULONG len; 02844 02845 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); 02846 if (len >= *val_count) 02847 { 02848 status = STATUS_BUFFER_OVERFLOW; 02849 if (*val_count) 02850 { 02851 len = *val_count - 1; 02852 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength ); 02853 value[len] = 0; 02854 } 02855 } 02856 else 02857 { 02858 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength ); 02859 value[len] = 0; 02860 *val_count = len; 02861 } 02862 } 02863 } 02864 else status = STATUS_SUCCESS; 02865 02866 if (type) *type = info->Type; 02867 if (count) *count = info->DataLength; 02868 02869 done: 02870 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 02871 ClosePredefKey(KeyHandle); 02872 return RtlNtStatusToDosError(status); 02873 } 02874 02875 02876 /****************************************************************************** 02877 * RegEnumValueW [ADVAPI32.@] 02878 * @implemented 02879 * 02880 * PARAMS 02881 * hkey [I] Handle to key to query 02882 * index [I] Index of value to query 02883 * value [O] Value string 02884 * val_count [I/O] Size of value buffer (in wchars) 02885 * reserved [I] Reserved 02886 * type [O] Type code 02887 * data [O] Value data 02888 * count [I/O] Size of data buffer (in bytes) 02889 * 02890 * RETURNS 02891 * Success: ERROR_SUCCESS 02892 * Failure: nonzero error code from Winerror.h 02893 */ 02894 LONG WINAPI 02895 RegEnumValueW(HKEY hKey, 02896 DWORD index, 02897 LPWSTR value, 02898 PDWORD val_count, 02899 PDWORD reserved, 02900 PDWORD type, 02901 LPBYTE data, 02902 PDWORD count) 02903 { 02904 HANDLE KeyHandle; 02905 NTSTATUS status; 02906 ULONG total_size; 02907 char buffer[256], *buf_ptr = buffer; 02908 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; 02909 static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name ); 02910 02911 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n", 02912 // hkey, index, value, val_count, reserved, type, data, count ); 02913 02914 /* NT only checks count, not val_count */ 02915 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 02916 02917 status = MapDefaultKey(&KeyHandle, hKey); 02918 if (!NT_SUCCESS(status)) 02919 { 02920 return RtlNtStatusToDosError(status); 02921 } 02922 02923 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); 02924 if (data) total_size += *count; 02925 total_size = min( sizeof(buffer), total_size ); 02926 02927 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 02928 buffer, total_size, &total_size ); 02929 if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done; 02930 02931 if (value || data) 02932 { 02933 /* retry with a dynamically allocated buffer */ 02934 while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL)) 02935 { 02936 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 02937 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 02938 { 02939 status = ERROR_NOT_ENOUGH_MEMORY; 02940 goto done; 02941 } 02942 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr; 02943 status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, 02944 buf_ptr, total_size, &total_size ); 02945 } 02946 02947 if (status) goto done; 02948 02949 if (value) 02950 { 02951 if (info->NameLength/sizeof(WCHAR) >= *val_count) 02952 { 02953 status = STATUS_BUFFER_OVERFLOW; 02954 goto overflow; 02955 } 02956 memcpy( value, info->Name, info->NameLength ); 02957 *val_count = info->NameLength / sizeof(WCHAR); 02958 value[*val_count] = 0; 02959 } 02960 02961 if (data) 02962 { 02963 if (info->DataLength > *count) 02964 { 02965 status = STATUS_BUFFER_OVERFLOW; 02966 goto overflow; 02967 } 02968 memcpy( data, buf_ptr + info->DataOffset, info->DataLength ); 02969 if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR)) 02970 { 02971 /* if the type is REG_SZ and data is not 0-terminated 02972 * and there is enough space in the buffer NT appends a \0 */ 02973 WCHAR *ptr = (WCHAR *)(data + info->DataLength); 02974 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 02975 } 02976 } 02977 } 02978 else status = STATUS_SUCCESS; 02979 02980 overflow: 02981 if (type) *type = info->Type; 02982 if (count) *count = info->DataLength; 02983 02984 done: 02985 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 02986 ClosePredefKey(KeyHandle); 02987 return RtlNtStatusToDosError(status); 02988 } 02989 02990 02991 /************************************************************************ 02992 * RegFlushKey 02993 * 02994 * @implemented 02995 */ 02996 LONG WINAPI 02997 RegFlushKey(HKEY hKey) 02998 { 02999 HANDLE KeyHandle; 03000 NTSTATUS Status; 03001 03002 if (hKey == HKEY_PERFORMANCE_DATA) 03003 { 03004 return ERROR_SUCCESS; 03005 } 03006 03007 Status = MapDefaultKey(&KeyHandle, 03008 hKey); 03009 if (!NT_SUCCESS(Status)) 03010 { 03011 return RtlNtStatusToDosError(Status); 03012 } 03013 03014 Status = NtFlushKey(KeyHandle); 03015 03016 ClosePredefKey(KeyHandle); 03017 03018 if (!NT_SUCCESS(Status)) 03019 { 03020 return RtlNtStatusToDosError(Status); 03021 } 03022 03023 return ERROR_SUCCESS; 03024 } 03025 03026 03027 /************************************************************************ 03028 * RegGetKeySecurity 03029 * 03030 * @implemented 03031 */ 03032 LONG WINAPI 03033 RegGetKeySecurity(HKEY hKey, 03034 SECURITY_INFORMATION SecurityInformation, 03035 PSECURITY_DESCRIPTOR pSecurityDescriptor, 03036 LPDWORD lpcbSecurityDescriptor) 03037 { 03038 HANDLE KeyHandle; 03039 NTSTATUS Status; 03040 03041 if (hKey == HKEY_PERFORMANCE_DATA) 03042 { 03043 return ERROR_INVALID_HANDLE; 03044 } 03045 03046 Status = MapDefaultKey(&KeyHandle, 03047 hKey); 03048 if (!NT_SUCCESS(Status)) 03049 { 03050 TRACE("MapDefaultKey() failed (Status %lx)\n", Status); 03051 return RtlNtStatusToDosError(Status); 03052 } 03053 03054 #if 0 03055 Status = NtQuerySecurityObject(KeyHandle, 03056 SecurityInformation, 03057 pSecurityDescriptor, 03058 *lpcbSecurityDescriptor, 03059 lpcbSecurityDescriptor); 03060 #endif 03061 03062 ClosePredefKey(KeyHandle); 03063 03064 if (!NT_SUCCESS(Status)) 03065 { 03066 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status); 03067 return RtlNtStatusToDosError(Status); 03068 } 03069 03070 return ERROR_SUCCESS; 03071 } 03072 03073 03074 /************************************************************************ 03075 * RegLoadKeyA 03076 * 03077 * @implemented 03078 */ 03079 LONG WINAPI 03080 RegLoadKeyA(HKEY hKey, 03081 LPCSTR lpSubKey, 03082 LPCSTR lpFile) 03083 { 03084 UNICODE_STRING FileName; 03085 UNICODE_STRING KeyName; 03086 LONG ErrorCode; 03087 03088 RtlCreateUnicodeStringFromAsciiz(&KeyName, 03089 (LPSTR)lpSubKey); 03090 RtlCreateUnicodeStringFromAsciiz(&FileName, 03091 (LPSTR)lpFile); 03092 03093 ErrorCode = RegLoadKeyW(hKey, 03094 KeyName.Buffer, 03095 FileName.Buffer); 03096 03097 RtlFreeUnicodeString(&FileName); 03098 RtlFreeUnicodeString(&KeyName); 03099 03100 return ErrorCode; 03101 } 03102 03103 03104 /************************************************************************ 03105 * RegLoadKeyW 03106 * 03107 * @implemented 03108 */ 03109 LONG WINAPI 03110 RegLoadKeyW(HKEY hKey, 03111 LPCWSTR lpSubKey, 03112 LPCWSTR lpFile) 03113 { 03114 OBJECT_ATTRIBUTES FileObjectAttributes; 03115 OBJECT_ATTRIBUTES KeyObjectAttributes; 03116 UNICODE_STRING FileName; 03117 UNICODE_STRING KeyName; 03118 HANDLE KeyHandle; 03119 NTSTATUS Status; 03120 LONG ErrorCode = ERROR_SUCCESS; 03121 03122 if (hKey == HKEY_PERFORMANCE_DATA) 03123 { 03124 return ERROR_INVALID_HANDLE; 03125 } 03126 03127 Status = MapDefaultKey(&KeyHandle, 03128 hKey); 03129 if (!NT_SUCCESS(Status)) 03130 { 03131 return RtlNtStatusToDosError(Status); 03132 } 03133 03134 if (!RtlDosPathNameToNtPathName_U(lpFile, 03135 &FileName, 03136 NULL, 03137 NULL)) 03138 { 03139 ErrorCode = ERROR_BAD_PATHNAME; 03140 goto Cleanup; 03141 } 03142 03143 InitializeObjectAttributes(&FileObjectAttributes, 03144 &FileName, 03145 OBJ_CASE_INSENSITIVE, 03146 NULL, 03147 NULL); 03148 03149 RtlInitUnicodeString(&KeyName, 03150 (LPWSTR)lpSubKey); 03151 03152 InitializeObjectAttributes(&KeyObjectAttributes, 03153 &KeyName, 03154 OBJ_CASE_INSENSITIVE, 03155 KeyHandle, 03156 NULL); 03157 03158 Status = NtLoadKey(&KeyObjectAttributes, 03159 &FileObjectAttributes); 03160 03161 RtlFreeHeap(RtlGetProcessHeap(), 03162 0, 03163 FileName.Buffer); 03164 03165 if (!NT_SUCCESS(Status)) 03166 { 03167 ErrorCode = RtlNtStatusToDosError(Status); 03168 goto Cleanup; 03169 } 03170 03171 Cleanup: 03172 ClosePredefKey(KeyHandle); 03173 03174 return ErrorCode; 03175 } 03176 03177 03178 /************************************************************************ 03179 * RegNotifyChangeKeyValue 03180 * 03181 * @unimplemented 03182 */ 03183 LONG WINAPI 03184 RegNotifyChangeKeyValue(HKEY hKey, 03185 BOOL bWatchSubtree, 03186 DWORD dwNotifyFilter, 03187 HANDLE hEvent, 03188 BOOL fAsynchronous) 03189 { 03190 IO_STATUS_BLOCK IoStatusBlock; 03191 HANDLE KeyHandle; 03192 NTSTATUS Status; 03193 LONG ErrorCode = ERROR_SUCCESS; 03194 03195 if (hKey == HKEY_PERFORMANCE_DATA) 03196 { 03197 return ERROR_INVALID_HANDLE; 03198 } 03199 03200 if (fAsynchronous == TRUE && hEvent == NULL) 03201 { 03202 return ERROR_INVALID_PARAMETER; 03203 } 03204 03205 Status = MapDefaultKey(&KeyHandle, 03206 hKey); 03207 if (!NT_SUCCESS(Status)) 03208 { 03209 return RtlNtStatusToDosError(Status); 03210 } 03211 03212 /* FIXME: Remote key handles must fail */ 03213 03214 Status = NtNotifyChangeKey(KeyHandle, 03215 hEvent, 03216 0, 03217 0, 03218 &IoStatusBlock, 03219 dwNotifyFilter, 03220 bWatchSubtree, 03221 0, 03222 0, 03223 fAsynchronous); 03224 if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT) 03225 { 03226 ErrorCode = RtlNtStatusToDosError(Status); 03227 } 03228 03229 ClosePredefKey(KeyHandle); 03230 03231 return ErrorCode; 03232 } 03233 03234 03235 /************************************************************************ 03236 * RegOpenCurrentUser 03237 * 03238 * @implemented 03239 */ 03240 LONG WINAPI 03241 RegOpenCurrentUser(IN REGSAM samDesired, 03242 OUT PHKEY phkResult) 03243 { 03244 NTSTATUS Status; 03245 03246 Status = RtlOpenCurrentUser((ACCESS_MASK)samDesired, 03247 (PHANDLE)phkResult); 03248 if (!NT_SUCCESS(Status)) 03249 { 03250 /* NOTE - don't set the last error code! just return the error! */ 03251 return RtlNtStatusToDosError(Status); 03252 } 03253 03254 return ERROR_SUCCESS; 03255 } 03256 03257 03258 /************************************************************************ 03259 * RegOpenKeyA 03260 * 03261 * 20050503 Fireball - imported from WINE 03262 * 03263 * @implemented 03264 */ 03265 LONG WINAPI 03266 RegOpenKeyA(HKEY hKey, 03267 LPCSTR lpSubKey, 03268 PHKEY phkResult) 03269 { 03270 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", 03271 hKey, lpSubKey, phkResult); 03272 03273 if (!phkResult) 03274 return ERROR_INVALID_PARAMETER; 03275 03276 if (!hKey && lpSubKey && phkResult) 03277 { 03278 return ERROR_INVALID_HANDLE; 03279 } 03280 03281 if (!lpSubKey || !*lpSubKey) 03282 { 03283 *phkResult = hKey; 03284 return ERROR_SUCCESS; 03285 } 03286 03287 return RegOpenKeyExA(hKey, 03288 lpSubKey, 03289 0, 03290 MAXIMUM_ALLOWED, 03291 phkResult); 03292 } 03293 03294 03295 /************************************************************************ 03296 * RegOpenKeyW 03297 * 03298 * 19981101 Ariadne 03299 * 19990525 EA 03300 * 20050503 Fireball - imported from WINE 03301 * 03302 * @implemented 03303 */ 03304 LONG WINAPI 03305 RegOpenKeyW(HKEY hKey, 03306 LPCWSTR lpSubKey, 03307 PHKEY phkResult) 03308 { 03309 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", 03310 hKey, lpSubKey, phkResult); 03311 03312 if (!phkResult) 03313 return ERROR_INVALID_PARAMETER; 03314 03315 if (!hKey && lpSubKey && phkResult) 03316 { 03317 return ERROR_INVALID_HANDLE; 03318 } 03319 03320 if (!lpSubKey || !*lpSubKey) 03321 { 03322 *phkResult = hKey; 03323 return ERROR_SUCCESS; 03324 } 03325 03326 return RegOpenKeyExW(hKey, 03327 lpSubKey, 03328 0, 03329 MAXIMUM_ALLOWED, 03330 phkResult); 03331 } 03332 03333 03334 /************************************************************************ 03335 * RegOpenKeyExA 03336 * 03337 * @implemented 03338 */ 03339 LONG WINAPI 03340 RegOpenKeyExA(HKEY hKey, 03341 LPCSTR lpSubKey, 03342 DWORD ulOptions, 03343 REGSAM samDesired, 03344 PHKEY phkResult) 03345 { 03346 OBJECT_ATTRIBUTES ObjectAttributes; 03347 UNICODE_STRING SubKeyString; 03348 HANDLE KeyHandle; 03349 NTSTATUS Status; 03350 LONG ErrorCode = ERROR_SUCCESS; 03351 03352 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n", 03353 hKey, lpSubKey, ulOptions, samDesired, phkResult); 03354 if (!phkResult) 03355 { 03356 return ERROR_INVALID_PARAMETER; 03357 } 03358 03359 Status = MapDefaultKey(&KeyHandle, 03360 hKey); 03361 if (!NT_SUCCESS(Status)) 03362 { 03363 return RtlNtStatusToDosError(Status); 03364 } 03365 03366 RtlCreateUnicodeStringFromAsciiz(&SubKeyString, 03367 (LPSTR)lpSubKey); 03368 InitializeObjectAttributes(&ObjectAttributes, 03369 &SubKeyString, 03370 OBJ_CASE_INSENSITIVE, 03371 KeyHandle, 03372 NULL); 03373 03374 Status = NtOpenKey((PHANDLE)phkResult, 03375 samDesired, 03376 &ObjectAttributes); 03377 RtlFreeUnicodeString(&SubKeyString); 03378 if (!NT_SUCCESS(Status)) 03379 { 03380 ErrorCode = RtlNtStatusToDosError(Status); 03381 } 03382 03383 ClosePredefKey(KeyHandle); 03384 03385 return ErrorCode; 03386 } 03387 03388 03389 /************************************************************************ 03390 * RegOpenKeyExW 03391 * 03392 * @implemented 03393 */ 03394 LONG WINAPI 03395 RegOpenKeyExW(HKEY hKey, 03396 LPCWSTR lpSubKey, 03397 DWORD ulOptions, 03398 REGSAM samDesired, 03399 PHKEY phkResult) 03400 { 03401 OBJECT_ATTRIBUTES ObjectAttributes; 03402 UNICODE_STRING SubKeyString; 03403 HANDLE KeyHandle; 03404 NTSTATUS Status; 03405 LONG ErrorCode = ERROR_SUCCESS; 03406 03407 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n", 03408 hKey, lpSubKey, ulOptions, samDesired, phkResult); 03409 if (!phkResult) 03410 { 03411 return ERROR_INVALID_PARAMETER; 03412 } 03413 03414 Status = MapDefaultKey(&KeyHandle, hKey); 03415 if (!NT_SUCCESS(Status)) 03416 { 03417 return RtlNtStatusToDosError(Status); 03418 } 03419 03420 if (lpSubKey != NULL) 03421 RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey); 03422 else 03423 RtlInitUnicodeString(&SubKeyString, (LPWSTR)L""); 03424 03425 InitializeObjectAttributes(&ObjectAttributes, 03426 &SubKeyString, 03427 OBJ_CASE_INSENSITIVE, 03428 KeyHandle, 03429 NULL); 03430 03431 Status = NtOpenKey((PHANDLE)phkResult, 03432 samDesired, 03433 &ObjectAttributes); 03434 if (!NT_SUCCESS(Status)) 03435 { 03436 ErrorCode = RtlNtStatusToDosError(Status); 03437 } 03438 03439 ClosePredefKey(KeyHandle); 03440 03441 return ErrorCode; 03442 } 03443 03444 03445 /************************************************************************ 03446 * RegOpenUserClassesRoot 03447 * 03448 * @implemented 03449 */ 03450 LONG WINAPI 03451 RegOpenUserClassesRoot(IN HANDLE hToken, 03452 IN DWORD dwOptions, 03453 IN REGSAM samDesired, 03454 OUT PHKEY phkResult) 03455 { 03456 const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\"; 03457 const WCHAR UserClassesKeySuffix[] = L"_Classes"; 03458 PTOKEN_USER TokenUserData; 03459 ULONG RequiredLength; 03460 UNICODE_STRING UserSidString, UserClassesKeyRoot; 03461 OBJECT_ATTRIBUTES ObjectAttributes; 03462 NTSTATUS Status; 03463 03464 /* check parameters */ 03465 if (hToken == NULL || dwOptions != 0 || phkResult == NULL) 03466 { 03467 return ERROR_INVALID_PARAMETER; 03468 } 03469 03470 /* 03471 * Get the user sid from the token 03472 */ 03473 03474 ReadTokenSid: 03475 /* determine how much memory we need */ 03476 Status = NtQueryInformationToken(hToken, 03477 TokenUser, 03478 NULL, 03479 0, 03480 &RequiredLength); 03481 if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL)) 03482 { 03483 /* NOTE - as opposed to all other registry functions windows does indeed 03484 change the last error code in case the caller supplied a invalid 03485 handle for example! */ 03486 return RtlNtStatusToDosError(Status); 03487 } 03488 RegInitialize(); /* HACK until delay-loading is implemented */ 03489 TokenUserData = RtlAllocateHeap(ProcessHeap, 03490 0, 03491 RequiredLength); 03492 if (TokenUserData == NULL) 03493 { 03494 return ERROR_NOT_ENOUGH_MEMORY; 03495 } 03496 03497 /* attempt to read the information */ 03498 Status = NtQueryInformationToken(hToken, 03499 TokenUser, 03500 TokenUserData, 03501 RequiredLength, 03502 &RequiredLength); 03503 if (!NT_SUCCESS(Status)) 03504 { 03505 RtlFreeHeap(ProcessHeap, 03506 0, 03507 TokenUserData); 03508 if (Status == STATUS_BUFFER_TOO_SMALL) 03509 { 03510 /* the information appears to have changed?! try again */ 03511 goto ReadTokenSid; 03512 } 03513 03514 /* NOTE - as opposed to all other registry functions windows does indeed 03515 change the last error code in case the caller supplied a invalid 03516 handle for example! */ 03517 return RtlNtStatusToDosError(Status); 03518 } 03519 03520 /* 03521 * Build the absolute path for the user's registry in the form 03522 * "\Registry\User<SID>_Classes" 03523 */ 03524 Status = RtlConvertSidToUnicodeString(&UserSidString, 03525 TokenUserData->User.Sid, 03526 TRUE); 03527 03528 /* we don't need the user data anymore, free it */ 03529 RtlFreeHeap(ProcessHeap, 03530 0, 03531 TokenUserData); 03532 03533 if (!NT_SUCCESS(Status)) 03534 { 03535 return RtlNtStatusToDosError(Status); 03536 } 03537 03538 /* allocate enough memory for the entire key string */ 03539 UserClassesKeyRoot.Length = 0; 03540 UserClassesKeyRoot.MaximumLength = UserSidString.Length + 03541 sizeof(UserClassesKeyPrefix) + 03542 sizeof(UserClassesKeySuffix); 03543 UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap, 03544 0, 03545 UserClassesKeyRoot.MaximumLength); 03546 if (UserClassesKeyRoot.Buffer == NULL) 03547 { 03548 RtlFreeUnicodeString(&UserSidString); 03549 return RtlNtStatusToDosError(Status); 03550 } 03551 03552 /* build the string */ 03553 RtlAppendUnicodeToString(&UserClassesKeyRoot, 03554 UserClassesKeyPrefix); 03555 RtlAppendUnicodeStringToString(&UserClassesKeyRoot, 03556 &UserSidString); 03557 RtlAppendUnicodeToString(&UserClassesKeyRoot, 03558 UserClassesKeySuffix); 03559 03560 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot); 03561 03562 /* 03563 * Open the key 03564 */ 03565 InitializeObjectAttributes(&ObjectAttributes, 03566 &UserClassesKeyRoot, 03567 OBJ_CASE_INSENSITIVE, 03568 NULL, 03569 NULL); 03570 03571 Status = NtOpenKey((PHANDLE)phkResult, 03572 samDesired, 03573 &ObjectAttributes); 03574 03575 RtlFreeUnicodeString(&UserSidString); 03576 RtlFreeUnicodeString(&UserClassesKeyRoot); 03577 03578 if (!NT_SUCCESS(Status)) 03579 { 03580 return RtlNtStatusToDosError(Status); 03581 } 03582 03583 return ERROR_SUCCESS; 03584 } 03585 03586 03587 /************************************************************************ 03588 * RegQueryInfoKeyA 03589 * 03590 * @implemented 03591 */ 03592 LONG WINAPI 03593 RegQueryInfoKeyA(HKEY hKey, 03594 LPSTR lpClass, 03595 LPDWORD lpcbClass, 03596 LPDWORD lpReserved, 03597 LPDWORD lpcSubKeys, 03598 LPDWORD lpcbMaxSubKeyLen, 03599 LPDWORD lpcbMaxClassLen, 03600 LPDWORD lpcValues, 03601 LPDWORD lpcbMaxValueNameLen, 03602 LPDWORD lpcbMaxValueLen, 03603 LPDWORD lpcbSecurityDescriptor, 03604 PFILETIME lpftLastWriteTime) 03605 { 03606 WCHAR ClassName[MAX_PATH]; 03607 UNICODE_STRING UnicodeString; 03608 ANSI_STRING AnsiString; 03609 LONG ErrorCode; 03610 03611 RtlInitUnicodeString(&UnicodeString, 03612 NULL); 03613 if (lpClass != NULL) 03614 { 03615 UnicodeString.Buffer = &ClassName[0]; 03616 UnicodeString.MaximumLength = sizeof(ClassName); 03617 AnsiString.MaximumLength = *lpcbClass; 03618 } 03619 03620 ErrorCode = RegQueryInfoKeyW(hKey, 03621 UnicodeString.Buffer, 03622 lpcbClass, 03623 lpReserved, 03624 lpcSubKeys, 03625 lpcbMaxSubKeyLen, 03626 lpcbMaxClassLen, 03627 lpcValues, 03628 lpcbMaxValueNameLen, 03629 lpcbMaxValueLen, 03630 lpcbSecurityDescriptor, 03631 lpftLastWriteTime); 03632 if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL)) 03633 { 03634 AnsiString.Buffer = lpClass; 03635 AnsiString.Length = 0; 03636 UnicodeString.Length = *lpcbClass * sizeof(WCHAR); 03637 RtlUnicodeStringToAnsiString(&AnsiString, 03638 &UnicodeString, 03639 FALSE); 03640 *lpcbClass = AnsiString.Length; 03641 lpClass[AnsiString.Length] = 0; 03642 } 03643 03644 return ErrorCode; 03645 } 03646 03647 03648 /************************************************************************ 03649 * RegQueryInfoKeyW 03650 * 03651 * @implemented 03652 */ 03653 LONG WINAPI 03654 RegQueryInfoKeyW(HKEY hKey, 03655 LPWSTR lpClass, 03656 LPDWORD lpcbClass, 03657 LPDWORD lpReserved, 03658 LPDWORD lpcSubKeys, 03659 LPDWORD lpcbMaxSubKeyLen, 03660 LPDWORD lpcbMaxClassLen, 03661 LPDWORD lpcValues, 03662 LPDWORD lpcbMaxValueNameLen, 03663 LPDWORD lpcbMaxValueLen, 03664 LPDWORD lpcbSecurityDescriptor, 03665 PFILETIME lpftLastWriteTime) 03666 { 03667 KEY_FULL_INFORMATION FullInfoBuffer; 03668 PKEY_FULL_INFORMATION FullInfo; 03669 ULONG FullInfoSize; 03670 ULONG ClassLength = 0; 03671 HANDLE KeyHandle; 03672 NTSTATUS Status; 03673 ULONG Length; 03674 LONG ErrorCode = ERROR_SUCCESS; 03675 03676 if ((lpClass) && (!lpcbClass)) 03677 { 03678 return ERROR_INVALID_PARAMETER; 03679 } 03680 03681 Status = MapDefaultKey(&KeyHandle, 03682 hKey); 03683 if (!NT_SUCCESS(Status)) 03684 { 03685 return RtlNtStatusToDosError(Status); 03686 } 03687 03688 if (lpClass != NULL) 03689 { 03690 if (*lpcbClass > 0) 03691 { 03692 ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); 03693 } 03694 else 03695 { 03696 ClassLength = 0; 03697 } 03698 03699 FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3); 03700 FullInfo = RtlAllocateHeap(ProcessHeap, 03701 0, 03702 FullInfoSize); 03703 if (FullInfo == NULL) 03704 { 03705 ErrorCode = ERROR_OUTOFMEMORY; 03706 goto Cleanup; 03707 } 03708 03709 FullInfo->ClassLength = ClassLength; 03710 } 03711 else 03712 { 03713 FullInfoSize = sizeof(KEY_FULL_INFORMATION); 03714 FullInfo = &FullInfoBuffer; 03715 FullInfo->ClassLength = 0; 03716 } 03717 FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); 03718 03719 Status = NtQueryKey(KeyHandle, 03720 KeyFullInformation, 03721 FullInfo, 03722 FullInfoSize, 03723 &Length); 03724 TRACE("NtQueryKey() returned status 0x%X\n", Status); 03725 if (!NT_SUCCESS(Status)) 03726 { 03727 if (lpClass != NULL) 03728 { 03729 RtlFreeHeap(ProcessHeap, 03730 0, 03731 FullInfo); 03732 } 03733 03734 ErrorCode = RtlNtStatusToDosError(Status); 03735 goto Cleanup; 03736 } 03737 03738 TRACE("SubKeys %d\n", FullInfo->SubKeys); 03739 if (lpcSubKeys != NULL) 03740 { 03741 *lpcSubKeys = FullInfo->SubKeys; 03742 } 03743 03744 TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen); 03745 if (lpcbMaxSubKeyLen != NULL) 03746 { 03747 *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1; 03748 } 03749 03750 TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen); 03751 if (lpcbMaxClassLen != NULL) 03752 { 03753 *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1; 03754 } 03755 03756 TRACE("Values %lu\n", FullInfo->Values); 03757 if (lpcValues != NULL) 03758 { 03759 *lpcValues = FullInfo->Values; 03760 } 03761 03762 TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen); 03763 if (lpcbMaxValueNameLen != NULL) 03764 { 03765 *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1; 03766 } 03767 03768 TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen); 03769 if (lpcbMaxValueLen != NULL) 03770 { 03771 *lpcbMaxValueLen = FullInfo->MaxValueDataLen; 03772 } 03773 03774 #if 0 03775 if (lpcbSecurityDescriptor != NULL) 03776 { 03777 Status = NtQuerySecurityObject(KeyHandle, 03778 OWNER_SECURITY_INFORMATION | 03779 GROUP_SECURITY_INFORMATION | 03780 DACL_SECURITY_INFORMATION, 03781 NULL, 03782 0, 03783 lpcbSecurityDescriptor); 03784 if (!NT_SUCCESS(Status)) 03785 { 03786 if (lpClass != NULL) 03787 { 03788 RtlFreeHeap(ProcessHeap, 03789 0, 03790 FullInfo); 03791 } 03792 03793 ErrorCode = RtlNtStatusToDosError(Status); 03794 goto Cleanup; 03795 } 03796 } 03797 #endif 03798 03799 if (lpftLastWriteTime != NULL) 03800 { 03801 lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart; 03802 lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart; 03803 } 03804 03805 if (lpClass != NULL) 03806 { 03807 if (FullInfo->ClassLength > ClassLength) 03808 { 03809 ErrorCode = ERROR_BUFFER_OVERFLOW; 03810 } 03811 else 03812 { 03813 RtlCopyMemory(lpClass, 03814 FullInfo->Class, 03815 FullInfo->ClassLength); 03816 *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR); 03817 lpClass[*lpcbClass] = 0; 03818 } 03819 03820 RtlFreeHeap(ProcessHeap, 03821 0, 03822 FullInfo); 03823 } 03824 03825 Cleanup: 03826 ClosePredefKey(KeyHandle); 03827 03828 return ErrorCode; 03829 } 03830 03831 03832 /************************************************************************ 03833 * RegQueryMultipleValuesA 03834 * 03835 * @implemented 03836 */ 03837 LONG WINAPI 03838 RegQueryMultipleValuesA(HKEY hKey, 03839 PVALENTA val_list, 03840 DWORD num_vals, 03841 LPSTR lpValueBuf, 03842 LPDWORD ldwTotsize) 03843 { 03844 ULONG i; 03845 DWORD maxBytes = *ldwTotsize; 03846 LPSTR bufptr = (LPSTR)lpValueBuf; 03847 LONG ErrorCode; 03848 03849 if (maxBytes >= (1024*1024)) 03850 return ERROR_TRANSFER_TOO_LONG; 03851 03852 *ldwTotsize = 0; 03853 03854 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n", 03855 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 03856 03857 for (i = 0; i < num_vals; i++) 03858 { 03859 val_list[i].ve_valuelen = 0; 03860 ErrorCode = RegQueryValueExA(hKey, 03861 val_list[i].ve_valuename, 03862 NULL, 03863 NULL, 03864 NULL, 03865 &val_list[i].ve_valuelen); 03866 if (ErrorCode != ERROR_SUCCESS) 03867 { 03868 return ErrorCode; 03869 } 03870 03871 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 03872 { 03873 ErrorCode = RegQueryValueExA(hKey, 03874 val_list[i].ve_valuename, 03875 NULL, 03876 &val_list[i].ve_type, 03877 (LPBYTE)bufptr, 03878 &val_list[i].ve_valuelen); 03879 if (ErrorCode != ERROR_SUCCESS) 03880 { 03881 return ErrorCode; 03882 } 03883 03884 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 03885 03886 bufptr += val_list[i].ve_valuelen; 03887 } 03888 03889 *ldwTotsize += val_list[i].ve_valuelen; 03890 } 03891 03892 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 03893 } 03894 03895 03896 /************************************************************************ 03897 * RegQueryMultipleValuesW 03898 * 03899 * @implemented 03900 */ 03901 LONG WINAPI 03902 RegQueryMultipleValuesW(HKEY hKey, 03903 PVALENTW val_list, 03904 DWORD num_vals, 03905 LPWSTR lpValueBuf, 03906 LPDWORD ldwTotsize) 03907 { 03908 ULONG i; 03909 DWORD maxBytes = *ldwTotsize; 03910 LPSTR bufptr = (LPSTR)lpValueBuf; 03911 LONG ErrorCode; 03912 03913 if (maxBytes >= (1024*1024)) 03914 return ERROR_TRANSFER_TOO_LONG; 03915 03916 *ldwTotsize = 0; 03917 03918 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n", 03919 hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); 03920 03921 for (i = 0; i < num_vals; i++) 03922 { 03923 val_list[i].ve_valuelen = 0; 03924 ErrorCode = RegQueryValueExW(hKey, 03925 val_list[i].ve_valuename, 03926 NULL, 03927 NULL, 03928 NULL, 03929 &val_list[i].ve_valuelen); 03930 if (ErrorCode != ERROR_SUCCESS) 03931 { 03932 return ErrorCode; 03933 } 03934 03935 if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) 03936 { 03937 ErrorCode = RegQueryValueExW(hKey, 03938 val_list[i].ve_valuename, 03939 NULL, 03940 &val_list[i].ve_type, 03941 (LPBYTE)bufptr, 03942 &val_list[i].ve_valuelen); 03943 if (ErrorCode != ERROR_SUCCESS) 03944 { 03945 return ErrorCode; 03946 } 03947 03948 val_list[i].ve_valueptr = (DWORD_PTR)bufptr; 03949 03950 bufptr += val_list[i].ve_valuelen; 03951 } 03952 03953 *ldwTotsize += val_list[i].ve_valuelen; 03954 } 03955 03956 return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA; 03957 } 03958 03959 03960 /************************************************************************ 03961 * RegQueryReflectionKey 03962 * 03963 * @unimplemented 03964 */ 03965 LONG WINAPI 03966 RegQueryReflectionKey(IN HKEY hBase, 03967 OUT BOOL* bIsReflectionDisabled) 03968 { 03969 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n", 03970 hBase, bIsReflectionDisabled); 03971 return ERROR_CALL_NOT_IMPLEMENTED; 03972 } 03973 03974 03975 /****************************************************************************** 03976 * RegQueryValueExA [ADVAPI32.@] 03977 * 03978 * Get the type and contents of a specified value under with a key. 03979 * 03980 * PARAMS 03981 * hkey [I] Handle of the key to query 03982 * name [I] Name of value under hkey to query 03983 * reserved [I] Reserved - must be NULL 03984 * type [O] Destination for the value type, or NULL if not required 03985 * data [O] Destination for the values contents, or NULL if not required 03986 * count [I/O] Size of data, updated with the number of bytes returned 03987 * 03988 * RETURNS 03989 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. 03990 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. 03991 * ERROR_INVALID_PARAMETER, if any other parameter is invalid. 03992 * ERROR_MORE_DATA, if on input *count is too small to hold the contents. 03993 * 03994 * NOTES 03995 * MSDN states that if data is too small it is partially filled. In reality 03996 * it remains untouched. 03997 */ 03998 LONG 03999 WINAPI 04000 RegQueryValueExA(HKEY hkeyorg, 04001 LPCSTR name, 04002 LPDWORD reserved, 04003 LPDWORD type, 04004 LPBYTE data, 04005 LPDWORD count) 04006 { 04007 HANDLE hkey; 04008 NTSTATUS status; 04009 ANSI_STRING nameA; 04010 UNICODE_STRING nameW; 04011 DWORD total_size, datalen = 0; 04012 char buffer[256], *buf_ptr = buffer; 04013 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 04014 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); 04015 04016 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", 04017 hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); 04018 04019 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 04020 status = MapDefaultKey(&hkey, hkeyorg); 04021 if (!NT_SUCCESS(status)) 04022 { 04023 return RtlNtStatusToDosError(status); 04024 } 04025 04026 if (count) datalen = *count; 04027 if (!data && count) *count = 0; 04028 04029 RtlInitAnsiString( &nameA, name ); 04030 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) 04031 { 04032 ClosePredefKey(hkey); 04033 return RtlNtStatusToDosError(status); 04034 } 04035 04036 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, 04037 buffer, sizeof(buffer), &total_size ); 04038 if (status && status != STATUS_BUFFER_OVERFLOW) goto done; 04039 04040 /* we need to fetch the contents for a string type even if not requested, 04041 * because we need to compute the length of the ASCII string. */ 04042 if (data || is_string(info->Type)) 04043 { 04044 /* retry with a dynamically allocated buffer */ 04045 while (status == STATUS_BUFFER_OVERFLOW) 04046 { 04047 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 04048 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 04049 { 04050 status = STATUS_NO_MEMORY; 04051 goto done; 04052 } 04053 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; 04054 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, 04055 buf_ptr, total_size, &total_size ); 04056 } 04057 04058 if (status) goto done; 04059 04060 if (is_string(info->Type)) 04061 { 04062 DWORD len; 04063 04064 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size), 04065 total_size - info_size ); 04066 if (data && len) 04067 { 04068 if (len > datalen) status = STATUS_BUFFER_OVERFLOW; 04069 else 04070 { 04071 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size), 04072 total_size - info_size ); 04073 /* if the type is REG_SZ and data is not 0-terminated 04074 * and there is enough space in the buffer NT appends a \0 */ 04075 if (len < datalen && data[len-1]) data[len] = 0; 04076 } 04077 } 04078 total_size = len + info_size; 04079 } 04080 else if (data) 04081 { 04082 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; 04083 else memcpy( data, buf_ptr + info_size, total_size - info_size ); 04084 } 04085 } 04086 else status = STATUS_SUCCESS; 04087 04088 if (type) *type = info->Type; 04089 if (count) *count = total_size - info_size; 04090 04091 done: 04092 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 04093 RtlFreeUnicodeString( &nameW ); 04094 ClosePredefKey(hkey); 04095 return RtlNtStatusToDosError(status); 04096 } 04097 04098 04099 /************************************************************************ 04100 * RegQueryValueExW 04101 * 04102 * @implemented 04103 */ 04104 LONG 04105 WINAPI 04106 RegQueryValueExW(HKEY hkeyorg, 04107 LPCWSTR name, 04108 LPDWORD reserved, 04109 LPDWORD type, 04110 LPBYTE data, 04111 LPDWORD count) 04112 { 04113 HANDLE hkey; 04114 NTSTATUS status; 04115 UNICODE_STRING name_str; 04116 DWORD total_size; 04117 char buffer[256], *buf_ptr = buffer; 04118 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; 04119 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); 04120 04121 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", 04122 hkeyorg, debugstr_w(name), reserved, type, data, count, 04123 (count && data) ? *count : 0 ); 04124 04125 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; 04126 04127 status = MapDefaultKey(&hkey, hkeyorg); 04128 if (!NT_SUCCESS(status)) 04129 { 04130 return RtlNtStatusToDosError(status); 04131 } 04132 04133 RtlInitUnicodeString( &name_str, name ); 04134 04135 if (data) total_size = min( sizeof(buffer), *count + info_size ); 04136 else 04137 { 04138 total_size = info_size; 04139 if (count) *count = 0; 04140 } 04141 04142 /* this matches Win9x behaviour - NT sets *type to a random value */ 04143 if (type) *type = REG_NONE; 04144 04145 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 04146 buffer, total_size, &total_size ); 04147 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done; 04148 04149 if (data) 04150 { 04151 /* retry with a dynamically allocated buffer */ 04152 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) 04153 { 04154 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 04155 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) 04156 { 04157 ClosePredefKey(hkey); 04158 return ERROR_NOT_ENOUGH_MEMORY; 04159 } 04160 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; 04161 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, 04162 buf_ptr, total_size, &total_size ); 04163 } 04164 04165 if (NT_SUCCESS(status)) 04166 { 04167 memcpy( data, buf_ptr + info_size, total_size - info_size ); 04168 /* if the type is REG_SZ and data is not 0-terminated 04169 * and there is enough space in the buffer NT appends a \0 */ 04170 if (is_string(info->Type) && total_size - info_size <= *count-sizeof(WCHAR)) 04171 { 04172 WCHAR *ptr = (WCHAR *)(data + total_size - info_size); 04173 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; 04174 } 04175 } 04176 else if (status != STATUS_BUFFER_OVERFLOW) goto done; 04177 } 04178 else status = STATUS_SUCCESS; 04179 04180 if (type) *type = info->Type; 04181 if (count) *count = total_size - info_size; 04182 04183 done: 04184 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); 04185 ClosePredefKey(hkey); 04186 return RtlNtStatusToDosError(status); 04187 } 04188 04189 04190 /************************************************************************ 04191 * RegQueryValueA 04192 * 04193 * @implemented 04194 */ 04195 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) 04196 { 04197 DWORD ret; 04198 HKEY subkey = hkey; 04199 04200 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); 04201 04202 if (name && name[0]) 04203 { 04204 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; 04205 } 04206 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 04207 if (subkey != hkey) RegCloseKey( subkey ); 04208 if (ret == ERROR_FILE_NOT_FOUND) 04209 { 04210 /* return empty string if default value not found */ 04211 if (data) *data = 0; 04212 if (count) *count = 1; 04213 ret = ERROR_SUCCESS; 04214 } 04215 return ret; 04216 } 04217 04218 04219 /************************************************************************ 04220 * RegQueryValueW 04221 * 04222 * @implemented 04223 */ 04224 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) 04225 { 04226 DWORD ret; 04227 HKEY subkey = hkey; 04228 04229 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); 04230 if (hkey == NULL) 04231 { 04232 return ERROR_INVALID_HANDLE; 04233 } 04234 if (name && name[0]) 04235 { 04236 ret = RegOpenKeyW( hkey, name, &subkey); 04237 if (ret != ERROR_SUCCESS) 04238 { 04239 return ret; 04240 } 04241 } 04242 04243 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); 04244 04245 if (subkey != hkey) 04246 { 04247 RegCloseKey( subkey ); 04248 } 04249 04250 if (ret == ERROR_FILE_NOT_FOUND) 04251 { 04252 /* return empty string if default value not found */ 04253 if (data) 04254 *data = 0; 04255 if (count) 04256 *count = sizeof(WCHAR); 04257 ret = ERROR_SUCCESS; 04258 } 04259 return ret; 04260 } 04261 04262 04263 /************************************************************************ 04264 * RegReplaceKeyA 04265 * 04266 * @implemented 04267 */ 04268 LONG WINAPI 04269 RegReplaceKeyA(HKEY hKey, 04270 LPCSTR lpSubKey, 04271 LPCSTR lpNewFile, 04272 LPCSTR lpOldFile) 04273 { 04274 UNICODE_STRING SubKey; 04275 UNICODE_STRING NewFile; 04276 UNICODE_STRING OldFile; 04277 LONG ErrorCode; 04278 04279 RtlCreateUnicodeStringFromAsciiz(&SubKey, 04280 (PCSZ)lpSubKey); 04281 RtlCreateUnicodeStringFromAsciiz(&OldFile, 04282 (PCSZ)lpOldFile); 04283 RtlCreateUnicodeStringFromAsciiz(&NewFile, 04284 (PCSZ)lpNewFile); 04285 04286 ErrorCode = RegReplaceKeyW(hKey, 04287 SubKey.Buffer, 04288 NewFile.Buffer, 04289 OldFile.Buffer); 04290 04291 RtlFreeUnicodeString(&OldFile); 04292 RtlFreeUnicodeString(&NewFile); 04293 RtlFreeUnicodeString(&SubKey); 04294 04295 return ErrorCode; 04296 } 04297 04298 04299 /************************************************************************ 04300 * RegReplaceKeyW 04301 * 04302 * @unimplemented 04303 */ 04304 LONG WINAPI 04305 RegReplaceKeyW(HKEY hKey, 04306 LPCWSTR lpSubKey, 04307 LPCWSTR lpNewFile, 04308 LPCWSTR lpOldFile) 04309 { 04310 OBJECT_ATTRIBUTES KeyObjectAttributes; 04311 OBJECT_ATTRIBUTES NewObjectAttributes; 04312 OBJECT_ATTRIBUTES OldObjectAttributes; 04313 UNICODE_STRING SubKeyName; 04314 UNICODE_STRING NewFileName; 04315 UNICODE_STRING OldFileName; 04316 BOOLEAN CloseRealKey; 04317 HANDLE RealKeyHandle; 04318 HANDLE KeyHandle; 04319 NTSTATUS Status; 04320 LONG ErrorCode = ERROR_SUCCESS; 04321 04322 if (hKey == HKEY_PERFORMANCE_DATA) 04323 { 04324 return ERROR_INVALID_HANDLE; 04325 } 04326 04327 Status = MapDefaultKey(&KeyHandle, 04328 hKey); 04329 if (!NT_SUCCESS(Status)) 04330 { 04331 return RtlNtStatusToDosError(Status); 04332 } 04333 04334 /* Open the real key */ 04335 if (lpSubKey != NULL && *lpSubKey != (WCHAR)0) 04336 { 04337 RtlInitUnicodeString(&SubKeyName, 04338 (PWSTR)lpSubKey); 04339 InitializeObjectAttributes(&KeyObjectAttributes, 04340 &SubKeyName, 04341 OBJ_CASE_INSENSITIVE, 04342 KeyHandle, 04343 NULL); 04344 Status = NtOpenKey(&RealKeyHandle, 04345 MAXIMUM_ALLOWED, 04346 &KeyObjectAttributes); 04347 if (!NT_SUCCESS(Status)) 04348 { 04349 ErrorCode = RtlNtStatusToDosError(Status); 04350 goto Cleanup; 04351 } 04352 04353 CloseRealKey = TRUE; 04354 } 04355 else 04356 { 04357 RealKeyHandle = KeyHandle; 04358 CloseRealKey = FALSE; 04359 } 04360 04361 /* Convert new file name */ 04362 if (!RtlDosPathNameToNtPathName_U(lpNewFile, 04363 &NewFileName, 04364 NULL, 04365 NULL)) 04366 { 04367 if (CloseRealKey) 04368 { 04369 NtClose(RealKeyHandle); 04370 } 04371 04372 ErrorCode = ERROR_INVALID_PARAMETER; 04373 goto Cleanup; 04374 } 04375 04376 InitializeObjectAttributes(&NewObjectAttributes, 04377 &NewFileName, 04378 OBJ_CASE_INSENSITIVE, 04379 NULL, 04380 NULL); 04381 04382 /* Convert old file name */ 04383 if (!RtlDosPathNameToNtPathName_U(lpOldFile, 04384 &OldFileName, 04385 NULL, 04386 NULL)) 04387 { 04388 RtlFreeHeap(RtlGetProcessHeap (), 04389 0, 04390 NewFileName.Buffer); 04391 if (CloseRealKey) 04392 { 04393 NtClose(RealKeyHandle); 04394 } 04395 04396 ErrorCode = ERROR_INVALID_PARAMETER; 04397 goto Cleanup; 04398 } 04399 04400 InitializeObjectAttributes(&OldObjectAttributes, 04401 &OldFileName, 04402 OBJ_CASE_INSENSITIVE, 04403 NULL, 04404 NULL); 04405 04406 Status = NtReplaceKey(&NewObjectAttributes, 04407 RealKeyHandle, 04408 &OldObjectAttributes); 04409 04410 RtlFreeHeap(RtlGetProcessHeap(), 04411 0, 04412 OldFileName.Buffer); 04413 RtlFreeHeap(RtlGetProcessHeap(), 04414 0, 04415 NewFileName.Buffer); 04416 04417 if (CloseRealKey) 04418 { 04419 NtClose(RealKeyHandle); 04420 } 04421 04422 if (!NT_SUCCESS(Status)) 04423 { 04424 return RtlNtStatusToDosError(Status); 04425 } 04426 04427 Cleanup: 04428 ClosePredefKey(KeyHandle); 04429 04430 return ErrorCode; 04431 } 04432 04433 04434 /************************************************************************ 04435 * RegRestoreKeyA 04436 * 04437 * @implemented 04438 */ 04439 LONG WINAPI 04440 RegRestoreKeyA(HKEY hKey, 04441 LPCSTR lpFile, 04442 DWORD dwFlags) 04443 { 04444 UNICODE_STRING FileName; 04445 LONG ErrorCode; 04446 04447 RtlCreateUnicodeStringFromAsciiz(&FileName, 04448 (PCSZ)lpFile); 04449 04450 ErrorCode = RegRestoreKeyW(hKey, 04451 FileName.Buffer, 04452 dwFlags); 04453 04454 RtlFreeUnicodeString(&FileName); 04455 04456 return ErrorCode; 04457 } 04458 04459 04460 /************************************************************************ 04461 * RegRestoreKeyW 04462 * 04463 * @implemented 04464 */ 04465 LONG WINAPI 04466 RegRestoreKeyW(HKEY hKey, 04467 LPCWSTR lpFile, 04468 DWORD dwFlags) 04469 { 04470 OBJECT_ATTRIBUTES ObjectAttributes; 04471 IO_STATUS_BLOCK IoStatusBlock; 04472 UNICODE_STRING FileName; 04473 HANDLE FileHandle; 04474 HANDLE KeyHandle; 04475 NTSTATUS Status; 04476 04477 if (hKey == HKEY_PERFORMANCE_DATA) 04478 { 04479 return ERROR_INVALID_HANDLE; 04480 } 04481 04482 Status = MapDefaultKey(&KeyHandle, 04483 hKey); 04484 if (!NT_SUCCESS(Status)) 04485 { 04486 return RtlNtStatusToDosError(Status); 04487 } 04488 04489 if (!RtlDosPathNameToNtPathName_U(lpFile, 04490 &FileName, 04491 NULL, 04492 NULL)) 04493 { 04494 Status = STATUS_INVALID_PARAMETER; 04495 goto Cleanup; 04496 } 04497 04498 InitializeObjectAttributes(&ObjectAttributes, 04499 &FileName, 04500 OBJ_CASE_INSENSITIVE, 04501 NULL, 04502 NULL); 04503 04504 Status = NtOpenFile(&FileHandle, 04505 FILE_GENERIC_READ, 04506 &ObjectAttributes, 04507 &IoStatusBlock, 04508 FILE_SHARE_READ, 04509 FILE_SYNCHRONOUS_IO_NONALERT); 04510 RtlFreeHeap(RtlGetProcessHeap(), 04511 0, 04512 FileName.Buffer); 04513 if (!NT_SUCCESS(Status)) 04514 { 04515 goto Cleanup; 04516 } 04517 04518 Status = NtRestoreKey(KeyHandle, 04519 FileHandle, 04520 (ULONG)dwFlags); 04521 NtClose (FileHandle); 04522 04523 Cleanup: 04524 ClosePredefKey(KeyHandle); 04525 04526 if (!NT_SUCCESS(Status)) 04527 { 04528 return RtlNtStatusToDosError(Status); 04529 } 04530 04531 return ERROR_SUCCESS; 04532 } 04533 04534 04535 /************************************************************************ 04536 * RegSaveKeyA 04537 * 04538 * @implemented 04539 */ 04540 LONG WINAPI 04541 RegSaveKeyA(HKEY hKey, 04542 LPCSTR lpFile, 04543 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 04544 { 04545 UNICODE_STRING FileName; 04546 LONG ErrorCode; 04547 04548 RtlCreateUnicodeStringFromAsciiz(&FileName, 04549 (LPSTR)lpFile); 04550 ErrorCode = RegSaveKeyW(hKey, 04551 FileName.Buffer, 04552 lpSecurityAttributes); 04553 RtlFreeUnicodeString(&FileName); 04554 04555 return ErrorCode; 04556 } 04557 04558 04559 /************************************************************************ 04560 * RegSaveKeyW 04561 * 04562 * @implemented 04563 */ 04564 LONG WINAPI 04565 RegSaveKeyW(HKEY hKey, 04566 LPCWSTR lpFile, 04567 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 04568 { 04569 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 04570 OBJECT_ATTRIBUTES ObjectAttributes; 04571 UNICODE_STRING FileName; 04572 IO_STATUS_BLOCK IoStatusBlock; 04573 HANDLE FileHandle; 04574 HANDLE KeyHandle; 04575 NTSTATUS Status; 04576 04577 Status = MapDefaultKey(&KeyHandle, 04578 hKey); 04579 if (!NT_SUCCESS(Status)) 04580 { 04581 return RtlNtStatusToDosError(Status); 04582 } 04583 04584 if (!RtlDosPathNameToNtPathName_U(lpFile, 04585 &FileName, 04586 NULL, 04587 NULL)) 04588 { 04589 Status = STATUS_INVALID_PARAMETER; 04590 goto Cleanup; 04591 } 04592 04593 if (lpSecurityAttributes != NULL) 04594 { 04595 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 04596 } 04597 04598 InitializeObjectAttributes(&ObjectAttributes, 04599 &FileName, 04600 OBJ_CASE_INSENSITIVE, 04601 NULL, 04602 SecurityDescriptor); 04603 Status = NtCreateFile(&FileHandle, 04604 GENERIC_WRITE | SYNCHRONIZE, 04605 &ObjectAttributes, 04606 &IoStatusBlock, 04607 NULL, 04608 FILE_ATTRIBUTE_NORMAL, 04609 FILE_SHARE_READ, 04610 FILE_CREATE, 04611 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 04612 NULL, 04613 0); 04614 RtlFreeHeap(RtlGetProcessHeap(), 04615 0, 04616 FileName.Buffer); 04617 if (!NT_SUCCESS(Status)) 04618 { 04619 goto Cleanup; 04620 } 04621 04622 Status = NtSaveKey(KeyHandle, 04623 FileHandle); 04624 NtClose (FileHandle); 04625 04626 Cleanup: 04627 ClosePredefKey(KeyHandle); 04628 04629 if (!NT_SUCCESS(Status)) 04630 { 04631 return RtlNtStatusToDosError(Status); 04632 } 04633 04634 return ERROR_SUCCESS; 04635 } 04636 04637 04638 /************************************************************************ 04639 * RegSaveKeyExA 04640 * 04641 * @implemented 04642 */ 04643 LONG 04644 WINAPI 04645 RegSaveKeyExA(HKEY hKey, 04646 LPCSTR lpFile, 04647 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 04648 DWORD Flags) 04649 { 04650 UNICODE_STRING FileName; 04651 LONG ErrorCode; 04652 04653 RtlCreateUnicodeStringFromAsciiz(&FileName, 04654 (LPSTR)lpFile); 04655 ErrorCode = RegSaveKeyExW(hKey, 04656 FileName.Buffer, 04657 lpSecurityAttributes, 04658 Flags); 04659 RtlFreeUnicodeString(&FileName); 04660 04661 return ErrorCode; 04662 } 04663 04664 04665 /************************************************************************ 04666 * RegSaveKeyExW 04667 * 04668 * @unimplemented 04669 */ 04670 LONG 04671 WINAPI 04672 RegSaveKeyExW(HKEY hKey, 04673 LPCWSTR lpFile, 04674 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 04675 DWORD Flags) 04676 { 04677 switch (Flags) 04678 { 04679 case REG_STANDARD_FORMAT: 04680 case REG_LATEST_FORMAT: 04681 case REG_NO_COMPRESSION: 04682 break; 04683 default: 04684 return ERROR_INVALID_PARAMETER; 04685 } 04686 04687 FIXME("RegSaveKeyExW(): Flags ignored!\n"); 04688 04689 return RegSaveKeyW(hKey, 04690 lpFile, 04691 lpSecurityAttributes); 04692 } 04693 04694 04695 /************************************************************************ 04696 * RegSetKeySecurity 04697 * 04698 * @implemented 04699 */ 04700 LONG WINAPI 04701 RegSetKeySecurity(HKEY hKey, 04702 SECURITY_INFORMATION SecurityInformation, 04703 PSECURITY_DESCRIPTOR pSecurityDescriptor) 04704 { 04705 HANDLE KeyHandle; 04706 NTSTATUS Status; 04707 04708 if (hKey == HKEY_PERFORMANCE_DATA) 04709 { 04710 return ERROR_INVALID_HANDLE; 04711 } 04712 04713 Status = MapDefaultKey(&KeyHandle, 04714 hKey); 04715 if (!NT_SUCCESS(Status)) 04716 { 04717 return RtlNtStatusToDosError(Status); 04718 } 04719 04720 Status = NtSetSecurityObject(KeyHandle, 04721 SecurityInformation, 04722 pSecurityDescriptor); 04723 04724 ClosePredefKey(KeyHandle); 04725 04726 if (!NT_SUCCESS(Status)) 04727 { 04728 return RtlNtStatusToDosError(Status); 04729 } 04730 04731 return ERROR_SUCCESS; 04732 } 04733 04734 04735 /************************************************************************ 04736 * RegSetValueExA 04737 * 04738 * @implemented 04739 */ 04740 LONG WINAPI 04741 RegSetValueExA(HKEY hKey, 04742 LPCSTR lpValueName, 04743 DWORD Reserved, 04744 DWORD dwType, 04745 CONST BYTE* lpData, 04746 DWORD cbData) 04747 { 04748 UNICODE_STRING ValueName; 04749 LPWSTR pValueName; 04750 ANSI_STRING AnsiString; 04751 UNICODE_STRING Data; 04752 LONG ErrorCode; 04753 LPBYTE pData; 04754 DWORD DataSize; 04755 NTSTATUS Status; 04756 04757 /* Convert SubKey name to Unicode */ 04758 if (lpValueName != NULL && lpValueName[0] != '\0') 04759 { 04760 BOOL bConverted; 04761 bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName, 04762 (PSTR)lpValueName); 04763 if(!bConverted) 04764 return ERROR_NOT_ENOUGH_MEMORY; 04765 } 04766 else 04767 { 04768 ValueName.Buffer = NULL; 04769 } 04770 04771 pValueName = (LPWSTR)ValueName.Buffer; 04772 04773 04774 if (is_string(dwType) && (cbData != 0)) 04775 { 04776 /* Convert ANSI string Data to Unicode */ 04777 /* If last character NOT zero then increment length */ 04778 LONG bNoNulledStr = ((lpData[cbData-1] != '\0') ? 1 : 0); 04779 AnsiString.Buffer = (PSTR)lpData; 04780 AnsiString.Length = cbData + bNoNulledStr; 04781 AnsiString.MaximumLength = cbData + bNoNulledStr; 04782 Status = RtlAnsiStringToUnicodeString(&Data, 04783 &AnsiString, 04784 TRUE); 04785 04786 if (!NT_SUCCESS(Status)) 04787 { 04788 if (pValueName != NULL) 04789 RtlFreeUnicodeString(&ValueName); 04790 04791 return RtlNtStatusToDosError(Status); 04792 } 04793 pData = (LPBYTE)Data.Buffer; 04794 DataSize = cbData * sizeof(WCHAR); 04795 } 04796 else 04797 { 04798 Data.Buffer = NULL; 04799 pData = (LPBYTE)lpData; 04800 DataSize = cbData; 04801 } 04802 04803 ErrorCode = RegSetValueExW(hKey, 04804 pValueName, 04805 Reserved, 04806 dwType, 04807 pData, 04808 DataSize); 04809 04810 if (pValueName != NULL) 04811 RtlFreeUnicodeString(&ValueName); 04812 04813 if (Data.Buffer != NULL) 04814 RtlFreeUnicodeString(&Data); 04815 04816 return ErrorCode; 04817 } 04818 04819 04820 /************************************************************************ 04821 * RegSetValueExW 04822 * 04823 * @implemented 04824 */ 04825 LONG WINAPI 04826 RegSetValueExW(HKEY hKey, 04827 LPCWSTR lpValueName, 04828 DWORD Reserved, 04829 DWORD dwType, 04830 CONST BYTE* lpData, 04831 DWORD cbData) 04832 { 04833 UNICODE_STRING ValueName; 04834 PUNICODE_STRING pValueName; 04835 HANDLE KeyHandle; 04836 NTSTATUS Status; 04837 04838 Status = MapDefaultKey(&KeyHandle, 04839 hKey); 04840 if (!NT_SUCCESS(Status)) 04841 { 04842 return RtlNtStatusToDosError(Status); 04843 } 04844 04845 RtlInitUnicodeString(&ValueName, lpValueName); 04846 pValueName = &ValueName; 04847 04848 if (is_string(dwType) && (cbData != 0)) 04849 { 04850 PWSTR pwsData = (PWSTR)lpData; 04851 04852 if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') && 04853 (pwsData[cbData / sizeof(WCHAR)] == L'\0')) 04854 { 04855 /* Increment length if last character is not zero and next is zero */ 04856 cbData += sizeof(WCHAR); 04857 } 04858 } 04859 04860 Status = NtSetValueKey(KeyHandle, 04861 pValueName, 04862 0, 04863 dwType, 04864 (PVOID)lpData, 04865 (ULONG)cbData); 04866 04867 ClosePredefKey(KeyHandle); 04868 04869 if (!NT_SUCCESS(Status)) 04870 { 04871 return RtlNtStatusToDosError(Status); 04872 } 04873 04874 return ERROR_SUCCESS; 04875 } 04876 04877 04878 /************************************************************************ 04879 * RegSetValueA 04880 * 04881 * @implemented 04882 */ 04883 LONG WINAPI 04884 RegSetValueA(HKEY hKeyOriginal, 04885 LPCSTR lpSubKey, 04886 DWORD dwType, 04887 LPCSTR lpData, 04888 DWORD cbData) 04889 { 04890 HKEY subkey; 04891 HANDLE hKey; 04892 DWORD ret; 04893 NTSTATUS Status; 04894 04895 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_a(lpSubKey), dwType, debugstr_a(lpData), cbData ); 04896 04897 if (dwType != REG_SZ || !lpData) return ERROR_INVALID_PARAMETER; 04898 04899 Status = MapDefaultKey(&hKey, hKeyOriginal); 04900 if (!NT_SUCCESS(Status)) 04901 { 04902 return RtlNtStatusToDosError (Status); 04903 } 04904 subkey = hKey; 04905 04906 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 04907 { 04908 ret = RegCreateKeyA(hKey, lpSubKey, &subkey); 04909 if (ret != ERROR_SUCCESS) 04910 goto Cleanup; 04911 } 04912 04913 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, strlen(lpData)+1 ); 04914 if (subkey != hKey) 04915 RegCloseKey(subkey); 04916 04917 Cleanup: 04918 ClosePredefKey(hKey); 04919 04920 return ret; 04921 } 04922 04923 04924 /************************************************************************ 04925 * RegSetValueW 04926 * 04927 * @implemented 04928 */ 04929 LONG WINAPI 04930 RegSetValueW(HKEY hKeyOriginal, 04931 LPCWSTR lpSubKey, 04932 DWORD dwType, 04933 LPCWSTR lpData, 04934 DWORD cbData) 04935 { 04936 HKEY subkey; 04937 HANDLE hKey; 04938 DWORD ret; 04939 NTSTATUS Status; 04940 04941 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal, debugstr_w(lpSubKey), dwType, debugstr_w(lpData), cbData ); 04942 04943 if (dwType != REG_SZ || !lpData) 04944 return ERROR_INVALID_PARAMETER; 04945 04946 Status = MapDefaultKey(&hKey, 04947 hKeyOriginal); 04948 if (!NT_SUCCESS(Status)) 04949 { 04950 return RtlNtStatusToDosError(Status); 04951 } 04952 subkey = hKey; 04953 04954 if (lpSubKey && lpSubKey[0]) /* need to create the subkey */ 04955 { 04956 ret = RegCreateKeyW(hKey, lpSubKey, &subkey); 04957 if (ret != ERROR_SUCCESS) 04958 goto Cleanup; 04959 } 04960 04961 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)lpData, 04962 (wcslen( lpData ) + 1) * sizeof(WCHAR) ); 04963 if (subkey != hKey) 04964 RegCloseKey(subkey); 04965 04966 Cleanup: 04967 ClosePredefKey(hKey); 04968 04969 return ret; 04970 } 04971 04972 04973 /************************************************************************ 04974 * RegUnLoadKeyA 04975 * 04976 * @implemented 04977 */ 04978 LONG WINAPI 04979 RegUnLoadKeyA(HKEY hKey, 04980 LPCSTR lpSubKey) 04981 { 04982 UNICODE_STRING KeyName; 04983 DWORD ErrorCode; 04984 04985 RtlCreateUnicodeStringFromAsciiz(&KeyName, 04986 (LPSTR)lpSubKey); 04987 04988 ErrorCode = RegUnLoadKeyW(hKey, 04989 KeyName.Buffer); 04990 04991 RtlFreeUnicodeString (&KeyName); 04992 04993 return ErrorCode; 04994 } 04995 04996 04997 /************************************************************************ 04998 * RegUnLoadKeyW 04999 * 05000 * @implemented 05001 */ 05002 LONG WINAPI 05003 RegUnLoadKeyW(HKEY hKey, 05004 LPCWSTR lpSubKey) 05005 { 05006 OBJECT_ATTRIBUTES ObjectAttributes; 05007 UNICODE_STRING KeyName; 05008 HANDLE KeyHandle; 05009 NTSTATUS Status; 05010 05011 if (hKey == HKEY_PERFORMANCE_DATA) 05012 { 05013 return ERROR_INVALID_HANDLE; 05014 } 05015 05016 Status = MapDefaultKey(&KeyHandle, hKey); 05017 if (!NT_SUCCESS(Status)) 05018 { 05019 return RtlNtStatusToDosError(Status); 05020 } 05021 05022 RtlInitUnicodeString(&KeyName, 05023 (LPWSTR)lpSubKey); 05024 05025 InitializeObjectAttributes(&ObjectAttributes, 05026 &KeyName, 05027 OBJ_CASE_INSENSITIVE, 05028 KeyHandle, 05029 NULL); 05030 05031 Status = NtUnloadKey(&ObjectAttributes); 05032 05033 ClosePredefKey(KeyHandle); 05034 05035 if (!NT_SUCCESS(Status)) 05036 { 05037 return RtlNtStatusToDosError(Status); 05038 } 05039 05040 return ERROR_SUCCESS; 05041 } 05042 05043 05044 /****************************************************************************** 05045 * load_string [Internal] 05046 * 05047 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to 05048 * avoid importing user32, which is higher level than advapi32. Helper for 05049 * RegLoadMUIString. 05050 */ 05051 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) 05052 { 05053 HGLOBAL hMemory; 05054 HRSRC hResource; 05055 WCHAR *pString; 05056 int idxString; 05057 05058 /* Negative values have to be inverted. */ 05059 if (HIWORD(resId) == 0xffff) 05060 resId = (UINT)(-((INT)resId)); 05061 05062 /* Load the resource into memory and get a pointer to it. */ 05063 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); 05064 if (!hResource) return 0; 05065 hMemory = LoadResource(hModule, hResource); 05066 if (!hMemory) return 0; 05067 pString = LockResource(hMemory); 05068 05069 /* Strings are length-prefixed. Lowest nibble of resId is an index. */ 05070 idxString = resId & 0xf; 05071 while (idxString--) pString += *pString + 1; 05072 05073 /* If no buffer is given, return length of the string. */ 05074 if (!pwszBuffer) return *pString; 05075 05076 /* Else copy over the string, respecting the buffer size. */ 05077 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); 05078 if (cMaxChars >= 0) 05079 { 05080 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); 05081 pwszBuffer[cMaxChars] = L'\0'; 05082 } 05083 05084 return cMaxChars; 05085 } 05086 05087 05088 /************************************************************************ 05089 * RegLoadMUIStringW 05090 * 05091 * @implemented 05092 */ 05093 LONG WINAPI 05094 RegLoadMUIStringW(IN HKEY hKey, 05095 IN LPCWSTR pszValue OPTIONAL, 05096 OUT LPWSTR pszOutBuf, 05097 IN DWORD cbOutBuf, 05098 OUT LPDWORD pcbData OPTIONAL, 05099 IN DWORD Flags, 05100 IN LPCWSTR pszDirectory OPTIONAL) 05101 { 05102 DWORD dwValueType, cbData; 05103 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; 05104 LONG result; 05105 05106 /* Parameter sanity checks. */ 05107 if (!hKey || !pszOutBuf) 05108 return ERROR_INVALID_PARAMETER; 05109 05110 if (pszDirectory && *pszDirectory) 05111 { 05112 FIXME("BaseDir parameter not yet supported!\n"); 05113 return ERROR_INVALID_PARAMETER; 05114 } 05115 05116 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ 05117 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); 05118 if (result != ERROR_SUCCESS) goto cleanup; 05119 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) 05120 { 05121 result = ERROR_FILE_NOT_FOUND; 05122 goto cleanup; 05123 } 05124 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 05125 if (!pwszTempBuffer) 05126 { 05127 result = ERROR_NOT_ENOUGH_MEMORY; 05128 goto cleanup; 05129 } 05130 result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); 05131 if (result != ERROR_SUCCESS) goto cleanup; 05132 05133 /* Expand environment variables, if appropriate, or copy the original string over. */ 05134 if (dwValueType == REG_EXPAND_SZ) 05135 { 05136 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); 05137 if (!cbData) goto cleanup; 05138 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 05139 if (!pwszExpandedBuffer) 05140 { 05141 result = ERROR_NOT_ENOUGH_MEMORY; 05142 goto cleanup; 05143 } 05144 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); 05145 } 05146 else 05147 { 05148 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData); 05149 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); 05150 } 05151 05152 /* If the value references a resource based string, parse the value and load the string. 05153 * Else just copy over the original value. */ 05154 result = ERROR_SUCCESS; 05155 if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ 05156 { 05157 lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); 05158 } 05159 else 05160 { 05161 WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L','); 05162 UINT uiStringId; 05163 HMODULE hModule; 05164 05165 /* Format of the expanded value is 'path_to_dll,-resId' */ 05166 if (!pComma || pComma[1] != L'-') 05167 { 05168 result = ERROR_BADKEY; 05169 goto cleanup; 05170 } 05171 05172 uiStringId = _wtoi(pComma+2); 05173 *pComma = L'\0'; 05174 05175 hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); 05176 if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) 05177 result = ERROR_BADKEY; 05178 FreeLibrary(hModule); 05179 } 05180 05181 cleanup: 05182 HeapFree(GetProcessHeap(), 0, pwszTempBuffer); 05183 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); 05184 return result; 05185 } 05186 05187 05188 /************************************************************************ 05189 * RegLoadMUIStringA 05190 * 05191 * @implemented 05192 */ 05193 LONG WINAPI 05194 RegLoadMUIStringA(IN HKEY hKey, 05195 IN LPCSTR pszValue OPTIONAL, 05196 OUT LPSTR pszOutBuf, 05197 IN DWORD cbOutBuf, 05198 OUT LPDWORD pcbData OPTIONAL, 05199 IN DWORD Flags, 05200 IN LPCSTR pszDirectory OPTIONAL) 05201 { 05202 UNICODE_STRING valueW, baseDirW; 05203 WCHAR *pwszBuffer; 05204 DWORD cbData = cbOutBuf * sizeof(WCHAR); 05205 LONG result; 05206 05207 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL; 05208 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) || 05209 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) || 05210 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData))) 05211 { 05212 result = ERROR_NOT_ENOUGH_MEMORY; 05213 goto cleanup; 05214 } 05215 05216 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags, 05217 baseDirW.Buffer); 05218 05219 if (result == ERROR_SUCCESS) 05220 { 05221 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL); 05222 if (pcbData) 05223 *pcbData = cbData; 05224 } 05225 05226 cleanup: 05227 HeapFree(GetProcessHeap(), 0, pwszBuffer); 05228 RtlFreeUnicodeString(&baseDirW); 05229 RtlFreeUnicodeString(&valueW); 05230 05231 return result; 05232 } 05233 05234 /* EOF */ Generated on Sat May 26 2012 04:15:33 for ReactOS by
1.7.6.1
|