3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/reg/reg.c
6 * PURPOSE: Registry functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
18 #include <wine/debug.h>
20 /* DEFINES ******************************************************************/
22 #define MAX_DEFAULT_HANDLES 6
23 #define REG_MAX_NAME_SIZE 256
24 #define REG_MAX_DATA_SIZE 2048
26 /* FIXME: should go into msvcrt.h header? */
27 #define offsetof(s,m) (size_t)&(((s*)NULL)->m)
29 /* GLOBALS ******************************************************************/
31 static RTL_CRITICAL_SECTION HandleTableCS
;
32 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
33 static HANDLE ProcessHeap
;
34 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
36 /* PROTOTYPES ***************************************************************/
38 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
39 static VOID
CloseDefaultKeys(VOID
);
40 #define CloseDefaultKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
45 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
46 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
47 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
48 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
51 /* FUNCTIONS ****************************************************************/
52 /* check if value type needs string conversion (Ansi<->Unicode) */
53 inline static int is_string( DWORD type
)
55 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
58 /************************************************************************
59 * RegInitDefaultHandles
64 TRACE("RegInitialize()\n");
66 ProcessHeap
= RtlGetProcessHeap();
67 RtlZeroMemory (DefaultHandleTable
,
68 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
69 RtlInitializeCriticalSection (&HandleTableCS
);
75 /************************************************************************
81 TRACE("RegCleanup()\n");
84 RtlDeleteCriticalSection (&HandleTableCS
);
91 MapDefaultKey (OUT PHANDLE RealKey
,
97 NTSTATUS Status
= STATUS_SUCCESS
;
99 TRACE("MapDefaultKey (Key %x)\n", Key
);
101 if (((ULONG
)Key
& 0xF0000000) != 0x80000000)
103 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
104 return STATUS_SUCCESS
;
107 /* Handle special cases here */
108 Index
= (ULONG
)Key
& 0x0FFFFFFF;
109 if (Index
>= MAX_DEFAULT_HANDLES
)
111 return STATUS_INVALID_PARAMETER
;
114 RtlEnterCriticalSection (&HandleTableCS
);
116 if (!DefaultHandlesDisabled
)
118 Handle
= &DefaultHandleTable
[Index
];
119 DoOpen
= (*Handle
== NULL
);
129 /* create/open the default handle */
132 case 0: /* HKEY_CLASSES_ROOT */
133 Status
= OpenClassesRootKey (Handle
);
136 case 1: /* HKEY_CURRENT_USER */
137 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
141 case 2: /* HKEY_LOCAL_MACHINE */
142 Status
= OpenLocalMachineKey (Handle
);
145 case 3: /* HKEY_USERS */
146 Status
= OpenUsersKey (Handle
);
149 case 4: /* HKEY_PERFORMANCE_DATA */
150 Status
= OpenPerformanceDataKey (Handle
);
153 case 5: /* HKEY_CURRENT_CONFIG */
154 Status
= OpenCurrentConfigKey (Handle
);
157 case 6: /* HKEY_DYN_DATA */
158 Status
= STATUS_NOT_IMPLEMENTED
;
162 WARN("MapDefaultHandle() no handle creator\n");
163 Status
= STATUS_INVALID_PARAMETER
;
168 if (NT_SUCCESS(Status
))
170 if (!DefaultHandlesDisabled
)
173 *(PULONG_PTR
)Handle
|= 0x1;
176 RtlLeaveCriticalSection (&HandleTableCS
);
183 CloseDefaultKeys (VOID
)
187 RtlEnterCriticalSection (&HandleTableCS
);
188 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
190 if (DefaultHandleTable
[i
] != NULL
)
192 NtClose (DefaultHandleTable
[i
]);
193 DefaultHandleTable
[i
] = NULL
;
196 RtlLeaveCriticalSection (&HandleTableCS
);
201 OpenClassesRootKey (PHANDLE KeyHandle
)
203 OBJECT_ATTRIBUTES Attributes
;
204 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
206 TRACE("OpenClassesRootKey()\n");
208 InitializeObjectAttributes (&Attributes
,
210 OBJ_CASE_INSENSITIVE
,
213 return NtOpenKey (KeyHandle
,
220 OpenLocalMachineKey (PHANDLE KeyHandle
)
222 OBJECT_ATTRIBUTES Attributes
;
223 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
226 TRACE("OpenLocalMachineKey()\n");
228 InitializeObjectAttributes (&Attributes
,
230 OBJ_CASE_INSENSITIVE
,
233 Status
= NtOpenKey (KeyHandle
,
237 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
243 OpenUsersKey (PHANDLE KeyHandle
)
245 OBJECT_ATTRIBUTES Attributes
;
246 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
248 TRACE("OpenUsersKey()\n");
250 InitializeObjectAttributes (&Attributes
,
252 OBJ_CASE_INSENSITIVE
,
255 return NtOpenKey (KeyHandle
,
262 OpenCurrentConfigKey (PHANDLE KeyHandle
)
264 OBJECT_ATTRIBUTES Attributes
;
265 UNICODE_STRING KeyName
=
266 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
268 TRACE("OpenCurrentConfigKey()\n");
270 InitializeObjectAttributes (&Attributes
,
272 OBJ_CASE_INSENSITIVE
,
275 return NtOpenKey (KeyHandle
,
281 /************************************************************************
282 * RegDisablePredefinedCacheEx
287 RegDisablePredefinedCacheEx(VOID
)
289 RtlEnterCriticalSection (&HandleTableCS
);
290 DefaultHandlesDisabled
= TRUE
;
291 RtlLeaveCriticalSection (&HandleTableCS
);
292 return ERROR_SUCCESS
;
296 /************************************************************************
302 RegCloseKey (HKEY hKey
)
306 /* don't close null handle or a pseudo handle */
307 if ((!hKey
) || (((ULONG
)hKey
& 0xF0000000) == 0x80000000))
309 return ERROR_INVALID_HANDLE
;
312 Status
= NtClose (hKey
);
313 if (!NT_SUCCESS(Status
))
315 return RtlNtStatusToDosError (Status
);
318 return ERROR_SUCCESS
;
322 /************************************************************************
323 * RegConnectRegistryA
328 RegConnectRegistryA (LPCSTR lpMachineName
,
332 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
333 return ERROR_CALL_NOT_IMPLEMENTED
;
337 /************************************************************************
343 RegCopyTreeW(IN HKEY hKeySrc
,
344 IN LPCWSTR lpSubKey OPTIONAL
,
347 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
350 Status
= MapDefaultKey(&KeyHandle
,
352 if (!NT_SUCCESS(Status
))
354 return RtlNtStatusToDosError(Status
);
357 Status
= MapDefaultKey(&DestKeyHandle
,
359 if (!NT_SUCCESS(Status
))
364 if (lpSubKey
!= NULL
)
366 OBJECT_ATTRIBUTES ObjectAttributes
;
367 UNICODE_STRING SubKeyName
;
369 RtlInitUnicodeString(&SubKeyName
,
372 InitializeObjectAttributes(&ObjectAttributes
,
374 OBJ_CASE_INSENSITIVE
,
378 Status
= NtOpenKey(&SubKeyHandle
,
381 if (!NT_SUCCESS(Status
))
386 CurKey
= SubKeyHandle
;
391 /* FIXME - copy all keys and values recursively */
392 Status
= STATUS_NOT_IMPLEMENTED
;
394 if (SubKeyHandle
!= NULL
)
396 NtClose(SubKeyHandle
);
400 CloseDefaultKey(DestKeyHandle
);
402 CloseDefaultKey(KeyHandle
);
404 if (!NT_SUCCESS(Status
))
406 return RtlNtStatusToDosError(Status
);
409 return ERROR_SUCCESS
;
413 /************************************************************************
419 RegCopyTreeA(IN HKEY hKeySrc
,
420 IN LPCSTR lpSubKey OPTIONAL
,
423 UNICODE_STRING SubKeyName
;
426 if (lpSubKey
!= NULL
)
428 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
431 return ERROR_NOT_ENOUGH_MEMORY
;
435 RtlInitUnicodeString(&SubKeyName
,
438 Ret
= RegCopyTreeW(hKeySrc
,
442 RtlFreeUnicodeString(&SubKeyName
);
448 /************************************************************************
449 * RegConnectRegistryW
454 RegConnectRegistryW (LPCWSTR lpMachineName
,
458 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
459 return ERROR_CALL_NOT_IMPLEMENTED
;
463 /************************************************************************
466 * Create key and all necessary intermediate keys
469 CreateNestedKey(PHKEY KeyHandle
,
470 POBJECT_ATTRIBUTES ObjectAttributes
,
471 PUNICODE_STRING ClassString
,
474 DWORD
*lpdwDisposition
)
476 OBJECT_ATTRIBUTES LocalObjectAttributes
;
477 UNICODE_STRING LocalKeyName
;
480 ULONG FullNameLength
;
483 HANDLE LocalKeyHandle
;
485 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
491 (PULONG
)lpdwDisposition
);
492 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
493 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
496 /* Copy object attributes */
497 RtlCopyMemory (&LocalObjectAttributes
,
499 sizeof(OBJECT_ATTRIBUTES
));
500 RtlCreateUnicodeString (&LocalKeyName
,
501 ObjectAttributes
->ObjectName
->Buffer
);
502 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
503 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
505 /* Remove the last part of the key name and try to create the key again. */
506 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
508 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
509 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
511 Status
= STATUS_UNSUCCESSFUL
;
515 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
517 Status
= NtCreateKey (&LocalKeyHandle
,
519 &LocalObjectAttributes
,
524 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
527 if (!NT_SUCCESS(Status
))
529 RtlFreeUnicodeString (&LocalKeyName
);
533 /* Add removed parts of the key name and create them too. */
534 Length
= wcslen (LocalKeyName
.Buffer
);
537 NtClose (LocalKeyHandle
);
539 LocalKeyName
.Buffer
[Length
] = L
'\\';
540 Length
= wcslen (LocalKeyName
.Buffer
);
541 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
543 if (Length
== FullNameLength
)
545 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
551 (PULONG
)lpdwDisposition
);
554 Status
= NtCreateKey (&LocalKeyHandle
,
556 &LocalObjectAttributes
,
561 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
562 if (!NT_SUCCESS(Status
))
566 RtlFreeUnicodeString (&LocalKeyName
);
572 /************************************************************************
578 RegCreateKeyExA (HKEY hKey
,
584 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
586 LPDWORD lpdwDisposition
)
588 UNICODE_STRING SubKeyString
;
589 UNICODE_STRING ClassString
;
590 OBJECT_ATTRIBUTES Attributes
;
594 TRACE("RegCreateKeyExA() called\n");
596 /* get the real parent key */
597 Status
= MapDefaultKey (&ParentKey
,
599 if (!NT_SUCCESS(Status
))
601 return RtlNtStatusToDosError (Status
);
603 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
607 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
611 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
613 InitializeObjectAttributes (&Attributes
,
615 OBJ_CASE_INSENSITIVE
,
617 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
618 Status
= CreateNestedKey(phkResult
,
620 (lpClass
== NULL
)? NULL
: &ClassString
,
624 RtlFreeUnicodeString (&SubKeyString
);
627 RtlFreeUnicodeString (&ClassString
);
630 CloseDefaultKey(ParentKey
);
632 TRACE("Status %x\n", Status
);
633 if (!NT_SUCCESS(Status
))
635 return RtlNtStatusToDosError (Status
);
638 return ERROR_SUCCESS
;
642 /************************************************************************
648 RegCreateKeyExW (HKEY hKey
,
654 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
656 LPDWORD lpdwDisposition
)
658 UNICODE_STRING SubKeyString
;
659 UNICODE_STRING ClassString
;
660 OBJECT_ATTRIBUTES Attributes
;
664 TRACE("RegCreateKeyExW() called\n");
666 /* get the real parent key */
667 Status
= MapDefaultKey (&ParentKey
,
669 if (!NT_SUCCESS(Status
))
671 return RtlNtStatusToDosError(Status
);
673 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
675 RtlInitUnicodeString (&ClassString
,
677 RtlInitUnicodeString (&SubKeyString
,
679 InitializeObjectAttributes (&Attributes
,
681 OBJ_CASE_INSENSITIVE
,
683 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
684 Status
= CreateNestedKey(phkResult
,
686 (lpClass
== NULL
)? NULL
: &ClassString
,
691 CloseDefaultKey(ParentKey
);
693 TRACE("Status %x\n", Status
);
694 if (!NT_SUCCESS(Status
))
696 return RtlNtStatusToDosError (Status
);
699 return ERROR_SUCCESS
;
703 /************************************************************************
709 RegCreateKeyA (HKEY hKey
,
713 return RegCreateKeyExA (hKey
,
725 /************************************************************************
731 RegCreateKeyW (HKEY hKey
,
735 return RegCreateKeyExW (hKey
,
747 /************************************************************************
753 RegDeleteKeyA (HKEY hKey
,
756 OBJECT_ATTRIBUTES ObjectAttributes
;
757 UNICODE_STRING SubKeyName
;
762 Status
= MapDefaultKey (&ParentKey
,
764 if (!NT_SUCCESS(Status
))
766 return RtlNtStatusToDosError (Status
);
769 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
771 InitializeObjectAttributes(&ObjectAttributes
,
773 OBJ_CASE_INSENSITIVE
,
777 Status
= NtOpenKey (&TargetKey
,
780 RtlFreeUnicodeString (&SubKeyName
);
781 if (!NT_SUCCESS(Status
))
786 Status
= NtDeleteKey (TargetKey
);
790 CloseDefaultKey(ParentKey
);
792 if (!NT_SUCCESS(Status
))
794 return RtlNtStatusToDosError(Status
);
797 return ERROR_SUCCESS
;
801 /************************************************************************
807 RegDeleteKeyW (HKEY hKey
,
810 OBJECT_ATTRIBUTES ObjectAttributes
;
811 UNICODE_STRING SubKeyName
;
816 Status
= MapDefaultKey (&ParentKey
,
818 if (!NT_SUCCESS(Status
))
820 return RtlNtStatusToDosError (Status
);
823 RtlInitUnicodeString (&SubKeyName
,
825 InitializeObjectAttributes (&ObjectAttributes
,
827 OBJ_CASE_INSENSITIVE
,
830 Status
= NtOpenKey (&TargetKey
,
833 if (!NT_SUCCESS(Status
))
838 Status
= NtDeleteKey (TargetKey
);
842 CloseDefaultKey(ParentKey
);
844 if (!NT_SUCCESS(Status
))
846 return RtlNtStatusToDosError (Status
);
849 return ERROR_SUCCESS
;
853 /************************************************************************
859 RegDeleteKeyValueW(IN HKEY hKey
,
860 IN LPCWSTR lpSubKey OPTIONAL
,
861 IN LPCWSTR lpValueName OPTIONAL
)
863 UNICODE_STRING ValueName
;
864 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
867 Status
= MapDefaultKey(&KeyHandle
,
869 if (!NT_SUCCESS(Status
))
871 return RtlNtStatusToDosError(Status
);
874 if (lpSubKey
!= NULL
)
876 OBJECT_ATTRIBUTES ObjectAttributes
;
877 UNICODE_STRING SubKeyName
;
879 RtlInitUnicodeString(&SubKeyName
,
882 InitializeObjectAttributes(&ObjectAttributes
,
884 OBJ_CASE_INSENSITIVE
,
888 Status
= NtOpenKey(&SubKeyHandle
,
891 if (!NT_SUCCESS(Status
))
896 CurKey
= SubKeyHandle
;
901 RtlInitUnicodeString(&ValueName
,
902 (LPWSTR
)lpValueName
);
904 Status
= NtDeleteValueKey(CurKey
,
907 if (SubKeyHandle
!= NULL
)
909 NtClose(SubKeyHandle
);
913 CloseDefaultKey(KeyHandle
);
915 if (!NT_SUCCESS(Status
))
917 return RtlNtStatusToDosError(Status
);
920 return ERROR_SUCCESS
;
924 /************************************************************************
930 RegDeleteKeyValueA(IN HKEY hKey
,
931 IN LPCSTR lpSubKey OPTIONAL
,
932 IN LPCSTR lpValueName OPTIONAL
)
934 UNICODE_STRING SubKey
, ValueName
;
937 if (lpSubKey
!= NULL
)
939 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey
,
942 return ERROR_NOT_ENOUGH_MEMORY
;
946 RtlInitUnicodeString(&SubKey
,
949 if (lpValueName
!= NULL
)
951 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName
,
954 RtlFreeUnicodeString(&SubKey
);
955 return ERROR_NOT_ENOUGH_MEMORY
;
959 RtlInitUnicodeString(&ValueName
,
962 Ret
= RegDeleteKeyValueW(hKey
,
966 RtlFreeUnicodeString(&SubKey
);
967 RtlFreeUnicodeString(&ValueName
);
974 RegpDeleteTree(IN HKEY hKey
)
978 LIST_ENTRY ListEntry
;
980 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
982 LIST_ENTRY delQueueHead
;
983 PREG_DEL_KEYS delKeys
= NULL
, newDelKeys
;
986 PKEY_BASIC_INFORMATION BasicInfo
;
987 PREG_DEL_KEYS KeyDelRoot
;
988 NTSTATUS Status
= STATUS_SUCCESS
;
989 NTSTATUS Status2
= STATUS_SUCCESS
;
991 InitializeListHead(&delQueueHead
);
993 ProcessHeap
= RtlGetProcessHeap();
995 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
996 structure for the root key, we only do that for subkeys as we need to
997 allocate REGP_DEL_KEYS structures anyway! */
998 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1000 sizeof(REGP_DEL_KEYS
));
1001 if (KeyDelRoot
!= NULL
)
1003 KeyDelRoot
->KeyHandle
= hKey
;
1004 InsertTailList(&delQueueHead
,
1005 &KeyDelRoot
->ListEntry
);
1009 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1018 /* check if this key contains subkeys and delete them first by queuing
1019 them at the head of the list */
1020 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1022 KeyBasicInformation
,
1027 if (NT_SUCCESS(Status2
))
1029 OBJECT_ATTRIBUTES ObjectAttributes
;
1030 UNICODE_STRING SubKeyName
;
1032 ASSERT(newDelKeys
!= NULL
);
1033 ASSERT(BasicInfo
!= NULL
);
1035 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1036 SubKeyName
.Length
= BasicInfo
->NameLength
;
1037 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1038 SubKeyName
.Buffer
= BasicInfo
->Name
;
1040 InitializeObjectAttributes(&ObjectAttributes
,
1042 OBJ_CASE_INSENSITIVE
,
1046 /* open the subkey */
1047 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1048 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1050 if (!NT_SUCCESS(Status2
))
1055 /* enqueue this key to the head of the deletion queue */
1056 InsertHeadList(&delQueueHead
,
1057 &newDelKeys
->ListEntry
);
1059 /* try again from the head of the list */
1064 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1066 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1068 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1069 if (newDelKeys
!= NULL
)
1071 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1074 goto ReadFirstSubKey
;
1078 /* don't break, let's try to delete as many keys as possible */
1079 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1080 goto SubKeyFailureNoFree
;
1083 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1085 PREG_DEL_KEYS newDelKeys2
;
1087 ASSERT(newDelKeys
!= NULL
);
1089 /* we need more memory to query the key name */
1090 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1093 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1094 if (newDelKeys2
!= NULL
)
1096 newDelKeys
= newDelKeys2
;
1097 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1100 goto ReadFirstSubKey
;
1104 /* don't break, let's try to delete as many keys as possible */
1105 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1109 RtlFreeHeap(ProcessHeap
,
1112 SubKeyFailureNoFree
:
1113 /* don't break, let's try to delete as many keys as possible */
1114 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
1120 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1122 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1124 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
1126 /* don't break, let's try to delete as many keys as possible */
1130 /* remove the entry from the list */
1131 RemoveEntryList(&delKeys
->ListEntry
);
1133 RtlFreeHeap(ProcessHeap
,
1136 } while (!IsListEmpty(&delQueueHead
));
1139 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1145 /************************************************************************
1151 RegDeleteTreeW(IN HKEY hKey
,
1152 IN LPCWSTR lpSubKey OPTIONAL
)
1154 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1157 Status
= MapDefaultKey(&KeyHandle
,
1159 if (!NT_SUCCESS(Status
))
1161 return RtlNtStatusToDosError(Status
);
1164 if (lpSubKey
!= NULL
)
1166 OBJECT_ATTRIBUTES ObjectAttributes
;
1167 UNICODE_STRING SubKeyName
;
1169 RtlInitUnicodeString(&SubKeyName
,
1172 InitializeObjectAttributes(&ObjectAttributes
,
1174 OBJ_CASE_INSENSITIVE
,
1178 Status
= NtOpenKey(&SubKeyHandle
,
1179 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1181 if (!NT_SUCCESS(Status
))
1186 CurKey
= SubKeyHandle
;
1191 Status
= RegpDeleteTree(CurKey
);
1193 if (SubKeyHandle
!= NULL
)
1195 NtClose(SubKeyHandle
);
1199 CloseDefaultKey(KeyHandle
);
1201 if (!NT_SUCCESS(Status
))
1203 return RtlNtStatusToDosError(Status
);
1206 return ERROR_SUCCESS
;
1210 /************************************************************************
1216 RegDeleteTreeA(IN HKEY hKey
,
1217 IN LPCSTR lpSubKey OPTIONAL
)
1219 UNICODE_STRING SubKeyName
;
1222 if (lpSubKey
!= NULL
)
1224 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1227 return ERROR_NOT_ENOUGH_MEMORY
;
1231 RtlInitUnicodeString(&SubKeyName
,
1234 Ret
= RegDeleteTreeW(hKey
,
1237 RtlFreeUnicodeString(&SubKeyName
);
1243 /************************************************************************
1249 RegSetKeyValueW(IN HKEY hKey
,
1250 IN LPCWSTR lpSubKey OPTIONAL
,
1251 IN LPCWSTR lpValueName OPTIONAL
,
1253 IN LPCVOID lpData OPTIONAL
,
1256 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1260 Status
= MapDefaultKey(&KeyHandle
,
1262 if (!NT_SUCCESS(Status
))
1264 return RtlNtStatusToDosError(Status
);
1267 if (lpSubKey
!= NULL
)
1269 OBJECT_ATTRIBUTES ObjectAttributes
;
1270 UNICODE_STRING SubKeyName
;
1272 RtlInitUnicodeString(&SubKeyName
,
1275 InitializeObjectAttributes(&ObjectAttributes
,
1277 OBJ_CASE_INSENSITIVE
,
1281 Status
= NtOpenKey(&SubKeyHandle
,
1284 if (!NT_SUCCESS(Status
))
1286 Ret
= RtlNtStatusToDosError(Status
);
1290 CurKey
= SubKeyHandle
;
1295 Ret
= RegSetValueExW(CurKey
,
1302 if (SubKeyHandle
!= NULL
)
1304 NtClose(SubKeyHandle
);
1308 CloseDefaultKey(KeyHandle
);
1314 /************************************************************************
1320 RegSetKeyValueA(IN HKEY hKey
,
1321 IN LPCSTR lpSubKey OPTIONAL
,
1322 IN LPCSTR lpValueName OPTIONAL
,
1324 IN LPCVOID lpData OPTIONAL
,
1327 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1331 Status
= MapDefaultKey(&KeyHandle
,
1333 if (!NT_SUCCESS(Status
))
1335 return RtlNtStatusToDosError(Status
);
1338 if (lpSubKey
!= NULL
)
1340 OBJECT_ATTRIBUTES ObjectAttributes
;
1341 UNICODE_STRING SubKeyName
;
1343 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1346 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
1350 InitializeObjectAttributes(&ObjectAttributes
,
1352 OBJ_CASE_INSENSITIVE
,
1356 Status
= NtOpenKey(&SubKeyHandle
,
1360 RtlFreeUnicodeString(&SubKeyName
);
1362 if (!NT_SUCCESS(Status
))
1364 Ret
= RtlNtStatusToDosError(Status
);
1368 CurKey
= SubKeyHandle
;
1373 Ret
= RegSetValueExA(CurKey
,
1380 if (SubKeyHandle
!= NULL
)
1382 NtClose(SubKeyHandle
);
1386 CloseDefaultKey(KeyHandle
);
1392 /************************************************************************
1398 RegDeleteValueA (HKEY hKey
,
1401 UNICODE_STRING ValueName
;
1405 Status
= MapDefaultKey (&KeyHandle
,
1407 if (!NT_SUCCESS(Status
))
1409 return RtlNtStatusToDosError (Status
);
1412 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
1413 (LPSTR
)lpValueName
);
1414 Status
= NtDeleteValueKey (KeyHandle
,
1416 RtlFreeUnicodeString (&ValueName
);
1418 CloseDefaultKey(KeyHandle
);
1420 if (!NT_SUCCESS(Status
))
1422 return RtlNtStatusToDosError (Status
);
1425 return ERROR_SUCCESS
;
1429 /************************************************************************
1435 RegDeleteValueW (HKEY hKey
,
1436 LPCWSTR lpValueName
)
1438 UNICODE_STRING ValueName
;
1442 Status
= MapDefaultKey (&KeyHandle
,
1444 if (!NT_SUCCESS(Status
))
1446 return RtlNtStatusToDosError (Status
);
1449 RtlInitUnicodeString (&ValueName
,
1450 (LPWSTR
)lpValueName
);
1452 Status
= NtDeleteValueKey (KeyHandle
,
1455 CloseDefaultKey(KeyHandle
);
1457 if (!NT_SUCCESS(Status
))
1459 return RtlNtStatusToDosError (Status
);
1462 return ERROR_SUCCESS
;
1466 /************************************************************************
1472 RegEnumKeyA (HKEY hKey
,
1480 return RegEnumKeyExA (hKey
,
1491 /************************************************************************
1497 RegEnumKeyW (HKEY hKey
,
1505 return RegEnumKeyExW (hKey
,
1516 /************************************************************************
1522 RegEnumKeyExA (HKEY hKey
,
1529 PFILETIME lpftLastWriteTime
)
1533 KEY_NODE_INFORMATION Node
;
1534 KEY_BASIC_INFORMATION Basic
;
1537 UNICODE_STRING StringU
;
1538 ANSI_STRING StringA
;
1539 LONG ErrorCode
= ERROR_SUCCESS
;
1541 DWORD ClassLength
= 0;
1547 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1548 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
1550 if ((lpClass
) && (!lpcbClass
))
1552 return ERROR_INVALID_PARAMETER
;
1555 Status
= MapDefaultKey(&KeyHandle
, hKey
);
1556 if (!NT_SUCCESS(Status
))
1558 return RtlNtStatusToDosError (Status
);
1563 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1574 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1581 /* The class name should start at a dword boundary */
1582 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1586 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1589 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
1590 if (KeyInfo
== NULL
)
1592 ErrorCode
= ERROR_OUTOFMEMORY
;
1596 Status
= NtEnumerateKey (KeyHandle
,
1598 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
1602 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1603 if (!NT_SUCCESS(Status
))
1605 ErrorCode
= RtlNtStatusToDosError (Status
);
1609 if (lpClass
== NULL
)
1611 if (KeyInfo
->Basic
.NameLength
> NameLength
)
1613 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1617 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
1618 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
1619 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
1624 if (KeyInfo
->Node
.NameLength
> NameLength
||
1625 KeyInfo
->Node
.ClassLength
> ClassLength
)
1627 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1631 StringA
.Buffer
= lpClass
;
1633 StringA
.MaximumLength
= *lpcbClass
;
1634 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
1635 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
1636 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
1637 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
1638 lpClass
[StringA
.Length
] = 0;
1639 *lpcbClass
= StringA
.Length
;
1640 StringU
.Buffer
= KeyInfo
->Node
.Name
;
1641 StringU
.Length
= KeyInfo
->Node
.NameLength
;
1642 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
1646 if (ErrorCode
== ERROR_SUCCESS
)
1648 StringA
.Buffer
= lpName
;
1650 StringA
.MaximumLength
= *lpcbName
;
1651 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
1652 lpName
[StringA
.Length
] = 0;
1653 *lpcbName
= StringA
.Length
;
1654 if (lpftLastWriteTime
!= NULL
)
1656 if (lpClass
== NULL
)
1658 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
1659 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
1663 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
1664 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
1670 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
1671 TRACE("Key Namea1 Length %d\n", NameLength
);
1672 TRACE("Key Namea Length %d\n", *lpcbName
);
1673 TRACE("Key Namea %s\n", lpName
);
1675 RtlFreeHeap (ProcessHeap
,
1680 CloseDefaultKey(KeyHandle
);
1686 /************************************************************************
1692 RegEnumKeyExW (HKEY hKey
,
1699 PFILETIME lpftLastWriteTime
)
1703 KEY_NODE_INFORMATION Node
;
1704 KEY_BASIC_INFORMATION Basic
;
1710 ULONG ClassLength
= 0;
1712 LONG ErrorCode
= ERROR_SUCCESS
;
1715 Status
= MapDefaultKey(&KeyHandle
,
1717 if (!NT_SUCCESS(Status
))
1719 return RtlNtStatusToDosError (Status
);
1724 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1735 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1742 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1746 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1749 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
1752 if (KeyInfo
== NULL
)
1754 ErrorCode
= ERROR_OUTOFMEMORY
;
1758 Status
= NtEnumerateKey (KeyHandle
,
1760 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
1764 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1765 if (!NT_SUCCESS(Status
))
1767 ErrorCode
= RtlNtStatusToDosError (Status
);
1771 if (lpClass
== NULL
)
1773 if (KeyInfo
->Basic
.NameLength
> NameLength
)
1775 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1779 RtlCopyMemory (lpName
,
1780 KeyInfo
->Basic
.Name
,
1781 KeyInfo
->Basic
.NameLength
);
1782 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
1783 lpName
[*lpcbName
] = 0;
1788 if (KeyInfo
->Node
.NameLength
> NameLength
||
1789 KeyInfo
->Node
.ClassLength
> ClassLength
)
1791 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1795 RtlCopyMemory (lpName
,
1797 KeyInfo
->Node
.NameLength
);
1798 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
1799 lpName
[*lpcbName
] = 0;
1800 RtlCopyMemory (lpClass
,
1801 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
1802 KeyInfo
->Node
.ClassLength
);
1803 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
1804 lpClass
[*lpcbClass
] = 0;
1808 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
1810 if (lpClass
== NULL
)
1812 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
1813 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
1817 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
1818 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
1823 RtlFreeHeap (ProcessHeap
,
1828 CloseDefaultKey(KeyHandle
);
1833 /************************************************************************
1839 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1840 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1845 char buffer
[256], *buf_ptr
= buffer
;
1846 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1847 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1849 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1850 // hkey, index, value, val_count, reserved, type, data, count );
1852 /* NT only checks count, not val_count */
1853 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1854 status
= MapDefaultKey (&KeyHandle
, hKey
);
1855 if (!NT_SUCCESS(status
))
1857 return RtlNtStatusToDosError (status
);
1860 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1861 if (data
) total_size
+= *count
;
1862 total_size
= min( sizeof(buffer
), total_size
);
1864 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
1865 buffer
, total_size
, &total_size
);
1866 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1868 /* we need to fetch the contents for a string type even if not requested,
1869 * because we need to compute the length of the ASCII string. */
1870 if (value
|| data
|| is_string(info
->Type
))
1872 /* retry with a dynamically allocated buffer */
1873 while (status
== STATUS_BUFFER_OVERFLOW
)
1875 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1876 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1878 status
= STATUS_INSUFFICIENT_RESOURCES
;
1881 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1882 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
1883 buf_ptr
, total_size
, &total_size
);
1886 if (status
) goto done
;
1888 if (is_string(info
->Type
))
1891 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1892 total_size
- info
->DataOffset
);
1895 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1898 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1899 total_size
- info
->DataOffset
);
1900 /* if the type is REG_SZ and data is not 0-terminated
1901 * and there is enough space in the buffer NT appends a \0 */
1902 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1905 info
->DataLength
= len
;
1909 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1910 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1913 if (value
&& !status
)
1917 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1918 if (len
>= *val_count
)
1920 status
= STATUS_BUFFER_OVERFLOW
;
1923 len
= *val_count
- 1;
1924 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1930 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1936 else status
= STATUS_SUCCESS
;
1938 if (type
) *type
= info
->Type
;
1939 if (count
) *count
= info
->DataLength
;
1942 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1943 CloseDefaultKey(KeyHandle
);
1944 return RtlNtStatusToDosError(status
);
1947 /******************************************************************************
1948 * RegEnumValueW [ADVAPI32.@]
1952 * hkey [I] Handle to key to query
1953 * index [I] Index of value to query
1954 * value [O] Value string
1955 * val_count [I/O] Size of value buffer (in wchars)
1956 * reserved [I] Reserved
1957 * type [O] Type code
1958 * data [O] Value data
1959 * count [I/O] Size of data buffer (in bytes)
1962 * Success: ERROR_SUCCESS
1963 * Failure: nonzero error code from Winerror.h
1966 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
1967 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
1972 char buffer
[256], *buf_ptr
= buffer
;
1973 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1974 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1976 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1977 // hkey, index, value, val_count, reserved, type, data, count );
1979 /* NT only checks count, not val_count */
1980 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1982 status
= MapDefaultKey (&KeyHandle
, hKey
);
1983 if (!NT_SUCCESS(status
))
1985 return RtlNtStatusToDosError (status
);
1988 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1989 if (data
) total_size
+= *count
;
1990 total_size
= min( sizeof(buffer
), total_size
);
1992 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
1993 buffer
, total_size
, &total_size
);
1994 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1998 /* retry with a dynamically allocated buffer */
1999 while (status
== STATUS_BUFFER_OVERFLOW
)
2001 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2002 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2004 status
= ERROR_NOT_ENOUGH_MEMORY
;
2007 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2008 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2009 buf_ptr
, total_size
, &total_size
);
2012 if (status
) goto done
;
2016 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2018 status
= STATUS_BUFFER_OVERFLOW
;
2021 memcpy( value
, info
->Name
, info
->NameLength
);
2022 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2023 value
[*val_count
] = 0;
2028 if (total_size
- info
->DataOffset
> *count
)
2030 status
= STATUS_BUFFER_OVERFLOW
;
2033 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2034 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2036 /* if the type is REG_SZ and data is not 0-terminated
2037 * and there is enough space in the buffer NT appends a \0 */
2038 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2039 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2043 else status
= STATUS_SUCCESS
;
2046 if (type
) *type
= info
->Type
;
2047 if (count
) *count
= info
->DataLength
;
2050 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2051 CloseDefaultKey(KeyHandle
);
2052 return RtlNtStatusToDosError(status
);
2055 /************************************************************************
2061 RegFlushKey(HKEY hKey
)
2066 if (hKey
== HKEY_PERFORMANCE_DATA
)
2068 return ERROR_SUCCESS
;
2071 Status
= MapDefaultKey (&KeyHandle
,
2073 if (!NT_SUCCESS(Status
))
2075 return RtlNtStatusToDosError (Status
);
2078 Status
= NtFlushKey (KeyHandle
);
2080 CloseDefaultKey(KeyHandle
);
2082 if (!NT_SUCCESS(Status
))
2084 return RtlNtStatusToDosError (Status
);
2087 return ERROR_SUCCESS
;
2091 /************************************************************************
2097 RegGetKeySecurity(HKEY hKey
,
2098 SECURITY_INFORMATION SecurityInformation
,
2099 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2100 LPDWORD lpcbSecurityDescriptor
)
2105 if (hKey
== HKEY_PERFORMANCE_DATA
)
2107 return ERROR_INVALID_HANDLE
;
2110 Status
= MapDefaultKey(&KeyHandle
,
2112 if (!NT_SUCCESS(Status
))
2114 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2115 return RtlNtStatusToDosError (Status
);
2118 Status
= NtQuerySecurityObject(KeyHandle
,
2119 SecurityInformation
,
2120 pSecurityDescriptor
,
2121 *lpcbSecurityDescriptor
,
2122 lpcbSecurityDescriptor
);
2124 CloseDefaultKey(KeyHandle
);
2126 if (!NT_SUCCESS(Status
))
2128 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
2129 return RtlNtStatusToDosError (Status
);
2132 return ERROR_SUCCESS
;
2136 /************************************************************************
2142 RegLoadKeyA (HKEY hKey
,
2146 UNICODE_STRING FileName
;
2147 UNICODE_STRING KeyName
;
2150 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
2152 RtlCreateUnicodeStringFromAsciiz (&FileName
,
2155 ErrorCode
= RegLoadKeyW (hKey
,
2159 RtlFreeUnicodeString (&FileName
);
2160 RtlFreeUnicodeString (&KeyName
);
2166 /************************************************************************
2172 RegLoadKeyW (HKEY hKey
,
2176 OBJECT_ATTRIBUTES FileObjectAttributes
;
2177 OBJECT_ATTRIBUTES KeyObjectAttributes
;
2178 UNICODE_STRING FileName
;
2179 UNICODE_STRING KeyName
;
2182 LONG ErrorCode
= ERROR_SUCCESS
;
2184 if (hKey
== HKEY_PERFORMANCE_DATA
)
2186 return ERROR_INVALID_HANDLE
;
2189 Status
= MapDefaultKey (&KeyHandle
,
2191 if (!NT_SUCCESS(Status
))
2193 return RtlNtStatusToDosError (Status
);
2196 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpFile
,
2201 ErrorCode
= ERROR_BAD_PATHNAME
;
2205 InitializeObjectAttributes (&FileObjectAttributes
,
2207 OBJ_CASE_INSENSITIVE
,
2211 RtlInitUnicodeString (&KeyName
,
2214 InitializeObjectAttributes (&KeyObjectAttributes
,
2216 OBJ_CASE_INSENSITIVE
,
2220 Status
= NtLoadKey (&KeyObjectAttributes
,
2221 &FileObjectAttributes
);
2223 RtlFreeUnicodeString (&FileName
);
2225 if (!NT_SUCCESS(Status
))
2227 ErrorCode
= RtlNtStatusToDosError (Status
);
2232 CloseDefaultKey(KeyHandle
);
2238 /************************************************************************
2239 * RegNotifyChangeKeyValue
2244 RegNotifyChangeKeyValue (HKEY hKey
,
2246 DWORD dwNotifyFilter
,
2250 IO_STATUS_BLOCK IoStatusBlock
;
2253 LONG ErrorCode
= ERROR_SUCCESS
;
2255 if (hKey
== HKEY_PERFORMANCE_DATA
)
2257 return ERROR_INVALID_HANDLE
;
2260 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
2262 return ERROR_INVALID_PARAMETER
;
2265 Status
= MapDefaultKey (&KeyHandle
,
2267 if (!NT_SUCCESS(Status
))
2269 return RtlNtStatusToDosError (Status
);
2272 /* FIXME: Remote key handles must fail */
2274 Status
= NtNotifyChangeKey (KeyHandle
,
2284 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
2286 ErrorCode
= RtlNtStatusToDosError (Status
);
2289 CloseDefaultKey(KeyHandle
);
2295 /************************************************************************
2296 * RegOpenCurrentUser
2301 RegOpenCurrentUser (IN REGSAM samDesired
,
2302 OUT PHKEY phkResult
)
2306 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
2307 (PHANDLE
)phkResult
);
2308 if (!NT_SUCCESS(Status
))
2310 /* NOTE - don't set the last error code! just return the error! */
2311 return RtlNtStatusToDosError(Status
);
2314 return ERROR_SUCCESS
;
2318 /************************************************************************
2321 * 20050503 Fireball - imported from WINE
2326 RegOpenKeyA (HKEY hKey
,
2330 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2332 if (!lpSubKey
|| !*lpSubKey
)
2335 return ERROR_SUCCESS
;
2338 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2342 /************************************************************************
2347 * 20050503 Fireball - imported from WINE
2352 RegOpenKeyW (HKEY hKey
,
2356 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2358 if (!lpSubKey
|| !*lpSubKey
)
2361 return ERROR_SUCCESS
;
2363 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2367 /************************************************************************
2373 RegOpenKeyExA (HKEY hKey
,
2379 OBJECT_ATTRIBUTES ObjectAttributes
;
2380 UNICODE_STRING SubKeyString
;
2383 LONG ErrorCode
= ERROR_SUCCESS
;
2385 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2386 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2388 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2389 if (!NT_SUCCESS(Status
))
2391 return RtlNtStatusToDosError (Status
);
2394 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
2395 InitializeObjectAttributes (&ObjectAttributes
,
2397 OBJ_CASE_INSENSITIVE
,
2401 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2402 RtlFreeUnicodeString (&SubKeyString
);
2403 if (!NT_SUCCESS(Status
))
2405 ErrorCode
= RtlNtStatusToDosError (Status
);
2408 CloseDefaultKey(KeyHandle
);
2414 /************************************************************************
2420 RegOpenKeyExW (HKEY hKey
,
2426 OBJECT_ATTRIBUTES ObjectAttributes
;
2427 UNICODE_STRING SubKeyString
;
2430 LONG ErrorCode
= ERROR_SUCCESS
;
2432 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2433 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2435 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2436 if (!NT_SUCCESS(Status
))
2438 return RtlNtStatusToDosError (Status
);
2441 if (lpSubKey
!= NULL
)
2442 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
2444 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
2446 InitializeObjectAttributes (&ObjectAttributes
,
2448 OBJ_CASE_INSENSITIVE
,
2452 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2454 if (!NT_SUCCESS(Status
))
2456 ErrorCode
= RtlNtStatusToDosError (Status
);
2459 CloseDefaultKey(KeyHandle
);
2465 /************************************************************************
2466 * RegOpenUserClassesRoot
2471 RegOpenUserClassesRoot (IN HANDLE hToken
,
2473 IN REGSAM samDesired
,
2474 OUT PHKEY phkResult
)
2476 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
2477 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
2478 PTOKEN_USER TokenUserData
;
2479 ULONG RequiredLength
;
2480 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
2481 OBJECT_ATTRIBUTES ObjectAttributes
;
2484 /* check parameters */
2485 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
2487 return ERROR_INVALID_PARAMETER
;
2491 * Get the user sid from the token
2495 /* determine how much memory we need */
2496 Status
= NtQueryInformationToken(hToken
,
2501 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
2503 /* NOTE - as opposed to all other registry functions windows does indeed
2504 change the last error code in case the caller supplied a invalid
2505 handle for example! */
2506 return RtlNtStatusToDosError (Status
);
2509 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
2512 if (TokenUserData
== NULL
)
2514 return ERROR_NOT_ENOUGH_MEMORY
;
2517 /* attempt to read the information */
2518 Status
= NtQueryInformationToken(hToken
,
2523 if (!NT_SUCCESS(Status
))
2525 RtlFreeHeap(ProcessHeap
,
2528 if (Status
== STATUS_BUFFER_TOO_SMALL
)
2530 /* the information appears to have changed?! try again */
2534 /* NOTE - as opposed to all other registry functions windows does indeed
2535 change the last error code in case the caller supplied a invalid
2536 handle for example! */
2537 return RtlNtStatusToDosError (Status
);
2541 * Build the absolute path for the user's registry in the form
2542 * "\Registry\User\<SID>_Classes"
2544 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
2545 TokenUserData
->User
.Sid
,
2548 /* we don't need the user data anymore, free it */
2549 RtlFreeHeap(ProcessHeap
,
2553 if (!NT_SUCCESS(Status
))
2555 return RtlNtStatusToDosError (Status
);
2558 /* allocate enough memory for the entire key string */
2559 UserClassesKeyRoot
.Length
= 0;
2560 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
2561 sizeof(UserClassesKeyPrefix
) +
2562 sizeof(UserClassesKeySuffix
);
2563 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
2565 UserClassesKeyRoot
.MaximumLength
);
2566 if (UserClassesKeyRoot
.Buffer
== NULL
)
2568 RtlFreeUnicodeString(&UserSidString
);
2569 return RtlNtStatusToDosError (Status
);
2572 /* build the string */
2573 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2574 UserClassesKeyPrefix
);
2575 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
2577 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2578 UserClassesKeySuffix
);
2580 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
2586 InitializeObjectAttributes (&ObjectAttributes
,
2587 &UserClassesKeyRoot
,
2588 OBJ_CASE_INSENSITIVE
,
2592 Status
= NtOpenKey((PHANDLE
)phkResult
,
2596 RtlFreeUnicodeString(&UserSidString
);
2597 RtlFreeUnicodeString(&UserClassesKeyRoot
);
2599 if (!NT_SUCCESS(Status
))
2601 return RtlNtStatusToDosError (Status
);
2604 return ERROR_SUCCESS
;
2608 /************************************************************************
2614 RegQueryInfoKeyA (HKEY hKey
,
2619 LPDWORD lpcbMaxSubKeyLen
,
2620 LPDWORD lpcbMaxClassLen
,
2622 LPDWORD lpcbMaxValueNameLen
,
2623 LPDWORD lpcbMaxValueLen
,
2624 LPDWORD lpcbSecurityDescriptor
,
2625 PFILETIME lpftLastWriteTime
)
2627 WCHAR ClassName
[MAX_PATH
];
2628 UNICODE_STRING UnicodeString
;
2629 ANSI_STRING AnsiString
;
2632 RtlInitUnicodeString (&UnicodeString
,
2634 if (lpClass
!= NULL
)
2636 UnicodeString
.Buffer
= &ClassName
[0];
2637 UnicodeString
.MaximumLength
= sizeof(ClassName
);
2638 AnsiString
.MaximumLength
= *lpcbClass
;
2641 ErrorCode
= RegQueryInfoKeyW (hKey
,
2642 UnicodeString
.Buffer
,
2649 lpcbMaxValueNameLen
,
2651 lpcbSecurityDescriptor
,
2653 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
2655 AnsiString
.Buffer
= lpClass
;
2656 AnsiString
.Length
= 0;
2657 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
2658 RtlUnicodeStringToAnsiString (&AnsiString
,
2661 *lpcbClass
= AnsiString
.Length
;
2662 lpClass
[AnsiString
.Length
] = 0;
2669 /************************************************************************
2675 RegQueryInfoKeyW (HKEY hKey
,
2680 LPDWORD lpcbMaxSubKeyLen
,
2681 LPDWORD lpcbMaxClassLen
,
2683 LPDWORD lpcbMaxValueNameLen
,
2684 LPDWORD lpcbMaxValueLen
,
2685 LPDWORD lpcbSecurityDescriptor
,
2686 PFILETIME lpftLastWriteTime
)
2688 KEY_FULL_INFORMATION FullInfoBuffer
;
2689 PKEY_FULL_INFORMATION FullInfo
;
2691 ULONG ClassLength
= 0;
2695 LONG ErrorCode
= ERROR_SUCCESS
;
2697 if ((lpClass
) && (!lpcbClass
))
2699 return ERROR_INVALID_PARAMETER
;
2702 Status
= MapDefaultKey (&KeyHandle
,
2704 if (!NT_SUCCESS(Status
))
2706 return RtlNtStatusToDosError (Status
);
2709 if (lpClass
!= NULL
)
2713 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2720 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
2721 FullInfo
= RtlAllocateHeap (ProcessHeap
,
2724 if (FullInfo
== NULL
)
2726 ErrorCode
= ERROR_OUTOFMEMORY
;
2730 FullInfo
->ClassLength
= ClassLength
;
2734 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
2735 FullInfo
= &FullInfoBuffer
;
2736 FullInfo
->ClassLength
= 0;
2738 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
2740 Status
= NtQueryKey (KeyHandle
,
2745 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
2746 if (!NT_SUCCESS(Status
))
2748 if (lpClass
!= NULL
)
2750 RtlFreeHeap (ProcessHeap
,
2755 ErrorCode
= RtlNtStatusToDosError (Status
);
2759 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
2760 if (lpcSubKeys
!= NULL
)
2762 *lpcSubKeys
= FullInfo
->SubKeys
;
2765 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
2766 if (lpcbMaxSubKeyLen
!= NULL
)
2768 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
2771 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
2772 if (lpcbMaxClassLen
!= NULL
)
2774 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
2777 TRACE("Values %lu\n", FullInfo
->Values
);
2778 if (lpcValues
!= NULL
)
2780 *lpcValues
= FullInfo
->Values
;
2783 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
2784 if (lpcbMaxValueNameLen
!= NULL
)
2786 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
2789 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
2790 if (lpcbMaxValueLen
!= NULL
)
2792 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
2795 if (lpcbSecurityDescriptor
!= NULL
)
2797 Status
= NtQuerySecurityObject(KeyHandle
,
2798 OWNER_SECURITY_INFORMATION
|
2799 GROUP_SECURITY_INFORMATION
|
2800 DACL_SECURITY_INFORMATION
,
2803 lpcbSecurityDescriptor
);
2804 if (!NT_SUCCESS(Status
))
2806 if (lpClass
!= NULL
)
2808 RtlFreeHeap(ProcessHeap
,
2813 ErrorCode
= RtlNtStatusToDosError (Status
);
2818 if (lpftLastWriteTime
!= NULL
)
2820 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
2821 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
2824 if (lpClass
!= NULL
)
2826 if (FullInfo
->ClassLength
> ClassLength
)
2828 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2832 RtlCopyMemory (lpClass
,
2834 FullInfo
->ClassLength
);
2835 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
2836 lpClass
[*lpcbClass
] = 0;
2839 RtlFreeHeap (ProcessHeap
,
2845 CloseDefaultKey(KeyHandle
);
2851 /************************************************************************
2852 * RegQueryMultipleValuesA
2857 RegQueryMultipleValuesA (HKEY hKey
,
2864 DWORD maxBytes
= *ldwTotsize
;
2865 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
2868 if (maxBytes
>= (1024*1024))
2869 return ERROR_TRANSFER_TOO_LONG
;
2873 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
2874 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
2876 for (i
= 0; i
< num_vals
; i
++)
2878 val_list
[i
].ve_valuelen
= 0;
2879 ErrorCode
= RegQueryValueExA (hKey
,
2880 val_list
[i
].ve_valuename
,
2884 &val_list
[i
].ve_valuelen
);
2885 if (ErrorCode
!= ERROR_SUCCESS
)
2890 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
2892 ErrorCode
= RegQueryValueExA (hKey
,
2893 val_list
[i
].ve_valuename
,
2895 &val_list
[i
].ve_type
,
2897 &val_list
[i
].ve_valuelen
);
2898 if (ErrorCode
!= ERROR_SUCCESS
)
2903 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
2905 bufptr
+= val_list
[i
].ve_valuelen
;
2908 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
2911 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
2915 /************************************************************************
2916 * RegQueryMultipleValuesW
2921 RegQueryMultipleValuesW (HKEY hKey
,
2928 DWORD maxBytes
= *ldwTotsize
;
2929 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
2932 if (maxBytes
>= (1024*1024))
2933 return ERROR_TRANSFER_TOO_LONG
;
2937 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
2938 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
2940 for (i
= 0; i
< num_vals
; i
++)
2942 val_list
[i
].ve_valuelen
= 0;
2943 ErrorCode
= RegQueryValueExW (hKey
,
2944 val_list
[i
].ve_valuename
,
2948 &val_list
[i
].ve_valuelen
);
2949 if (ErrorCode
!= ERROR_SUCCESS
)
2954 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
2956 ErrorCode
= RegQueryValueExW (hKey
,
2957 val_list
[i
].ve_valuename
,
2959 &val_list
[i
].ve_type
,
2961 &val_list
[i
].ve_valuelen
);
2962 if (ErrorCode
!= ERROR_SUCCESS
)
2967 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
2969 bufptr
+= val_list
[i
].ve_valuelen
;
2972 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
2975 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
2979 /************************************************************************
2985 RegQueryValueExW (HKEY hKey
,
2986 LPCWSTR lpValueName
,
2992 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
2993 UNICODE_STRING ValueName
;
2998 LONG ErrorCode
= ERROR_SUCCESS
;
2999 ULONG MaxCopy
= lpcbData
!= NULL
&& lpData
!= NULL
? *lpcbData
: 0;
3001 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3002 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3004 Status
= MapDefaultKey (&KeyHandle
,
3006 if (!NT_SUCCESS(Status
))
3008 return RtlNtStatusToDosError (Status
);
3011 if (lpData
!= NULL
&& lpcbData
== NULL
)
3013 ErrorCode
= ERROR_INVALID_PARAMETER
;
3017 RtlInitUnicodeString (&ValueName
,
3019 BufferSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MaxCopy
;
3020 ValueInfo
= RtlAllocateHeap (ProcessHeap
,
3023 if (ValueInfo
== NULL
)
3025 ErrorCode
= ERROR_OUTOFMEMORY
;
3029 Status
= NtQueryValueKey (KeyHandle
,
3031 KeyValuePartialInformation
,
3035 TRACE("Status 0x%X\n", Status
);
3036 if (Status
== STATUS_BUFFER_OVERFLOW
)
3038 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3040 ErrorCode
= lpData
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
3042 else if (!NT_SUCCESS(Status
))
3044 ErrorCode
= RtlNtStatusToDosError (Status
);
3046 if (lpcbData
!= NULL
)
3048 ResultSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + *lpcbData
;
3054 *lpType
= ValueInfo
->Type
;
3057 if (NT_SUCCESS(Status
) && lpData
!= NULL
)
3059 RtlMoveMemory (lpData
,
3061 min(ValueInfo
->DataLength
, MaxCopy
));
3064 if ((ValueInfo
->Type
== REG_SZ
) ||
3065 (ValueInfo
->Type
== REG_MULTI_SZ
) ||
3066 (ValueInfo
->Type
== REG_EXPAND_SZ
))
3068 if (lpData
!= NULL
&& MaxCopy
> ValueInfo
->DataLength
)
3070 ((PWSTR
)lpData
)[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = 0;
3073 if (lpcbData
!= NULL
)
3075 *lpcbData
= (ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]));
3076 TRACE("(string) Returning Size: %lu\n", *lpcbData
);
3081 if (lpcbData
!= NULL
)
3083 *lpcbData
= ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
3084 TRACE("(other) Returning Size: %lu\n", *lpcbData
);
3088 TRACE("Type %d Size %d\n", ValueInfo
->Type
, ValueInfo
->DataLength
);
3090 RtlFreeHeap (ProcessHeap
,
3095 CloseDefaultKey(KeyHandle
);
3101 /************************************************************************
3107 RegQueryValueExA (HKEY hKey
,
3114 UNICODE_STRING ValueName
;
3115 UNICODE_STRING ValueData
;
3116 ANSI_STRING AnsiString
;
3121 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3122 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3124 if (lpData
!= NULL
&& lpcbData
== NULL
)
3126 return ERROR_INVALID_PARAMETER
;
3131 ValueData
.Length
= 0;
3132 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3133 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3135 ValueData
.MaximumLength
);
3136 if (!ValueData
.Buffer
)
3138 return ERROR_OUTOFMEMORY
;
3143 ValueData
.Buffer
= NULL
;
3144 ValueData
.Length
= 0;
3145 ValueData
.MaximumLength
= 0;
3148 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3149 (LPSTR
)lpValueName
);
3151 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
3152 ErrorCode
= RegQueryValueExW (hKey
,
3156 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
3158 TRACE("ErrorCode %lu\n", ErrorCode
);
3159 RtlFreeUnicodeString(&ValueName
);
3161 if (ErrorCode
== ERROR_SUCCESS
||
3162 ErrorCode
== ERROR_MORE_DATA
)
3169 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
3171 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3173 RtlInitAnsiString(&AnsiString
, NULL
);
3174 AnsiString
.Buffer
= (LPSTR
)lpData
;
3175 AnsiString
.MaximumLength
= *lpcbData
;
3176 ValueData
.Length
= Length
;
3177 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
3178 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
3180 Length
= Length
/ sizeof(WCHAR
);
3182 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3184 if (*lpcbData
< Length
)
3186 ErrorCode
= ERROR_MORE_DATA
;
3190 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
3194 if (lpcbData
!= NULL
)
3200 if (ValueData
.Buffer
!= NULL
)
3202 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
3209 /************************************************************************
3215 RegQueryValueA (HKEY hKey
,
3220 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
3221 UNICODE_STRING SubKeyName
;
3222 UNICODE_STRING Value
;
3223 ANSI_STRING AnsiString
;
3227 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3228 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3230 if (lpValue
!= NULL
&&
3233 return ERROR_INVALID_PARAMETER
;
3236 RtlInitUnicodeString (&SubKeyName
,
3238 RtlInitUnicodeString (&Value
,
3240 if (lpSubKey
!= NULL
&&
3241 strlen(lpSubKey
) != 0)
3243 RtlInitAnsiString (&AnsiString
,
3245 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
3246 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
3247 RtlAnsiStringToUnicodeString (&SubKeyName
,
3252 if (lpValue
!= NULL
)
3254 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
3255 Value
.MaximumLength
= ValueSize
;
3256 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3259 if (Value
.Buffer
== NULL
)
3261 return ERROR_OUTOFMEMORY
;
3269 ErrorCode
= RegQueryValueW (hKey
,
3270 (LPCWSTR
)SubKeyName
.Buffer
,
3273 if (ErrorCode
== ERROR_SUCCESS
)
3275 Value
.Length
= ValueSize
;
3276 RtlInitAnsiString (&AnsiString
,
3278 AnsiString
.Buffer
= lpValue
;
3279 AnsiString
.MaximumLength
= *lpcbValue
;
3280 RtlUnicodeStringToAnsiString (&AnsiString
,
3285 *lpcbValue
= ValueSize
;
3286 if (Value
.Buffer
!= NULL
)
3288 RtlFreeHeap (ProcessHeap
,
3297 /************************************************************************
3303 RegQueryValueW (HKEY hKey
,
3308 OBJECT_ATTRIBUTES ObjectAttributes
;
3309 UNICODE_STRING SubKeyString
;
3316 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3317 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3319 Status
= MapDefaultKey (&KeyHandle
,
3321 if (!NT_SUCCESS(Status
))
3323 return RtlNtStatusToDosError (Status
);
3326 if (lpSubKey
!= NULL
&&
3327 wcslen(lpSubKey
) != 0)
3329 RtlInitUnicodeString (&SubKeyString
,
3331 InitializeObjectAttributes (&ObjectAttributes
,
3333 OBJ_CASE_INSENSITIVE
,
3336 Status
= NtOpenKey (&RealKey
,
3339 if (!NT_SUCCESS(Status
))
3341 ErrorCode
= RtlNtStatusToDosError (Status
);
3344 CloseRealKey
= TRUE
;
3349 CloseRealKey
= FALSE
;
3352 ErrorCode
= RegQueryValueExW (RealKey
,
3357 (LPDWORD
)lpcbValue
);
3364 CloseDefaultKey(KeyHandle
);
3370 /************************************************************************
3376 RegReplaceKeyA (HKEY hKey
,
3381 UNICODE_STRING SubKey
;
3382 UNICODE_STRING NewFile
;
3383 UNICODE_STRING OldFile
;
3386 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
3388 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
3390 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
3393 ErrorCode
= RegReplaceKeyW (hKey
,
3398 RtlFreeUnicodeString (&OldFile
);
3399 RtlFreeUnicodeString (&NewFile
);
3400 RtlFreeUnicodeString (&SubKey
);
3406 /************************************************************************
3412 RegReplaceKeyW (HKEY hKey
,
3417 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3418 OBJECT_ATTRIBUTES NewObjectAttributes
;
3419 OBJECT_ATTRIBUTES OldObjectAttributes
;
3420 UNICODE_STRING SubKeyName
;
3421 UNICODE_STRING NewFileName
;
3422 UNICODE_STRING OldFileName
;
3423 BOOLEAN CloseRealKey
;
3424 HANDLE RealKeyHandle
;
3427 LONG ErrorCode
= ERROR_SUCCESS
;
3429 if (hKey
== HKEY_PERFORMANCE_DATA
)
3431 return ERROR_INVALID_HANDLE
;
3434 Status
= MapDefaultKey (&KeyHandle
,
3436 if (!NT_SUCCESS(Status
))
3438 return RtlNtStatusToDosError (Status
);
3441 /* Open the real key */
3442 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
3444 RtlInitUnicodeString (&SubKeyName
,
3446 InitializeObjectAttributes (&KeyObjectAttributes
,
3448 OBJ_CASE_INSENSITIVE
,
3451 Status
= NtOpenKey (&RealKeyHandle
,
3453 &KeyObjectAttributes
);
3454 if (!NT_SUCCESS(Status
))
3456 ErrorCode
= RtlNtStatusToDosError (Status
);
3459 CloseRealKey
= TRUE
;
3463 RealKeyHandle
= KeyHandle
;
3464 CloseRealKey
= FALSE
;
3467 /* Convert new file name */
3468 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpNewFile
,
3475 NtClose (RealKeyHandle
);
3477 ErrorCode
= ERROR_INVALID_PARAMETER
;
3481 InitializeObjectAttributes (&NewObjectAttributes
,
3483 OBJ_CASE_INSENSITIVE
,
3487 /* Convert old file name */
3488 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpOldFile
,