2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
17 #include <wine/debug.h>
19 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
21 /* DEFINES ******************************************************************/
23 #define MAX_DEFAULT_HANDLES 6
24 #define REG_MAX_NAME_SIZE 256
25 #define REG_MAX_DATA_SIZE 2048
27 /* GLOBALS ******************************************************************/
29 static RTL_CRITICAL_SECTION HandleTableCS
;
30 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
31 static HANDLE ProcessHeap
;
32 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
33 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
35 /* PROTOTYPES ***************************************************************/
37 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
38 static VOID
CloseDefaultKeys(VOID
);
39 #define ClosePredefKey(Handle) \
40 if ((ULONG_PTR)Handle & 0x1) { \
43 #define IsPredefKey(HKey) \
44 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
45 #define GetPredefKeyIndex(HKey) \
46 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
48 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
49 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
54 /* FUNCTIONS ****************************************************************/
55 /* check if value type needs string conversion (Ansi<->Unicode) */
56 __inline
static int is_string( DWORD type
)
58 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
61 /************************************************************************
62 * RegInitDefaultHandles
67 TRACE("RegInitialize()\n");
69 ProcessHeap
= RtlGetProcessHeap();
70 RtlZeroMemory (DefaultHandleTable
,
71 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
72 RtlInitializeCriticalSection (&HandleTableCS
);
78 /************************************************************************
84 TRACE("RegCleanup()\n");
87 RtlDeleteCriticalSection (&HandleTableCS
);
94 OpenPredefinedKey(IN ULONG Index
,
101 case 0: /* HKEY_CLASSES_ROOT */
102 Status
= OpenClassesRootKey (Handle
);
105 case 1: /* HKEY_CURRENT_USER */
106 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
110 case 2: /* HKEY_LOCAL_MACHINE */
111 Status
= OpenLocalMachineKey (Handle
);
114 case 3: /* HKEY_USERS */
115 Status
= OpenUsersKey (Handle
);
118 case 4: /* HKEY_PERFORMANCE_DATA */
119 Status
= OpenPerformanceDataKey (Handle
);
123 case 5: /* HKEY_CURRENT_CONFIG */
124 Status
= OpenCurrentConfigKey (Handle
);
127 case 6: /* HKEY_DYN_DATA */
128 Status
= STATUS_NOT_IMPLEMENTED
;
132 WARN("MapDefaultHandle() no handle creator\n");
133 Status
= STATUS_INVALID_PARAMETER
;
142 MapDefaultKey (OUT PHANDLE RealKey
,
147 BOOLEAN DoOpen
, DefDisabled
;
148 NTSTATUS Status
= STATUS_SUCCESS
;
150 TRACE("MapDefaultKey (Key %x)\n", Key
);
152 if (!IsPredefKey(Key
))
154 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
155 return STATUS_SUCCESS
;
158 /* Handle special cases here */
159 Index
= GetPredefKeyIndex(Key
);
160 if (Index
>= MAX_DEFAULT_HANDLES
)
162 return STATUS_INVALID_PARAMETER
;
165 RtlEnterCriticalSection (&HandleTableCS
);
167 if (Key
== HKEY_CURRENT_USER
)
168 DefDisabled
= DefaultHandleHKUDisabled
;
170 DefDisabled
= DefaultHandlesDisabled
;
174 Handle
= &DefaultHandleTable
[Index
];
175 DoOpen
= (*Handle
== NULL
);
185 /* create/open the default handle */
186 Status
= OpenPredefinedKey(Index
,
190 if (NT_SUCCESS(Status
))
195 *(PULONG_PTR
)Handle
|= 0x1;
198 RtlLeaveCriticalSection (&HandleTableCS
);
205 CloseDefaultKeys (VOID
)
209 RtlEnterCriticalSection (&HandleTableCS
);
210 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
212 if (DefaultHandleTable
[i
] != NULL
)
214 NtClose (DefaultHandleTable
[i
]);
215 DefaultHandleTable
[i
] = NULL
;
218 RtlLeaveCriticalSection (&HandleTableCS
);
223 OpenClassesRootKey (PHANDLE KeyHandle
)
225 OBJECT_ATTRIBUTES Attributes
;
226 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
228 TRACE("OpenClassesRootKey()\n");
230 InitializeObjectAttributes (&Attributes
,
232 OBJ_CASE_INSENSITIVE
,
235 return NtOpenKey (KeyHandle
,
242 OpenLocalMachineKey (PHANDLE KeyHandle
)
244 OBJECT_ATTRIBUTES Attributes
;
245 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
248 TRACE("OpenLocalMachineKey()\n");
250 InitializeObjectAttributes (&Attributes
,
252 OBJ_CASE_INSENSITIVE
,
255 Status
= NtOpenKey (KeyHandle
,
259 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
265 OpenUsersKey (PHANDLE KeyHandle
)
267 OBJECT_ATTRIBUTES Attributes
;
268 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
270 TRACE("OpenUsersKey()\n");
272 InitializeObjectAttributes (&Attributes
,
274 OBJ_CASE_INSENSITIVE
,
277 return NtOpenKey (KeyHandle
,
284 OpenCurrentConfigKey (PHANDLE KeyHandle
)
286 OBJECT_ATTRIBUTES Attributes
;
287 UNICODE_STRING KeyName
=
288 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
290 TRACE("OpenCurrentConfigKey()\n");
292 InitializeObjectAttributes (&Attributes
,
294 OBJ_CASE_INSENSITIVE
,
297 return NtOpenKey (KeyHandle
,
303 /************************************************************************
304 * RegDisablePredefinedCache
309 RegDisablePredefinedCache(VOID
)
311 RtlEnterCriticalSection (&HandleTableCS
);
312 DefaultHandleHKUDisabled
= TRUE
;
313 RtlLeaveCriticalSection (&HandleTableCS
);
314 return ERROR_SUCCESS
;
318 /************************************************************************
319 * RegDisablePredefinedCacheEx
324 RegDisablePredefinedCacheEx(VOID
)
326 RtlEnterCriticalSection (&HandleTableCS
);
327 DefaultHandlesDisabled
= TRUE
;
328 DefaultHandleHKUDisabled
= TRUE
;
329 RtlLeaveCriticalSection (&HandleTableCS
);
330 return ERROR_SUCCESS
;
334 /************************************************************************
335 * RegOverridePredefKey
340 RegOverridePredefKey(IN HKEY hKey
,
341 IN HKEY hNewHKey OPTIONAL
)
343 LONG ErrorCode
= ERROR_SUCCESS
;
345 if ((hKey
== HKEY_CLASSES_ROOT
||
346 hKey
== HKEY_CURRENT_CONFIG
||
347 hKey
== HKEY_CURRENT_USER
||
348 hKey
== HKEY_LOCAL_MACHINE
||
349 hKey
== HKEY_PERFORMANCE_DATA
||
350 hKey
== HKEY_USERS
) &&
351 !IsPredefKey(hNewHKey
))
356 Index
= GetPredefKeyIndex(hKey
);
357 Handle
= &DefaultHandleTable
[Index
];
359 if (hNewHKey
== NULL
)
361 /* restore the default mapping */
362 NTSTATUS Status
= OpenPredefinedKey(Index
,
364 if (!NT_SUCCESS(Status
))
366 return RtlNtStatusToDosError(Status
);
369 ASSERT(hNewHKey
!= NULL
);
372 RtlEnterCriticalSection (&HandleTableCS
);
374 /* close the currently mapped handle if existing */
380 /* update the mapping */
383 RtlLeaveCriticalSection (&HandleTableCS
);
386 ErrorCode
= ERROR_INVALID_HANDLE
;
392 /************************************************************************
398 RegCloseKey (HKEY hKey
)
402 /* don't close null handle or a pseudo handle */
403 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
405 return ERROR_INVALID_HANDLE
;
408 Status
= NtClose (hKey
);
409 if (!NT_SUCCESS(Status
))
411 return RtlNtStatusToDosError (Status
);
414 return ERROR_SUCCESS
;
419 RegpCopyTree(IN HKEY hKeySrc
,
424 LIST_ENTRY ListEntry
;
427 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
429 LIST_ENTRY copyQueueHead
;
430 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
433 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
434 KEY_NODE_INFORMATION
*KeyNode
;
437 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
438 NTSTATUS Status
= STATUS_SUCCESS
;
439 NTSTATUS Status2
= STATUS_SUCCESS
;
441 InitializeListHead(©QueueHead
);
443 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
446 if (Info
.Buffer
== NULL
)
448 return STATUS_INSUFFICIENT_RESOURCES
;
451 copyKeys
= RtlAllocateHeap(ProcessHeap
,
453 sizeof(REGP_COPY_KEYS
));
454 if (copyKeys
!= NULL
)
456 copyKeys
->hKeySrc
= hKeySrc
;
457 copyKeys
->hKeyDest
= hKeyDest
;
458 InsertHeadList(©QueueHead
,
459 ©Keys
->ListEntry
);
461 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
465 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
469 /* enumerate all values and copy them */
473 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
475 KeyValueFullInformation
,
478 &BufferSizeRequired
);
479 if (NT_SUCCESS(Status2
))
481 UNICODE_STRING ValueName
;
484 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
485 ValueName
.Length
= Info
.KeyValue
->NameLength
;
486 ValueName
.MaximumLength
= ValueName
.Length
;
487 ValueName
.Buffer
= Info
.KeyValue
->Name
;
489 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
491 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
493 Info
.KeyValue
->TitleIndex
,
496 Info
.KeyValue
->DataLength
);
498 /* don't break, let's try to copy as many values as possible */
499 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
506 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
510 ASSERT(BufferSize
< BufferSizeRequired
);
512 Buffer
= RtlReAllocateHeap(ProcessHeap
,
518 Info
.Buffer
= Buffer
;
523 /* don't break, let's try to copy as many values as possible */
524 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
527 if (NT_SUCCESS(Status
))
535 /* break to avoid an infinite loop in case of denied access or
537 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
546 /* enumerate all subkeys and open and enqueue them */
550 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
555 &BufferSizeRequired
);
556 if (NT_SUCCESS(Status2
))
558 HANDLE KeyHandle
, NewKeyHandle
;
559 OBJECT_ATTRIBUTES ObjectAttributes
;
560 UNICODE_STRING SubKeyName
, ClassName
;
562 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
563 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
564 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
565 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
566 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
567 ClassName
.MaximumLength
= ClassName
.Length
;
568 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
570 /* open the subkey with sufficient rights */
572 InitializeObjectAttributes(&ObjectAttributes
,
574 OBJ_CASE_INSENSITIVE
,
578 Status2
= NtOpenKey(&KeyHandle
,
579 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
581 if (NT_SUCCESS(Status2
))
583 /* FIXME - attempt to query the security information */
585 InitializeObjectAttributes(&ObjectAttributes
,
587 OBJ_CASE_INSENSITIVE
,
591 Status2
= NtCreateKey(&NewKeyHandle
,
594 Info
.KeyNode
->TitleIndex
,
598 if (NT_SUCCESS(Status2
))
600 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
602 sizeof(REGP_COPY_KEYS
));
603 if (newCopyKeys
!= NULL
)
605 /* save the handles and enqueue the subkey */
606 newCopyKeys
->hKeySrc
= KeyHandle
;
607 newCopyKeys
->hKeyDest
= NewKeyHandle
;
608 InsertTailList(©QueueHead
,
609 &newCopyKeys
->ListEntry
);
614 NtClose(NewKeyHandle
);
616 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
625 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
632 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
636 ASSERT(BufferSize
< BufferSizeRequired
);
638 Buffer
= RtlReAllocateHeap(ProcessHeap
,
644 Info
.Buffer
= Buffer
;
649 /* don't break, let's try to copy as many keys as possible */
650 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
653 if (NT_SUCCESS(Status
))
661 /* break to avoid an infinite loop in case of denied access or
663 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
672 /* close the handles and remove the entry from the list */
673 if (copyKeys
->hKeySrc
!= hKeySrc
)
675 NtClose(copyKeys
->hKeySrc
);
677 if (copyKeys
->hKeyDest
!= hKeyDest
)
679 NtClose(copyKeys
->hKeyDest
);
682 RemoveEntryList(©Keys
->ListEntry
);
684 RtlFreeHeap(ProcessHeap
,
687 } while (!IsListEmpty(©QueueHead
));
690 Status
= STATUS_INSUFFICIENT_RESOURCES
;
692 RtlFreeHeap(ProcessHeap
,
700 /************************************************************************
706 RegCopyTreeW(IN HKEY hKeySrc
,
707 IN LPCWSTR lpSubKey OPTIONAL
,
710 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
713 Status
= MapDefaultKey(&KeyHandle
,
715 if (!NT_SUCCESS(Status
))
717 return RtlNtStatusToDosError(Status
);
720 Status
= MapDefaultKey(&DestKeyHandle
,
722 if (!NT_SUCCESS(Status
))
727 if (lpSubKey
!= NULL
)
729 OBJECT_ATTRIBUTES ObjectAttributes
;
730 UNICODE_STRING SubKeyName
;
732 RtlInitUnicodeString(&SubKeyName
,
735 InitializeObjectAttributes(&ObjectAttributes
,
737 OBJ_CASE_INSENSITIVE
,
741 Status
= NtOpenKey(&SubKeyHandle
,
742 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
744 if (!NT_SUCCESS(Status
))
749 CurKey
= SubKeyHandle
;
754 Status
= RegpCopyTree(CurKey
,
757 if (SubKeyHandle
!= NULL
)
759 NtClose(SubKeyHandle
);
763 ClosePredefKey(DestKeyHandle
);
765 ClosePredefKey(KeyHandle
);
767 if (!NT_SUCCESS(Status
))
769 return RtlNtStatusToDosError(Status
);
772 return ERROR_SUCCESS
;
776 /************************************************************************
782 RegCopyTreeA(IN HKEY hKeySrc
,
783 IN LPCSTR lpSubKey OPTIONAL
,
786 UNICODE_STRING SubKeyName
= {0};
789 if (lpSubKey
!= NULL
&&
790 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
793 return ERROR_NOT_ENOUGH_MEMORY
;
796 Ret
= RegCopyTreeW(hKeySrc
,
800 RtlFreeUnicodeString(&SubKeyName
);
806 /************************************************************************
807 * RegConnectRegistryA
812 RegConnectRegistryA (IN LPCSTR lpMachineName
,
816 UNICODE_STRING MachineName
= {0};
819 if (lpMachineName
!= NULL
&&
820 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
821 (LPSTR
)lpMachineName
))
823 return ERROR_NOT_ENOUGH_MEMORY
;
826 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
830 RtlFreeUnicodeString(&MachineName
);
836 /************************************************************************
837 * RegConnectRegistryW
842 RegConnectRegistryW (LPCWSTR lpMachineName
,
848 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
850 if (!lpMachineName
|| !*lpMachineName
) {
851 /* Use the local machine name */
852 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
855 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
856 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
858 /* MSDN says lpMachineName must start with \\ : not so */
859 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
861 if (GetComputerNameW(compName
, &len
))
863 if (!_wcsicmp(lpMachineName
, compName
))
864 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
867 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
868 ret
= ERROR_BAD_NETPATH
;
872 ret
= GetLastError();
878 /************************************************************************
881 * Create key and all necessary intermediate keys
884 CreateNestedKey(PHKEY KeyHandle
,
885 POBJECT_ATTRIBUTES ObjectAttributes
,
886 PUNICODE_STRING ClassString
,
889 DWORD
*lpdwDisposition
)
891 OBJECT_ATTRIBUTES LocalObjectAttributes
;
892 UNICODE_STRING LocalKeyName
;
895 ULONG FullNameLength
;
898 HANDLE LocalKeyHandle
;
900 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
906 (PULONG
)lpdwDisposition
);
907 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
908 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
911 /* Copy object attributes */
912 RtlCopyMemory (&LocalObjectAttributes
,
914 sizeof(OBJECT_ATTRIBUTES
));
915 RtlCreateUnicodeString (&LocalKeyName
,
916 ObjectAttributes
->ObjectName
->Buffer
);
917 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
918 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
920 LocalKeyHandle
= NULL
;
922 /* Remove the last part of the key name and try to create the key again. */
923 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
925 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
926 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
928 Status
= STATUS_UNSUCCESSFUL
;
932 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
934 Status
= NtCreateKey (&LocalKeyHandle
,
936 &LocalObjectAttributes
,
941 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
944 if (!NT_SUCCESS(Status
))
946 RtlFreeUnicodeString (&LocalKeyName
);
950 /* Add removed parts of the key name and create them too. */
951 Length
= wcslen (LocalKeyName
.Buffer
);
955 NtClose (LocalKeyHandle
);
957 LocalKeyName
.Buffer
[Length
] = L
'\\';
958 Length
= wcslen (LocalKeyName
.Buffer
);
959 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
961 if (Length
== FullNameLength
)
963 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
969 (PULONG
)lpdwDisposition
);
972 Status
= NtCreateKey (&LocalKeyHandle
,
974 &LocalObjectAttributes
,
979 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
980 if (!NT_SUCCESS(Status
))
984 RtlFreeUnicodeString (&LocalKeyName
);
990 /************************************************************************
996 RegCreateKeyExA (HKEY hKey
,
1002 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1004 LPDWORD lpdwDisposition
)
1006 UNICODE_STRING SubKeyString
;
1007 UNICODE_STRING ClassString
;
1008 OBJECT_ATTRIBUTES Attributes
;
1012 TRACE("RegCreateKeyExA() called\n");
1014 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1015 return ERROR_INVALID_USER_BUFFER
;
1017 /* get the real parent key */
1018 Status
= MapDefaultKey (&ParentKey
,
1020 if (!NT_SUCCESS(Status
))
1022 return RtlNtStatusToDosError (Status
);
1024 TRACE("ParentKey %p\n", ParentKey
);
1026 if (lpClass
!= NULL
)
1028 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
1032 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1034 InitializeObjectAttributes (&Attributes
,
1036 OBJ_CASE_INSENSITIVE
,
1038 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1039 Status
= CreateNestedKey(phkResult
,
1041 (lpClass
== NULL
)? NULL
: &ClassString
,
1045 RtlFreeUnicodeString (&SubKeyString
);
1046 if (lpClass
!= NULL
)
1048 RtlFreeUnicodeString (&ClassString
);
1051 ClosePredefKey(ParentKey
);
1053 TRACE("Status %x\n", Status
);
1054 if (!NT_SUCCESS(Status
))
1056 return RtlNtStatusToDosError (Status
);
1059 return ERROR_SUCCESS
;
1063 /************************************************************************
1069 RegCreateKeyExW (HKEY hKey
,
1075 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1077 LPDWORD lpdwDisposition
)
1079 UNICODE_STRING SubKeyString
;
1080 UNICODE_STRING ClassString
;
1081 OBJECT_ATTRIBUTES Attributes
;
1085 TRACE("RegCreateKeyExW() called\n");
1087 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1088 return ERROR_INVALID_USER_BUFFER
;
1090 /* get the real parent key */
1091 Status
= MapDefaultKey (&ParentKey
,
1093 if (!NT_SUCCESS(Status
))
1095 return RtlNtStatusToDosError(Status
);
1097 TRACE("ParentKey %p\n", ParentKey
);
1099 RtlInitUnicodeString (&ClassString
,
1101 RtlInitUnicodeString (&SubKeyString
,
1103 InitializeObjectAttributes (&Attributes
,
1105 OBJ_CASE_INSENSITIVE
,
1107 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1108 Status
= CreateNestedKey(phkResult
,
1110 (lpClass
== NULL
)? NULL
: &ClassString
,
1115 ClosePredefKey(ParentKey
);
1117 TRACE("Status %x\n", Status
);
1118 if (!NT_SUCCESS(Status
))
1120 return RtlNtStatusToDosError (Status
);
1123 return ERROR_SUCCESS
;
1127 /************************************************************************
1133 RegCreateKeyA (HKEY hKey
,
1137 return RegCreateKeyExA (hKey
,
1149 /************************************************************************
1155 RegCreateKeyW (HKEY hKey
,
1159 return RegCreateKeyExW (hKey
,
1171 /************************************************************************
1177 RegDeleteKeyA (HKEY hKey
,
1180 OBJECT_ATTRIBUTES ObjectAttributes
;
1181 UNICODE_STRING SubKeyName
;
1186 /* Make sure we got a subkey */
1190 return ERROR_INVALID_PARAMETER
;
1193 Status
= MapDefaultKey (&ParentKey
,
1195 if (!NT_SUCCESS(Status
))
1197 return RtlNtStatusToDosError (Status
);
1200 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
1202 InitializeObjectAttributes(&ObjectAttributes
,
1204 OBJ_CASE_INSENSITIVE
,
1208 Status
= NtOpenKey (&TargetKey
,
1211 RtlFreeUnicodeString (&SubKeyName
);
1212 if (!NT_SUCCESS(Status
))
1217 Status
= NtDeleteKey (TargetKey
);
1218 NtClose (TargetKey
);
1221 ClosePredefKey(ParentKey
);
1223 if (!NT_SUCCESS(Status
))
1225 return RtlNtStatusToDosError(Status
);
1228 return ERROR_SUCCESS
;
1232 /************************************************************************
1238 RegDeleteKeyW (HKEY hKey
,
1241 OBJECT_ATTRIBUTES ObjectAttributes
;
1242 UNICODE_STRING SubKeyName
;
1247 /* Make sure we got a subkey */
1251 return ERROR_INVALID_PARAMETER
;
1254 Status
= MapDefaultKey (&ParentKey
,
1256 if (!NT_SUCCESS(Status
))
1258 return RtlNtStatusToDosError (Status
);
1261 RtlInitUnicodeString (&SubKeyName
,
1263 InitializeObjectAttributes (&ObjectAttributes
,
1265 OBJ_CASE_INSENSITIVE
,
1268 Status
= NtOpenKey (&TargetKey
,
1271 if (!NT_SUCCESS(Status
))
1276 Status
= NtDeleteKey (TargetKey
);
1277 NtClose (TargetKey
);
1280 ClosePredefKey(ParentKey
);
1282 if (!NT_SUCCESS(Status
))
1284 return RtlNtStatusToDosError (Status
);
1287 return ERROR_SUCCESS
;
1290 /************************************************************************
1297 RegDeleteKeyExA ( HKEY hKey
,
1303 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1304 return ERROR_CALL_NOT_IMPLEMENTED
;
1307 /************************************************************************
1314 RegDeleteKeyExW (HKEY hKey
,
1320 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1321 return ERROR_CALL_NOT_IMPLEMENTED
;
1324 /************************************************************************
1325 * RegDeleteKeyValueW
1330 RegDeleteKeyValueW(IN HKEY hKey
,
1331 IN LPCWSTR lpSubKey OPTIONAL
,
1332 IN LPCWSTR lpValueName OPTIONAL
)
1334 UNICODE_STRING ValueName
;
1335 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1338 Status
= MapDefaultKey(&KeyHandle
,
1340 if (!NT_SUCCESS(Status
))
1342 return RtlNtStatusToDosError(Status
);
1345 if (lpSubKey
!= NULL
)
1347 OBJECT_ATTRIBUTES ObjectAttributes
;
1348 UNICODE_STRING SubKeyName
;
1350 RtlInitUnicodeString(&SubKeyName
,
1353 InitializeObjectAttributes(&ObjectAttributes
,
1355 OBJ_CASE_INSENSITIVE
,
1359 Status
= NtOpenKey(&SubKeyHandle
,
1362 if (!NT_SUCCESS(Status
))
1367 CurKey
= SubKeyHandle
;
1372 RtlInitUnicodeString(&ValueName
,
1373 (LPWSTR
)lpValueName
);
1375 Status
= NtDeleteValueKey(CurKey
,
1378 if (SubKeyHandle
!= NULL
)
1380 NtClose(SubKeyHandle
);
1384 ClosePredefKey(KeyHandle
);
1386 if (!NT_SUCCESS(Status
))
1388 return RtlNtStatusToDosError(Status
);
1391 return ERROR_SUCCESS
;
1395 /************************************************************************
1396 * RegDeleteKeyValueA
1401 RegDeleteKeyValueA(IN HKEY hKey
,
1402 IN LPCSTR lpSubKey OPTIONAL
,
1403 IN LPCSTR lpValueName OPTIONAL
)
1405 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1408 if (lpSubKey
!= NULL
&&
1409 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1412 return ERROR_NOT_ENOUGH_MEMORY
;
1415 if (lpValueName
!= NULL
&&
1416 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1417 (LPSTR
)lpValueName
))
1419 RtlFreeUnicodeString(&SubKey
);
1420 return ERROR_NOT_ENOUGH_MEMORY
;
1423 Ret
= RegDeleteKeyValueW(hKey
,
1427 RtlFreeUnicodeString(&SubKey
);
1428 RtlFreeUnicodeString(&ValueName
);
1434 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1436 RegpDeleteTree(IN HKEY hKey
)
1440 LIST_ENTRY ListEntry
;
1442 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1444 LIST_ENTRY delQueueHead
;
1445 PREG_DEL_KEYS delKeys
, newDelKeys
;
1448 PKEY_BASIC_INFORMATION BasicInfo
;
1449 PREG_DEL_KEYS KeyDelRoot
;
1450 NTSTATUS Status
= STATUS_SUCCESS
;
1451 NTSTATUS Status2
= STATUS_SUCCESS
;
1453 InitializeListHead(&delQueueHead
);
1455 ProcessHeap
= RtlGetProcessHeap();
1457 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1458 structure for the root key, we only do that for subkeys as we need to
1459 allocate REGP_DEL_KEYS structures anyway! */
1460 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1462 sizeof(REGP_DEL_KEYS
));
1463 if (KeyDelRoot
!= NULL
)
1465 KeyDelRoot
->KeyHandle
= hKey
;
1466 InsertTailList(&delQueueHead
,
1467 &KeyDelRoot
->ListEntry
);
1471 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1480 /* check if this key contains subkeys and delete them first by queuing
1481 them at the head of the list */
1482 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1484 KeyBasicInformation
,
1489 if (NT_SUCCESS(Status2
))
1491 OBJECT_ATTRIBUTES ObjectAttributes
;
1492 UNICODE_STRING SubKeyName
;
1494 ASSERT(newDelKeys
!= NULL
);
1495 ASSERT(BasicInfo
!= NULL
);
1497 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1498 SubKeyName
.Length
= BasicInfo
->NameLength
;
1499 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1500 SubKeyName
.Buffer
= BasicInfo
->Name
;
1502 InitializeObjectAttributes(&ObjectAttributes
,
1504 OBJ_CASE_INSENSITIVE
,
1508 /* open the subkey */
1509 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1510 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1512 if (!NT_SUCCESS(Status2
))
1517 /* enqueue this key to the head of the deletion queue */
1518 InsertHeadList(&delQueueHead
,
1519 &newDelKeys
->ListEntry
);
1521 /* try again from the head of the list */
1526 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1528 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1530 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1531 if (newDelKeys
!= NULL
)
1533 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1536 goto ReadFirstSubKey
;
1540 /* don't break, let's try to delete as many keys as possible */
1541 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1542 goto SubKeyFailureNoFree
;
1545 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1547 PREG_DEL_KEYS newDelKeys2
;
1549 ASSERT(newDelKeys
!= NULL
);
1551 /* we need more memory to query the key name */
1552 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1555 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1556 if (newDelKeys2
!= NULL
)
1558 newDelKeys
= newDelKeys2
;
1559 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1562 goto ReadFirstSubKey
;
1566 /* don't break, let's try to delete as many keys as possible */
1567 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1570 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1572 /* in some race conditions where another thread would delete
1573 the same tree at the same time, newDelKeys could actually
1575 if (newDelKeys
!= NULL
)
1577 RtlFreeHeap(ProcessHeap
,
1585 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1586 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1587 if (newDelKeys
!= NULL
)
1589 RtlFreeHeap(ProcessHeap
,
1594 SubKeyFailureNoFree
:
1595 /* don't break, let's try to delete as many keys as possible */
1596 if (NT_SUCCESS(Status
))
1602 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1604 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1606 if (!NT_SUCCESS(Status2
))
1608 /* close the key handle so we don't leak handles for keys we were
1609 unable to delete. But only do this for handles not supplied
1612 if (delKeys
->KeyHandle
!= hKey
)
1614 NtClose(delKeys
->KeyHandle
);
1617 if (NT_SUCCESS(Status
))
1619 /* don't break, let's try to delete as many keys as possible */
1624 /* remove the entry from the list */
1625 RemoveEntryList(&delKeys
->ListEntry
);
1627 RtlFreeHeap(ProcessHeap
,
1630 } while (!IsListEmpty(&delQueueHead
));
1633 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1639 /************************************************************************
1645 RegDeleteTreeW(IN HKEY hKey
,
1646 IN LPCWSTR lpSubKey OPTIONAL
)
1648 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1651 Status
= MapDefaultKey(&KeyHandle
,
1653 if (!NT_SUCCESS(Status
))
1655 return RtlNtStatusToDosError(Status
);
1658 if (lpSubKey
!= NULL
)
1660 OBJECT_ATTRIBUTES ObjectAttributes
;
1661 UNICODE_STRING SubKeyName
;
1663 RtlInitUnicodeString(&SubKeyName
,
1666 InitializeObjectAttributes(&ObjectAttributes
,
1668 OBJ_CASE_INSENSITIVE
,
1672 Status
= NtOpenKey(&SubKeyHandle
,
1673 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1675 if (!NT_SUCCESS(Status
))
1680 CurKey
= SubKeyHandle
;
1685 Status
= RegpDeleteTree(CurKey
);
1687 if (NT_SUCCESS(Status
))
1689 /* make sure we only close hKey (KeyHandle) when the caller specified a
1690 subkey, because the handle would be invalid already! */
1691 if (CurKey
!= KeyHandle
)
1693 ClosePredefKey(KeyHandle
);
1696 return ERROR_SUCCESS
;
1700 /* make sure we close all handles we created! */
1701 if (SubKeyHandle
!= NULL
)
1703 NtClose(SubKeyHandle
);
1707 ClosePredefKey(KeyHandle
);
1709 return RtlNtStatusToDosError(Status
);
1714 /************************************************************************
1721 RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
1724 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1725 DWORD dwMaxLen
, dwSize
;
1729 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1731 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1733 Status
= MapDefaultKey(&KeyHandle
,
1735 if (!NT_SUCCESS(Status
))
1737 return RtlNtStatusToDosError(Status
);
1740 hSubKey
= KeyHandle
;
1744 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1747 ClosePredefKey(KeyHandle
);
1752 /* Get highest length for keys, values */
1753 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1754 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1755 if (ret
) goto cleanup
;
1759 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1760 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1762 /* Name too big: alloc a buffer for it */
1763 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1765 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1771 /* Recursively delete all the subkeys */
1775 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1776 NULL
, NULL
, NULL
)) break;
1778 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1779 if (ret
) goto cleanup
;
1783 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1788 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1789 NULL
, NULL
, NULL
, NULL
)) break;
1791 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1792 if (ret
) goto cleanup
;
1796 /* Free buffer if allocated */
1797 if (lpszName
!= szNameBuf
)
1798 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1800 RegCloseKey(hSubKey
);
1802 ClosePredefKey(KeyHandle
);
1808 /************************************************************************
1814 RegDeleteTreeA(IN HKEY hKey
,
1815 IN LPCSTR lpSubKey OPTIONAL
)
1817 UNICODE_STRING SubKeyName
= {0};
1820 if (lpSubKey
!= NULL
&&
1821 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1824 return ERROR_NOT_ENOUGH_MEMORY
;
1827 Ret
= RegDeleteTreeW(hKey
,
1830 RtlFreeUnicodeString(&SubKeyName
);
1836 /************************************************************************
1837 * RegDisableReflectionKey
1842 RegDisableReflectionKey(IN HKEY hBase
)
1844 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1845 return ERROR_CALL_NOT_IMPLEMENTED
;
1849 /************************************************************************
1850 * RegEnableReflectionKey
1855 RegEnableReflectionKey(IN HKEY hBase
)
1857 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1858 return ERROR_CALL_NOT_IMPLEMENTED
;
1861 /******************************************************************************
1862 * RegpApplyRestrictions [internal]
1864 * Helper function for RegGetValueA/W.
1867 RegpApplyRestrictions( DWORD dwFlags
, DWORD dwType
, DWORD cbData
,
1870 /* Check if the type is restricted by the passed flags */
1871 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1877 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1878 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1879 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1880 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1881 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1882 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1883 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1886 if (dwFlags
& dwMask
)
1888 /* Type is not restricted, check for size mismatch */
1889 if (dwType
== REG_BINARY
)
1893 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1895 else if ((dwFlags
& RRF_RT_QWORD
) == RRF_RT_QWORD
)
1898 if (cbExpect
&& cbData
!= cbExpect
)
1899 *ret
= ERROR_DATATYPE_MISMATCH
;
1902 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1907 /******************************************************************************
1908 * RegGetValueW [ADVAPI32.@]
1910 * Retrieves the type and data for a value name associated with a key,
1911 * optionally expanding its content and restricting its type.
1914 * hKey [I] Handle to an open key.
1915 * pszSubKey [I] Name of the subkey of hKey.
1916 * pszValue [I] Name of value under hKey/szSubKey to query.
1917 * dwFlags [I] Flags restricting the value type to retrieve.
1918 * pdwType [O] Destination for the values type, may be NULL.
1919 * pvData [O] Destination for the values content, may be NULL.
1920 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1921 * retrieve the whole content, including the trailing '\0'
1925 * Success: ERROR_SUCCESS
1926 * Failure: nonzero error code from Winerror.h
1929 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1930 * expanded and pdwType is set to REG_SZ instead.
1931 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1932 * without RRF_NOEXPAND is thus not allowed.
1933 * An exception is the case where RRF_RT_ANY is specified, because then
1934 * RRF_NOEXPAND is allowed.
1936 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1937 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1940 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1944 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1945 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1946 pvData
, pcbData
, cbData
);
1948 if (pvData
&& !pcbData
)
1949 return ERROR_INVALID_PARAMETER
;
1950 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1951 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1952 return ERROR_INVALID_PARAMETER
;
1954 if (pszSubKey
&& pszSubKey
[0])
1956 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1957 if (ret
!= ERROR_SUCCESS
) return ret
;
1960 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1962 /* If we are going to expand we need to read in the whole the value even
1963 * if the passed buffer was too small as the expanded string might be
1964 * smaller than the unexpanded one and could fit into cbData bytes. */
1965 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1966 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1969 HeapFree(GetProcessHeap(), 0, pvBuf
);
1971 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1974 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1978 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1979 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1980 &dwType
, pvBuf
, &cbData
);
1983 /* Even if cbData was large enough we have to copy the
1984 * string since ExpandEnvironmentStrings can't handle
1985 * overlapping buffers. */
1986 CopyMemory(pvBuf
, pvData
, cbData
);
1989 /* Both the type or the value itself could have been modified in
1990 * between so we have to keep retrying until the buffer is large
1991 * enough or we no longer have to expand the value. */
1992 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1994 if (ret
== ERROR_SUCCESS
)
1996 /* Recheck dwType in case it changed since the first call */
1997 if (dwType
== REG_EXPAND_SZ
)
1999 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2000 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2002 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2003 ret
= ERROR_MORE_DATA
;
2006 CopyMemory(pvData
, pvBuf
, *pcbData
);
2009 HeapFree(GetProcessHeap(), 0, pvBuf
);
2012 if (pszSubKey
&& pszSubKey
[0])
2015 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2017 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2018 ZeroMemory(pvData
, *pcbData
);
2020 if (pdwType
) *pdwType
= dwType
;
2021 if (pcbData
) *pcbData
= cbData
;
2027 /******************************************************************************
2028 * RegGetValueA [ADVAPI32.@]
2032 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
2033 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
2036 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2040 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2041 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2044 if (pvData
&& !pcbData
)
2045 return ERROR_INVALID_PARAMETER
;
2046 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2047 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2048 return ERROR_INVALID_PARAMETER
;
2050 if (pszSubKey
&& pszSubKey
[0])
2052 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2053 if (ret
!= ERROR_SUCCESS
) return ret
;
2056 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2058 /* If we are going to expand we need to read in the whole the value even
2059 * if the passed buffer was too small as the expanded string might be
2060 * smaller than the unexpanded one and could fit into cbData bytes. */
2061 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2062 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2065 HeapFree(GetProcessHeap(), 0, pvBuf
);
2067 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2070 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2074 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2075 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2076 &dwType
, pvBuf
, &cbData
);
2079 /* Even if cbData was large enough we have to copy the
2080 * string since ExpandEnvironmentStrings can't handle
2081 * overlapping buffers. */
2082 CopyMemory(pvBuf
, pvData
, cbData
);
2085 /* Both the type or the value itself could have been modified in
2086 * between so we have to keep retrying until the buffer is large
2087 * enough or we no longer have to expand the value. */
2088 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2090 if (ret
== ERROR_SUCCESS
)
2092 /* Recheck dwType in case it changed since the first call */
2093 if (dwType
== REG_EXPAND_SZ
)
2095 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2096 pcbData
? *pcbData
: 0);
2098 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2099 ret
= ERROR_MORE_DATA
;
2102 CopyMemory(pvData
, pvBuf
, *pcbData
);
2105 HeapFree(GetProcessHeap(), 0, pvBuf
);
2108 if (pszSubKey
&& pszSubKey
[0])
2111 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2113 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2114 ZeroMemory(pvData
, *pcbData
);
2116 if (pdwType
) *pdwType
= dwType
;
2117 if (pcbData
) *pcbData
= cbData
;
2123 /************************************************************************
2129 RegSetKeyValueW(IN HKEY hKey
,
2130 IN LPCWSTR lpSubKey OPTIONAL
,
2131 IN LPCWSTR lpValueName OPTIONAL
,
2133 IN LPCVOID lpData OPTIONAL
,
2136 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2140 Status
= MapDefaultKey(&KeyHandle
,
2142 if (!NT_SUCCESS(Status
))
2144 return RtlNtStatusToDosError(Status
);
2147 if (lpSubKey
!= NULL
)
2149 OBJECT_ATTRIBUTES ObjectAttributes
;
2150 UNICODE_STRING SubKeyName
;
2152 RtlInitUnicodeString(&SubKeyName
,
2155 InitializeObjectAttributes(&ObjectAttributes
,
2157 OBJ_CASE_INSENSITIVE
,
2161 Status
= NtOpenKey(&SubKeyHandle
,
2164 if (!NT_SUCCESS(Status
))
2166 Ret
= RtlNtStatusToDosError(Status
);
2170 CurKey
= SubKeyHandle
;
2175 Ret
= RegSetValueExW(CurKey
,
2182 if (SubKeyHandle
!= NULL
)
2184 NtClose(SubKeyHandle
);
2188 ClosePredefKey(KeyHandle
);
2194 /************************************************************************
2200 RegSetKeyValueA(IN HKEY hKey
,
2201 IN LPCSTR lpSubKey OPTIONAL
,
2202 IN LPCSTR lpValueName OPTIONAL
,
2204 IN LPCVOID lpData OPTIONAL
,
2207 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2211 Status
= MapDefaultKey(&KeyHandle
,
2213 if (!NT_SUCCESS(Status
))
2215 return RtlNtStatusToDosError(Status
);
2218 if (lpSubKey
!= NULL
)
2220 OBJECT_ATTRIBUTES ObjectAttributes
;
2221 UNICODE_STRING SubKeyName
;
2223 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2226 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2230 InitializeObjectAttributes(&ObjectAttributes
,
2232 OBJ_CASE_INSENSITIVE
,
2236 Status
= NtOpenKey(&SubKeyHandle
,
2240 RtlFreeUnicodeString(&SubKeyName
);
2242 if (!NT_SUCCESS(Status
))
2244 Ret
= RtlNtStatusToDosError(Status
);
2248 CurKey
= SubKeyHandle
;
2253 Ret
= RegSetValueExA(CurKey
,
2260 if (SubKeyHandle
!= NULL
)
2262 NtClose(SubKeyHandle
);
2266 ClosePredefKey(KeyHandle
);
2272 /************************************************************************
2278 RegDeleteValueA (HKEY hKey
,
2281 UNICODE_STRING ValueName
;
2285 Status
= MapDefaultKey (&KeyHandle
,
2287 if (!NT_SUCCESS(Status
))
2289 return RtlNtStatusToDosError (Status
);
2292 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
2293 (LPSTR
)lpValueName
);
2294 Status
= NtDeleteValueKey (KeyHandle
,
2296 RtlFreeUnicodeString (&ValueName
);
2298 ClosePredefKey(KeyHandle
);
2300 if (!NT_SUCCESS(Status
))
2302 return RtlNtStatusToDosError (Status
);
2305 return ERROR_SUCCESS
;
2309 /************************************************************************
2315 RegDeleteValueW (HKEY hKey
,
2316 LPCWSTR lpValueName
)
2318 UNICODE_STRING ValueName
;
2322 Status
= MapDefaultKey (&KeyHandle
,
2324 if (!NT_SUCCESS(Status
))
2326 return RtlNtStatusToDosError (Status
);
2329 RtlInitUnicodeString (&ValueName
,
2330 (LPWSTR
)lpValueName
);
2332 Status
= NtDeleteValueKey (KeyHandle
,
2335 ClosePredefKey(KeyHandle
);
2337 if (!NT_SUCCESS(Status
))
2339 return RtlNtStatusToDosError (Status
);
2342 return ERROR_SUCCESS
;
2346 /************************************************************************
2352 RegEnumKeyA (HKEY hKey
,
2360 return RegEnumKeyExA (hKey
,
2371 /************************************************************************
2377 RegEnumKeyW (HKEY hKey
,
2385 return RegEnumKeyExW (hKey
,
2396 /************************************************************************
2402 RegEnumKeyExA (HKEY hKey
,
2409 PFILETIME lpftLastWriteTime
)
2413 KEY_NODE_INFORMATION Node
;
2414 KEY_BASIC_INFORMATION Basic
;
2417 UNICODE_STRING StringU
;
2418 ANSI_STRING StringA
;
2419 LONG ErrorCode
= ERROR_SUCCESS
;
2421 DWORD ClassLength
= 0;
2427 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2428 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2430 if ((lpClass
) && (!lpcbClass
))
2432 return ERROR_INVALID_PARAMETER
;
2435 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2436 if (!NT_SUCCESS(Status
))
2438 return RtlNtStatusToDosError (Status
);
2443 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2454 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2461 /* The class name should start at a dword boundary */
2462 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2466 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2469 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2470 if (KeyInfo
== NULL
)
2472 ErrorCode
= ERROR_OUTOFMEMORY
;
2476 Status
= NtEnumerateKey (KeyHandle
,
2478 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2482 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2483 if (!NT_SUCCESS(Status
))
2485 ErrorCode
= RtlNtStatusToDosError (Status
);
2489 if (lpClass
== NULL
)
2491 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2493 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2497 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2498 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2499 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2504 if (KeyInfo
->Node
.NameLength
> NameLength
||
2505 KeyInfo
->Node
.ClassLength
> ClassLength
)
2507 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2511 StringA
.Buffer
= lpClass
;
2513 StringA
.MaximumLength
= *lpcbClass
;
2514 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2515 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2516 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2517 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2518 lpClass
[StringA
.Length
] = 0;
2519 *lpcbClass
= StringA
.Length
;
2520 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2521 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2522 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2526 if (ErrorCode
== ERROR_SUCCESS
)
2528 StringA
.Buffer
= lpName
;
2530 StringA
.MaximumLength
= *lpcbName
;
2531 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2532 lpName
[StringA
.Length
] = 0;
2533 *lpcbName
= StringA
.Length
;
2534 if (lpftLastWriteTime
!= NULL
)
2536 if (lpClass
== NULL
)
2538 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2539 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2543 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2544 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2550 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2551 TRACE("Key Namea1 Length %d\n", NameLength
);
2552 TRACE("Key Namea Length %d\n", *lpcbName
);
2553 TRACE("Key Namea %s\n", lpName
);
2555 RtlFreeHeap (ProcessHeap
,
2560 ClosePredefKey(KeyHandle
);
2566 /************************************************************************
2572 RegEnumKeyExW (HKEY hKey
,
2579 PFILETIME lpftLastWriteTime
)
2583 KEY_NODE_INFORMATION Node
;
2584 KEY_BASIC_INFORMATION Basic
;
2590 ULONG ClassLength
= 0;
2592 LONG ErrorCode
= ERROR_SUCCESS
;
2595 Status
= MapDefaultKey(&KeyHandle
,
2597 if (!NT_SUCCESS(Status
))
2599 return RtlNtStatusToDosError (Status
);
2604 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2615 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2622 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2626 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2629 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
2632 if (KeyInfo
== NULL
)
2634 ErrorCode
= ERROR_OUTOFMEMORY
;
2638 Status
= NtEnumerateKey (KeyHandle
,
2640 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2644 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2645 if (!NT_SUCCESS(Status
))
2647 ErrorCode
= RtlNtStatusToDosError (Status
);
2651 if (lpClass
== NULL
)
2653 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2655 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2659 RtlCopyMemory (lpName
,
2660 KeyInfo
->Basic
.Name
,
2661 KeyInfo
->Basic
.NameLength
);
2662 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2663 lpName
[*lpcbName
] = 0;
2668 if (KeyInfo
->Node
.NameLength
> NameLength
||
2669 KeyInfo
->Node
.ClassLength
> ClassLength
)
2671 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2675 RtlCopyMemory (lpName
,
2677 KeyInfo
->Node
.NameLength
);
2678 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2679 lpName
[*lpcbName
] = 0;
2680 RtlCopyMemory (lpClass
,
2681 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2682 KeyInfo
->Node
.ClassLength
);
2683 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2684 lpClass
[*lpcbClass
] = 0;
2688 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2690 if (lpClass
== NULL
)
2692 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2693 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2697 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2698 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2703 RtlFreeHeap (ProcessHeap
,
2708 ClosePredefKey(KeyHandle
);
2713 /************************************************************************
2719 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2720 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2725 char buffer
[256], *buf_ptr
= buffer
;
2726 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2727 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2729 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2730 // hkey, index, value, val_count, reserved, type, data, count );
2732 /* NT only checks count, not val_count */
2733 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2734 status
= MapDefaultKey (&KeyHandle
, hKey
);
2735 if (!NT_SUCCESS(status
))
2737 return RtlNtStatusToDosError (status
);
2740 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2741 if (data
) total_size
+= *count
;
2742 total_size
= min( sizeof(buffer
), total_size
);
2744 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2745 buffer
, total_size
, &total_size
);
2746 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2748 /* we need to fetch the contents for a string type even if not requested,
2749 * because we need to compute the length of the ASCII string. */
2750 if (value
|| data
|| is_string(info
->Type
))
2752 /* retry with a dynamically allocated buffer */
2753 while (status
== STATUS_BUFFER_OVERFLOW
)
2755 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2756 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2758 status
= STATUS_INSUFFICIENT_RESOURCES
;
2761 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2762 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2763 buf_ptr
, total_size
, &total_size
);
2766 if (status
) goto done
;
2768 if (is_string(info
->Type
))
2771 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2772 total_size
- info
->DataOffset
);
2775 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2778 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2779 total_size
- info
->DataOffset
);
2780 /* if the type is REG_SZ and data is not 0-terminated
2781 * and there is enough space in the buffer NT appends a \0 */
2782 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2785 info
->DataLength
= len
;
2789 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2790 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2793 if (value
&& !status
)
2797 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2798 if (len
>= *val_count
)
2800 status
= STATUS_BUFFER_OVERFLOW
;
2803 len
= *val_count
- 1;
2804 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2810 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2816 else status
= STATUS_SUCCESS
;
2818 if (type
) *type
= info
->Type
;
2819 if (count
) *count
= info
->DataLength
;
2822 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2823 ClosePredefKey(KeyHandle
);
2824 return RtlNtStatusToDosError(status
);
2827 /******************************************************************************
2828 * RegEnumValueW [ADVAPI32.@]
2832 * hkey [I] Handle to key to query
2833 * index [I] Index of value to query
2834 * value [O] Value string
2835 * val_count [I/O] Size of value buffer (in wchars)
2836 * reserved [I] Reserved
2837 * type [O] Type code
2838 * data [O] Value data
2839 * count [I/O] Size of data buffer (in bytes)
2842 * Success: ERROR_SUCCESS
2843 * Failure: nonzero error code from Winerror.h
2846 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2847 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2852 char buffer
[256], *buf_ptr
= buffer
;
2853 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2854 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2856 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2857 // hkey, index, value, val_count, reserved, type, data, count );
2859 /* NT only checks count, not val_count */
2860 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2862 status
= MapDefaultKey (&KeyHandle
, hKey
);
2863 if (!NT_SUCCESS(status
))
2865 return RtlNtStatusToDosError (status
);
2868 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2869 if (data
) total_size
+= *count
;
2870 total_size
= min( sizeof(buffer
), total_size
);
2872 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2873 buffer
, total_size
, &total_size
);
2874 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2878 /* retry with a dynamically allocated buffer */
2879 while (status
== STATUS_BUFFER_OVERFLOW
)
2881 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2882 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2884 status
= ERROR_NOT_ENOUGH_MEMORY
;
2887 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2888 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2889 buf_ptr
, total_size
, &total_size
);
2892 if (status
) goto done
;
2896 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2898 status
= STATUS_BUFFER_OVERFLOW
;
2901 memcpy( value
, info
->Name
, info
->NameLength
);
2902 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2903 value
[*val_count
] = 0;
2908 if (total_size
- info
->DataOffset
> *count
)
2910 status
= STATUS_BUFFER_OVERFLOW
;
2913 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2914 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2916 /* if the type is REG_SZ and data is not 0-terminated
2917 * and there is enough space in the buffer NT appends a \0 */
2918 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2919 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2923 else status
= STATUS_SUCCESS
;
2926 if (type
) *type
= info
->Type
;
2927 if (count
) *count
= info
->DataLength
;
2930 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2931 ClosePredefKey(KeyHandle
);
2932 return RtlNtStatusToDosError(status
);
2935 /************************************************************************
2941 RegFlushKey(HKEY hKey
)
2946 if (hKey
== HKEY_PERFORMANCE_DATA
)
2948 return ERROR_SUCCESS
;
2951 Status
= MapDefaultKey (&KeyHandle
,
2953 if (!NT_SUCCESS(Status
))
2955 return RtlNtStatusToDosError (Status
);
2958 Status
= NtFlushKey (KeyHandle
);
2960 ClosePredefKey(KeyHandle
);
2962 if (!NT_SUCCESS(Status
))
2964 return RtlNtStatusToDosError (Status
);
2967 return ERROR_SUCCESS
;
2971 /************************************************************************
2977 RegGetKeySecurity(HKEY hKey
,
2978 SECURITY_INFORMATION SecurityInformation
,
2979 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2980 LPDWORD lpcbSecurityDescriptor
)
2985 if (hKey
== HKEY_PERFORMANCE_DATA
)
2987 return ERROR_INVALID_HANDLE
;
2990 Status
= MapDefaultKey(&KeyHandle
,
2992 if (!NT_SUCCESS(Status
))
2994 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2995 return RtlNtStatusToDosError (Status
);
2998 Status
= NtQuerySecurityObject(KeyHandle
,
2999 SecurityInformation
,
3000 pSecurityDescriptor
,
3001 *lpcbSecurityDescriptor
,
3002 lpcbSecurityDescriptor
);
3005 ClosePredefKey(KeyHandle
);
3007 if (!NT_SUCCESS(Status
))
3009 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3010 return RtlNtStatusToDosError (Status
);
3013 return ERROR_SUCCESS
;
3017 /************************************************************************
3023 RegLoadKeyA (HKEY hKey
,
3027 UNICODE_STRING FileName
;
3028 UNICODE_STRING KeyName
;
3031 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
3033 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3036 ErrorCode
= RegLoadKeyW (hKey
,
3040 RtlFreeUnicodeString (&FileName
);
3041 RtlFreeUnicodeString (&KeyName
);
3047 /************************************************************************
3053 RegLoadKeyW (HKEY hKey
,
3057 OBJECT_ATTRIBUTES FileObjectAttributes
;
3058 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3059 UNICODE_STRING FileName
;
3060 UNICODE_STRING KeyName
;
3063 LONG ErrorCode
= ERROR_SUCCESS
;
3065 if (hKey
== HKEY_PERFORMANCE_DATA
)
3067 return ERROR_INVALID_HANDLE
;
3070 Status
= MapDefaultKey (&KeyHandle
,
3072 if (!NT_SUCCESS(Status
))
3074 return RtlNtStatusToDosError (Status
);
3077 if (!RtlDosPathNameToNtPathName_U (lpFile
,
3082 ErrorCode
= ERROR_BAD_PATHNAME
;
3086 InitializeObjectAttributes (&FileObjectAttributes
,
3088 OBJ_CASE_INSENSITIVE
,
3092 RtlInitUnicodeString (&KeyName
,
3095 InitializeObjectAttributes (&KeyObjectAttributes
,
3097 OBJ_CASE_INSENSITIVE
,
3101 Status
= NtLoadKey (&KeyObjectAttributes
,
3102 &FileObjectAttributes
);
3104 RtlFreeHeap (RtlGetProcessHeap (),
3108 if (!NT_SUCCESS(Status
))
3110 ErrorCode
= RtlNtStatusToDosError (Status
);
3115 ClosePredefKey(KeyHandle
);
3121 /************************************************************************
3122 * RegNotifyChangeKeyValue
3127 RegNotifyChangeKeyValue (HKEY hKey
,
3129 DWORD dwNotifyFilter
,
3133 IO_STATUS_BLOCK IoStatusBlock
;
3136 LONG ErrorCode
= ERROR_SUCCESS
;
3138 if (hKey
== HKEY_PERFORMANCE_DATA
)
3140 return ERROR_INVALID_HANDLE
;
3143 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3145 return ERROR_INVALID_PARAMETER
;
3148 Status
= MapDefaultKey (&KeyHandle
,
3150 if (!NT_SUCCESS(Status
))
3152 return RtlNtStatusToDosError (Status
);
3155 /* FIXME: Remote key handles must fail */
3157 Status
= NtNotifyChangeKey (KeyHandle
,
3167 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3169 ErrorCode
= RtlNtStatusToDosError (Status
);
3172 ClosePredefKey(KeyHandle
);
3178 /************************************************************************
3179 * RegOpenCurrentUser
3184 RegOpenCurrentUser (IN REGSAM samDesired
,
3185 OUT PHKEY phkResult
)
3189 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3190 (PHANDLE
)phkResult
);
3191 if (!NT_SUCCESS(Status
))
3193 /* NOTE - don't set the last error code! just return the error! */
3194 return RtlNtStatusToDosError(Status
);
3197 return ERROR_SUCCESS
;
3201 /************************************************************************
3204 * 20050503 Fireball - imported from WINE
3209 RegOpenKeyA (HKEY hKey
,
3213 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3215 if (!hKey
&& lpSubKey
&& phkResult
)
3217 return ERROR_INVALID_HANDLE
;
3220 if (!lpSubKey
|| !*lpSubKey
)
3223 return ERROR_SUCCESS
;
3226 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3230 /************************************************************************
3235 * 20050503 Fireball - imported from WINE
3240 RegOpenKeyW (HKEY hKey
,
3244 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3246 if (!hKey
&& lpSubKey
&& phkResult
)
3248 return ERROR_INVALID_HANDLE
;
3251 if (!lpSubKey
|| !*lpSubKey
)
3254 return ERROR_SUCCESS
;
3256 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3260 /************************************************************************
3266 RegOpenKeyExA (HKEY hKey
,
3272 OBJECT_ATTRIBUTES ObjectAttributes
;
3273 UNICODE_STRING SubKeyString
;
3276 LONG ErrorCode
= ERROR_SUCCESS
;
3278 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3279 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3281 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3282 if (!NT_SUCCESS(Status
))
3284 return RtlNtStatusToDosError (Status
);
3287 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
3288 InitializeObjectAttributes (&ObjectAttributes
,
3290 OBJ_CASE_INSENSITIVE
,
3294 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3295 RtlFreeUnicodeString (&SubKeyString
);
3296 if (!NT_SUCCESS(Status
))
3298 ErrorCode
= RtlNtStatusToDosError (Status
);
3301 ClosePredefKey(KeyHandle
);
3307 /************************************************************************
3313 RegOpenKeyExW (HKEY hKey
,
3319 OBJECT_ATTRIBUTES ObjectAttributes
;
3320 UNICODE_STRING SubKeyString
;
3323 LONG ErrorCode
= ERROR_SUCCESS
;
3325 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3326 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3328 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3329 if (!NT_SUCCESS(Status
))
3331 return RtlNtStatusToDosError (Status
);
3334 if (lpSubKey
!= NULL
)
3335 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
3337 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
3339 InitializeObjectAttributes (&ObjectAttributes
,
3341 OBJ_CASE_INSENSITIVE
,
3345 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3347 if (!NT_SUCCESS(Status
))
3349 ErrorCode
= RtlNtStatusToDosError (Status
);
3352 ClosePredefKey(KeyHandle
);
3358 /************************************************************************
3359 * RegOpenUserClassesRoot
3364 RegOpenUserClassesRoot (IN HANDLE hToken
,
3366 IN REGSAM samDesired
,
3367 OUT PHKEY phkResult
)
3369 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3370 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3371 PTOKEN_USER TokenUserData
;
3372 ULONG RequiredLength
;
3373 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3374 OBJECT_ATTRIBUTES ObjectAttributes
;
3377 /* check parameters */
3378 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3380 return ERROR_INVALID_PARAMETER
;
3384 * Get the user sid from the token
3388 /* determine how much memory we need */
3389 Status
= NtQueryInformationToken(hToken
,
3394 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3396 /* NOTE - as opposed to all other registry functions windows does indeed
3397 change the last error code in case the caller supplied a invalid
3398 handle for example! */
3399 return RtlNtStatusToDosError (Status
);
3402 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3405 if (TokenUserData
== NULL
)
3407 return ERROR_NOT_ENOUGH_MEMORY
;
3410 /* attempt to read the information */
3411 Status
= NtQueryInformationToken(hToken
,
3416 if (!NT_SUCCESS(Status
))
3418 RtlFreeHeap(ProcessHeap
,
3421 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3423 /* the information appears to have changed?! try again */
3427 /* NOTE - as opposed to all other registry functions windows does indeed
3428 change the last error code in case the caller supplied a invalid
3429 handle for example! */
3430 return RtlNtStatusToDosError (Status
);
3434 * Build the absolute path for the user's registry in the form
3435 * "\Registry\User\<SID>_Classes"
3437 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3438 TokenUserData
->User
.Sid
,
3441 /* we don't need the user data anymore, free it */
3442 RtlFreeHeap(ProcessHeap
,
3446 if (!NT_SUCCESS(Status
))
3448 return RtlNtStatusToDosError (Status
);
3451 /* allocate enough memory for the entire key string */
3452 UserClassesKeyRoot
.Length
= 0;
3453 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3454 sizeof(UserClassesKeyPrefix
) +
3455 sizeof(UserClassesKeySuffix
);
3456 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3458 UserClassesKeyRoot
.MaximumLength
);
3459 if (UserClassesKeyRoot
.Buffer
== NULL
)
3461 RtlFreeUnicodeString(&UserSidString
);
3462 return RtlNtStatusToDosError (Status
);
3465 /* build the string */
3466 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3467 UserClassesKeyPrefix
);
3468 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3470 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3471 UserClassesKeySuffix
);
3473 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3479 InitializeObjectAttributes (&ObjectAttributes
,
3480 &UserClassesKeyRoot
,
3481 OBJ_CASE_INSENSITIVE
,
3485 Status
= NtOpenKey((PHANDLE
)phkResult
,
3489 RtlFreeUnicodeString(&UserSidString
);
3490 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3492 if (!NT_SUCCESS(Status
))
3494 return RtlNtStatusToDosError (Status
);
3497 return ERROR_SUCCESS
;
3501 /************************************************************************
3507 RegQueryInfoKeyA (HKEY hKey
,
3512 LPDWORD lpcbMaxSubKeyLen
,
3513 LPDWORD lpcbMaxClassLen
,
3515 LPDWORD lpcbMaxValueNameLen
,
3516 LPDWORD lpcbMaxValueLen
,
3517 LPDWORD lpcbSecurityDescriptor
,
3518 PFILETIME lpftLastWriteTime
)
3520 WCHAR ClassName
[MAX_PATH
];
3521 UNICODE_STRING UnicodeString
;
3522 ANSI_STRING AnsiString
;
3525 RtlInitUnicodeString (&UnicodeString
,
3527 if (lpClass
!= NULL
)
3529 UnicodeString
.Buffer
= &ClassName
[0];
3530 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3531 AnsiString
.MaximumLength
= *lpcbClass
;
3534 ErrorCode
= RegQueryInfoKeyW (hKey
,
3535 UnicodeString
.Buffer
,
3542 lpcbMaxValueNameLen
,
3544 lpcbSecurityDescriptor
,
3546 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3548 AnsiString
.Buffer
= lpClass
;
3549 AnsiString
.Length
= 0;
3550 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3551 RtlUnicodeStringToAnsiString (&AnsiString
,
3554 *lpcbClass
= AnsiString
.Length
;
3555 lpClass
[AnsiString
.Length
] = 0;
3562 /************************************************************************
3568 RegQueryInfoKeyW (HKEY hKey
,
3573 LPDWORD lpcbMaxSubKeyLen
,
3574 LPDWORD lpcbMaxClassLen
,
3576 LPDWORD lpcbMaxValueNameLen
,
3577 LPDWORD lpcbMaxValueLen
,
3578 LPDWORD lpcbSecurityDescriptor
,
3579 PFILETIME lpftLastWriteTime
)
3581 KEY_FULL_INFORMATION FullInfoBuffer
;
3582 PKEY_FULL_INFORMATION FullInfo
;
3584 ULONG ClassLength
= 0;
3588 LONG ErrorCode
= ERROR_SUCCESS
;
3590 if ((lpClass
) && (!lpcbClass
))
3592 return ERROR_INVALID_PARAMETER
;
3595 Status
= MapDefaultKey (&KeyHandle
,
3597 if (!NT_SUCCESS(Status
))
3599 return RtlNtStatusToDosError (Status
);
3602 if (lpClass
!= NULL
)
3606 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3613 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3614 FullInfo
= RtlAllocateHeap (ProcessHeap
,
3617 if (FullInfo
== NULL
)
3619 ErrorCode
= ERROR_OUTOFMEMORY
;
3623 FullInfo
->ClassLength
= ClassLength
;
3627 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3628 FullInfo
= &FullInfoBuffer
;
3629 FullInfo
->ClassLength
= 0;
3631 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3633 Status
= NtQueryKey (KeyHandle
,
3638 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3639 if (!NT_SUCCESS(Status
))
3641 if (lpClass
!= NULL
)
3643 RtlFreeHeap (ProcessHeap
,
3648 ErrorCode
= RtlNtStatusToDosError (Status
);
3652 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3653 if (lpcSubKeys
!= NULL
)
3655 *lpcSubKeys
= FullInfo
->SubKeys
;
3658 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3659 if (lpcbMaxSubKeyLen
!= NULL
)
3661 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3664 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3665 if (lpcbMaxClassLen
!= NULL
)
3667 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3670 TRACE("Values %lu\n", FullInfo
->Values
);
3671 if (lpcValues
!= NULL
)
3673 *lpcValues
= FullInfo
->Values
;
3676 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3677 if (lpcbMaxValueNameLen
!= NULL
)
3679 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3682 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3683 if (lpcbMaxValueLen
!= NULL
)
3685 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3688 if (lpcbSecurityDescriptor
!= NULL
)
3690 Status
= NtQuerySecurityObject(KeyHandle
,
3691 OWNER_SECURITY_INFORMATION
|
3692 GROUP_SECURITY_INFORMATION
|
3693 DACL_SECURITY_INFORMATION
,
3696 lpcbSecurityDescriptor
);
3697 if (!NT_SUCCESS(Status
))
3699 if (lpClass
!= NULL
)
3701 RtlFreeHeap(ProcessHeap
,
3706 ErrorCode
= RtlNtStatusToDosError (Status
);
3712 if (lpftLastWriteTime
!= NULL
)
3714 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3715 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3718 if (lpClass
!= NULL
)
3720 if (FullInfo
->ClassLength
> ClassLength
)
3722 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3726 RtlCopyMemory (lpClass
,
3728 FullInfo
->ClassLength
);
3729 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3730 lpClass
[*lpcbClass
] = 0;
3733 RtlFreeHeap (ProcessHeap
,
3739 ClosePredefKey(KeyHandle
);
3745 /************************************************************************
3746 * RegQueryMultipleValuesA
3751 RegQueryMultipleValuesA (HKEY hKey
,
3758 DWORD maxBytes
= *ldwTotsize
;
3759 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3762 if (maxBytes
>= (1024*1024))
3763 return ERROR_TRANSFER_TOO_LONG
;
3767 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3768 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3770 for (i
= 0; i
< num_vals
; i
++)
3772 val_list
[i
].ve_valuelen
= 0;
3773 ErrorCode
= RegQueryValueExA (hKey
,
3774 val_list
[i
].ve_valuename
,
3778 &val_list
[i
].ve_valuelen
);
3779 if (ErrorCode
!= ERROR_SUCCESS
)
3784 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3786 ErrorCode
= RegQueryValueExA (hKey
,
3787 val_list
[i
].ve_valuename
,
3789 &val_list
[i
].ve_type
,
3791 &val_list
[i
].ve_valuelen
);
3792 if (ErrorCode
!= ERROR_SUCCESS
)
3797 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3799 bufptr
+= val_list
[i
].ve_valuelen
;
3802 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3805 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3809 /************************************************************************
3810 * RegQueryMultipleValuesW
3815 RegQueryMultipleValuesW (HKEY hKey
,
3822 DWORD maxBytes
= *ldwTotsize
;
3823 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3826 if (maxBytes
>= (1024*1024))
3827 return ERROR_TRANSFER_TOO_LONG
;
3831 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3832 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3834 for (i
= 0; i
< num_vals
; i
++)
3836 val_list
[i
].ve_valuelen
= 0;
3837 ErrorCode
= RegQueryValueExW (hKey
,
3838 val_list
[i
].ve_valuename
,
3842 &val_list
[i
].ve_valuelen
);
3843 if (ErrorCode
!= ERROR_SUCCESS
)
3848 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3850 ErrorCode
= RegQueryValueExW (hKey
,
3851 val_list
[i
].ve_valuename
,
3853 &val_list
[i
].ve_type
,
3855 &val_list
[i
].ve_valuelen
);
3856 if (ErrorCode
!= ERROR_SUCCESS
)
3861 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3863 bufptr
+= val_list
[i
].ve_valuelen
;
3866 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3869 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3873 /************************************************************************
3874 * RegQueryReflectionKey
3879 RegQueryReflectionKey(IN HKEY hBase
,
3880 OUT BOOL
* bIsReflectionDisabled
)
3882 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3883 hBase
, bIsReflectionDisabled
);
3884 return ERROR_CALL_NOT_IMPLEMENTED
;
3888 /************************************************************************
3895 RegQueryValueExW(HKEY hkeyorg
,
3904 UNICODE_STRING name_str
;
3906 char buffer
[256], *buf_ptr
= buffer
;
3907 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
3908 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
3910 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
3911 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
3912 (count
&& data
) ? *count
: 0 );
3914 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3915 //if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
3917 status
= MapDefaultKey(&hkey
, hkeyorg
);
3918 if (!NT_SUCCESS(status
))
3920 return RtlNtStatusToDosError(status
);
3923 RtlInitUnicodeString( &name_str
, name
);
3925 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
3928 total_size
= info_size
;
3929 if (count
) *count
= 0;
3932 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
3933 buffer
, total_size
, &total_size
);
3934 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
3938 /* retry with a dynamically allocated buffer */
3939 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
3941 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3942 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3943 return ERROR_NOT_ENOUGH_MEMORY
;
3944 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
3945 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
3946 buf_ptr
, total_size
, &total_size
);
3951 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
3952 /* if the type is REG_SZ and data is not 0-terminated
3953 * and there is enough space in the buffer NT appends a \0 */
3954 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
3956 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
3957 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3960 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
3962 else status
= STATUS_SUCCESS
;
3964 if (type
) *type
= info
->Type
;
3965 if (count
) *count
= total_size
- info_size
;
3968 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3969 ClosePredefKey(hkey
);
3970 return RtlNtStatusToDosError(status
);
3974 /************************************************************************
3980 RegQueryValueExA (HKEY hKey
,
3987 UNICODE_STRING ValueName
;
3988 UNICODE_STRING ValueData
;
3989 ANSI_STRING AnsiString
;
3994 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3995 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3997 if (lpData
!= NULL
&& lpcbData
== NULL
)
3999 return ERROR_INVALID_PARAMETER
;
4004 ValueData
.Length
= 0;
4005 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
4006 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
4008 ValueData
.MaximumLength
);
4009 if (!ValueData
.Buffer
)
4011 return ERROR_OUTOFMEMORY
;
4016 ValueData
.Buffer
= NULL
;
4017 ValueData
.Length
= 0;
4018 ValueData
.MaximumLength
= 0;
4024 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4025 (LPSTR
)lpValueName
);
4027 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
4028 ErrorCode
= RegQueryValueExW (hKey
,
4032 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
4034 TRACE("ErrorCode %lu\n", ErrorCode
);
4035 RtlFreeUnicodeString(&ValueName
);
4037 if (ErrorCode
== ERROR_SUCCESS
||
4038 ErrorCode
== ERROR_MORE_DATA
)
4045 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
4047 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4049 RtlInitAnsiString(&AnsiString
, NULL
);
4050 AnsiString
.Buffer
= (LPSTR
)lpData
;
4051 AnsiString
.MaximumLength
= *lpcbData
;
4052 ValueData
.Length
= Length
;
4053 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
4054 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
4056 Length
= Length
/ sizeof(WCHAR
);
4058 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4060 if (*lpcbData
< Length
)
4062 ErrorCode
= ERROR_MORE_DATA
;
4066 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
4070 if (lpcbData
!= NULL
)
4076 if (ValueData
.Buffer
!= NULL
)
4078 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
4085 /************************************************************************
4091 RegQueryValueA (HKEY hKey
,
4096 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
4097 UNICODE_STRING SubKeyName
;
4098 UNICODE_STRING Value
;
4099 ANSI_STRING AnsiString
;
4103 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
4104 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4106 if (lpValue
!= NULL
&&
4109 return ERROR_INVALID_PARAMETER
;
4112 RtlInitUnicodeString (&SubKeyName
,
4114 RtlInitUnicodeString (&Value
,
4116 if (lpSubKey
!= NULL
&&
4117 strlen(lpSubKey
) != 0)
4119 RtlInitAnsiString (&AnsiString
,
4121 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
4122 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
4123 RtlAnsiStringToUnicodeString (&SubKeyName
,
4128 if (lpValue
!= NULL
)
4130 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
4131 Value
.MaximumLength
= ValueSize
;
4132 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
4135 if (Value
.Buffer
== NULL
)
4137 return ERROR_OUTOFMEMORY
;
4145 ErrorCode
= RegQueryValueW (hKey
,
4146 (LPCWSTR
)SubKeyName
.Buffer
,
4149 if (ErrorCode
== ERROR_SUCCESS
)
4151 if (lpValue
!= NULL
)
4153 Value
.Length
= ValueSize
;
4154 RtlInitAnsiString (&AnsiString
,
4156 AnsiString
.Buffer
= lpValue
;
4157 AnsiString
.MaximumLength
= *lpcbValue
;
4158 RtlUnicodeStringToAnsiString (&AnsiString
,
4161 *lpcbValue
= ValueSize
;
4163 else if (lpcbValue
!= NULL
)
4165 *lpcbValue
= ValueSize
;
4169 if (Value
.Buffer
!= NULL
)
4171 RtlFreeHeap (ProcessHeap
,
4180 /************************************************************************
4186 RegQueryValueW (HKEY hKey
,
4191 OBJECT_ATTRIBUTES ObjectAttributes
;
4192 UNICODE_STRING SubKeyString
;
4199 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
4200 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4202 Status
= MapDefaultKey (&KeyHandle
,
4204 if (!NT_SUCCESS(Status
))
4206 return RtlNtStatusToDosError (Status
);
4209 if (lpSubKey
!= NULL
&&
4210 wcslen(lpSubKey
) != 0)
4212 RtlInitUnicodeString (&SubKeyString
,
4214 InitializeObjectAttributes (&ObjectAttributes
,
4216 OBJ_CASE_INSENSITIVE
,
4219 Status
= NtOpenKey (&RealKey
,
4222 if (!NT_SUCCESS(Status
))
4224 ErrorCode
= RtlNtStatusToDosError (Status
);
4227 CloseRealKey
= TRUE
;
4232 CloseRealKey
= FALSE
;
4235 ErrorCode
= RegQueryValueExW (RealKey
,
4240 (LPDWORD
)lpcbValue
);
4247 ClosePredefKey(KeyHandle
);
4253 /************************************************************************
4259 RegReplaceKeyA (HKEY hKey
,
4264 UNICODE_STRING SubKey
;
4265 UNICODE_STRING NewFile
;
4266 UNICODE_STRING OldFile
;
4269 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
4271 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
4273 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
4276 ErrorCode
= RegReplaceKeyW (hKey
,
4281 RtlFreeUnicodeString (&OldFile
);
4282 RtlFreeUnicodeString (&NewFile
);
4283 RtlFreeUnicodeString (&SubKey
);
4289 /************************************************************************
4295 RegReplaceKeyW (HKEY hKey
,
4300 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4301 OBJECT_ATTRIBUTES NewObjectAttributes
;
4302 OBJECT_ATTRIBUTES OldObjectAttributes
;
4303 UNICODE_STRING SubKeyName
;
4304 UNICODE_STRING NewFileName
;
4305 UNICODE_STRING OldFileName
;
4306 BOOLEAN CloseRealKey
;
4307 HANDLE RealKeyHandle
;
4310 LONG ErrorCode
= ERROR_SUCCESS
;
4312 if (hKey
== HKEY_PERFORMANCE_DATA
)
4314 return ERROR_INVALID_HANDLE
;
4317 Status
= MapDefaultKey (&KeyHandle
,
4319 if (!NT_SUCCESS(Status
))
4321 return RtlNtStatusToDosError (Status
);
4324 /* Open the real key */
4325 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4327 RtlInitUnicodeString (&SubKeyName
,
4329 InitializeObjectAttributes (&KeyObjectAttributes
,
4331 OBJ_CASE_INSENSITIVE
,
4334 Status
= NtOpenKey (&RealKeyHandle
,
4336 &KeyObjectAttributes
);
4337 if (!NT_SUCCESS(Status
))
4339 ErrorCode
= RtlNtStatusToDosError (Status
);
4342 CloseRealKey
= TRUE
;
4346 RealKeyHandle
= KeyHandle
;
4347 CloseRealKey
= FALSE
;
4350 /* Convert new file name */
4351 if (!RtlDosPathNameToNtPathName_U (lpNewFile
,
4358 NtClose (RealKeyHandle
);
4360 ErrorCode
= ERROR_INVALID_PARAMETER
;
4364 InitializeObjectAttributes (&NewObjectAttributes
,
4366 OBJ_CASE_INSENSITIVE
,
4370 /* Convert old file name */
4371 if (!RtlDosPathNameToNtPathName_U (lpOldFile
,
4376 RtlFreeHeap (RtlGetProcessHeap (),
4378 NewFileName
.Buffer
);
4381 NtClose (RealKeyHandle
);
4383 ErrorCode
= ERROR_INVALID_PARAMETER
;
4387 InitializeObjectAttributes (&OldObjectAttributes
,
4389 OBJ_CASE_INSENSITIVE
,
4393 Status
= NtReplaceKey (&NewObjectAttributes
,
4395 &OldObjectAttributes
);
4397 RtlFreeHeap (RtlGetProcessHeap (),
4399 OldFileName
.Buffer
);
4400 RtlFreeHeap (RtlGetProcessHeap (),
4402 NewFileName
.Buffer
);
4406 NtClose (RealKeyHandle
);
4409 if (!NT_SUCCESS(Status
))
4411 return RtlNtStatusToDosError (Status
);
4415 ClosePredefKey(KeyHandle
);
4421 /************************************************************************
4427 RegRestoreKeyA (HKEY hKey
,
4431 UNICODE_STRING FileName
;
4434 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4437 ErrorCode
= RegRestoreKeyW (hKey
,
4441 RtlFreeUnicodeString (&FileName
);
4447 /************************************************************************
4453 RegRestoreKeyW (HKEY hKey
,
4457 OBJECT_ATTRIBUTES ObjectAttributes
;
4458 IO_STATUS_BLOCK IoStatusBlock
;
4459 UNICODE_STRING FileName
;
4464 if (hKey
== HKEY_PERFORMANCE_DATA
)
4466 return ERROR_INVALID_HANDLE
;
4469 Status
= MapDefaultKey (&KeyHandle
,
4471 if (!NT_SUCCESS(Status
))
4473 return RtlNtStatusToDosError (Status
);
4476 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4481 Status
= STATUS_INVALID_PARAMETER
;
4485 InitializeObjectAttributes (&ObjectAttributes
,
4487 OBJ_CASE_INSENSITIVE
,
4491 Status
= NtOpenFile (&FileHandle
,
4496 FILE_SYNCHRONOUS_IO_NONALERT
);
4497 RtlFreeHeap (RtlGetProcessHeap(),
4500 if (!NT_SUCCESS(Status
))
4505 Status
= NtRestoreKey (KeyHandle
,
4508 NtClose (FileHandle
);
4511 ClosePredefKey(KeyHandle
);
4513 if (!NT_SUCCESS(Status
))
4515 return RtlNtStatusToDosError (Status
);
4518 return ERROR_SUCCESS
;
4522 /************************************************************************
4528 RegSaveKeyA (HKEY hKey
,
4530 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4532 UNICODE_STRING FileName
;
4535 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4537 ErrorCode
= RegSaveKeyW (hKey
,
4539 lpSecurityAttributes
);
4540 RtlFreeUnicodeString (&FileName
);
4546 /************************************************************************
4552 RegSaveKeyW (HKEY hKey
,
4554 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4556 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4557 OBJECT_ATTRIBUTES ObjectAttributes
;
4558 UNICODE_STRING FileName
;
4559 IO_STATUS_BLOCK IoStatusBlock
;
4564 Status
= MapDefaultKey (&KeyHandle
,
4566 if (!NT_SUCCESS(Status
))
4568 return RtlNtStatusToDosError (Status
);
4571 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4576 Status
= STATUS_INVALID_PARAMETER
;
4580 if (lpSecurityAttributes
!= NULL
)
4582 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4585 InitializeObjectAttributes (&ObjectAttributes
,
4587 OBJ_CASE_INSENSITIVE
,
4589 SecurityDescriptor
);
4590 Status
= NtCreateFile (&FileHandle
,
4591 GENERIC_WRITE
| SYNCHRONIZE
,
4595 FILE_ATTRIBUTE_NORMAL
,
4598 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4601 RtlFreeHeap (RtlGetProcessHeap (),
4604 if (!NT_SUCCESS(Status
))
4609 Status
= NtSaveKey (KeyHandle
,
4611 NtClose (FileHandle
);
4614 ClosePredefKey(KeyHandle
);
4616 if (!NT_SUCCESS(Status
))
4618 return RtlNtStatusToDosError (Status
);
4621 return ERROR_SUCCESS
;
4625 /************************************************************************
4631 RegSetKeySecurity (HKEY hKey
,
4632 SECURITY_INFORMATION SecurityInformation
,
4633 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4638 if (hKey
== HKEY_PERFORMANCE_DATA
)
4640 return ERROR_INVALID_HANDLE
;
4643 Status
= MapDefaultKey (&KeyHandle
,
4645 if (!NT_SUCCESS(Status
))
4647 return RtlNtStatusToDosError (Status
);
4650 Status
= NtSetSecurityObject (KeyHandle
,
4651 SecurityInformation
,
4652 pSecurityDescriptor
);
4654 ClosePredefKey(KeyHandle
);
4656 if (!NT_SUCCESS(Status
))
4658 return RtlNtStatusToDosError (Status
);
4661 return ERROR_SUCCESS
;
4665 /************************************************************************
4671 RegSetValueExA (HKEY hKey
,
4678 UNICODE_STRING ValueName
;
4680 ANSI_STRING AnsiString
;
4681 UNICODE_STRING Data
;
4686 if (lpValueName
!= NULL
&&
4687 strlen(lpValueName
) != 0)
4689 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4694 ValueName
.Buffer
= NULL
;
4697 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4699 if (((dwType
== REG_SZ
) ||
4700 (dwType
== REG_MULTI_SZ
) ||
4701 (dwType
== REG_EXPAND_SZ
)) &&
4704 /* NT adds one if the caller forgot the NULL-termination character */
4705 if (lpData
[cbData
- 1] != '\0')
4710 RtlInitAnsiString (&AnsiString
,
4712 AnsiString
.Buffer
= (PSTR
)lpData
;
4713 AnsiString
.Length
= cbData
- 1;
4714 AnsiString
.MaximumLength
= cbData
;
4715 RtlAnsiStringToUnicodeString (&Data
,
4718 pData
= (LPBYTE
)Data
.Buffer
;
4719 DataSize
= cbData
* sizeof(WCHAR
);
4723 RtlInitUnicodeString (&Data
,
4725 pData
= (LPBYTE
)lpData
;
4729 ErrorCode
= RegSetValueExW (hKey
,
4735 if (pValueName
!= NULL
)
4737 RtlFreeHeap (ProcessHeap
,
4742 if (Data
.Buffer
!= NULL
)
4744 RtlFreeHeap (ProcessHeap
,
4753 /************************************************************************
4759 RegSetValueExW (HKEY hKey
,
4760 LPCWSTR lpValueName
,
4766 UNICODE_STRING ValueName
;
4767 PUNICODE_STRING pValueName
;
4771 Status
= MapDefaultKey (&KeyHandle
,
4773 if (!NT_SUCCESS(Status
))
4775 return RtlNtStatusToDosError (Status
);
4778 if (lpValueName
!= NULL
)
4780 RtlInitUnicodeString (&ValueName
,
4785 RtlInitUnicodeString (&ValueName
, L
"");
4787 pValueName
= &ValueName
;
4789 if (((dwType
== REG_SZ
) ||
4790 (dwType
== REG_MULTI_SZ
) ||
4791 (dwType
== REG_EXPAND_SZ
)) &&
4792 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4794 /* NT adds one if the caller forgot the NULL-termination character */
4795 cbData
+= sizeof(WCHAR
);
4798 Status
= NtSetValueKey (KeyHandle
,
4805 ClosePredefKey(KeyHandle
);
4807 if (!NT_SUCCESS(Status
))
4809 return RtlNtStatusToDosError (Status
);
4812 return ERROR_SUCCESS
;
4816 /************************************************************************
4822 RegSetValueA (HKEY hKeyOriginal
,
4833 TRACE("(%p,%s,%d,%s,%d)\n", hKey
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4835 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4837 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4838 if (!NT_SUCCESS(Status
))
4840 return RtlNtStatusToDosError (Status
);
4844 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4846 if ((ret
= RegCreateKeyA( hKey
, lpSubKey
, &subkey
)) != ERROR_SUCCESS
) goto Cleanup
;
4848 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4849 if (subkey
!= hKey
) RegCloseKey( subkey
);
4852 ClosePredefKey(hKey
);
4858 /************************************************************************
4864 RegSetValueW (HKEY hKeyOriginal
,
4875 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4877 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4879 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4880 if (!NT_SUCCESS(Status
))
4882 return RtlNtStatusToDosError (Status
);
4886 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4888 if ((ret
= RegCreateKeyW( hKey
, lpSubKey
, &subkey
)) != ERROR_SUCCESS
) goto Cleanup
;
4891 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
4892 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
4893 if (subkey
!= hKey
) RegCloseKey( subkey
);
4896 ClosePredefKey(hKey
);
4902 /************************************************************************
4908 RegUnLoadKeyA (HKEY hKey
,
4911 UNICODE_STRING KeyName
;
4914 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4917 ErrorCode
= RegUnLoadKeyW (hKey
,
4920 RtlFreeUnicodeString (&KeyName
);
4926 /************************************************************************
4932 RegUnLoadKeyW (HKEY hKey
,
4935 OBJECT_ATTRIBUTES ObjectAttributes
;
4936 UNICODE_STRING KeyName
;
4940 if (hKey
== HKEY_PERFORMANCE_DATA
)
4942 return ERROR_INVALID_HANDLE
;
4945 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4946 if (!NT_SUCCESS(Status
))
4948 return RtlNtStatusToDosError (Status
);
4951 RtlInitUnicodeString (&KeyName
,
4954 InitializeObjectAttributes (&ObjectAttributes
,
4956 OBJ_CASE_INSENSITIVE
,
4960 Status
= NtUnloadKey (&ObjectAttributes
);
4962 ClosePredefKey(KeyHandle
);
4964 if (!NT_SUCCESS(Status
))
4966 return RtlNtStatusToDosError (Status
);
4969 return ERROR_SUCCESS
;
4972 /******************************************************************************
4973 * load_string [Internal]
4975 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
4976 * avoid importing user32, which is higher level than advapi32. Helper for
4979 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
4986 /* Negative values have to be inverted. */
4987 if (HIWORD(resId
) == 0xffff)
4988 resId
= (UINT
)(-((INT
)resId
));
4990 /* Load the resource into memory and get a pointer to it. */
4991 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
4992 if (!hResource
) return 0;
4993 hMemory
= LoadResource(hModule
, hResource
);
4994 if (!hMemory
) return 0;
4995 pString
= LockResource(hMemory
);
4997 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
4998 idxString
= resId
& 0xf;
4999 while (idxString
--) pString
+= *pString
+ 1;
5001 /* If no buffer is given, return length of the string. */
5002 if (!pwszBuffer
) return *pString
;
5004 /* Else copy over the string, respecting the buffer size. */
5005 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5006 if (cMaxChars
>= 0) {
5007 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5008 pwszBuffer
[cMaxChars
] = L
'\0';
5015 /************************************************************************
5021 RegLoadMUIStringW(IN HKEY hKey
,
5022 IN LPCWSTR pszValue OPTIONAL
,
5023 OUT LPWSTR pszOutBuf
,
5025 OUT LPDWORD pcbData OPTIONAL
,
5027 IN LPCWSTR pszDirectory OPTIONAL
)
5029 DWORD dwValueType
, cbData
;
5030 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5033 /* Parameter sanity checks. */
5034 if (!hKey
|| !pszOutBuf
)
5035 return ERROR_INVALID_PARAMETER
;
5037 if (pszDirectory
&& *pszDirectory
) {
5038 FIXME("BaseDir parameter not yet supported!\n");
5039 return ERROR_INVALID_PARAMETER
;
5042 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5043 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5044 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5045 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
5046 result
= ERROR_FILE_NOT_FOUND
;
5049 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5050 if (!pwszTempBuffer
) {
5051 result
= ERROR_NOT_ENOUGH_MEMORY
;
5054 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5055 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5057 /* Expand environment variables, if appropriate, or copy the original string over. */
5058 if (dwValueType
== REG_EXPAND_SZ
) {
5059 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5060 if (!cbData
) goto cleanup
;
5061 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5062 if (!pwszExpandedBuffer
) {
5063 result
= ERROR_NOT_ENOUGH_MEMORY
;
5066 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5068 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5069 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5072 /* If the value references a resource based string, parse the value and load the string.
5073 * Else just copy over the original value. */
5074 result
= ERROR_SUCCESS
;
5075 if (*pwszExpandedBuffer
!= L
'@') { /* '@' is the prefix for resource based string entries. */
5076 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5078 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5082 /* Format of the expanded value is 'path_to_dll,-resId' */
5083 if (!pComma
|| pComma
[1] != L
'-') {
5084 result
= ERROR_BADKEY
;
5088 uiStringId
= _wtoi(pComma
+2);
5091 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5092 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5093 result
= ERROR_BADKEY
;
5094 FreeLibrary(hModule
);
5098 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5099 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5104 /************************************************************************
5110 RegLoadMUIStringA(IN HKEY hKey
,
5111 IN LPCSTR pszValue OPTIONAL
,
5112 OUT LPSTR pszOutBuf
,
5114 OUT LPDWORD pcbData OPTIONAL
,
5116 IN LPCSTR pszDirectory OPTIONAL
)
5118 UNICODE_STRING valueW
, baseDirW
;
5120 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5123 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5124 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5125 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5126 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5128 result
= ERROR_NOT_ENOUGH_MEMORY
;
5132 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5135 if (result
== ERROR_SUCCESS
) {
5136 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5142 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5143 RtlFreeUnicodeString(&baseDirW
);
5144 RtlFreeUnicodeString(&valueW
);