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 /************************************************************************
1018 _In_ LPCSTR lpSubKey
,
1019 _In_ DWORD Reserved
,
1021 _In_ DWORD dwOptions
,
1022 _In_ REGSAM samDesired
,
1023 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1024 _Out_ PHKEY phkResult
,
1025 _Out_ LPDWORD lpdwDisposition
)
1027 UNICODE_STRING SubKeyString
;
1028 UNICODE_STRING ClassString
;
1031 RtlCreateUnicodeStringFromAsciiz(&ClassString
, lpClass
);
1032 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, (LPSTR
)lpSubKey
);
1034 ErrorCode
= RegCreateKeyExW(
1036 SubKeyString
.Buffer
,
1041 lpSecurityAttributes
,
1045 RtlFreeUnicodeString(&SubKeyString
);
1046 RtlFreeUnicodeString(&ClassString
);
1052 /************************************************************************
1058 RegCreateKeyExW(HKEY hKey
,
1064 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1066 LPDWORD lpdwDisposition
)
1068 UNICODE_STRING SubKeyString
;
1069 UNICODE_STRING ClassString
;
1070 OBJECT_ATTRIBUTES ObjectAttributes
;
1072 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1075 TRACE("RegCreateKeyExW() called\n");
1077 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1078 return ERROR_INVALID_USER_BUFFER
;
1080 /* get the real parent key */
1081 Status
= MapDefaultKey(&ParentKey
,
1083 if (!NT_SUCCESS(Status
))
1085 return RtlNtStatusToDosError(Status
);
1088 TRACE("ParentKey %p\n", ParentKey
);
1090 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1091 Attributes
|= OBJ_OPENLINK
;
1093 RtlInitUnicodeString(&ClassString
,
1095 RtlInitUnicodeString(&SubKeyString
,
1097 InitializeObjectAttributes(&ObjectAttributes
,
1101 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1102 Status
= CreateNestedKey(phkResult
,
1104 (lpClass
== NULL
)? NULL
: &ClassString
,
1109 ClosePredefKey(ParentKey
);
1111 TRACE("Status %x\n", Status
);
1112 if (!NT_SUCCESS(Status
))
1114 return RtlNtStatusToDosError(Status
);
1117 return ERROR_SUCCESS
;
1121 /************************************************************************
1127 RegCreateKeyA(HKEY hKey
,
1131 return RegCreateKeyExA(hKey
,
1143 /************************************************************************
1149 RegCreateKeyW(HKEY hKey
,
1153 return RegCreateKeyExW(hKey
,
1165 /************************************************************************
1171 RegDeleteKeyA(HKEY hKey
,
1174 OBJECT_ATTRIBUTES ObjectAttributes
;
1175 UNICODE_STRING SubKeyName
;
1180 /* Make sure we got a subkey */
1184 return ERROR_INVALID_PARAMETER
;
1187 Status
= MapDefaultKey(&ParentKey
,
1189 if (!NT_SUCCESS(Status
))
1191 return RtlNtStatusToDosError(Status
);
1194 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1196 InitializeObjectAttributes(&ObjectAttributes
,
1198 OBJ_CASE_INSENSITIVE
,
1202 Status
= NtOpenKey(&TargetKey
,
1205 RtlFreeUnicodeString(&SubKeyName
);
1206 if (!NT_SUCCESS(Status
))
1211 Status
= NtDeleteKey(TargetKey
);
1212 NtClose (TargetKey
);
1215 ClosePredefKey(ParentKey
);
1217 if (!NT_SUCCESS(Status
))
1219 return RtlNtStatusToDosError(Status
);
1222 return ERROR_SUCCESS
;
1226 /************************************************************************
1232 RegDeleteKeyW(HKEY hKey
,
1235 OBJECT_ATTRIBUTES ObjectAttributes
;
1236 UNICODE_STRING SubKeyName
;
1241 /* Make sure we got a subkey */
1245 return ERROR_INVALID_PARAMETER
;
1248 Status
= MapDefaultKey(&ParentKey
,
1250 if (!NT_SUCCESS(Status
))
1252 return RtlNtStatusToDosError(Status
);
1255 RtlInitUnicodeString(&SubKeyName
,
1257 InitializeObjectAttributes(&ObjectAttributes
,
1259 OBJ_CASE_INSENSITIVE
,
1262 Status
= NtOpenKey(&TargetKey
,
1265 if (!NT_SUCCESS(Status
))
1270 Status
= NtDeleteKey(TargetKey
);
1274 ClosePredefKey(ParentKey
);
1276 if (!NT_SUCCESS(Status
))
1278 return RtlNtStatusToDosError(Status
);
1281 return ERROR_SUCCESS
;
1285 /************************************************************************
1292 RegDeleteKeyExA(HKEY hKey
,
1297 OBJECT_ATTRIBUTES ObjectAttributes
;
1298 UNICODE_STRING SubKeyName
;
1303 /* Make sure we got a subkey */
1307 return ERROR_INVALID_PARAMETER
;
1310 Status
= MapDefaultKey(&ParentKey
,
1312 if (!NT_SUCCESS(Status
))
1314 return RtlNtStatusToDosError(Status
);
1317 if (samDesired
& KEY_WOW64_32KEY
)
1318 ERR("Wow64 not yet supported!\n");
1320 if (samDesired
& KEY_WOW64_64KEY
)
1321 ERR("Wow64 not yet supported!\n");
1323 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1325 InitializeObjectAttributes(&ObjectAttributes
,
1327 OBJ_CASE_INSENSITIVE
,
1331 Status
= NtOpenKey(&TargetKey
,
1334 RtlFreeUnicodeString(&SubKeyName
);
1335 if (!NT_SUCCESS(Status
))
1340 Status
= NtDeleteKey(TargetKey
);
1341 NtClose (TargetKey
);
1344 ClosePredefKey(ParentKey
);
1346 if (!NT_SUCCESS(Status
))
1348 return RtlNtStatusToDosError(Status
);
1351 return ERROR_SUCCESS
;
1355 /************************************************************************
1362 RegDeleteKeyExW(HKEY hKey
,
1367 OBJECT_ATTRIBUTES ObjectAttributes
;
1368 UNICODE_STRING SubKeyName
;
1373 /* Make sure we got a subkey */
1377 return ERROR_INVALID_PARAMETER
;
1380 Status
= MapDefaultKey(&ParentKey
,
1382 if (!NT_SUCCESS(Status
))
1384 return RtlNtStatusToDosError(Status
);
1387 if (samDesired
& KEY_WOW64_32KEY
)
1388 ERR("Wow64 not yet supported!\n");
1390 if (samDesired
& KEY_WOW64_64KEY
)
1391 ERR("Wow64 not yet supported!\n");
1394 RtlInitUnicodeString(&SubKeyName
,
1396 InitializeObjectAttributes(&ObjectAttributes
,
1398 OBJ_CASE_INSENSITIVE
,
1401 Status
= NtOpenKey(&TargetKey
,
1404 if (!NT_SUCCESS(Status
))
1409 Status
= NtDeleteKey(TargetKey
);
1413 ClosePredefKey(ParentKey
);
1415 if (!NT_SUCCESS(Status
))
1417 return RtlNtStatusToDosError(Status
);
1420 return ERROR_SUCCESS
;
1424 /************************************************************************
1425 * RegDeleteKeyValueW
1430 RegDeleteKeyValueW(IN HKEY hKey
,
1431 IN LPCWSTR lpSubKey OPTIONAL
,
1432 IN LPCWSTR lpValueName OPTIONAL
)
1434 UNICODE_STRING ValueName
;
1435 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1438 Status
= MapDefaultKey(&KeyHandle
,
1440 if (!NT_SUCCESS(Status
))
1442 return RtlNtStatusToDosError(Status
);
1445 if (lpSubKey
!= NULL
)
1447 OBJECT_ATTRIBUTES ObjectAttributes
;
1448 UNICODE_STRING SubKeyName
;
1450 RtlInitUnicodeString(&SubKeyName
,
1453 InitializeObjectAttributes(&ObjectAttributes
,
1455 OBJ_CASE_INSENSITIVE
,
1459 Status
= NtOpenKey(&SubKeyHandle
,
1462 if (!NT_SUCCESS(Status
))
1467 CurKey
= SubKeyHandle
;
1472 RtlInitUnicodeString(&ValueName
,
1473 (LPWSTR
)lpValueName
);
1475 Status
= NtDeleteValueKey(CurKey
,
1478 if (SubKeyHandle
!= NULL
)
1480 NtClose(SubKeyHandle
);
1484 ClosePredefKey(KeyHandle
);
1486 if (!NT_SUCCESS(Status
))
1488 return RtlNtStatusToDosError(Status
);
1491 return ERROR_SUCCESS
;
1495 /************************************************************************
1496 * RegDeleteKeyValueA
1501 RegDeleteKeyValueA(IN HKEY hKey
,
1502 IN LPCSTR lpSubKey OPTIONAL
,
1503 IN LPCSTR lpValueName OPTIONAL
)
1505 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1508 if (lpSubKey
!= NULL
&&
1509 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1512 return ERROR_NOT_ENOUGH_MEMORY
;
1515 if (lpValueName
!= NULL
&&
1516 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1517 (LPSTR
)lpValueName
))
1519 RtlFreeUnicodeString(&SubKey
);
1520 return ERROR_NOT_ENOUGH_MEMORY
;
1523 Ret
= RegDeleteKeyValueW(hKey
,
1527 RtlFreeUnicodeString(&SubKey
);
1528 RtlFreeUnicodeString(&ValueName
);
1534 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1536 RegpDeleteTree(IN HKEY hKey
)
1540 LIST_ENTRY ListEntry
;
1542 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1544 LIST_ENTRY delQueueHead
;
1545 PREG_DEL_KEYS delKeys
, newDelKeys
;
1548 PKEY_BASIC_INFORMATION BasicInfo
;
1549 PREG_DEL_KEYS KeyDelRoot
;
1550 NTSTATUS Status
= STATUS_SUCCESS
;
1551 NTSTATUS Status2
= STATUS_SUCCESS
;
1553 InitializeListHead(&delQueueHead
);
1555 ProcessHeap
= RtlGetProcessHeap();
1557 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1558 structure for the root key, we only do that for subkeys as we need to
1559 allocate REGP_DEL_KEYS structures anyway! */
1560 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1562 sizeof(REGP_DEL_KEYS
));
1563 if (KeyDelRoot
!= NULL
)
1565 KeyDelRoot
->KeyHandle
= hKey
;
1566 InsertTailList(&delQueueHead
,
1567 &KeyDelRoot
->ListEntry
);
1571 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1580 /* check if this key contains subkeys and delete them first by queuing
1581 them at the head of the list */
1582 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1584 KeyBasicInformation
,
1589 if (NT_SUCCESS(Status2
))
1591 OBJECT_ATTRIBUTES ObjectAttributes
;
1592 UNICODE_STRING SubKeyName
;
1594 ASSERT(newDelKeys
!= NULL
);
1595 ASSERT(BasicInfo
!= NULL
);
1597 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1598 SubKeyName
.Length
= BasicInfo
->NameLength
;
1599 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1600 SubKeyName
.Buffer
= BasicInfo
->Name
;
1602 InitializeObjectAttributes(&ObjectAttributes
,
1604 OBJ_CASE_INSENSITIVE
,
1608 /* open the subkey */
1609 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1610 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1612 if (!NT_SUCCESS(Status2
))
1617 /* enqueue this key to the head of the deletion queue */
1618 InsertHeadList(&delQueueHead
,
1619 &newDelKeys
->ListEntry
);
1621 /* try again from the head of the list */
1626 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1628 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1630 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1631 if (newDelKeys
!= NULL
)
1633 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1636 goto ReadFirstSubKey
;
1640 /* don't break, let's try to delete as many keys as possible */
1641 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1642 goto SubKeyFailureNoFree
;
1645 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1647 PREG_DEL_KEYS newDelKeys2
;
1649 ASSERT(newDelKeys
!= NULL
);
1651 /* we need more memory to query the key name */
1652 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1655 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1656 if (newDelKeys2
!= NULL
)
1658 newDelKeys
= newDelKeys2
;
1659 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1662 goto ReadFirstSubKey
;
1666 /* don't break, let's try to delete as many keys as possible */
1667 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1670 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1672 /* in some race conditions where another thread would delete
1673 the same tree at the same time, newDelKeys could actually
1675 if (newDelKeys
!= NULL
)
1677 RtlFreeHeap(ProcessHeap
,
1685 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1686 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1687 if (newDelKeys
!= NULL
)
1689 RtlFreeHeap(ProcessHeap
,
1694 SubKeyFailureNoFree
:
1695 /* don't break, let's try to delete as many keys as possible */
1696 if (NT_SUCCESS(Status
))
1702 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1704 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1706 if (!NT_SUCCESS(Status2
))
1708 /* close the key handle so we don't leak handles for keys we were
1709 unable to delete. But only do this for handles not supplied
1712 if (delKeys
->KeyHandle
!= hKey
)
1714 NtClose(delKeys
->KeyHandle
);
1717 if (NT_SUCCESS(Status
))
1719 /* don't break, let's try to delete as many keys as possible */
1724 /* remove the entry from the list */
1725 RemoveEntryList(&delKeys
->ListEntry
);
1727 RtlFreeHeap(ProcessHeap
,
1730 } while (!IsListEmpty(&delQueueHead
));
1733 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1739 /************************************************************************
1745 RegDeleteTreeW(IN HKEY hKey
,
1746 IN LPCWSTR lpSubKey OPTIONAL
)
1748 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1751 Status
= MapDefaultKey(&KeyHandle
,
1753 if (!NT_SUCCESS(Status
))
1755 return RtlNtStatusToDosError(Status
);
1758 if (lpSubKey
!= NULL
)
1760 OBJECT_ATTRIBUTES ObjectAttributes
;
1761 UNICODE_STRING SubKeyName
;
1763 RtlInitUnicodeString(&SubKeyName
,
1766 InitializeObjectAttributes(&ObjectAttributes
,
1768 OBJ_CASE_INSENSITIVE
,
1772 Status
= NtOpenKey(&SubKeyHandle
,
1773 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1775 if (!NT_SUCCESS(Status
))
1780 CurKey
= SubKeyHandle
;
1785 Status
= RegpDeleteTree(CurKey
);
1787 if (NT_SUCCESS(Status
))
1789 /* make sure we only close hKey (KeyHandle) when the caller specified a
1790 subkey, because the handle would be invalid already! */
1791 if (CurKey
!= KeyHandle
)
1793 ClosePredefKey(KeyHandle
);
1796 return ERROR_SUCCESS
;
1800 /* make sure we close all handles we created! */
1801 if (SubKeyHandle
!= NULL
)
1803 NtClose(SubKeyHandle
);
1807 ClosePredefKey(KeyHandle
);
1809 return RtlNtStatusToDosError(Status
);
1815 /************************************************************************
1822 RegDeleteTreeW(HKEY hKey
,
1826 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1827 DWORD dwMaxLen
, dwSize
;
1831 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1833 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1835 Status
= MapDefaultKey(&KeyHandle
,
1837 if (!NT_SUCCESS(Status
))
1839 return RtlNtStatusToDosError(Status
);
1842 hSubKey
= KeyHandle
;
1846 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1849 ClosePredefKey(KeyHandle
);
1854 /* Get highest length for keys, values */
1855 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1856 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1857 if (ret
) goto cleanup
;
1861 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1862 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1864 /* Name too big: alloc a buffer for it */
1865 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1867 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1873 /* Recursively delete all the subkeys */
1877 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1878 NULL
, NULL
, NULL
)) break;
1880 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1881 if (ret
) goto cleanup
;
1885 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1890 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1891 NULL
, NULL
, NULL
, NULL
)) break;
1893 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1894 if (ret
) goto cleanup
;
1898 /* Free buffer if allocated */
1899 if (lpszName
!= szNameBuf
)
1900 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1902 RegCloseKey(hSubKey
);
1904 ClosePredefKey(KeyHandle
);
1910 /************************************************************************
1916 RegDeleteTreeA(IN HKEY hKey
,
1917 IN LPCSTR lpSubKey OPTIONAL
)
1919 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1922 if (lpSubKey
!= NULL
&&
1923 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1926 return ERROR_NOT_ENOUGH_MEMORY
;
1929 Ret
= RegDeleteTreeW(hKey
,
1932 RtlFreeUnicodeString(&SubKeyName
);
1938 /************************************************************************
1939 * RegDisableReflectionKey
1944 RegDisableReflectionKey(IN HKEY hBase
)
1946 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1947 return ERROR_CALL_NOT_IMPLEMENTED
;
1951 /************************************************************************
1952 * RegEnableReflectionKey
1957 RegEnableReflectionKey(IN HKEY hBase
)
1959 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1960 return ERROR_CALL_NOT_IMPLEMENTED
;
1964 /******************************************************************************
1965 * RegpApplyRestrictions [internal]
1967 * Helper function for RegGetValueA/W.
1970 RegpApplyRestrictions(DWORD dwFlags
,
1975 /* Check if the type is restricted by the passed flags */
1976 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1982 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1983 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1984 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1985 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1986 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1987 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1988 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1991 if (dwFlags
& dwMask
)
1993 /* Type is not restricted, check for size mismatch */
1994 if (dwType
== REG_BINARY
)
1998 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2000 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2003 if (cbExpect
&& cbData
!= cbExpect
)
2004 *ret
= ERROR_DATATYPE_MISMATCH
;
2007 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2012 /******************************************************************************
2013 * RegGetValueW [ADVAPI32.@]
2015 * Retrieves the type and data for a value name associated with a key,
2016 * optionally expanding its content and restricting its type.
2019 * hKey [I] Handle to an open key.
2020 * pszSubKey [I] Name of the subkey of hKey.
2021 * pszValue [I] Name of value under hKey/szSubKey to query.
2022 * dwFlags [I] Flags restricting the value type to retrieve.
2023 * pdwType [O] Destination for the values type, may be NULL.
2024 * pvData [O] Destination for the values content, may be NULL.
2025 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2026 * retrieve the whole content, including the trailing '\0'
2030 * Success: ERROR_SUCCESS
2031 * Failure: nonzero error code from Winerror.h
2034 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2035 * expanded and pdwType is set to REG_SZ instead.
2036 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2037 * without RRF_NOEXPAND is thus not allowed.
2038 * An exception is the case where RRF_RT_ANY is specified, because then
2039 * RRF_NOEXPAND is allowed.
2042 RegGetValueW(HKEY hKey
,
2050 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2054 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2055 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2056 pvData
, pcbData
, cbData
);
2058 if (pvData
&& !pcbData
)
2059 return ERROR_INVALID_PARAMETER
;
2060 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2061 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2062 return ERROR_INVALID_PARAMETER
;
2064 if (pszSubKey
&& pszSubKey
[0])
2066 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2067 if (ret
!= ERROR_SUCCESS
) return ret
;
2070 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2072 /* If we are going to expand we need to read in the whole the value even
2073 * if the passed buffer was too small as the expanded string might be
2074 * smaller than the unexpanded one and could fit into cbData bytes. */
2075 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2076 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2080 HeapFree(GetProcessHeap(), 0, pvBuf
);
2082 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2085 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2089 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2090 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2091 &dwType
, pvBuf
, &cbData
);
2094 /* Even if cbData was large enough we have to copy the
2095 * string since ExpandEnvironmentStrings can't handle
2096 * overlapping buffers. */
2097 CopyMemory(pvBuf
, pvData
, cbData
);
2100 /* Both the type or the value itself could have been modified in
2101 * between so we have to keep retrying until the buffer is large
2102 * enough or we no longer have to expand the value. */
2104 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2106 if (ret
== ERROR_SUCCESS
)
2108 /* Recheck dwType in case it changed since the first call */
2109 if (dwType
== REG_EXPAND_SZ
)
2111 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2112 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2114 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2115 ret
= ERROR_MORE_DATA
;
2118 CopyMemory(pvData
, pvBuf
, *pcbData
);
2121 HeapFree(GetProcessHeap(), 0, pvBuf
);
2124 if (pszSubKey
&& pszSubKey
[0])
2127 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2129 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2130 ZeroMemory(pvData
, *pcbData
);
2142 /******************************************************************************
2143 * RegGetValueA [ADVAPI32.@]
2148 RegGetValueA(HKEY hKey
,
2156 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2160 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2161 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2164 if (pvData
&& !pcbData
)
2165 return ERROR_INVALID_PARAMETER
;
2166 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2167 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2168 return ERROR_INVALID_PARAMETER
;
2170 if (pszSubKey
&& pszSubKey
[0])
2172 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2173 if (ret
!= ERROR_SUCCESS
) return ret
;
2176 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2178 /* If we are going to expand we need to read in the whole the value even
2179 * if the passed buffer was too small as the expanded string might be
2180 * smaller than the unexpanded one and could fit into cbData bytes. */
2181 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2182 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2185 HeapFree(GetProcessHeap(), 0, pvBuf
);
2187 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2190 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2194 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2195 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2196 &dwType
, pvBuf
, &cbData
);
2199 /* Even if cbData was large enough we have to copy the
2200 * string since ExpandEnvironmentStrings can't handle
2201 * overlapping buffers. */
2202 CopyMemory(pvBuf
, pvData
, cbData
);
2205 /* Both the type or the value itself could have been modified in
2206 * between so we have to keep retrying until the buffer is large
2207 * enough or we no longer have to expand the value. */
2208 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2210 if (ret
== ERROR_SUCCESS
)
2212 /* Recheck dwType in case it changed since the first call */
2213 if (dwType
== REG_EXPAND_SZ
)
2215 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2216 pcbData
? *pcbData
: 0);
2218 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2219 ret
= ERROR_MORE_DATA
;
2222 CopyMemory(pvData
, pvBuf
, *pcbData
);
2225 HeapFree(GetProcessHeap(), 0, pvBuf
);
2228 if (pszSubKey
&& pszSubKey
[0])
2231 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2233 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2234 ZeroMemory(pvData
, *pcbData
);
2236 if (pdwType
) *pdwType
= dwType
;
2237 if (pcbData
) *pcbData
= cbData
;
2243 /************************************************************************
2249 RegSetKeyValueW(IN HKEY hKey
,
2250 IN LPCWSTR lpSubKey OPTIONAL
,
2251 IN LPCWSTR lpValueName OPTIONAL
,
2253 IN LPCVOID lpData OPTIONAL
,
2256 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2260 Status
= MapDefaultKey(&KeyHandle
,
2262 if (!NT_SUCCESS(Status
))
2264 return RtlNtStatusToDosError(Status
);
2267 if (lpSubKey
!= NULL
)
2269 OBJECT_ATTRIBUTES ObjectAttributes
;
2270 UNICODE_STRING SubKeyName
;
2272 RtlInitUnicodeString(&SubKeyName
,
2275 InitializeObjectAttributes(&ObjectAttributes
,
2277 OBJ_CASE_INSENSITIVE
,
2281 Status
= NtOpenKey(&SubKeyHandle
,
2284 if (!NT_SUCCESS(Status
))
2286 Ret
= RtlNtStatusToDosError(Status
);
2290 CurKey
= SubKeyHandle
;
2295 Ret
= RegSetValueExW(CurKey
,
2302 if (SubKeyHandle
!= NULL
)
2304 NtClose(SubKeyHandle
);
2308 ClosePredefKey(KeyHandle
);
2314 /************************************************************************
2320 RegSetKeyValueA(IN HKEY hKey
,
2321 IN LPCSTR lpSubKey OPTIONAL
,
2322 IN LPCSTR lpValueName OPTIONAL
,
2324 IN LPCVOID lpData OPTIONAL
,
2327 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2331 Status
= MapDefaultKey(&KeyHandle
,
2333 if (!NT_SUCCESS(Status
))
2335 return RtlNtStatusToDosError(Status
);
2338 if (lpSubKey
!= NULL
)
2340 OBJECT_ATTRIBUTES ObjectAttributes
;
2341 UNICODE_STRING SubKeyName
;
2343 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2346 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2350 InitializeObjectAttributes(&ObjectAttributes
,
2352 OBJ_CASE_INSENSITIVE
,
2356 Status
= NtOpenKey(&SubKeyHandle
,
2360 RtlFreeUnicodeString(&SubKeyName
);
2362 if (!NT_SUCCESS(Status
))
2364 Ret
= RtlNtStatusToDosError(Status
);
2368 CurKey
= SubKeyHandle
;
2373 Ret
= RegSetValueExA(CurKey
,
2380 if (SubKeyHandle
!= NULL
)
2382 NtClose(SubKeyHandle
);
2386 ClosePredefKey(KeyHandle
);
2392 /************************************************************************
2398 RegDeleteValueA(HKEY hKey
,
2401 UNICODE_STRING ValueName
;
2405 Status
= MapDefaultKey(&KeyHandle
,
2407 if (!NT_SUCCESS(Status
))
2409 return RtlNtStatusToDosError(Status
);
2412 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2413 (LPSTR
)lpValueName
);
2414 Status
= NtDeleteValueKey(KeyHandle
,
2416 RtlFreeUnicodeString (&ValueName
);
2418 ClosePredefKey(KeyHandle
);
2420 if (!NT_SUCCESS(Status
))
2422 return RtlNtStatusToDosError(Status
);
2425 return ERROR_SUCCESS
;
2429 /************************************************************************
2435 RegDeleteValueW(HKEY hKey
,
2436 LPCWSTR lpValueName
)
2438 UNICODE_STRING ValueName
;
2442 Status
= MapDefaultKey(&KeyHandle
,
2444 if (!NT_SUCCESS(Status
))
2446 return RtlNtStatusToDosError(Status
);
2449 RtlInitUnicodeString(&ValueName
,
2450 (LPWSTR
)lpValueName
);
2452 Status
= NtDeleteValueKey(KeyHandle
,
2455 ClosePredefKey(KeyHandle
);
2457 if (!NT_SUCCESS(Status
))
2459 return RtlNtStatusToDosError(Status
);
2462 return ERROR_SUCCESS
;
2466 /************************************************************************
2472 RegEnumKeyA(HKEY hKey
,
2480 return RegEnumKeyExA(hKey
,
2491 /************************************************************************
2497 RegEnumKeyW(HKEY hKey
,
2505 return RegEnumKeyExW(hKey
,
2516 /************************************************************************
2522 RegEnumKeyExA(HKEY hKey
,
2529 PFILETIME lpftLastWriteTime
)
2533 KEY_NODE_INFORMATION Node
;
2534 KEY_BASIC_INFORMATION Basic
;
2537 UNICODE_STRING StringU
;
2538 ANSI_STRING StringA
;
2539 LONG ErrorCode
= ERROR_SUCCESS
;
2541 DWORD ClassLength
= 0;
2547 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2548 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2550 if ((lpClass
) && (!lpcbClass
))
2552 return ERROR_INVALID_PARAMETER
;
2555 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2556 if (!NT_SUCCESS(Status
))
2558 return RtlNtStatusToDosError(Status
);
2563 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2574 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2581 /* The class name should start at a dword boundary */
2582 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2586 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2589 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2590 if (KeyInfo
== NULL
)
2592 ErrorCode
= ERROR_OUTOFMEMORY
;
2596 Status
= NtEnumerateKey(KeyHandle
,
2598 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2602 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2603 if (!NT_SUCCESS(Status
))
2605 ErrorCode
= RtlNtStatusToDosError (Status
);
2609 if (lpClass
== NULL
)
2611 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2613 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2617 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2618 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2619 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2624 if (KeyInfo
->Node
.NameLength
> NameLength
||
2625 KeyInfo
->Node
.ClassLength
> ClassLength
)
2627 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2631 StringA
.Buffer
= lpClass
;
2633 StringA
.MaximumLength
= *lpcbClass
;
2634 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2635 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2636 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2637 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2638 lpClass
[StringA
.Length
] = 0;
2639 *lpcbClass
= StringA
.Length
;
2640 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2641 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2642 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2646 if (ErrorCode
== ERROR_SUCCESS
)
2648 StringA
.Buffer
= lpName
;
2650 StringA
.MaximumLength
= *lpcbName
;
2651 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2652 lpName
[StringA
.Length
] = 0;
2653 *lpcbName
= StringA
.Length
;
2654 if (lpftLastWriteTime
!= NULL
)
2656 if (lpClass
== NULL
)
2658 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2659 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2663 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2664 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2670 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2671 TRACE("Key Name1 Length %d\n", NameLength
);
2672 TRACE("Key Name Length %d\n", *lpcbName
);
2673 TRACE("Key Name %s\n", lpName
);
2675 RtlFreeHeap(ProcessHeap
,
2680 ClosePredefKey(KeyHandle
);
2686 /************************************************************************
2692 RegEnumKeyExW(HKEY hKey
,
2699 PFILETIME lpftLastWriteTime
)
2703 KEY_NODE_INFORMATION Node
;
2704 KEY_BASIC_INFORMATION Basic
;
2710 ULONG ClassLength
= 0;
2712 LONG ErrorCode
= ERROR_SUCCESS
;
2715 Status
= MapDefaultKey(&KeyHandle
,
2717 if (!NT_SUCCESS(Status
))
2719 return RtlNtStatusToDosError(Status
);
2724 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2735 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2742 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2746 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2749 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2752 if (KeyInfo
== NULL
)
2754 ErrorCode
= ERROR_OUTOFMEMORY
;
2758 Status
= NtEnumerateKey(KeyHandle
,
2760 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2764 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2765 if (!NT_SUCCESS(Status
))
2767 ErrorCode
= RtlNtStatusToDosError (Status
);
2771 if (lpClass
== NULL
)
2773 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2775 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2779 RtlCopyMemory(lpName
,
2780 KeyInfo
->Basic
.Name
,
2781 KeyInfo
->Basic
.NameLength
);
2782 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2783 lpName
[*lpcbName
] = 0;
2788 if (KeyInfo
->Node
.NameLength
> NameLength
||
2789 KeyInfo
->Node
.ClassLength
> ClassLength
)
2791 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2795 RtlCopyMemory(lpName
,
2797 KeyInfo
->Node
.NameLength
);
2798 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2799 lpName
[*lpcbName
] = 0;
2800 RtlCopyMemory(lpClass
,
2801 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2802 KeyInfo
->Node
.ClassLength
);
2803 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2804 lpClass
[*lpcbClass
] = 0;
2808 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2810 if (lpClass
== NULL
)
2812 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2813 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2817 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2818 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2823 RtlFreeHeap(ProcessHeap
,
2828 ClosePredefKey(KeyHandle
);
2834 /************************************************************************
2840 RegEnumValueA(HKEY hKey
,
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
)
2861 return ERROR_INVALID_PARAMETER
;
2863 status
= MapDefaultKey(&KeyHandle
, hKey
);
2864 if (!NT_SUCCESS(status
))
2866 return RtlNtStatusToDosError(status
);
2869 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2870 if (data
) total_size
+= *count
;
2871 total_size
= min( sizeof(buffer
), total_size
);
2873 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2874 buffer
, total_size
, &total_size
);
2875 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2877 /* we need to fetch the contents for a string type even if not requested,
2878 * because we need to compute the length of the ASCII string. */
2879 if (value
|| data
|| is_string(info
->Type
))
2881 /* retry with a dynamically allocated buffer */
2882 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2884 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2885 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2887 status
= STATUS_INSUFFICIENT_RESOURCES
;
2890 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2891 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2892 buf_ptr
, total_size
, &total_size
);
2895 if (status
) goto done
;
2897 if (is_string(info
->Type
))
2900 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2904 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2907 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2909 /* if the type is REG_SZ and data is not 0-terminated
2910 * and there is enough space in the buffer NT appends a \0 */
2911 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2914 info
->DataLength
= len
;
2918 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2919 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2922 if (value
&& !status
)
2926 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2927 if (len
>= *val_count
)
2929 status
= STATUS_BUFFER_OVERFLOW
;
2932 len
= *val_count
- 1;
2933 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2939 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2945 else status
= STATUS_SUCCESS
;
2947 if (type
) *type
= info
->Type
;
2948 if (count
) *count
= info
->DataLength
;
2951 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2952 ClosePredefKey(KeyHandle
);
2953 return RtlNtStatusToDosError(status
);
2957 /******************************************************************************
2958 * RegEnumValueW [ADVAPI32.@]
2962 * hkey [I] Handle to key to query
2963 * index [I] Index of value to query
2964 * value [O] Value string
2965 * val_count [I/O] Size of value buffer (in wchars)
2966 * reserved [I] Reserved
2967 * type [O] Type code
2968 * data [O] Value data
2969 * count [I/O] Size of data buffer (in bytes)
2972 * Success: ERROR_SUCCESS
2973 * Failure: nonzero error code from Winerror.h
2976 RegEnumValueW(HKEY hKey
,
2988 char buffer
[256], *buf_ptr
= buffer
;
2989 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2990 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2992 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2993 // hkey, index, value, val_count, reserved, type, data, count );
2995 /* NT only checks count, not val_count */
2996 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2998 status
= MapDefaultKey(&KeyHandle
, hKey
);
2999 if (!NT_SUCCESS(status
))
3001 return RtlNtStatusToDosError(status
);
3004 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
3005 if (data
) total_size
+= *count
;
3006 total_size
= min( sizeof(buffer
), total_size
);
3008 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3009 buffer
, total_size
, &total_size
);
3010 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
3014 /* retry with a dynamically allocated buffer */
3015 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
3017 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3018 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3020 status
= ERROR_NOT_ENOUGH_MEMORY
;
3023 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
3024 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3025 buf_ptr
, total_size
, &total_size
);
3028 if (status
) goto done
;
3032 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3034 status
= STATUS_BUFFER_OVERFLOW
;
3037 memcpy( value
, info
->Name
, info
->NameLength
);
3038 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3039 value
[*val_count
] = 0;
3044 if (info
->DataLength
> *count
)
3046 status
= STATUS_BUFFER_OVERFLOW
;
3049 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3050 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3052 /* if the type is REG_SZ and data is not 0-terminated
3053 * and there is enough space in the buffer NT appends a \0 */
3054 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3055 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3059 else status
= STATUS_SUCCESS
;
3062 if (type
) *type
= info
->Type
;
3063 if (count
) *count
= info
->DataLength
;
3066 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3067 ClosePredefKey(KeyHandle
);
3068 return RtlNtStatusToDosError(status
);
3072 /************************************************************************
3078 RegFlushKey(HKEY hKey
)
3083 if (hKey
== HKEY_PERFORMANCE_DATA
)
3085 return ERROR_SUCCESS
;
3088 Status
= MapDefaultKey(&KeyHandle
,
3090 if (!NT_SUCCESS(Status
))
3092 return RtlNtStatusToDosError(Status
);
3095 Status
= NtFlushKey(KeyHandle
);
3097 ClosePredefKey(KeyHandle
);
3099 if (!NT_SUCCESS(Status
))
3101 return RtlNtStatusToDosError(Status
);
3104 return ERROR_SUCCESS
;
3108 /************************************************************************
3114 RegGetKeySecurity(HKEY hKey
,
3115 SECURITY_INFORMATION SecurityInformation
,
3116 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3117 LPDWORD lpcbSecurityDescriptor
)
3122 if (hKey
== HKEY_PERFORMANCE_DATA
)
3124 return ERROR_INVALID_HANDLE
;
3127 Status
= MapDefaultKey(&KeyHandle
,
3129 if (!NT_SUCCESS(Status
))
3131 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3132 return RtlNtStatusToDosError(Status
);
3135 Status
= NtQuerySecurityObject(KeyHandle
,
3136 SecurityInformation
,
3137 pSecurityDescriptor
,
3138 *lpcbSecurityDescriptor
,
3139 lpcbSecurityDescriptor
);
3141 ClosePredefKey(KeyHandle
);
3143 if (!NT_SUCCESS(Status
))
3145 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3146 return RtlNtStatusToDosError(Status
);
3149 return ERROR_SUCCESS
;
3153 /************************************************************************
3159 RegLoadKeyA(HKEY hKey
,
3163 UNICODE_STRING FileName
;
3164 UNICODE_STRING KeyName
;
3167 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3169 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3172 ErrorCode
= RegLoadKeyW(hKey
,
3176 RtlFreeUnicodeString(&FileName
);
3177 RtlFreeUnicodeString(&KeyName
);
3183 /************************************************************************
3189 RegLoadKeyW(HKEY hKey
,
3193 OBJECT_ATTRIBUTES FileObjectAttributes
;
3194 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3195 UNICODE_STRING FileName
;
3196 UNICODE_STRING KeyName
;
3199 LONG ErrorCode
= ERROR_SUCCESS
;
3201 if (hKey
== HKEY_PERFORMANCE_DATA
)
3203 return ERROR_INVALID_HANDLE
;
3206 Status
= MapDefaultKey(&KeyHandle
,
3208 if (!NT_SUCCESS(Status
))
3210 return RtlNtStatusToDosError(Status
);
3213 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3218 ErrorCode
= ERROR_BAD_PATHNAME
;
3222 InitializeObjectAttributes(&FileObjectAttributes
,
3224 OBJ_CASE_INSENSITIVE
,
3228 RtlInitUnicodeString(&KeyName
,
3231 InitializeObjectAttributes(&KeyObjectAttributes
,
3233 OBJ_CASE_INSENSITIVE
,
3237 Status
= NtLoadKey(&KeyObjectAttributes
,
3238 &FileObjectAttributes
);
3240 RtlFreeHeap(RtlGetProcessHeap(),
3244 if (!NT_SUCCESS(Status
))
3246 ErrorCode
= RtlNtStatusToDosError(Status
);
3251 ClosePredefKey(KeyHandle
);
3257 /************************************************************************
3258 * RegNotifyChangeKeyValue
3263 RegNotifyChangeKeyValue(HKEY hKey
,
3265 DWORD dwNotifyFilter
,
3269 IO_STATUS_BLOCK IoStatusBlock
;
3272 LONG ErrorCode
= ERROR_SUCCESS
;
3274 if (hKey
== HKEY_PERFORMANCE_DATA
)
3276 return ERROR_INVALID_HANDLE
;
3279 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3281 return ERROR_INVALID_PARAMETER
;
3284 Status
= MapDefaultKey(&KeyHandle
,
3286 if (!NT_SUCCESS(Status
))
3288 return RtlNtStatusToDosError(Status
);
3291 /* FIXME: Remote key handles must fail */
3293 Status
= NtNotifyChangeKey(KeyHandle
,
3303 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3305 ErrorCode
= RtlNtStatusToDosError(Status
);
3308 ClosePredefKey(KeyHandle
);
3314 /************************************************************************
3315 * RegOpenCurrentUser
3320 RegOpenCurrentUser(IN REGSAM samDesired
,
3321 OUT PHKEY phkResult
)
3325 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3326 (PHANDLE
)phkResult
);
3327 if (!NT_SUCCESS(Status
))
3329 /* NOTE - don't set the last error code! just return the error! */
3330 return RtlNtStatusToDosError(Status
);
3333 return ERROR_SUCCESS
;
3337 /************************************************************************
3340 * 20050503 Fireball - imported from WINE
3345 RegOpenKeyA(HKEY hKey
,
3349 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3350 hKey
, lpSubKey
, phkResult
);
3353 return ERROR_INVALID_PARAMETER
;
3355 if (!hKey
&& lpSubKey
&& phkResult
)
3357 return ERROR_INVALID_HANDLE
;
3360 if (!lpSubKey
|| !*lpSubKey
)
3363 return ERROR_SUCCESS
;
3366 return RegOpenKeyExA(hKey
,
3374 /************************************************************************
3379 * 20050503 Fireball - imported from WINE
3384 RegOpenKeyW(HKEY hKey
,
3388 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3389 hKey
, lpSubKey
, phkResult
);
3392 return ERROR_INVALID_PARAMETER
;
3394 if (!hKey
&& lpSubKey
&& phkResult
)
3396 return ERROR_INVALID_HANDLE
;
3399 if (!lpSubKey
|| !*lpSubKey
)
3402 return ERROR_SUCCESS
;
3405 return RegOpenKeyExW(hKey
,
3413 /************************************************************************
3421 _In_ LPCSTR lpSubKey
,
3422 _In_ DWORD ulOptions
,
3423 _In_ REGSAM samDesired
,
3424 _Out_ PHKEY phkResult
)
3426 UNICODE_STRING SubKeyString
;
3429 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3430 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);