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 *****************************************************************/
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
21 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
23 /* DEFINES ******************************************************************/
25 #define MAX_DEFAULT_HANDLES 6
26 #define REG_MAX_NAME_SIZE 256
27 #define REG_MAX_DATA_SIZE 2048
29 /* GLOBALS ******************************************************************/
31 static RTL_CRITICAL_SECTION HandleTableCS
;
32 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
33 static HANDLE ProcessHeap
;
34 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
35 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
36 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
38 /* PROTOTYPES ***************************************************************/
40 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
41 static VOID
CloseDefaultKeys(VOID
);
42 #define ClosePredefKey(Handle) \
43 if ((ULONG_PTR)Handle & 0x1) { \
46 #define IsPredefKey(HKey) \
47 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
48 #define GetPredefKeyIndex(HKey) \
49 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
51 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
52 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
53 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
54 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
57 /* FUNCTIONS ****************************************************************/
58 /* check if value type needs string conversion (Ansi<->Unicode) */
59 __inline
static int is_string( DWORD type
)
61 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
64 /************************************************************************
65 * RegInitDefaultHandles
70 TRACE("RegInitialize()\n");
75 ProcessHeap
= RtlGetProcessHeap();
76 RtlZeroMemory(DefaultHandleTable
,
77 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
78 RtlInitializeCriticalSection(&HandleTableCS
);
80 DllInitialized
= TRUE
;
87 /************************************************************************
93 TRACE("RegCleanup()\n");
96 RtlDeleteCriticalSection(&HandleTableCS
);
103 OpenPredefinedKey(IN ULONG Index
,
110 case 0: /* HKEY_CLASSES_ROOT */
111 Status
= OpenClassesRootKey (Handle
);
114 case 1: /* HKEY_CURRENT_USER */
115 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
119 case 2: /* HKEY_LOCAL_MACHINE */
120 Status
= OpenLocalMachineKey (Handle
);
123 case 3: /* HKEY_USERS */
124 Status
= OpenUsersKey (Handle
);
127 case 4: /* HKEY_PERFORMANCE_DATA */
128 Status
= OpenPerformanceDataKey (Handle
);
132 case 5: /* HKEY_CURRENT_CONFIG */
133 Status
= OpenCurrentConfigKey (Handle
);
136 case 6: /* HKEY_DYN_DATA */
137 Status
= STATUS_NOT_IMPLEMENTED
;
141 WARN("MapDefaultHandle() no handle creator\n");
142 Status
= STATUS_INVALID_PARAMETER
;
151 MapDefaultKey(OUT PHANDLE RealKey
,
156 BOOLEAN DoOpen
, DefDisabled
;
157 NTSTATUS Status
= STATUS_SUCCESS
;
159 TRACE("MapDefaultKey (Key %x)\n", Key
);
161 if (!IsPredefKey(Key
))
163 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
164 return STATUS_SUCCESS
;
167 /* Handle special cases here */
168 Index
= GetPredefKeyIndex(Key
);
169 if (Index
>= MAX_DEFAULT_HANDLES
)
171 return STATUS_INVALID_PARAMETER
;
173 RegInitialize(); /* HACK until delay-loading is implemented */
174 RtlEnterCriticalSection (&HandleTableCS
);
176 if (Key
== HKEY_CURRENT_USER
)
177 DefDisabled
= DefaultHandleHKUDisabled
;
179 DefDisabled
= DefaultHandlesDisabled
;
183 Handle
= &DefaultHandleTable
[Index
];
184 DoOpen
= (*Handle
== NULL
);
194 /* create/open the default handle */
195 Status
= OpenPredefinedKey(Index
,
199 if (NT_SUCCESS(Status
))
204 *(PULONG_PTR
)Handle
|= 0x1;
207 RtlLeaveCriticalSection (&HandleTableCS
);
214 CloseDefaultKeys(VOID
)
217 RegInitialize(); /* HACK until delay-loading is implemented */
218 RtlEnterCriticalSection(&HandleTableCS
);
220 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
222 if (DefaultHandleTable
[i
] != NULL
)
224 NtClose(DefaultHandleTable
[i
]);
225 DefaultHandleTable
[i
] = NULL
;
229 RtlLeaveCriticalSection(&HandleTableCS
);
234 OpenClassesRootKey(PHANDLE KeyHandle
)
236 OBJECT_ATTRIBUTES Attributes
;
237 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
239 TRACE("OpenClassesRootKey()\n");
241 InitializeObjectAttributes(&Attributes
,
243 OBJ_CASE_INSENSITIVE
,
246 return NtOpenKey(KeyHandle
,
253 OpenLocalMachineKey(PHANDLE KeyHandle
)
255 OBJECT_ATTRIBUTES Attributes
;
256 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
259 TRACE("OpenLocalMachineKey()\n");
261 InitializeObjectAttributes(&Attributes
,
263 OBJ_CASE_INSENSITIVE
,
266 Status
= NtOpenKey(KeyHandle
,
270 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
277 OpenUsersKey(PHANDLE KeyHandle
)
279 OBJECT_ATTRIBUTES Attributes
;
280 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
282 TRACE("OpenUsersKey()\n");
284 InitializeObjectAttributes(&Attributes
,
286 OBJ_CASE_INSENSITIVE
,
289 return NtOpenKey(KeyHandle
,
296 OpenCurrentConfigKey (PHANDLE KeyHandle
)
298 OBJECT_ATTRIBUTES Attributes
;
299 UNICODE_STRING KeyName
=
300 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
302 TRACE("OpenCurrentConfigKey()\n");
304 InitializeObjectAttributes(&Attributes
,
306 OBJ_CASE_INSENSITIVE
,
309 return NtOpenKey(KeyHandle
,
315 /************************************************************************
316 * RegDisablePredefinedCache
321 RegDisablePredefinedCache(VOID
)
323 RegInitialize(); /* HACK until delay-loading is implemented */
324 RtlEnterCriticalSection(&HandleTableCS
);
325 DefaultHandleHKUDisabled
= TRUE
;
326 RtlLeaveCriticalSection(&HandleTableCS
);
327 return ERROR_SUCCESS
;
331 /************************************************************************
332 * RegDisablePredefinedCacheEx
337 RegDisablePredefinedCacheEx(VOID
)
339 RegInitialize(); /* HACK until delay-loading is implemented */
340 RtlEnterCriticalSection(&HandleTableCS
);
341 DefaultHandlesDisabled
= TRUE
;
342 DefaultHandleHKUDisabled
= TRUE
;
343 RtlLeaveCriticalSection(&HandleTableCS
);
344 return ERROR_SUCCESS
;
348 /************************************************************************
349 * RegOverridePredefKey
354 RegOverridePredefKey(IN HKEY hKey
,
355 IN HKEY hNewHKey OPTIONAL
)
357 LONG ErrorCode
= ERROR_SUCCESS
;
359 if ((hKey
== HKEY_CLASSES_ROOT
||
360 hKey
== HKEY_CURRENT_CONFIG
||
361 hKey
== HKEY_CURRENT_USER
||
362 hKey
== HKEY_LOCAL_MACHINE
||
363 hKey
== HKEY_PERFORMANCE_DATA
||
364 hKey
== HKEY_USERS
) &&
365 !IsPredefKey(hNewHKey
))
370 Index
= GetPredefKeyIndex(hKey
);
371 Handle
= &DefaultHandleTable
[Index
];
373 if (hNewHKey
== NULL
)
375 /* restore the default mapping */
376 NTSTATUS Status
= OpenPredefinedKey(Index
,
378 if (!NT_SUCCESS(Status
))
380 return RtlNtStatusToDosError(Status
);
383 ASSERT(hNewHKey
!= NULL
);
385 RegInitialize(); /* HACK until delay-loading is implemented */
386 RtlEnterCriticalSection(&HandleTableCS
);
388 /* close the currently mapped handle if existing */
394 /* update the mapping */
397 RtlLeaveCriticalSection(&HandleTableCS
);
400 ErrorCode
= ERROR_INVALID_HANDLE
;
406 /************************************************************************
412 RegCloseKey(HKEY hKey
)
416 /* don't close null handle or a pseudo handle */
417 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
419 return ERROR_INVALID_HANDLE
;
422 Status
= NtClose(hKey
);
423 if (!NT_SUCCESS(Status
))
425 return RtlNtStatusToDosError(Status
);
428 return ERROR_SUCCESS
;
433 RegpCopyTree(IN HKEY hKeySrc
,
438 LIST_ENTRY ListEntry
;
441 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
443 LIST_ENTRY copyQueueHead
;
444 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
447 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
448 KEY_NODE_INFORMATION
*KeyNode
;
451 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
452 NTSTATUS Status
= STATUS_SUCCESS
;
453 NTSTATUS Status2
= STATUS_SUCCESS
;
455 InitializeListHead(©QueueHead
);
457 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
460 if (Info
.Buffer
== NULL
)
462 return STATUS_INSUFFICIENT_RESOURCES
;
465 copyKeys
= RtlAllocateHeap(ProcessHeap
,
467 sizeof(REGP_COPY_KEYS
));
468 if (copyKeys
!= NULL
)
470 copyKeys
->hKeySrc
= hKeySrc
;
471 copyKeys
->hKeyDest
= hKeyDest
;
472 InsertHeadList(©QueueHead
,
473 ©Keys
->ListEntry
);
475 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
479 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
483 /* enumerate all values and copy them */
487 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
489 KeyValueFullInformation
,
492 &BufferSizeRequired
);
493 if (NT_SUCCESS(Status2
))
495 UNICODE_STRING ValueName
;
498 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
499 ValueName
.Length
= Info
.KeyValue
->NameLength
;
500 ValueName
.MaximumLength
= ValueName
.Length
;
501 ValueName
.Buffer
= Info
.KeyValue
->Name
;
503 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
505 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
507 Info
.KeyValue
->TitleIndex
,
510 Info
.KeyValue
->DataLength
);
512 /* don't break, let's try to copy as many values as possible */
513 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
520 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
524 ASSERT(BufferSize
< BufferSizeRequired
);
526 Buffer
= RtlReAllocateHeap(ProcessHeap
,
532 Info
.Buffer
= Buffer
;
537 /* don't break, let's try to copy as many values as possible */
538 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
541 if (NT_SUCCESS(Status
))
549 /* break to avoid an infinite loop in case of denied access or
551 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
560 /* enumerate all subkeys and open and enqueue them */
564 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
569 &BufferSizeRequired
);
570 if (NT_SUCCESS(Status2
))
572 HANDLE KeyHandle
, NewKeyHandle
;
573 OBJECT_ATTRIBUTES ObjectAttributes
;
574 UNICODE_STRING SubKeyName
, ClassName
;
576 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
577 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
578 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
579 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
580 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
581 ClassName
.MaximumLength
= ClassName
.Length
;
582 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
584 /* open the subkey with sufficient rights */
586 InitializeObjectAttributes(&ObjectAttributes
,
588 OBJ_CASE_INSENSITIVE
,
592 Status2
= NtOpenKey(&KeyHandle
,
593 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
595 if (NT_SUCCESS(Status2
))
597 /* FIXME - attempt to query the security information */
599 InitializeObjectAttributes(&ObjectAttributes
,
601 OBJ_CASE_INSENSITIVE
,
605 Status2
= NtCreateKey(&NewKeyHandle
,
608 Info
.KeyNode
->TitleIndex
,
612 if (NT_SUCCESS(Status2
))
614 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
616 sizeof(REGP_COPY_KEYS
));
617 if (newCopyKeys
!= NULL
)
619 /* save the handles and enqueue the subkey */
620 newCopyKeys
->hKeySrc
= KeyHandle
;
621 newCopyKeys
->hKeyDest
= NewKeyHandle
;
622 InsertTailList(©QueueHead
,
623 &newCopyKeys
->ListEntry
);
628 NtClose(NewKeyHandle
);
630 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
639 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
646 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
650 ASSERT(BufferSize
< BufferSizeRequired
);
652 Buffer
= RtlReAllocateHeap(ProcessHeap
,
658 Info
.Buffer
= Buffer
;
663 /* don't break, let's try to copy as many keys as possible */
664 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
667 if (NT_SUCCESS(Status
))
675 /* break to avoid an infinite loop in case of denied access or
677 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
686 /* close the handles and remove the entry from the list */
687 if (copyKeys
->hKeySrc
!= hKeySrc
)
689 NtClose(copyKeys
->hKeySrc
);
691 if (copyKeys
->hKeyDest
!= hKeyDest
)
693 NtClose(copyKeys
->hKeyDest
);
696 RemoveEntryList(©Keys
->ListEntry
);
698 RtlFreeHeap(ProcessHeap
,
701 } while (!IsListEmpty(©QueueHead
));
704 Status
= STATUS_INSUFFICIENT_RESOURCES
;
706 RtlFreeHeap(ProcessHeap
,
714 /************************************************************************
720 RegCopyTreeW(IN HKEY hKeySrc
,
721 IN LPCWSTR lpSubKey OPTIONAL
,
724 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
727 Status
= MapDefaultKey(&KeyHandle
,
729 if (!NT_SUCCESS(Status
))
731 return RtlNtStatusToDosError(Status
);
734 Status
= MapDefaultKey(&DestKeyHandle
,
736 if (!NT_SUCCESS(Status
))
741 if (lpSubKey
!= NULL
)
743 OBJECT_ATTRIBUTES ObjectAttributes
;
744 UNICODE_STRING SubKeyName
;
746 RtlInitUnicodeString(&SubKeyName
,
749 InitializeObjectAttributes(&ObjectAttributes
,
751 OBJ_CASE_INSENSITIVE
,
755 Status
= NtOpenKey(&SubKeyHandle
,
756 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
758 if (!NT_SUCCESS(Status
))
763 CurKey
= SubKeyHandle
;
768 Status
= RegpCopyTree(CurKey
,
771 if (SubKeyHandle
!= NULL
)
773 NtClose(SubKeyHandle
);
777 ClosePredefKey(DestKeyHandle
);
779 ClosePredefKey(KeyHandle
);
781 if (!NT_SUCCESS(Status
))
783 return RtlNtStatusToDosError(Status
);
786 return ERROR_SUCCESS
;
790 /************************************************************************
796 RegCopyTreeA(IN HKEY hKeySrc
,
797 IN LPCSTR lpSubKey OPTIONAL
,
800 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
803 if (lpSubKey
!= NULL
&&
804 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
807 return ERROR_NOT_ENOUGH_MEMORY
;
810 Ret
= RegCopyTreeW(hKeySrc
,
814 RtlFreeUnicodeString(&SubKeyName
);
820 /************************************************************************
821 * RegConnectRegistryA
826 RegConnectRegistryA(IN LPCSTR lpMachineName
,
830 UNICODE_STRING MachineName
= { 0, 0, NULL
};
833 if (lpMachineName
!= NULL
&&
834 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
835 (LPSTR
)lpMachineName
))
837 return ERROR_NOT_ENOUGH_MEMORY
;
840 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
844 RtlFreeUnicodeString(&MachineName
);
850 /************************************************************************
851 * RegConnectRegistryW
856 RegConnectRegistryW(LPCWSTR lpMachineName
,
862 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
864 if (!lpMachineName
|| !*lpMachineName
)
866 /* Use the local machine name */
867 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
871 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
872 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
874 /* MSDN says lpMachineName must start with \\ : not so */
875 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
878 if (GetComputerNameW(compName
, &len
))
880 if (!_wcsicmp(lpMachineName
, compName
))
881 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
884 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
885 ret
= ERROR_BAD_NETPATH
;
889 ret
= GetLastError();
896 /************************************************************************
899 * Create key and all necessary intermediate keys
902 CreateNestedKey(PHKEY KeyHandle
,
903 POBJECT_ATTRIBUTES ObjectAttributes
,
904 PUNICODE_STRING ClassString
,
907 DWORD
*lpdwDisposition
)
909 OBJECT_ATTRIBUTES LocalObjectAttributes
;
910 UNICODE_STRING LocalKeyName
;
913 ULONG FullNameLength
;
916 HANDLE LocalKeyHandle
;
918 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
924 (PULONG
)lpdwDisposition
);
925 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
926 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
929 /* Copy object attributes */
930 RtlCopyMemory(&LocalObjectAttributes
,
932 sizeof(OBJECT_ATTRIBUTES
));
933 RtlCreateUnicodeString(&LocalKeyName
,
934 ObjectAttributes
->ObjectName
->Buffer
);
935 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
936 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
938 LocalKeyHandle
= NULL
;
940 /* Remove the last part of the key name and try to create the key again. */
941 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
943 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
944 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
946 Status
= STATUS_UNSUCCESSFUL
;
951 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
953 Status
= NtCreateKey(&LocalKeyHandle
,
955 &LocalObjectAttributes
,
960 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
963 if (!NT_SUCCESS(Status
))
965 RtlFreeUnicodeString(&LocalKeyName
);
969 /* Add removed parts of the key name and create them too. */
970 Length
= wcslen(LocalKeyName
.Buffer
);
974 NtClose (LocalKeyHandle
);
976 LocalKeyName
.Buffer
[Length
] = L
'\\';
977 Length
= wcslen (LocalKeyName
.Buffer
);
978 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
980 if (Length
== FullNameLength
)
982 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
988 (PULONG
)lpdwDisposition
);
992 Status
= NtCreateKey(&LocalKeyHandle
,
994 &LocalObjectAttributes
,
999 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
1000 if (!NT_SUCCESS(Status
))
1004 RtlFreeUnicodeString(&LocalKeyName
);
1010 /************************************************************************
1016 RegCreateKeyExA(HKEY hKey
,
1022 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1024 LPDWORD lpdwDisposition
)
1026 UNICODE_STRING SubKeyString
;
1027 UNICODE_STRING ClassString
;
1028 OBJECT_ATTRIBUTES ObjectAttributes
;
1030 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1033 TRACE("RegCreateKeyExA() called\n");
1035 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1036 return ERROR_INVALID_USER_BUFFER
;
1038 /* get the real parent key */
1039 Status
= MapDefaultKey(&ParentKey
,
1041 if (!NT_SUCCESS(Status
))
1043 return RtlNtStatusToDosError(Status
);
1046 TRACE("ParentKey %p\n", ParentKey
);
1048 if (lpClass
!= NULL
)
1050 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1054 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1055 Attributes
|= OBJ_OPENLINK
;
1057 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1059 InitializeObjectAttributes(&ObjectAttributes
,
1063 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1064 Status
= CreateNestedKey(phkResult
,
1066 (lpClass
== NULL
)? NULL
: &ClassString
,
1070 RtlFreeUnicodeString(&SubKeyString
);
1071 if (lpClass
!= NULL
)
1073 RtlFreeUnicodeString(&ClassString
);
1076 ClosePredefKey(ParentKey
);
1078 TRACE("Status %x\n", Status
);
1079 if (!NT_SUCCESS(Status
))
1081 return RtlNtStatusToDosError(Status
);
1084 return ERROR_SUCCESS
;
1088 /************************************************************************
1094 RegCreateKeyExW(HKEY hKey
,
1100 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1102 LPDWORD lpdwDisposition
)
1104 UNICODE_STRING SubKeyString
;
1105 UNICODE_STRING ClassString
;
1106 OBJECT_ATTRIBUTES ObjectAttributes
;
1108 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1111 TRACE("RegCreateKeyExW() called\n");
1113 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1114 return ERROR_INVALID_USER_BUFFER
;
1116 /* get the real parent key */
1117 Status
= MapDefaultKey(&ParentKey
,
1119 if (!NT_SUCCESS(Status
))
1121 return RtlNtStatusToDosError(Status
);
1124 TRACE("ParentKey %p\n", ParentKey
);
1126 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1127 Attributes
|= OBJ_OPENLINK
;
1129 RtlInitUnicodeString(&ClassString
,
1131 RtlInitUnicodeString(&SubKeyString
,
1133 InitializeObjectAttributes(&ObjectAttributes
,
1137 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1138 Status
= CreateNestedKey(phkResult
,
1140 (lpClass
== NULL
)? NULL
: &ClassString
,
1145 ClosePredefKey(ParentKey
);
1147 TRACE("Status %x\n", Status
);
1148 if (!NT_SUCCESS(Status
))
1150 return RtlNtStatusToDosError(Status
);
1153 return ERROR_SUCCESS
;
1157 /************************************************************************
1163 RegCreateKeyA(HKEY hKey
,
1167 return RegCreateKeyExA(hKey
,
1179 /************************************************************************
1185 RegCreateKeyW(HKEY hKey
,
1189 return RegCreateKeyExW(hKey
,
1201 /************************************************************************
1207 RegDeleteKeyA(HKEY hKey
,
1210 OBJECT_ATTRIBUTES ObjectAttributes
;
1211 UNICODE_STRING SubKeyName
;
1216 /* Make sure we got a subkey */
1220 return ERROR_INVALID_PARAMETER
;
1223 Status
= MapDefaultKey(&ParentKey
,
1225 if (!NT_SUCCESS(Status
))
1227 return RtlNtStatusToDosError(Status
);
1230 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1232 InitializeObjectAttributes(&ObjectAttributes
,
1234 OBJ_CASE_INSENSITIVE
,
1238 Status
= NtOpenKey(&TargetKey
,
1241 RtlFreeUnicodeString(&SubKeyName
);
1242 if (!NT_SUCCESS(Status
))
1247 Status
= NtDeleteKey(TargetKey
);
1248 NtClose (TargetKey
);
1251 ClosePredefKey(ParentKey
);
1253 if (!NT_SUCCESS(Status
))
1255 return RtlNtStatusToDosError(Status
);
1258 return ERROR_SUCCESS
;
1262 /************************************************************************
1268 RegDeleteKeyW(HKEY hKey
,
1271 OBJECT_ATTRIBUTES ObjectAttributes
;
1272 UNICODE_STRING SubKeyName
;
1277 /* Make sure we got a subkey */
1281 return ERROR_INVALID_PARAMETER
;
1284 Status
= MapDefaultKey(&ParentKey
,
1286 if (!NT_SUCCESS(Status
))
1288 return RtlNtStatusToDosError(Status
);
1291 RtlInitUnicodeString(&SubKeyName
,
1293 InitializeObjectAttributes(&ObjectAttributes
,
1295 OBJ_CASE_INSENSITIVE
,
1298 Status
= NtOpenKey(&TargetKey
,
1301 if (!NT_SUCCESS(Status
))
1306 Status
= NtDeleteKey(TargetKey
);
1310 ClosePredefKey(ParentKey
);
1312 if (!NT_SUCCESS(Status
))
1314 return RtlNtStatusToDosError(Status
);
1317 return ERROR_SUCCESS
;
1321 /************************************************************************
1328 RegDeleteKeyExA(HKEY hKey
,
1333 OBJECT_ATTRIBUTES ObjectAttributes
;
1334 UNICODE_STRING SubKeyName
;
1339 /* Make sure we got a subkey */
1343 return ERROR_INVALID_PARAMETER
;
1346 Status
= MapDefaultKey(&ParentKey
,
1348 if (!NT_SUCCESS(Status
))
1350 return RtlNtStatusToDosError(Status
);
1353 if (samDesired
& KEY_WOW64_32KEY
)
1354 ERR("Wow64 not yet supported!\n");
1356 if (samDesired
& KEY_WOW64_64KEY
)
1357 ERR("Wow64 not yet supported!\n");
1359 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1361 InitializeObjectAttributes(&ObjectAttributes
,
1363 OBJ_CASE_INSENSITIVE
,
1367 Status
= NtOpenKey(&TargetKey
,
1370 RtlFreeUnicodeString(&SubKeyName
);
1371 if (!NT_SUCCESS(Status
))
1376 Status
= NtDeleteKey(TargetKey
);
1377 NtClose (TargetKey
);
1380 ClosePredefKey(ParentKey
);
1382 if (!NT_SUCCESS(Status
))
1384 return RtlNtStatusToDosError(Status
);
1387 return ERROR_SUCCESS
;
1391 /************************************************************************
1398 RegDeleteKeyExW(HKEY hKey
,
1403 OBJECT_ATTRIBUTES ObjectAttributes
;
1404 UNICODE_STRING SubKeyName
;
1409 /* Make sure we got a subkey */
1413 return ERROR_INVALID_PARAMETER
;
1416 Status
= MapDefaultKey(&ParentKey
,
1418 if (!NT_SUCCESS(Status
))
1420 return RtlNtStatusToDosError(Status
);
1423 if (samDesired
& KEY_WOW64_32KEY
)
1424 ERR("Wow64 not yet supported!\n");
1426 if (samDesired
& KEY_WOW64_64KEY
)
1427 ERR("Wow64 not yet supported!\n");
1430 RtlInitUnicodeString(&SubKeyName
,
1432 InitializeObjectAttributes(&ObjectAttributes
,
1434 OBJ_CASE_INSENSITIVE
,
1437 Status
= NtOpenKey(&TargetKey
,
1440 if (!NT_SUCCESS(Status
))
1445 Status
= NtDeleteKey(TargetKey
);
1449 ClosePredefKey(ParentKey
);
1451 if (!NT_SUCCESS(Status
))
1453 return RtlNtStatusToDosError(Status
);
1456 return ERROR_SUCCESS
;
1460 /************************************************************************
1461 * RegDeleteKeyValueW
1466 RegDeleteKeyValueW(IN HKEY hKey
,
1467 IN LPCWSTR lpSubKey OPTIONAL
,
1468 IN LPCWSTR lpValueName OPTIONAL
)
1470 UNICODE_STRING ValueName
;
1471 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1474 Status
= MapDefaultKey(&KeyHandle
,
1476 if (!NT_SUCCESS(Status
))
1478 return RtlNtStatusToDosError(Status
);
1481 if (lpSubKey
!= NULL
)
1483 OBJECT_ATTRIBUTES ObjectAttributes
;
1484 UNICODE_STRING SubKeyName
;
1486 RtlInitUnicodeString(&SubKeyName
,
1489 InitializeObjectAttributes(&ObjectAttributes
,
1491 OBJ_CASE_INSENSITIVE
,
1495 Status
= NtOpenKey(&SubKeyHandle
,
1498 if (!NT_SUCCESS(Status
))
1503 CurKey
= SubKeyHandle
;
1508 RtlInitUnicodeString(&ValueName
,
1509 (LPWSTR
)lpValueName
);
1511 Status
= NtDeleteValueKey(CurKey
,
1514 if (SubKeyHandle
!= NULL
)
1516 NtClose(SubKeyHandle
);
1520 ClosePredefKey(KeyHandle
);
1522 if (!NT_SUCCESS(Status
))
1524 return RtlNtStatusToDosError(Status
);
1527 return ERROR_SUCCESS
;
1531 /************************************************************************
1532 * RegDeleteKeyValueA
1537 RegDeleteKeyValueA(IN HKEY hKey
,
1538 IN LPCSTR lpSubKey OPTIONAL
,
1539 IN LPCSTR lpValueName OPTIONAL
)
1541 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1544 if (lpSubKey
!= NULL
&&
1545 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1548 return ERROR_NOT_ENOUGH_MEMORY
;
1551 if (lpValueName
!= NULL
&&
1552 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1553 (LPSTR
)lpValueName
))
1555 RtlFreeUnicodeString(&SubKey
);
1556 return ERROR_NOT_ENOUGH_MEMORY
;
1559 Ret
= RegDeleteKeyValueW(hKey
,
1563 RtlFreeUnicodeString(&SubKey
);
1564 RtlFreeUnicodeString(&ValueName
);
1570 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1572 RegpDeleteTree(IN HKEY hKey
)
1576 LIST_ENTRY ListEntry
;
1578 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1580 LIST_ENTRY delQueueHead
;
1581 PREG_DEL_KEYS delKeys
, newDelKeys
;
1584 PKEY_BASIC_INFORMATION BasicInfo
;
1585 PREG_DEL_KEYS KeyDelRoot
;
1586 NTSTATUS Status
= STATUS_SUCCESS
;
1587 NTSTATUS Status2
= STATUS_SUCCESS
;
1589 InitializeListHead(&delQueueHead
);
1591 ProcessHeap
= RtlGetProcessHeap();
1593 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1594 structure for the root key, we only do that for subkeys as we need to
1595 allocate REGP_DEL_KEYS structures anyway! */
1596 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1598 sizeof(REGP_DEL_KEYS
));
1599 if (KeyDelRoot
!= NULL
)
1601 KeyDelRoot
->KeyHandle
= hKey
;
1602 InsertTailList(&delQueueHead
,
1603 &KeyDelRoot
->ListEntry
);
1607 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1616 /* check if this key contains subkeys and delete them first by queuing
1617 them at the head of the list */
1618 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1620 KeyBasicInformation
,
1625 if (NT_SUCCESS(Status2
))
1627 OBJECT_ATTRIBUTES ObjectAttributes
;
1628 UNICODE_STRING SubKeyName
;
1630 ASSERT(newDelKeys
!= NULL
);
1631 ASSERT(BasicInfo
!= NULL
);
1633 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1634 SubKeyName
.Length
= BasicInfo
->NameLength
;
1635 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1636 SubKeyName
.Buffer
= BasicInfo
->Name
;
1638 InitializeObjectAttributes(&ObjectAttributes
,
1640 OBJ_CASE_INSENSITIVE
,
1644 /* open the subkey */
1645 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1646 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1648 if (!NT_SUCCESS(Status2
))
1653 /* enqueue this key to the head of the deletion queue */
1654 InsertHeadList(&delQueueHead
,
1655 &newDelKeys
->ListEntry
);
1657 /* try again from the head of the list */
1662 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1664 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1666 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1667 if (newDelKeys
!= NULL
)
1669 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1672 goto ReadFirstSubKey
;
1676 /* don't break, let's try to delete as many keys as possible */
1677 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1678 goto SubKeyFailureNoFree
;
1681 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1683 PREG_DEL_KEYS newDelKeys2
;
1685 ASSERT(newDelKeys
!= NULL
);
1687 /* we need more memory to query the key name */
1688 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1691 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1692 if (newDelKeys2
!= NULL
)
1694 newDelKeys
= newDelKeys2
;
1695 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1698 goto ReadFirstSubKey
;
1702 /* don't break, let's try to delete as many keys as possible */
1703 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1706 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1708 /* in some race conditions where another thread would delete
1709 the same tree at the same time, newDelKeys could actually
1711 if (newDelKeys
!= NULL
)
1713 RtlFreeHeap(ProcessHeap
,
1721 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1722 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1723 if (newDelKeys
!= NULL
)
1725 RtlFreeHeap(ProcessHeap
,
1730 SubKeyFailureNoFree
:
1731 /* don't break, let's try to delete as many keys as possible */
1732 if (NT_SUCCESS(Status
))
1738 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1740 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1742 if (!NT_SUCCESS(Status2
))
1744 /* close the key handle so we don't leak handles for keys we were
1745 unable to delete. But only do this for handles not supplied
1748 if (delKeys
->KeyHandle
!= hKey
)
1750 NtClose(delKeys
->KeyHandle
);
1753 if (NT_SUCCESS(Status
))
1755 /* don't break, let's try to delete as many keys as possible */
1760 /* remove the entry from the list */
1761 RemoveEntryList(&delKeys
->ListEntry
);
1763 RtlFreeHeap(ProcessHeap
,
1766 } while (!IsListEmpty(&delQueueHead
));
1769 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1775 /************************************************************************
1781 RegDeleteTreeW(IN HKEY hKey
,
1782 IN LPCWSTR lpSubKey OPTIONAL
)
1784 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1787 Status
= MapDefaultKey(&KeyHandle
,
1789 if (!NT_SUCCESS(Status
))
1791 return RtlNtStatusToDosError(Status
);
1794 if (lpSubKey
!= NULL
)
1796 OBJECT_ATTRIBUTES ObjectAttributes
;
1797 UNICODE_STRING SubKeyName
;
1799 RtlInitUnicodeString(&SubKeyName
,
1802 InitializeObjectAttributes(&ObjectAttributes
,
1804 OBJ_CASE_INSENSITIVE
,
1808 Status
= NtOpenKey(&SubKeyHandle
,
1809 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1811 if (!NT_SUCCESS(Status
))
1816 CurKey
= SubKeyHandle
;
1821 Status
= RegpDeleteTree(CurKey
);
1823 if (NT_SUCCESS(Status
))
1825 /* make sure we only close hKey (KeyHandle) when the caller specified a
1826 subkey, because the handle would be invalid already! */
1827 if (CurKey
!= KeyHandle
)
1829 ClosePredefKey(KeyHandle
);
1832 return ERROR_SUCCESS
;
1836 /* make sure we close all handles we created! */
1837 if (SubKeyHandle
!= NULL
)
1839 NtClose(SubKeyHandle
);
1843 ClosePredefKey(KeyHandle
);
1845 return RtlNtStatusToDosError(Status
);
1851 /************************************************************************
1858 RegDeleteTreeW(HKEY hKey
,
1862 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1863 DWORD dwMaxLen
, dwSize
;
1867 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1869 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1871 Status
= MapDefaultKey(&KeyHandle
,
1873 if (!NT_SUCCESS(Status
))
1875 return RtlNtStatusToDosError(Status
);
1878 hSubKey
= KeyHandle
;
1882 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1885 ClosePredefKey(KeyHandle
);
1890 /* Get highest length for keys, values */
1891 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1892 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1893 if (ret
) goto cleanup
;
1897 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1898 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1900 /* Name too big: alloc a buffer for it */
1901 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1903 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1909 /* Recursively delete all the subkeys */
1913 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1914 NULL
, NULL
, NULL
)) break;
1916 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1917 if (ret
) goto cleanup
;
1921 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1926 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1927 NULL
, NULL
, NULL
, NULL
)) break;
1929 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1930 if (ret
) goto cleanup
;
1934 /* Free buffer if allocated */
1935 if (lpszName
!= szNameBuf
)
1936 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1938 RegCloseKey(hSubKey
);
1940 ClosePredefKey(KeyHandle
);
1946 /************************************************************************
1952 RegDeleteTreeA(IN HKEY hKey
,
1953 IN LPCSTR lpSubKey OPTIONAL
)
1955 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1958 if (lpSubKey
!= NULL
&&
1959 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1962 return ERROR_NOT_ENOUGH_MEMORY
;
1965 Ret
= RegDeleteTreeW(hKey
,
1968 RtlFreeUnicodeString(&SubKeyName
);
1974 /************************************************************************
1975 * RegDisableReflectionKey
1980 RegDisableReflectionKey(IN HKEY hBase
)
1982 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1983 return ERROR_CALL_NOT_IMPLEMENTED
;
1987 /************************************************************************
1988 * RegEnableReflectionKey
1993 RegEnableReflectionKey(IN HKEY hBase
)
1995 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1996 return ERROR_CALL_NOT_IMPLEMENTED
;
2000 /******************************************************************************
2001 * RegpApplyRestrictions [internal]
2003 * Helper function for RegGetValueA/W.
2006 RegpApplyRestrictions(DWORD dwFlags
,
2011 /* Check if the type is restricted by the passed flags */
2012 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
2018 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
2019 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
2020 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
2021 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
2022 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
2023 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
2024 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
2027 if (dwFlags
& dwMask
)
2029 /* Type is not restricted, check for size mismatch */
2030 if (dwType
== REG_BINARY
)
2034 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2036 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2039 if (cbExpect
&& cbData
!= cbExpect
)
2040 *ret
= ERROR_DATATYPE_MISMATCH
;
2043 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2048 /******************************************************************************
2049 * RegGetValueW [ADVAPI32.@]
2051 * Retrieves the type and data for a value name associated with a key,
2052 * optionally expanding its content and restricting its type.
2055 * hKey [I] Handle to an open key.
2056 * pszSubKey [I] Name of the subkey of hKey.
2057 * pszValue [I] Name of value under hKey/szSubKey to query.
2058 * dwFlags [I] Flags restricting the value type to retrieve.
2059 * pdwType [O] Destination for the values type, may be NULL.
2060 * pvData [O] Destination for the values content, may be NULL.
2061 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2062 * retrieve the whole content, including the trailing '\0'
2066 * Success: ERROR_SUCCESS
2067 * Failure: nonzero error code from Winerror.h
2070 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2071 * expanded and pdwType is set to REG_SZ instead.
2072 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2073 * without RRF_NOEXPAND is thus not allowed.
2074 * An exception is the case where RRF_RT_ANY is specified, because then
2075 * RRF_NOEXPAND is allowed.
2078 RegGetValueW(HKEY hKey
,
2086 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2090 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2091 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2092 pvData
, pcbData
, cbData
);
2094 if (pvData
&& !pcbData
)
2095 return ERROR_INVALID_PARAMETER
;
2096 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2097 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2098 return ERROR_INVALID_PARAMETER
;
2100 if (pszSubKey
&& pszSubKey
[0])
2102 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2103 if (ret
!= ERROR_SUCCESS
) return ret
;
2106 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2108 /* If we are going to expand we need to read in the whole the value even
2109 * if the passed buffer was too small as the expanded string might be
2110 * smaller than the unexpanded one and could fit into cbData bytes. */
2111 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2112 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2116 HeapFree(GetProcessHeap(), 0, pvBuf
);
2118 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2121 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2125 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2126 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2127 &dwType
, pvBuf
, &cbData
);
2130 /* Even if cbData was large enough we have to copy the
2131 * string since ExpandEnvironmentStrings can't handle
2132 * overlapping buffers. */
2133 CopyMemory(pvBuf
, pvData
, cbData
);
2136 /* Both the type or the value itself could have been modified in
2137 * between so we have to keep retrying until the buffer is large
2138 * enough or we no longer have to expand the value. */
2140 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2142 if (ret
== ERROR_SUCCESS
)
2144 /* Recheck dwType in case it changed since the first call */
2145 if (dwType
== REG_EXPAND_SZ
)
2147 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2148 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2150 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2151 ret
= ERROR_MORE_DATA
;
2154 CopyMemory(pvData
, pvBuf
, *pcbData
);
2157 HeapFree(GetProcessHeap(), 0, pvBuf
);
2160 if (pszSubKey
&& pszSubKey
[0])
2163 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2165 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2166 ZeroMemory(pvData
, *pcbData
);
2178 /******************************************************************************
2179 * RegGetValueA [ADVAPI32.@]
2184 RegGetValueA(HKEY hKey
,
2192 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2196 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2197 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2200 if (pvData
&& !pcbData
)
2201 return ERROR_INVALID_PARAMETER
;
2202 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2203 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2204 return ERROR_INVALID_PARAMETER
;
2206 if (pszSubKey
&& pszSubKey
[0])
2208 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2209 if (ret
!= ERROR_SUCCESS
) return ret
;
2212 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2214 /* If we are going to expand we need to read in the whole the value even
2215 * if the passed buffer was too small as the expanded string might be
2216 * smaller than the unexpanded one and could fit into cbData bytes. */
2217 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2218 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2221 HeapFree(GetProcessHeap(), 0, pvBuf
);
2223 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2226 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2230 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2231 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2232 &dwType
, pvBuf
, &cbData
);
2235 /* Even if cbData was large enough we have to copy the
2236 * string since ExpandEnvironmentStrings can't handle
2237 * overlapping buffers. */
2238 CopyMemory(pvBuf
, pvData
, cbData
);
2241 /* Both the type or the value itself could have been modified in
2242 * between so we have to keep retrying until the buffer is large
2243 * enough or we no longer have to expand the value. */
2244 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2246 if (ret
== ERROR_SUCCESS
)
2248 /* Recheck dwType in case it changed since the first call */
2249 if (dwType
== REG_EXPAND_SZ
)
2251 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2252 pcbData
? *pcbData
: 0);
2254 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2255 ret
= ERROR_MORE_DATA
;
2258 CopyMemory(pvData
, pvBuf
, *pcbData
);
2261 HeapFree(GetProcessHeap(), 0, pvBuf
);
2264 if (pszSubKey
&& pszSubKey
[0])
2267 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2269 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2270 ZeroMemory(pvData
, *pcbData
);
2272 if (pdwType
) *pdwType
= dwType
;
2273 if (pcbData
) *pcbData
= cbData
;
2279 /************************************************************************
2285 RegSetKeyValueW(IN HKEY hKey
,
2286 IN LPCWSTR lpSubKey OPTIONAL
,
2287 IN LPCWSTR lpValueName OPTIONAL
,
2289 IN LPCVOID lpData OPTIONAL
,
2292 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2296 Status
= MapDefaultKey(&KeyHandle
,
2298 if (!NT_SUCCESS(Status
))
2300 return RtlNtStatusToDosError(Status
);
2303 if (lpSubKey
!= NULL
)
2305 OBJECT_ATTRIBUTES ObjectAttributes
;
2306 UNICODE_STRING SubKeyName
;
2308 RtlInitUnicodeString(&SubKeyName
,
2311 InitializeObjectAttributes(&ObjectAttributes
,
2313 OBJ_CASE_INSENSITIVE
,
2317 Status
= NtOpenKey(&SubKeyHandle
,
2320 if (!NT_SUCCESS(Status
))
2322 Ret
= RtlNtStatusToDosError(Status
);
2326 CurKey
= SubKeyHandle
;
2331 Ret
= RegSetValueExW(CurKey
,
2338 if (SubKeyHandle
!= NULL
)
2340 NtClose(SubKeyHandle
);
2344 ClosePredefKey(KeyHandle
);
2350 /************************************************************************
2356 RegSetKeyValueA(IN HKEY hKey
,
2357 IN LPCSTR lpSubKey OPTIONAL
,
2358 IN LPCSTR lpValueName OPTIONAL
,
2360 IN LPCVOID lpData OPTIONAL
,
2363 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2367 Status
= MapDefaultKey(&KeyHandle
,
2369 if (!NT_SUCCESS(Status
))
2371 return RtlNtStatusToDosError(Status
);
2374 if (lpSubKey
!= NULL
)
2376 OBJECT_ATTRIBUTES ObjectAttributes
;
2377 UNICODE_STRING SubKeyName
;
2379 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2382 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2386 InitializeObjectAttributes(&ObjectAttributes
,
2388 OBJ_CASE_INSENSITIVE
,
2392 Status
= NtOpenKey(&SubKeyHandle
,
2396 RtlFreeUnicodeString(&SubKeyName
);
2398 if (!NT_SUCCESS(Status
))
2400 Ret
= RtlNtStatusToDosError(Status
);
2404 CurKey
= SubKeyHandle
;
2409 Ret
= RegSetValueExA(CurKey
,
2416 if (SubKeyHandle
!= NULL
)
2418 NtClose(SubKeyHandle
);
2422 ClosePredefKey(KeyHandle
);
2428 /************************************************************************
2434 RegDeleteValueA(HKEY hKey
,
2437 UNICODE_STRING ValueName
;
2441 Status
= MapDefaultKey(&KeyHandle
,
2443 if (!NT_SUCCESS(Status
))
2445 return RtlNtStatusToDosError(Status
);
2448 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2449 (LPSTR
)lpValueName
);
2450 Status
= NtDeleteValueKey(KeyHandle
,
2452 RtlFreeUnicodeString (&ValueName
);
2454 ClosePredefKey(KeyHandle
);
2456 if (!NT_SUCCESS(Status
))
2458 return RtlNtStatusToDosError(Status
);
2461 return ERROR_SUCCESS
;
2465 /************************************************************************
2471 RegDeleteValueW(HKEY hKey
,
2472 LPCWSTR lpValueName
)
2474 UNICODE_STRING ValueName
;
2478 Status
= MapDefaultKey(&KeyHandle
,
2480 if (!NT_SUCCESS(Status
))
2482 return RtlNtStatusToDosError(Status
);
2485 RtlInitUnicodeString(&ValueName
,
2486 (LPWSTR
)lpValueName
);
2488 Status
= NtDeleteValueKey(KeyHandle
,
2491 ClosePredefKey(KeyHandle
);
2493 if (!NT_SUCCESS(Status
))
2495 return RtlNtStatusToDosError(Status
);
2498 return ERROR_SUCCESS
;
2502 /************************************************************************
2508 RegEnumKeyA(HKEY hKey
,
2516 return RegEnumKeyExA(hKey
,
2527 /************************************************************************
2533 RegEnumKeyW(HKEY hKey
,
2541 return RegEnumKeyExW(hKey
,
2552 /************************************************************************
2558 RegEnumKeyExA(HKEY hKey
,
2565 PFILETIME lpftLastWriteTime
)
2569 KEY_NODE_INFORMATION Node
;
2570 KEY_BASIC_INFORMATION Basic
;
2573 UNICODE_STRING StringU
;
2574 ANSI_STRING StringA
;
2575 LONG ErrorCode
= ERROR_SUCCESS
;
2577 DWORD ClassLength
= 0;
2583 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2584 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2586 if ((lpClass
) && (!lpcbClass
))
2588 return ERROR_INVALID_PARAMETER
;
2591 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2592 if (!NT_SUCCESS(Status
))
2594 return RtlNtStatusToDosError(Status
);
2599 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2610 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2617 /* The class name should start at a dword boundary */
2618 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2622 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2625 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2626 if (KeyInfo
== NULL
)
2628 ErrorCode
= ERROR_OUTOFMEMORY
;
2632 Status
= NtEnumerateKey(KeyHandle
,
2634 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2638 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2639 if (!NT_SUCCESS(Status
))
2641 ErrorCode
= RtlNtStatusToDosError (Status
);
2645 if (lpClass
== NULL
)
2647 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2649 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2653 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2654 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2655 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2660 if (KeyInfo
->Node
.NameLength
> NameLength
||
2661 KeyInfo
->Node
.ClassLength
> ClassLength
)
2663 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2667 StringA
.Buffer
= lpClass
;
2669 StringA
.MaximumLength
= *lpcbClass
;
2670 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2671 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2672 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2673 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2674 lpClass
[StringA
.Length
] = 0;
2675 *lpcbClass
= StringA
.Length
;
2676 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2677 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2678 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2682 if (ErrorCode
== ERROR_SUCCESS
)
2684 StringA
.Buffer
= lpName
;
2686 StringA
.MaximumLength
= *lpcbName
;
2687 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2688 lpName
[StringA
.Length
] = 0;
2689 *lpcbName
= StringA
.Length
;
2690 if (lpftLastWriteTime
!= NULL
)
2692 if (lpClass
== NULL
)
2694 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2695 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2699 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2700 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2706 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2707 TRACE("Key Name1 Length %d\n", NameLength
);
2708 TRACE("Key Name Length %d\n", *lpcbName
);
2709 TRACE("Key Name %s\n", lpName
);
2711 RtlFreeHeap(ProcessHeap
,
2716 ClosePredefKey(KeyHandle
);
2722 /************************************************************************
2728 RegEnumKeyExW(HKEY hKey
,
2735 PFILETIME lpftLastWriteTime
)
2739 KEY_NODE_INFORMATION Node
;
2740 KEY_BASIC_INFORMATION Basic
;
2746 ULONG ClassLength
= 0;
2748 LONG ErrorCode
= ERROR_SUCCESS
;
2751 Status
= MapDefaultKey(&KeyHandle
,
2753 if (!NT_SUCCESS(Status
))
2755 return RtlNtStatusToDosError(Status
);
2760 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2771 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2778 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2782 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2785 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2788 if (KeyInfo
== NULL
)
2790 ErrorCode
= ERROR_OUTOFMEMORY
;
2794 Status
= NtEnumerateKey(KeyHandle
,
2796 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2800 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2801 if (!NT_SUCCESS(Status
))
2803 ErrorCode
= RtlNtStatusToDosError (Status
);
2807 if (lpClass
== NULL
)
2809 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2811 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2815 RtlCopyMemory(lpName
,
2816 KeyInfo
->Basic
.Name
,
2817 KeyInfo
->Basic
.NameLength
);
2818 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2819 lpName
[*lpcbName
] = 0;
2824 if (KeyInfo
->Node
.NameLength
> NameLength
||
2825 KeyInfo
->Node
.ClassLength
> ClassLength
)
2827 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2831 RtlCopyMemory(lpName
,
2833 KeyInfo
->Node
.NameLength
);
2834 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2835 lpName
[*lpcbName
] = 0;
2836 RtlCopyMemory(lpClass
,
2837 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2838 KeyInfo
->Node
.ClassLength
);
2839 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2840 lpClass
[*lpcbClass
] = 0;
2844 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2846 if (lpClass
== NULL
)
2848 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2849 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2853 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2854 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2859 RtlFreeHeap(ProcessHeap
,
2864 ClosePredefKey(KeyHandle
);
2870 /************************************************************************
2876 RegEnumValueA(HKEY hKey
,
2888 char buffer
[256], *buf_ptr
= buffer
;
2889 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2890 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2892 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2893 // hkey, index, value, val_count, reserved, type, data, count );
2895 /* NT only checks count, not val_count */
2896 if ((data
&& !count
) || reserved
)
2897 return ERROR_INVALID_PARAMETER
;
2899 status
= MapDefaultKey(&KeyHandle
, hKey
);
2900 if (!NT_SUCCESS(status
))
2902 return RtlNtStatusToDosError(status
);
2905 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2906 if (data
) total_size
+= *count
;
2907 total_size
= min( sizeof(buffer
), total_size
);
2909 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2910 buffer
, total_size
, &total_size
);
2911 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2913 /* we need to fetch the contents for a string type even if not requested,
2914 * because we need to compute the length of the ASCII string. */
2915 if (value
|| data
|| is_string(info
->Type
))
2917 /* retry with a dynamically allocated buffer */
2918 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2920 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2921 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2923 status
= STATUS_INSUFFICIENT_RESOURCES
;
2926 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2927 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2928 buf_ptr
, total_size
, &total_size
);
2931 if (status
) goto done
;
2933 if (is_string(info
->Type
))
2936 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2940 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2943 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2945 /* if the type is REG_SZ and data is not 0-terminated
2946 * and there is enough space in the buffer NT appends a \0 */
2947 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2950 info
->DataLength
= len
;
2954 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2955 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2958 if (value
&& !status
)
2962 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2963 if (len
>= *val_count
)
2965 status
= STATUS_BUFFER_OVERFLOW
;
2968 len
= *val_count
- 1;
2969 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2975 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2981 else status
= STATUS_SUCCESS
;
2983 if (type
) *type
= info
->Type
;
2984 if (count
) *count
= info
->DataLength
;
2987 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2988 ClosePredefKey(KeyHandle
);
2989 return RtlNtStatusToDosError(status
);
2993 /******************************************************************************
2994 * RegEnumValueW [ADVAPI32.@]
2998 * hkey [I] Handle to key to query
2999 * index [I] Index of value to query
3000 * value [O] Value string
3001 * val_count [I/O] Size of value buffer (in wchars)
3002 * reserved [I] Reserved
3003 * type [O] Type code
3004 * data [O] Value data
3005 * count [I/O] Size of data buffer (in bytes)
3008 * Success: ERROR_SUCCESS
3009 * Failure: nonzero error code from Winerror.h
3012 RegEnumValueW(HKEY hKey
,
3024 char buffer
[256], *buf_ptr
= buffer
;
3025 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
3026 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
3028 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
3029 // hkey, index, value, val_count, reserved, type, data, count );
3031 /* NT only checks count, not val_count */
3032 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3034 status
= MapDefaultKey(&KeyHandle
, hKey
);
3035 if (!NT_SUCCESS(status
))
3037 return RtlNtStatusToDosError(status
);
3040 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
3041 if (data
) total_size
+= *count
;
3042 total_size
= min( sizeof(buffer
), total_size
);
3044 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3045 buffer
, total_size
, &total_size
);
3046 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
3050 /* retry with a dynamically allocated buffer */
3051 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
3053 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3054 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3056 status
= ERROR_NOT_ENOUGH_MEMORY
;
3059 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
3060 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3061 buf_ptr
, total_size
, &total_size
);
3064 if (status
) goto done
;
3068 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3070 status
= STATUS_BUFFER_OVERFLOW
;
3073 memcpy( value
, info
->Name
, info
->NameLength
);
3074 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3075 value
[*val_count
] = 0;
3080 if (info
->DataLength
> *count
)
3082 status
= STATUS_BUFFER_OVERFLOW
;
3085 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3086 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3088 /* if the type is REG_SZ and data is not 0-terminated
3089 * and there is enough space in the buffer NT appends a \0 */
3090 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3091 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3095 else status
= STATUS_SUCCESS
;
3098 if (type
) *type
= info
->Type
;
3099 if (count
) *count
= info
->DataLength
;
3102 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3103 ClosePredefKey(KeyHandle
);
3104 return RtlNtStatusToDosError(status
);
3108 /************************************************************************
3114 RegFlushKey(HKEY hKey
)
3119 if (hKey
== HKEY_PERFORMANCE_DATA
)
3121 return ERROR_SUCCESS
;
3124 Status
= MapDefaultKey(&KeyHandle
,
3126 if (!NT_SUCCESS(Status
))
3128 return RtlNtStatusToDosError(Status
);
3131 Status
= NtFlushKey(KeyHandle
);
3133 ClosePredefKey(KeyHandle
);
3135 if (!NT_SUCCESS(Status
))
3137 return RtlNtStatusToDosError(Status
);
3140 return ERROR_SUCCESS
;
3144 /************************************************************************
3150 RegGetKeySecurity(HKEY hKey
,
3151 SECURITY_INFORMATION SecurityInformation
,
3152 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3153 LPDWORD lpcbSecurityDescriptor
)
3158 if (hKey
== HKEY_PERFORMANCE_DATA
)
3160 return ERROR_INVALID_HANDLE
;
3163 Status
= MapDefaultKey(&KeyHandle
,
3165 if (!NT_SUCCESS(Status
))
3167 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3168 return RtlNtStatusToDosError(Status
);
3172 Status
= NtQuerySecurityObject(KeyHandle
,
3173 SecurityInformation
,
3174 pSecurityDescriptor
,
3175 *lpcbSecurityDescriptor
,
3176 lpcbSecurityDescriptor
);
3179 ClosePredefKey(KeyHandle
);
3181 if (!NT_SUCCESS(Status
))
3183 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3184 return RtlNtStatusToDosError(Status
);
3187 return ERROR_SUCCESS
;
3191 /************************************************************************
3197 RegLoadKeyA(HKEY hKey
,
3201 UNICODE_STRING FileName
;
3202 UNICODE_STRING KeyName
;
3205 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3207 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3210 ErrorCode
= RegLoadKeyW(hKey
,
3214 RtlFreeUnicodeString(&FileName
);
3215 RtlFreeUnicodeString(&KeyName
);
3221 /************************************************************************
3227 RegLoadKeyW(HKEY hKey
,
3231 OBJECT_ATTRIBUTES FileObjectAttributes
;
3232 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3233 UNICODE_STRING FileName
;
3234 UNICODE_STRING KeyName
;
3237 LONG ErrorCode
= ERROR_SUCCESS
;
3239 if (hKey
== HKEY_PERFORMANCE_DATA
)
3241 return ERROR_INVALID_HANDLE
;
3244 Status
= MapDefaultKey(&KeyHandle
,
3246 if (!NT_SUCCESS(Status
))
3248 return RtlNtStatusToDosError(Status
);
3251 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3256 ErrorCode
= ERROR_BAD_PATHNAME
;
3260 InitializeObjectAttributes(&FileObjectAttributes
,
3262 OBJ_CASE_INSENSITIVE
,
3266 RtlInitUnicodeString(&KeyName
,
3269 InitializeObjectAttributes(&KeyObjectAttributes
,
3271 OBJ_CASE_INSENSITIVE
,
3275 Status
= NtLoadKey(&KeyObjectAttributes
,
3276 &FileObjectAttributes
);
3278 RtlFreeHeap(RtlGetProcessHeap(),
3282 if (!NT_SUCCESS(Status
))
3284 ErrorCode
= RtlNtStatusToDosError(Status
);
3289 ClosePredefKey(KeyHandle
);
3295 /************************************************************************
3296 * RegNotifyChangeKeyValue
3301 RegNotifyChangeKeyValue(HKEY hKey
,
3303 DWORD dwNotifyFilter
,
3307 IO_STATUS_BLOCK IoStatusBlock
;
3310 LONG ErrorCode
= ERROR_SUCCESS
;
3312 if (hKey
== HKEY_PERFORMANCE_DATA
)
3314 return ERROR_INVALID_HANDLE
;
3317 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3319 return ERROR_INVALID_PARAMETER
;
3322 Status
= MapDefaultKey(&KeyHandle
,
3324 if (!NT_SUCCESS(Status
))
3326 return RtlNtStatusToDosError(Status
);
3329 /* FIXME: Remote key handles must fail */
3331 Status
= NtNotifyChangeKey(KeyHandle
,
3341 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3343 ErrorCode
= RtlNtStatusToDosError(Status
);
3346 ClosePredefKey(KeyHandle
);
3352 /************************************************************************
3353 * RegOpenCurrentUser
3358 RegOpenCurrentUser(IN REGSAM samDesired
,
3359 OUT PHKEY phkResult
)
3363 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3364 (PHANDLE
)phkResult
);
3365 if (!NT_SUCCESS(Status
))
3367 /* NOTE - don't set the last error code! just return the error! */
3368 return RtlNtStatusToDosError(Status
);
3371 return ERROR_SUCCESS
;
3375 /************************************************************************
3378 * 20050503 Fireball - imported from WINE
3383 RegOpenKeyA(HKEY hKey
,
3387 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3388 hKey
, lpSubKey
, phkResult
);
3391 return ERROR_INVALID_PARAMETER
;
3393 if (!hKey
&& lpSubKey
&& phkResult
)
3395 return ERROR_INVALID_HANDLE
;
3398 if (!lpSubKey
|| !*lpSubKey
)
3401 return ERROR_SUCCESS
;
3404 return RegOpenKeyExA(hKey
,
3412 /************************************************************************
3417 * 20050503 Fireball - imported from WINE
3422 RegOpenKeyW(HKEY hKey
,
3426 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3427 hKey
, lpSubKey
, phkResult
);
3430 return ERROR_INVALID_PARAMETER
;
3432 if (!hKey
&& lpSubKey
&& phkResult
)
3434 return ERROR_INVALID_HANDLE
;
3437 if (!lpSubKey
|| !*lpSubKey
)
3440 return ERROR_SUCCESS
;
3443 return RegOpenKeyExW(hKey
,
3451 /************************************************************************
3457 RegOpenKeyExA(HKEY hKey
,
3463 OBJECT_ATTRIBUTES ObjectAttributes
;
3464 UNICODE_STRING SubKeyString
;
3467 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3468 LONG ErrorCode
= ERROR_SUCCESS
;
3470 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3471 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3474 return ERROR_INVALID_PARAMETER
;
3477 Status
= MapDefaultKey(&KeyHandle
,
3479 if (!NT_SUCCESS(Status
))
3481 return RtlNtStatusToDosError(Status
);
3484 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3485 Attributes
|= OBJ_OPENLINK
;
3487 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3489 InitializeObjectAttributes(&ObjectAttributes
,
3495 Status
= NtOpenKey((PHANDLE
)phkResult
,
3498 RtlFreeUnicodeString(&SubKeyString
);
3499 if (!NT_SUCCESS(Status
))
3501 ErrorCode
= RtlNtStatusToDosError(Status
);
3504 ClosePredefKey(KeyHandle
);
3510 /************************************************************************
3516 RegOpenKeyExW(HKEY hKey
,
3522 OBJECT_ATTRIBUTES ObjectAttributes
;
3523 UNICODE_STRING SubKeyString
;
3526 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3527 LONG ErrorCode
= ERROR_SUCCESS
;
3529 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3530 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3533 return ERROR_INVALID_PARAMETER
;
3536 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3537 if (!NT_SUCCESS(Status
))
3539 return RtlNtStatusToDosError(Status
);
3542 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3543 Attributes
|= OBJ_OPENLINK
;
3545 if (lpSubKey
!= NULL
)
3546 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3548 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3550 InitializeObjectAttributes(&ObjectAttributes
,
3556 Status
= NtOpenKey((PHANDLE
)phkResult
,
3559 if (!NT_SUCCESS(Status
))
3561 ErrorCode
= RtlNtStatusToDosError(Status
);
3564 ClosePredefKey(KeyHandle
);
3570 /************************************************************************
3571 * RegOpenUserClassesRoot
3576 RegOpenUserClassesRoot(IN HANDLE hToken
,
3578 IN REGSAM samDesired
,
3579 OUT PHKEY phkResult
)
3581 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3582 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3583 PTOKEN_USER TokenUserData
;
3584 ULONG RequiredLength
;
3585 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3586 OBJECT_ATTRIBUTES ObjectAttributes
;
3589 /* check parameters */
3590 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3592 return ERROR_INVALID_PARAMETER
;
3596 * Get the user sid from the token
3600 /* determine how much memory we need */
3601 Status
= NtQueryInformationToken(hToken
,
3606 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3608 /* NOTE - as opposed to all other registry functions windows does indeed
3609 change the last error code in case the caller supplied a invalid
3610 handle for example! */
3611 return RtlNtStatusToDosError(Status
);
3613 RegInitialize(); /* HACK until delay-loading is implemented */
3614 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3617 if (TokenUserData
== NULL
)
3619 return ERROR_NOT_ENOUGH_MEMORY
;
3622 /* attempt to read the information */
3623 Status
= NtQueryInformationToken(hToken
,
3628 if (!NT_SUCCESS(Status
))
3630 RtlFreeHeap(ProcessHeap
,
3633 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3635 /* the information appears to have changed?! try again */
3639 /* NOTE - as opposed to all other registry functions windows does indeed
3640 change the last error code in case the caller supplied a invalid
3641 handle for example! */
3642 return RtlNtStatusToDosError(Status
);
3646 * Build the absolute path for the user's registry in the form
3647 * "\Registry\User\<SID>_Classes"
3649 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3650 TokenUserData
->User
.Sid
,
3653 /* we don't need the user data anymore, free it */
3654 RtlFreeHeap(ProcessHeap
,
3658 if (!NT_SUCCESS(Status
))
3660 return RtlNtStatusToDosError(Status
);
3663 /* allocate enough memory for the entire key string */
3664 UserClassesKeyRoot
.Length
= 0;
3665 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3666 sizeof(UserClassesKeyPrefix
) +
3667 sizeof(UserClassesKeySuffix
);
3668 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3670 UserClassesKeyRoot
.MaximumLength
);
3671 if (UserClassesKeyRoot
.Buffer
== NULL
)
3673 RtlFreeUnicodeString(&UserSidString
);
3674 return RtlNtStatusToDosError(Status
);
3677 /* build the string */
3678 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3679 UserClassesKeyPrefix
);
3680 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3682 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3683 UserClassesKeySuffix
);
3685 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3690 InitializeObjectAttributes(&ObjectAttributes
,
3691 &UserClassesKeyRoot
,
3692 OBJ_CASE_INSENSITIVE
,
3696 Status
= NtOpenKey((PHANDLE
)phkResult
,
3700 RtlFreeUnicodeString(&UserSidString
);
3701 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3703 if (!NT_SUCCESS(Status
))
3705 return RtlNtStatusToDosError(Status
);
3708 return ERROR_SUCCESS
;
3712 /************************************************************************
3718 RegQueryInfoKeyA(HKEY hKey
,
3723 LPDWORD lpcbMaxSubKeyLen
,
3724 LPDWORD lpcbMaxClassLen
,
3726 LPDWORD lpcbMaxValueNameLen
,
3727 LPDWORD lpcbMaxValueLen
,
3728 LPDWORD lpcbSecurityDescriptor
,
3729 PFILETIME lpftLastWriteTime
)
3731 WCHAR ClassName
[MAX_PATH
];
3732 UNICODE_STRING UnicodeString
;
3733 ANSI_STRING AnsiString
;
3736 RtlInitUnicodeString(&UnicodeString
,
3738 if (lpClass
!= NULL
)
3740 UnicodeString
.Buffer
= &ClassName
[0];
3741 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3742 AnsiString
.MaximumLength
= *lpcbClass
;
3745 ErrorCode
= RegQueryInfoKeyW(hKey
,
3746 UnicodeString
.Buffer
,
3753 lpcbMaxValueNameLen
,
3755 lpcbSecurityDescriptor
,
3757 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3759 AnsiString
.Buffer
= lpClass
;
3760 AnsiString
.Length
= 0;
3761 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3762 RtlUnicodeStringToAnsiString(&AnsiString
,
3765 *lpcbClass
= AnsiString
.Length
;
3766 lpClass
[AnsiString
.Length
] = 0;
3773 /************************************************************************
3779 RegQueryInfoKeyW(HKEY hKey
,
3784 LPDWORD lpcbMaxSubKeyLen
,
3785 LPDWORD lpcbMaxClassLen
,
3787 LPDWORD lpcbMaxValueNameLen
,
3788 LPDWORD lpcbMaxValueLen
,
3789 LPDWORD lpcbSecurityDescriptor
,
3790 PFILETIME lpftLastWriteTime
)
3792 KEY_FULL_INFORMATION FullInfoBuffer
;
3793 PKEY_FULL_INFORMATION FullInfo
;
3795 ULONG ClassLength
= 0;
3799 LONG ErrorCode
= ERROR_SUCCESS
;
3801 if ((lpClass
) && (!lpcbClass
))
3803 return ERROR_INVALID_PARAMETER
;
3806 Status
= MapDefaultKey(&KeyHandle
,
3808 if (!NT_SUCCESS(Status
))
3810 return RtlNtStatusToDosError(Status
);
3813 if (lpClass
!= NULL
)
3817 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3824 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3825 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3828 if (FullInfo
== NULL
)
3830 ErrorCode
= ERROR_OUTOFMEMORY
;
3834 FullInfo
->ClassLength
= ClassLength
;
3838 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3839 FullInfo
= &FullInfoBuffer
;
3840 FullInfo
->ClassLength
= 0;
3842 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3844 Status
= NtQueryKey(KeyHandle
,
3849 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3850 if (!NT_SUCCESS(Status
))
3852 if (lpClass
!= NULL
)
3854 RtlFreeHeap(ProcessHeap
,
3859 ErrorCode
= RtlNtStatusToDosError(Status
);
3863 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3864 if (lpcSubKeys
!= NULL
)
3866 *lpcSubKeys
= FullInfo
->SubKeys
;
3869 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3870 if (lpcbMaxSubKeyLen
!= NULL
)
3872 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3875 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3876 if (lpcbMaxClassLen
!= NULL
)
3878 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3881 TRACE("Values %lu\n", FullInfo
->Values
);
3882 if (lpcValues
!= NULL
)
3884 *lpcValues
= FullInfo
->Values
;
3887 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3888 if (lpcbMaxValueNameLen
!= NULL
)
3890 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3893 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3894 if (lpcbMaxValueLen
!= NULL
)
3896 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3900 if (lpcbSecurityDescriptor
!= NULL
)
3902 Status
= NtQuerySecurityObject(KeyHandle
,
3903 OWNER_SECURITY_INFORMATION
|
3904 GROUP_SECURITY_INFORMATION
|
3905 DACL_SECURITY_INFORMATION
,
3908 lpcbSecurityDescriptor
);
3909 if (!NT_SUCCESS(Status
))
3911 if (lpClass
!= NULL
)
3913 RtlFreeHeap(ProcessHeap
,
3918 ErrorCode
= RtlNtStatusToDosError(Status
);
3924 if (lpftLastWriteTime
!= NULL
)
3926 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3927 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3930 if (lpClass
!= NULL
)
3932 if (FullInfo
->ClassLength
> ClassLength
)
3934 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3938 RtlCopyMemory(lpClass
,
3940 FullInfo
->ClassLength
);
3941 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3942 lpClass
[*lpcbClass
] = 0;
3945 RtlFreeHeap(ProcessHeap
,
3951 ClosePredefKey(KeyHandle
);
3957 /************************************************************************
3958 * RegQueryMultipleValuesA
3963 RegQueryMultipleValuesA(HKEY hKey
,
3970 DWORD maxBytes
= *ldwTotsize
;
3971 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3974 if (maxBytes
>= (1024*1024))
3975 return ERROR_TRANSFER_TOO_LONG
;
3979 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3980 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3982 for (i
= 0; i
< num_vals
; i
++)
3984 val_list
[i
].ve_valuelen
= 0;
3985 ErrorCode
= RegQueryValueExA(hKey
,
3986 val_list
[i
].ve_valuename
,
3990 &val_list
[i
].ve_valuelen
);
3991 if (ErrorCode
!= ERROR_SUCCESS
)
3996 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)