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 /************************************************************************
328 RegCopyTreeW(IN HKEY hKeySrc
,
329 IN LPCWSTR lpSubKey OPTIONAL
,
332 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
335 Status
= MapDefaultKey(&KeyHandle
,
337 if (!NT_SUCCESS(Status
))
339 return RtlNtStatusToDosError(Status
);
342 Status
= MapDefaultKey(&DestKeyHandle
,
344 if (!NT_SUCCESS(Status
))
349 if (lpSubKey
!= NULL
)
351 OBJECT_ATTRIBUTES ObjectAttributes
;
352 UNICODE_STRING SubKeyName
;
354 RtlInitUnicodeString(&SubKeyName
,
357 InitializeObjectAttributes(&ObjectAttributes
,
359 OBJ_CASE_INSENSITIVE
,
363 Status
= NtOpenKey(&SubKeyHandle
,
366 if (!NT_SUCCESS(Status
))
371 CurKey
= SubKeyHandle
;
376 /* FIXME - copy all keys and values recursively */
377 Status
= STATUS_NOT_IMPLEMENTED
;
379 if (SubKeyHandle
!= NULL
)
381 NtClose(SubKeyHandle
);
385 CloseDefaultKey(DestKeyHandle
);
387 CloseDefaultKey(KeyHandle
);
389 if (!NT_SUCCESS(Status
))
391 return RtlNtStatusToDosError(Status
);
394 return ERROR_SUCCESS
;
398 /************************************************************************
404 RegCopyTreeA(IN HKEY hKeySrc
,
405 IN LPCSTR lpSubKey OPTIONAL
,
408 UNICODE_STRING SubKeyName
;
411 if (lpSubKey
!= NULL
)
413 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
416 return ERROR_NOT_ENOUGH_MEMORY
;
420 RtlInitUnicodeString(&SubKeyName
,
423 Ret
= RegCopyTreeW(hKeySrc
,
427 RtlFreeUnicodeString(&SubKeyName
);
433 /************************************************************************
434 * RegConnectRegistryA
439 RegConnectRegistryA (IN LPCSTR lpMachineName
,
443 UNICODE_STRING MachineName
;
446 if (lpMachineName
!= NULL
)
448 if (!RtlCreateUnicodeStringFromAsciiz(&MachineName
,
449 (LPSTR
)lpMachineName
))
451 return ERROR_NOT_ENOUGH_MEMORY
;
455 RtlInitUnicodeString(&MachineName
,
458 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
462 RtlFreeUnicodeString(&MachineName
);
468 /************************************************************************
469 * RegConnectRegistryW
474 RegConnectRegistryW (LPCWSTR lpMachineName
,
478 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
479 return ERROR_CALL_NOT_IMPLEMENTED
;
483 /************************************************************************
486 * Create key and all necessary intermediate keys
489 CreateNestedKey(PHKEY KeyHandle
,
490 POBJECT_ATTRIBUTES ObjectAttributes
,
491 PUNICODE_STRING ClassString
,
494 DWORD
*lpdwDisposition
)
496 OBJECT_ATTRIBUTES LocalObjectAttributes
;
497 UNICODE_STRING LocalKeyName
;
500 ULONG FullNameLength
;
503 HANDLE LocalKeyHandle
;
505 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
511 (PULONG
)lpdwDisposition
);
512 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
513 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
516 /* Copy object attributes */
517 RtlCopyMemory (&LocalObjectAttributes
,
519 sizeof(OBJECT_ATTRIBUTES
));
520 RtlCreateUnicodeString (&LocalKeyName
,
521 ObjectAttributes
->ObjectName
->Buffer
);
522 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
523 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
525 /* Remove the last part of the key name and try to create the key again. */
526 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
528 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
529 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
531 Status
= STATUS_UNSUCCESSFUL
;
535 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
537 Status
= NtCreateKey (&LocalKeyHandle
,
539 &LocalObjectAttributes
,
544 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
547 if (!NT_SUCCESS(Status
))
549 RtlFreeUnicodeString (&LocalKeyName
);
553 /* Add removed parts of the key name and create them too. */
554 Length
= wcslen (LocalKeyName
.Buffer
);
557 NtClose (LocalKeyHandle
);
559 LocalKeyName
.Buffer
[Length
] = L
'\\';
560 Length
= wcslen (LocalKeyName
.Buffer
);
561 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
563 if (Length
== FullNameLength
)
565 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
571 (PULONG
)lpdwDisposition
);
574 Status
= NtCreateKey (&LocalKeyHandle
,
576 &LocalObjectAttributes
,
581 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
582 if (!NT_SUCCESS(Status
))
586 RtlFreeUnicodeString (&LocalKeyName
);
592 /************************************************************************
598 RegCreateKeyExA (HKEY hKey
,
604 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
606 LPDWORD lpdwDisposition
)
608 UNICODE_STRING SubKeyString
;
609 UNICODE_STRING ClassString
;
610 OBJECT_ATTRIBUTES Attributes
;
614 TRACE("RegCreateKeyExA() called\n");
616 /* get the real parent key */
617 Status
= MapDefaultKey (&ParentKey
,
619 if (!NT_SUCCESS(Status
))
621 return RtlNtStatusToDosError (Status
);
623 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
627 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
631 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
633 InitializeObjectAttributes (&Attributes
,
635 OBJ_CASE_INSENSITIVE
,
637 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
638 Status
= CreateNestedKey(phkResult
,
640 (lpClass
== NULL
)? NULL
: &ClassString
,
644 RtlFreeUnicodeString (&SubKeyString
);
647 RtlFreeUnicodeString (&ClassString
);
650 CloseDefaultKey(ParentKey
);
652 TRACE("Status %x\n", Status
);
653 if (!NT_SUCCESS(Status
))
655 return RtlNtStatusToDosError (Status
);
658 return ERROR_SUCCESS
;
662 /************************************************************************
668 RegCreateKeyExW (HKEY hKey
,
674 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
676 LPDWORD lpdwDisposition
)
678 UNICODE_STRING SubKeyString
;
679 UNICODE_STRING ClassString
;
680 OBJECT_ATTRIBUTES Attributes
;
684 TRACE("RegCreateKeyExW() called\n");
686 /* get the real parent key */
687 Status
= MapDefaultKey (&ParentKey
,
689 if (!NT_SUCCESS(Status
))
691 return RtlNtStatusToDosError(Status
);
693 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
695 RtlInitUnicodeString (&ClassString
,
697 RtlInitUnicodeString (&SubKeyString
,
699 InitializeObjectAttributes (&Attributes
,
701 OBJ_CASE_INSENSITIVE
,
703 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
704 Status
= CreateNestedKey(phkResult
,
706 (lpClass
== NULL
)? NULL
: &ClassString
,
711 CloseDefaultKey(ParentKey
);
713 TRACE("Status %x\n", Status
);
714 if (!NT_SUCCESS(Status
))
716 return RtlNtStatusToDosError (Status
);
719 return ERROR_SUCCESS
;
723 /************************************************************************
729 RegCreateKeyA (HKEY hKey
,
733 return RegCreateKeyExA (hKey
,
745 /************************************************************************
751 RegCreateKeyW (HKEY hKey
,
755 return RegCreateKeyExW (hKey
,
767 /************************************************************************
773 RegDeleteKeyA (HKEY hKey
,
776 OBJECT_ATTRIBUTES ObjectAttributes
;
777 UNICODE_STRING SubKeyName
;
782 Status
= MapDefaultKey (&ParentKey
,
784 if (!NT_SUCCESS(Status
))
786 return RtlNtStatusToDosError (Status
);
789 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
791 InitializeObjectAttributes(&ObjectAttributes
,
793 OBJ_CASE_INSENSITIVE
,
797 Status
= NtOpenKey (&TargetKey
,
800 RtlFreeUnicodeString (&SubKeyName
);
801 if (!NT_SUCCESS(Status
))
806 Status
= NtDeleteKey (TargetKey
);
810 CloseDefaultKey(ParentKey
);
812 if (!NT_SUCCESS(Status
))
814 return RtlNtStatusToDosError(Status
);
817 return ERROR_SUCCESS
;
821 /************************************************************************
827 RegDeleteKeyW (HKEY hKey
,
830 OBJECT_ATTRIBUTES ObjectAttributes
;
831 UNICODE_STRING SubKeyName
;
836 Status
= MapDefaultKey (&ParentKey
,
838 if (!NT_SUCCESS(Status
))
840 return RtlNtStatusToDosError (Status
);
843 RtlInitUnicodeString (&SubKeyName
,
845 InitializeObjectAttributes (&ObjectAttributes
,
847 OBJ_CASE_INSENSITIVE
,
850 Status
= NtOpenKey (&TargetKey
,
853 if (!NT_SUCCESS(Status
))
858 Status
= NtDeleteKey (TargetKey
);
862 CloseDefaultKey(ParentKey
);
864 if (!NT_SUCCESS(Status
))
866 return RtlNtStatusToDosError (Status
);
869 return ERROR_SUCCESS
;
873 /************************************************************************
879 RegDeleteKeyValueW(IN HKEY hKey
,
880 IN LPCWSTR lpSubKey OPTIONAL
,
881 IN LPCWSTR lpValueName OPTIONAL
)
883 UNICODE_STRING ValueName
;
884 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
887 Status
= MapDefaultKey(&KeyHandle
,
889 if (!NT_SUCCESS(Status
))
891 return RtlNtStatusToDosError(Status
);
894 if (lpSubKey
!= NULL
)
896 OBJECT_ATTRIBUTES ObjectAttributes
;
897 UNICODE_STRING SubKeyName
;
899 RtlInitUnicodeString(&SubKeyName
,
902 InitializeObjectAttributes(&ObjectAttributes
,
904 OBJ_CASE_INSENSITIVE
,
908 Status
= NtOpenKey(&SubKeyHandle
,
911 if (!NT_SUCCESS(Status
))
916 CurKey
= SubKeyHandle
;
921 RtlInitUnicodeString(&ValueName
,
922 (LPWSTR
)lpValueName
);
924 Status
= NtDeleteValueKey(CurKey
,
927 if (SubKeyHandle
!= NULL
)
929 NtClose(SubKeyHandle
);
933 CloseDefaultKey(KeyHandle
);
935 if (!NT_SUCCESS(Status
))
937 return RtlNtStatusToDosError(Status
);
940 return ERROR_SUCCESS
;
944 /************************************************************************
950 RegDeleteKeyValueA(IN HKEY hKey
,
951 IN LPCSTR lpSubKey OPTIONAL
,
952 IN LPCSTR lpValueName OPTIONAL
)
954 UNICODE_STRING SubKey
, ValueName
;
957 if (lpSubKey
!= NULL
)
959 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey
,
962 return ERROR_NOT_ENOUGH_MEMORY
;
966 RtlInitUnicodeString(&SubKey
,
969 if (lpValueName
!= NULL
)
971 if (!RtlCreateUnicodeStringFromAsciiz(&ValueName
,
974 RtlFreeUnicodeString(&SubKey
);
975 return ERROR_NOT_ENOUGH_MEMORY
;
979 RtlInitUnicodeString(&ValueName
,
982 Ret
= RegDeleteKeyValueW(hKey
,
986 RtlFreeUnicodeString(&SubKey
);
987 RtlFreeUnicodeString(&ValueName
);
994 RegpDeleteTree(IN HKEY hKey
,
995 OUT PBOOLEAN KeysDeleted
)
999 LIST_ENTRY ListEntry
;
1001 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1003 LIST_ENTRY delQueueHead
;
1004 PREG_DEL_KEYS delKeys
, newDelKeys
;
1007 PKEY_BASIC_INFORMATION BasicInfo
;
1008 PREG_DEL_KEYS KeyDelRoot
;
1009 NTSTATUS Status
= STATUS_SUCCESS
;
1010 NTSTATUS Status2
= STATUS_SUCCESS
;
1012 *KeysDeleted
= FALSE
;
1014 InitializeListHead(&delQueueHead
);
1016 ProcessHeap
= RtlGetProcessHeap();
1018 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1019 structure for the root key, we only do that for subkeys as we need to
1020 allocate REGP_DEL_KEYS structures anyway! */
1021 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1023 sizeof(REGP_DEL_KEYS
));
1024 if (KeyDelRoot
!= NULL
)
1026 KeyDelRoot
->KeyHandle
= hKey
;
1027 InsertTailList(&delQueueHead
,
1028 &KeyDelRoot
->ListEntry
);
1032 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1041 /* check if this key contains subkeys and delete them first by queuing
1042 them at the head of the list */
1043 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1045 KeyBasicInformation
,
1050 if (NT_SUCCESS(Status2
))
1052 OBJECT_ATTRIBUTES ObjectAttributes
;
1053 UNICODE_STRING SubKeyName
;
1055 ASSERT(newDelKeys
!= NULL
);
1056 ASSERT(BasicInfo
!= NULL
);
1058 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1059 SubKeyName
.Length
= BasicInfo
->NameLength
;
1060 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1061 SubKeyName
.Buffer
= BasicInfo
->Name
;
1063 InitializeObjectAttributes(&ObjectAttributes
,
1065 OBJ_CASE_INSENSITIVE
,
1069 /* open the subkey */
1070 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1071 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1073 if (!NT_SUCCESS(Status2
))
1078 /* enqueue this key to the head of the deletion queue */
1079 InsertHeadList(&delQueueHead
,
1080 &newDelKeys
->ListEntry
);
1082 /* try again from the head of the list */
1087 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1089 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1091 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1092 if (newDelKeys
!= NULL
)
1094 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1097 goto ReadFirstSubKey
;
1101 /* don't break, let's try to delete as many keys as possible */
1102 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1103 goto SubKeyFailureNoFree
;
1106 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1108 PREG_DEL_KEYS newDelKeys2
;
1110 ASSERT(newDelKeys
!= NULL
);
1112 /* we need more memory to query the key name */
1113 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1116 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1117 if (newDelKeys2
!= NULL
)
1119 newDelKeys
= newDelKeys2
;
1120 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1123 goto ReadFirstSubKey
;
1127 /* don't break, let's try to delete as many keys as possible */
1128 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1133 ASSERT(newDelKeys
!= NULL
);
1134 RtlFreeHeap(ProcessHeap
,
1138 SubKeyFailureNoFree
:
1139 /* don't break, let's try to delete as many keys as possible */
1140 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
1146 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1148 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1150 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
1152 /* don't break, let's try to delete as many keys as possible */
1156 /* remove the entry from the list */
1157 RemoveEntryList(&delKeys
->ListEntry
);
1159 RtlFreeHeap(ProcessHeap
,
1162 } while (!IsListEmpty(&delQueueHead
));
1164 *KeysDeleted
= TRUE
;
1167 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1173 /************************************************************************
1179 RegDeleteTreeW(IN HKEY hKey
,
1180 IN LPCWSTR lpSubKey OPTIONAL
)
1182 BOOLEAN KeysDeleted
;
1183 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1186 Status
= MapDefaultKey(&KeyHandle
,
1188 if (!NT_SUCCESS(Status
))
1190 return RtlNtStatusToDosError(Status
);
1193 if (lpSubKey
!= NULL
)
1195 OBJECT_ATTRIBUTES ObjectAttributes
;
1196 UNICODE_STRING SubKeyName
;
1198 RtlInitUnicodeString(&SubKeyName
,
1201 InitializeObjectAttributes(&ObjectAttributes
,
1203 OBJ_CASE_INSENSITIVE
,
1207 Status
= NtOpenKey(&SubKeyHandle
,
1208 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1210 if (!NT_SUCCESS(Status
))
1215 CurKey
= SubKeyHandle
;
1220 Status
= RegpDeleteTree(CurKey
,
1225 /* only close handles of keys that weren't deleted! */
1226 if (SubKeyHandle
!= NULL
)
1228 NtClose(SubKeyHandle
);
1232 CloseDefaultKey(KeyHandle
);
1235 if (!NT_SUCCESS(Status
))
1237 return RtlNtStatusToDosError(Status
);
1240 return ERROR_SUCCESS
;
1244 /************************************************************************
1250 RegDeleteTreeA(IN HKEY hKey
,
1251 IN LPCSTR lpSubKey OPTIONAL
)
1253 UNICODE_STRING SubKeyName
;
1256 if (lpSubKey
!= NULL
)
1258 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1261 return ERROR_NOT_ENOUGH_MEMORY
;
1265 RtlInitUnicodeString(&SubKeyName
,
1268 Ret
= RegDeleteTreeW(hKey
,
1271 RtlFreeUnicodeString(&SubKeyName
);
1277 /************************************************************************
1283 RegSetKeyValueW(IN HKEY hKey
,
1284 IN LPCWSTR lpSubKey OPTIONAL
,
1285 IN LPCWSTR lpValueName OPTIONAL
,
1287 IN LPCVOID lpData OPTIONAL
,
1290 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1294 Status
= MapDefaultKey(&KeyHandle
,
1296 if (!NT_SUCCESS(Status
))
1298 return RtlNtStatusToDosError(Status
);
1301 if (lpSubKey
!= NULL
)
1303 OBJECT_ATTRIBUTES ObjectAttributes
;
1304 UNICODE_STRING SubKeyName
;
1306 RtlInitUnicodeString(&SubKeyName
,
1309 InitializeObjectAttributes(&ObjectAttributes
,
1311 OBJ_CASE_INSENSITIVE
,
1315 Status
= NtOpenKey(&SubKeyHandle
,
1318 if (!NT_SUCCESS(Status
))
1320 Ret
= RtlNtStatusToDosError(Status
);
1324 CurKey
= SubKeyHandle
;
1329 Ret
= RegSetValueExW(CurKey
,
1336 if (SubKeyHandle
!= NULL
)
1338 NtClose(SubKeyHandle
);
1342 CloseDefaultKey(KeyHandle
);
1348 /************************************************************************
1354 RegSetKeyValueA(IN HKEY hKey
,
1355 IN LPCSTR lpSubKey OPTIONAL
,
1356 IN LPCSTR lpValueName OPTIONAL
,
1358 IN LPCVOID lpData OPTIONAL
,
1361 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1365 Status
= MapDefaultKey(&KeyHandle
,
1367 if (!NT_SUCCESS(Status
))
1369 return RtlNtStatusToDosError(Status
);
1372 if (lpSubKey
!= NULL
)
1374 OBJECT_ATTRIBUTES ObjectAttributes
;
1375 UNICODE_STRING SubKeyName
;
1377 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1380 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
1384 InitializeObjectAttributes(&ObjectAttributes
,
1386 OBJ_CASE_INSENSITIVE
,
1390 Status
= NtOpenKey(&SubKeyHandle
,
1394 RtlFreeUnicodeString(&SubKeyName
);
1396 if (!NT_SUCCESS(Status
))
1398 Ret
= RtlNtStatusToDosError(Status
);
1402 CurKey
= SubKeyHandle
;
1407 Ret
= RegSetValueExA(CurKey
,
1414 if (SubKeyHandle
!= NULL
)
1416 NtClose(SubKeyHandle
);
1420 CloseDefaultKey(KeyHandle
);
1426 /************************************************************************
1432 RegDeleteValueA (HKEY hKey
,
1435 UNICODE_STRING ValueName
;
1439 Status
= MapDefaultKey (&KeyHandle
,
1441 if (!NT_SUCCESS(Status
))
1443 return RtlNtStatusToDosError (Status
);
1446 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
1447 (LPSTR
)lpValueName
);
1448 Status
= NtDeleteValueKey (KeyHandle
,
1450 RtlFreeUnicodeString (&ValueName
);
1452 CloseDefaultKey(KeyHandle
);
1454 if (!NT_SUCCESS(Status
))
1456 return RtlNtStatusToDosError (Status
);
1459 return ERROR_SUCCESS
;
1463 /************************************************************************
1469 RegDeleteValueW (HKEY hKey
,
1470 LPCWSTR lpValueName
)
1472 UNICODE_STRING ValueName
;
1476 Status
= MapDefaultKey (&KeyHandle
,
1478 if (!NT_SUCCESS(Status
))
1480 return RtlNtStatusToDosError (Status
);
1483 RtlInitUnicodeString (&ValueName
,
1484 (LPWSTR
)lpValueName
);
1486 Status
= NtDeleteValueKey (KeyHandle
,
1489 CloseDefaultKey(KeyHandle
);
1491 if (!NT_SUCCESS(Status
))
1493 return RtlNtStatusToDosError (Status
);
1496 return ERROR_SUCCESS
;
1500 /************************************************************************
1506 RegEnumKeyA (HKEY hKey
,
1514 return RegEnumKeyExA (hKey
,
1525 /************************************************************************
1531 RegEnumKeyW (HKEY hKey
,
1539 return RegEnumKeyExW (hKey
,
1550 /************************************************************************
1556 RegEnumKeyExA (HKEY hKey
,
1563 PFILETIME lpftLastWriteTime
)
1567 KEY_NODE_INFORMATION Node
;
1568 KEY_BASIC_INFORMATION Basic
;
1571 UNICODE_STRING StringU
;
1572 ANSI_STRING StringA
;
1573 LONG ErrorCode
= ERROR_SUCCESS
;
1575 DWORD ClassLength
= 0;
1581 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1582 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
1584 if ((lpClass
) && (!lpcbClass
))
1586 return ERROR_INVALID_PARAMETER
;
1589 Status
= MapDefaultKey(&KeyHandle
, hKey
);
1590 if (!NT_SUCCESS(Status
))
1592 return RtlNtStatusToDosError (Status
);
1597 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1608 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1615 /* The class name should start at a dword boundary */
1616 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1620 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1623 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
1624 if (KeyInfo
== NULL
)
1626 ErrorCode
= ERROR_OUTOFMEMORY
;
1630 Status
= NtEnumerateKey (KeyHandle
,
1632 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
1636 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1637 if (!NT_SUCCESS(Status
))
1639 ErrorCode
= RtlNtStatusToDosError (Status
);
1643 if (lpClass
== NULL
)
1645 if (KeyInfo
->Basic
.NameLength
> NameLength
)
1647 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1651 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
1652 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
1653 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
1658 if (KeyInfo
->Node
.NameLength
> NameLength
||
1659 KeyInfo
->Node
.ClassLength
> ClassLength
)
1661 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1665 StringA
.Buffer
= lpClass
;
1667 StringA
.MaximumLength
= *lpcbClass
;
1668 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
1669 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
1670 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
1671 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
1672 lpClass
[StringA
.Length
] = 0;
1673 *lpcbClass
= StringA
.Length
;
1674 StringU
.Buffer
= KeyInfo
->Node
.Name
;
1675 StringU
.Length
= KeyInfo
->Node
.NameLength
;
1676 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
1680 if (ErrorCode
== ERROR_SUCCESS
)
1682 StringA
.Buffer
= lpName
;
1684 StringA
.MaximumLength
= *lpcbName
;
1685 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
1686 lpName
[StringA
.Length
] = 0;
1687 *lpcbName
= StringA
.Length
;
1688 if (lpftLastWriteTime
!= NULL
)
1690 if (lpClass
== NULL
)
1692 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
1693 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
1697 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
1698 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
1704 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
1705 TRACE("Key Namea1 Length %d\n", NameLength
);
1706 TRACE("Key Namea Length %d\n", *lpcbName
);
1707 TRACE("Key Namea %s\n", lpName
);
1709 RtlFreeHeap (ProcessHeap
,
1714 CloseDefaultKey(KeyHandle
);
1720 /************************************************************************
1726 RegEnumKeyExW (HKEY hKey
,
1733 PFILETIME lpftLastWriteTime
)
1737 KEY_NODE_INFORMATION Node
;
1738 KEY_BASIC_INFORMATION Basic
;
1744 ULONG ClassLength
= 0;
1746 LONG ErrorCode
= ERROR_SUCCESS
;
1749 Status
= MapDefaultKey(&KeyHandle
,
1751 if (!NT_SUCCESS(Status
))
1753 return RtlNtStatusToDosError (Status
);
1758 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1769 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1776 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1780 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1783 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
1786 if (KeyInfo
== NULL
)
1788 ErrorCode
= ERROR_OUTOFMEMORY
;
1792 Status
= NtEnumerateKey (KeyHandle
,
1794 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
1798 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1799 if (!NT_SUCCESS(Status
))
1801 ErrorCode
= RtlNtStatusToDosError (Status
);
1805 if (lpClass
== NULL
)
1807 if (KeyInfo
->Basic
.NameLength
> NameLength
)
1809 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1813 RtlCopyMemory (lpName
,
1814 KeyInfo
->Basic
.Name
,
1815 KeyInfo
->Basic
.NameLength
);
1816 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
1817 lpName
[*lpcbName
] = 0;
1822 if (KeyInfo
->Node
.NameLength
> NameLength
||
1823 KeyInfo
->Node
.ClassLength
> ClassLength
)
1825 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1829 RtlCopyMemory (lpName
,
1831 KeyInfo
->Node
.NameLength
);
1832 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
1833 lpName
[*lpcbName
] = 0;
1834 RtlCopyMemory (lpClass
,
1835 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
1836 KeyInfo
->Node
.ClassLength
);
1837 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
1838 lpClass
[*lpcbClass
] = 0;
1842 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
1844 if (lpClass
== NULL
)
1846 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
1847 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
1851 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
1852 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
1857 RtlFreeHeap (ProcessHeap
,
1862 CloseDefaultKey(KeyHandle
);
1867 /************************************************************************
1873 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1874 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1879 char buffer
[256], *buf_ptr
= buffer
;
1880 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1881 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1883 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1884 // hkey, index, value, val_count, reserved, type, data, count );
1886 /* NT only checks count, not val_count */
1887 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1888 status
= MapDefaultKey (&KeyHandle
, hKey
);
1889 if (!NT_SUCCESS(status
))
1891 return RtlNtStatusToDosError (status
);
1894 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1895 if (data
) total_size
+= *count
;
1896 total_size
= min( sizeof(buffer
), total_size
);
1898 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
1899 buffer
, total_size
, &total_size
);
1900 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1902 /* we need to fetch the contents for a string type even if not requested,
1903 * because we need to compute the length of the ASCII string. */
1904 if (value
|| data
|| is_string(info
->Type
))
1906 /* retry with a dynamically allocated buffer */
1907 while (status
== STATUS_BUFFER_OVERFLOW
)
1909 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1910 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1912 status
= STATUS_INSUFFICIENT_RESOURCES
;
1915 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1916 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
1917 buf_ptr
, total_size
, &total_size
);
1920 if (status
) goto done
;
1922 if (is_string(info
->Type
))
1925 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1926 total_size
- info
->DataOffset
);
1929 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1932 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1933 total_size
- info
->DataOffset
);
1934 /* if the type is REG_SZ and data is not 0-terminated
1935 * and there is enough space in the buffer NT appends a \0 */
1936 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1939 info
->DataLength
= len
;
1943 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1944 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1947 if (value
&& !status
)
1951 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1952 if (len
>= *val_count
)
1954 status
= STATUS_BUFFER_OVERFLOW
;
1957 len
= *val_count
- 1;
1958 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1964 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1970 else status
= STATUS_SUCCESS
;
1972 if (type
) *type
= info
->Type
;
1973 if (count
) *count
= info
->DataLength
;
1976 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1977 CloseDefaultKey(KeyHandle
);
1978 return RtlNtStatusToDosError(status
);
1981 /******************************************************************************
1982 * RegEnumValueW [ADVAPI32.@]
1986 * hkey [I] Handle to key to query
1987 * index [I] Index of value to query
1988 * value [O] Value string
1989 * val_count [I/O] Size of value buffer (in wchars)
1990 * reserved [I] Reserved
1991 * type [O] Type code
1992 * data [O] Value data
1993 * count [I/O] Size of data buffer (in bytes)
1996 * Success: ERROR_SUCCESS
1997 * Failure: nonzero error code from Winerror.h
2000 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2001 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2006 char buffer
[256], *buf_ptr
= buffer
;
2007 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2008 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2010 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2011 // hkey, index, value, val_count, reserved, type, data, count );
2013 /* NT only checks count, not val_count */
2014 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2016 status
= MapDefaultKey (&KeyHandle
, hKey
);
2017 if (!NT_SUCCESS(status
))
2019 return RtlNtStatusToDosError (status
);
2022 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2023 if (data
) total_size
+= *count
;
2024 total_size
= min( sizeof(buffer
), total_size
);
2026 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2027 buffer
, total_size
, &total_size
);
2028 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2032 /* retry with a dynamically allocated buffer */
2033 while (status
== STATUS_BUFFER_OVERFLOW
)
2035 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2036 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2038 status
= ERROR_NOT_ENOUGH_MEMORY
;
2041 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2042 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2043 buf_ptr
, total_size
, &total_size
);
2046 if (status
) goto done
;
2050 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2052 status
= STATUS_BUFFER_OVERFLOW
;
2055 memcpy( value
, info
->Name
, info
->NameLength
);
2056 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2057 value
[*val_count
] = 0;
2062 if (total_size
- info
->DataOffset
> *count
)
2064 status
= STATUS_BUFFER_OVERFLOW
;
2067 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2068 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2070 /* if the type is REG_SZ and data is not 0-terminated
2071 * and there is enough space in the buffer NT appends a \0 */
2072 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2073 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2077 else status
= STATUS_SUCCESS
;
2080 if (type
) *type
= info
->Type
;
2081 if (count
) *count
= info
->DataLength
;
2084 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2085 CloseDefaultKey(KeyHandle
);
2086 return RtlNtStatusToDosError(status
);
2089 /************************************************************************
2095 RegFlushKey(HKEY hKey
)
2100 if (hKey
== HKEY_PERFORMANCE_DATA
)
2102 return ERROR_SUCCESS
;
2105 Status
= MapDefaultKey (&KeyHandle
,
2107 if (!NT_SUCCESS(Status
))
2109 return RtlNtStatusToDosError (Status
);
2112 Status
= NtFlushKey (KeyHandle
);
2114 CloseDefaultKey(KeyHandle
);
2116 if (!NT_SUCCESS(Status
))
2118 return RtlNtStatusToDosError (Status
);
2121 return ERROR_SUCCESS
;
2125 /************************************************************************
2131 RegGetKeySecurity(HKEY hKey
,
2132 SECURITY_INFORMATION SecurityInformation
,
2133 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2134 LPDWORD lpcbSecurityDescriptor
)
2139 if (hKey
== HKEY_PERFORMANCE_DATA
)
2141 return ERROR_INVALID_HANDLE
;
2144 Status
= MapDefaultKey(&KeyHandle
,
2146 if (!NT_SUCCESS(Status
))
2148 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2149 return RtlNtStatusToDosError (Status
);
2152 Status
= NtQuerySecurityObject(KeyHandle
,
2153 SecurityInformation
,
2154 pSecurityDescriptor
,
2155 *lpcbSecurityDescriptor
,
2156 lpcbSecurityDescriptor
);
2158 CloseDefaultKey(KeyHandle
);
2160 if (!NT_SUCCESS(Status
))
2162 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
2163 return RtlNtStatusToDosError (Status
);
2166 return ERROR_SUCCESS
;
2170 /************************************************************************
2176 RegLoadKeyA (HKEY hKey
,
2180 UNICODE_STRING FileName
;
2181 UNICODE_STRING KeyName
;
2184 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
2186 RtlCreateUnicodeStringFromAsciiz (&FileName
,
2189 ErrorCode
= RegLoadKeyW (hKey
,
2193 RtlFreeUnicodeString (&FileName
);
2194 RtlFreeUnicodeString (&KeyName
);
2200 /************************************************************************
2206 RegLoadKeyW (HKEY hKey
,
2210 OBJECT_ATTRIBUTES FileObjectAttributes
;
2211 OBJECT_ATTRIBUTES KeyObjectAttributes
;
2212 UNICODE_STRING FileName
;
2213 UNICODE_STRING KeyName
;
2216 LONG ErrorCode
= ERROR_SUCCESS
;
2218 if (hKey
== HKEY_PERFORMANCE_DATA
)
2220 return ERROR_INVALID_HANDLE
;
2223 Status
= MapDefaultKey (&KeyHandle
,
2225 if (!NT_SUCCESS(Status
))
2227 return RtlNtStatusToDosError (Status
);
2230 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpFile
,
2235 ErrorCode
= ERROR_BAD_PATHNAME
;
2239 InitializeObjectAttributes (&FileObjectAttributes
,
2241 OBJ_CASE_INSENSITIVE
,
2245 RtlInitUnicodeString (&KeyName
,
2248 InitializeObjectAttributes (&KeyObjectAttributes
,
2250 OBJ_CASE_INSENSITIVE
,
2254 Status
= NtLoadKey (&KeyObjectAttributes
,
2255 &FileObjectAttributes
);
2257 RtlFreeUnicodeString (&FileName
);
2259 if (!NT_SUCCESS(Status
))
2261 ErrorCode
= RtlNtStatusToDosError (Status
);
2266 CloseDefaultKey(KeyHandle
);
2272 /************************************************************************
2273 * RegNotifyChangeKeyValue
2278 RegNotifyChangeKeyValue (HKEY hKey
,
2280 DWORD dwNotifyFilter
,
2284 IO_STATUS_BLOCK IoStatusBlock
;
2287 LONG ErrorCode
= ERROR_SUCCESS
;
2289 if (hKey
== HKEY_PERFORMANCE_DATA
)
2291 return ERROR_INVALID_HANDLE
;
2294 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
2296 return ERROR_INVALID_PARAMETER
;
2299 Status
= MapDefaultKey (&KeyHandle
,
2301 if (!NT_SUCCESS(Status
))
2303 return RtlNtStatusToDosError (Status
);
2306 /* FIXME: Remote key handles must fail */
2308 Status
= NtNotifyChangeKey (KeyHandle
,
2318 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
2320 ErrorCode
= RtlNtStatusToDosError (Status
);
2323 CloseDefaultKey(KeyHandle
);
2329 /************************************************************************
2330 * RegOpenCurrentUser
2335 RegOpenCurrentUser (IN REGSAM samDesired
,
2336 OUT PHKEY phkResult
)
2340 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
2341 (PHANDLE
)phkResult
);
2342 if (!NT_SUCCESS(Status
))
2344 /* NOTE - don't set the last error code! just return the error! */
2345 return RtlNtStatusToDosError(Status
);
2348 return ERROR_SUCCESS
;
2352 /************************************************************************
2355 * 20050503 Fireball - imported from WINE
2360 RegOpenKeyA (HKEY hKey
,
2364 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2366 if (!lpSubKey
|| !*lpSubKey
)
2369 return ERROR_SUCCESS
;
2372 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2376 /************************************************************************
2381 * 20050503 Fireball - imported from WINE
2386 RegOpenKeyW (HKEY hKey
,
2390 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2392 if (!lpSubKey
|| !*lpSubKey
)
2395 return ERROR_SUCCESS
;
2397 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2401 /************************************************************************
2407 RegOpenKeyExA (HKEY hKey
,
2413 OBJECT_ATTRIBUTES ObjectAttributes
;
2414 UNICODE_STRING SubKeyString
;
2417 LONG ErrorCode
= ERROR_SUCCESS
;
2419 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2420 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2422 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2423 if (!NT_SUCCESS(Status
))
2425 return RtlNtStatusToDosError (Status
);
2428 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
2429 InitializeObjectAttributes (&ObjectAttributes
,
2431 OBJ_CASE_INSENSITIVE
,
2435 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2436 RtlFreeUnicodeString (&SubKeyString
);
2437 if (!NT_SUCCESS(Status
))
2439 ErrorCode
= RtlNtStatusToDosError (Status
);
2442 CloseDefaultKey(KeyHandle
);
2448 /************************************************************************
2454 RegOpenKeyExW (HKEY hKey
,
2460 OBJECT_ATTRIBUTES ObjectAttributes
;
2461 UNICODE_STRING SubKeyString
;
2464 LONG ErrorCode
= ERROR_SUCCESS
;
2466 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2467 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2469 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2470 if (!NT_SUCCESS(Status
))
2472 return RtlNtStatusToDosError (Status
);
2475 if (lpSubKey
!= NULL
)
2476 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
2478 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
2480 InitializeObjectAttributes (&ObjectAttributes
,
2482 OBJ_CASE_INSENSITIVE
,
2486 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2488 if (!NT_SUCCESS(Status
))
2490 ErrorCode
= RtlNtStatusToDosError (Status
);
2493 CloseDefaultKey(KeyHandle
);
2499 /************************************************************************
2500 * RegOpenUserClassesRoot
2505 RegOpenUserClassesRoot (IN HANDLE hToken
,
2507 IN REGSAM samDesired
,
2508 OUT PHKEY phkResult
)
2510 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
2511 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
2512 PTOKEN_USER TokenUserData
;
2513 ULONG RequiredLength
;
2514 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
2515 OBJECT_ATTRIBUTES ObjectAttributes
;
2518 /* check parameters */
2519 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
2521 return ERROR_INVALID_PARAMETER
;
2525 * Get the user sid from the token
2529 /* determine how much memory we need */
2530 Status
= NtQueryInformationToken(hToken
,
2535 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
2537 /* NOTE - as opposed to all other registry functions windows does indeed
2538 change the last error code in case the caller supplied a invalid
2539 handle for example! */
2540 return RtlNtStatusToDosError (Status
);
2543 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
2546 if (TokenUserData
== NULL
)
2548 return ERROR_NOT_ENOUGH_MEMORY
;
2551 /* attempt to read the information */
2552 Status
= NtQueryInformationToken(hToken
,
2557 if (!NT_SUCCESS(Status
))
2559 RtlFreeHeap(ProcessHeap
,
2562 if (Status
== STATUS_BUFFER_TOO_SMALL
)
2564 /* the information appears to have changed?! try again */
2568 /* NOTE - as opposed to all other registry functions windows does indeed
2569 change the last error code in case the caller supplied a invalid
2570 handle for example! */
2571 return RtlNtStatusToDosError (Status
);
2575 * Build the absolute path for the user's registry in the form
2576 * "\Registry\User\<SID>_Classes"
2578 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
2579 TokenUserData
->User
.Sid
,
2582 /* we don't need the user data anymore, free it */
2583 RtlFreeHeap(ProcessHeap
,
2587 if (!NT_SUCCESS(Status
))
2589 return RtlNtStatusToDosError (Status
);
2592 /* allocate enough memory for the entire key string */
2593 UserClassesKeyRoot
.Length
= 0;
2594 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
2595 sizeof(UserClassesKeyPrefix
) +
2596 sizeof(UserClassesKeySuffix
);
2597 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
2599 UserClassesKeyRoot
.MaximumLength
);
2600 if (UserClassesKeyRoot
.Buffer
== NULL
)
2602 RtlFreeUnicodeString(&UserSidString
);
2603 return RtlNtStatusToDosError (Status
);
2606 /* build the string */
2607 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2608 UserClassesKeyPrefix
);
2609 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
2611 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2612 UserClassesKeySuffix
);
2614 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
2620 InitializeObjectAttributes (&ObjectAttributes
,
2621 &UserClassesKeyRoot
,
2622 OBJ_CASE_INSENSITIVE
,
2626 Status
= NtOpenKey((PHANDLE
)phkResult
,
2630 RtlFreeUnicodeString(&UserSidString
);
2631 RtlFreeUnicodeString(&UserClassesKeyRoot
);
2633 if (!NT_SUCCESS(Status
))
2635 return RtlNtStatusToDosError (Status
);
2638 return ERROR_SUCCESS
;
2642 /************************************************************************
2648 RegQueryInfoKeyA (HKEY hKey
,
2653 LPDWORD lpcbMaxSubKeyLen
,
2654 LPDWORD lpcbMaxClassLen
,
2656 LPDWORD lpcbMaxValueNameLen
,
2657 LPDWORD lpcbMaxValueLen
,
2658 LPDWORD lpcbSecurityDescriptor
,
2659 PFILETIME lpftLastWriteTime
)
2661 WCHAR ClassName
[MAX_PATH
];
2662 UNICODE_STRING UnicodeString
;
2663 ANSI_STRING AnsiString
;
2666 RtlInitUnicodeString (&UnicodeString
,
2668 if (lpClass
!= NULL
)
2670 UnicodeString
.Buffer
= &ClassName
[0];
2671 UnicodeString
.MaximumLength
= sizeof(ClassName
);
2672 AnsiString
.MaximumLength
= *lpcbClass
;
2675 ErrorCode
= RegQueryInfoKeyW (hKey
,
2676 UnicodeString
.Buffer
,
2683 lpcbMaxValueNameLen
,
2685 lpcbSecurityDescriptor
,
2687 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
2689 AnsiString
.Buffer
= lpClass
;
2690 AnsiString
.Length
= 0;
2691 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
2692 RtlUnicodeStringToAnsiString (&AnsiString
,
2695 *lpcbClass
= AnsiString
.Length
;
2696 lpClass
[AnsiString
.Length
] = 0;
2703 /************************************************************************
2709 RegQueryInfoKeyW (HKEY hKey
,
2714 LPDWORD lpcbMaxSubKeyLen
,
2715 LPDWORD lpcbMaxClassLen
,
2717 LPDWORD lpcbMaxValueNameLen
,
2718 LPDWORD lpcbMaxValueLen
,
2719 LPDWORD lpcbSecurityDescriptor
,
2720 PFILETIME lpftLastWriteTime
)
2722 KEY_FULL_INFORMATION FullInfoBuffer
;
2723 PKEY_FULL_INFORMATION FullInfo
;
2725 ULONG ClassLength
= 0;
2729 LONG ErrorCode
= ERROR_SUCCESS
;
2731 if ((lpClass
) && (!lpcbClass
))
2733 return ERROR_INVALID_PARAMETER
;
2736 Status
= MapDefaultKey (&KeyHandle
,
2738 if (!NT_SUCCESS(Status
))
2740 return RtlNtStatusToDosError (Status
);
2743 if (lpClass
!= NULL
)
2747 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2754 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
2755 FullInfo
= RtlAllocateHeap (ProcessHeap
,
2758 if (FullInfo
== NULL
)
2760 ErrorCode
= ERROR_OUTOFMEMORY
;
2764 FullInfo
->ClassLength
= ClassLength
;
2768 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
2769 FullInfo
= &FullInfoBuffer
;
2770 FullInfo
->ClassLength
= 0;
2772 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
2774 Status
= NtQueryKey (KeyHandle
,
2779 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
2780 if (!NT_SUCCESS(Status
))
2782 if (lpClass
!= NULL
)
2784 RtlFreeHeap (ProcessHeap
,
2789 ErrorCode
= RtlNtStatusToDosError (Status
);
2793 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
2794 if (lpcSubKeys
!= NULL
)
2796 *lpcSubKeys
= FullInfo
->SubKeys
;
2799 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
2800 if (lpcbMaxSubKeyLen
!= NULL
)
2802 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
2805 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
2806 if (lpcbMaxClassLen
!= NULL
)
2808 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
2811 TRACE("Values %lu\n", FullInfo
->Values
);
2812 if (lpcValues
!= NULL
)
2814 *lpcValues
= FullInfo
->Values
;
2817 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
2818 if (lpcbMaxValueNameLen
!= NULL
)
2820 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
2823 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
2824 if (lpcbMaxValueLen
!= NULL
)
2826 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
2829 if (lpcbSecurityDescriptor
!= NULL
)
2831 Status
= NtQuerySecurityObject(KeyHandle
,
2832 OWNER_SECURITY_INFORMATION
|
2833 GROUP_SECURITY_INFORMATION
|
2834 DACL_SECURITY_INFORMATION
,
2837 lpcbSecurityDescriptor
);
2838 if (!NT_SUCCESS(Status
))
2840 if (lpClass
!= NULL
)
2842 RtlFreeHeap(ProcessHeap
,
2847 ErrorCode
= RtlNtStatusToDosError (Status
);
2852 if (lpftLastWriteTime
!= NULL
)
2854 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
2855 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
2858 if (lpClass
!= NULL
)
2860 if (FullInfo
->ClassLength
> ClassLength
)
2862 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2866 RtlCopyMemory (lpClass
,
2868 FullInfo
->ClassLength
);
2869 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
2870 lpClass
[*lpcbClass
] = 0;
2873 RtlFreeHeap (ProcessHeap
,
2879 CloseDefaultKey(KeyHandle
);
2885 /************************************************************************
2886 * RegQueryMultipleValuesA
2891 RegQueryMultipleValuesA (HKEY hKey
,
2898 DWORD maxBytes
= *ldwTotsize
;
2899 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
2902 if (maxBytes
>= (1024*1024))
2903 return ERROR_TRANSFER_TOO_LONG
;
2907 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
2908 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
2910 for (i
= 0; i
< num_vals
; i
++)
2912 val_list
[i
].ve_valuelen
= 0;
2913 ErrorCode
= RegQueryValueExA (hKey
,
2914 val_list
[i
].ve_valuename
,
2918 &val_list
[i
].ve_valuelen
);
2919 if (ErrorCode
!= ERROR_SUCCESS
)
2924 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
2926 ErrorCode
= RegQueryValueExA (hKey
,
2927 val_list
[i
].ve_valuename
,
2929 &val_list
[i
].ve_type
,
2931 &val_list
[i
].ve_valuelen
);
2932 if (ErrorCode
!= ERROR_SUCCESS
)
2937 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
2939 bufptr
+= val_list
[i
].ve_valuelen
;
2942 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
2945 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
2949 /************************************************************************
2950 * RegQueryMultipleValuesW
2955 RegQueryMultipleValuesW (HKEY hKey
,
2962 DWORD maxBytes
= *ldwTotsize
;
2963 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
2966 if (maxBytes
>= (1024*1024))
2967 return ERROR_TRANSFER_TOO_LONG
;
2971 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
2972 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
2974 for (i
= 0; i
< num_vals
; i
++)
2976 val_list
[i
].ve_valuelen
= 0;
2977 ErrorCode
= RegQueryValueExW (hKey
,
2978 val_list
[i
].ve_valuename
,
2982 &val_list
[i
].ve_valuelen
);
2983 if (ErrorCode
!= ERROR_SUCCESS
)
2988 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
2990 ErrorCode
= RegQueryValueExW (hKey
,
2991 val_list
[i
].ve_valuename
,
2993 &val_list
[i
].ve_type
,
2995 &val_list
[i
].ve_valuelen
);
2996 if (ErrorCode
!= ERROR_SUCCESS
)
3001 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3003 bufptr
+= val_list
[i
].ve_valuelen
;
3006 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3009 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3013 /************************************************************************
3019 RegQueryValueExW (HKEY hKey
,
3020 LPCWSTR lpValueName
,
3026 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
3027 UNICODE_STRING ValueName
;
3032 LONG ErrorCode
= ERROR_SUCCESS
;
3033 ULONG MaxCopy
= lpcbData
!= NULL
&& lpData
!= NULL
? *lpcbData
: 0;
3035 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3036 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3038 Status
= MapDefaultKey (&KeyHandle
,
3040 if (!NT_SUCCESS(Status
))
3042 return RtlNtStatusToDosError (Status
);
3045 if (lpData
!= NULL
&& lpcbData
== NULL
)
3047 ErrorCode
= ERROR_INVALID_PARAMETER
;
3051 RtlInitUnicodeString (&ValueName
,
3053 BufferSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MaxCopy
;
3054 ValueInfo
= RtlAllocateHeap (ProcessHeap
,
3057 if (ValueInfo
== NULL
)
3059 ErrorCode
= ERROR_OUTOFMEMORY
;
3063 Status
= NtQueryValueKey (KeyHandle
,
3065 KeyValuePartialInformation
,
3069 TRACE("Status 0x%X\n", Status
);
3070 if (Status
== STATUS_BUFFER_OVERFLOW
)
3072 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3074 ErrorCode
= lpData
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
3076 else if (!NT_SUCCESS(Status
))
3078 ErrorCode
= RtlNtStatusToDosError (Status
);
3080 if (lpcbData
!= NULL
)
3082 ResultSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + *lpcbData
;
3088 *lpType
= ValueInfo
->Type
;
3091 if (NT_SUCCESS(Status
) && lpData
!= NULL
)
3093 RtlMoveMemory (lpData
,
3095 min(ValueInfo
->DataLength
, MaxCopy
));
3098 if ((ValueInfo
->Type
== REG_SZ
) ||
3099 (ValueInfo
->Type
== REG_MULTI_SZ
) ||
3100 (ValueInfo
->Type
== REG_EXPAND_SZ
))
3102 if (lpData
!= NULL
&& MaxCopy
> ValueInfo
->DataLength
)
3104 ((PWSTR
)lpData
)[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = 0;
3107 if (lpcbData
!= NULL
)
3109 *lpcbData
= (ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]));
3110 TRACE("(string) Returning Size: %lu\n", *lpcbData
);
3115 if (lpcbData
!= NULL
)
3117 *lpcbData
= ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
3118 TRACE("(other) Returning Size: %lu\n", *lpcbData
);
3122 TRACE("Type %d Size %d\n", ValueInfo
->Type
, ValueInfo
->DataLength
);
3124 RtlFreeHeap (ProcessHeap
,
3129 CloseDefaultKey(KeyHandle
);
3135 /************************************************************************
3141 RegQueryValueExA (HKEY hKey
,
3148 UNICODE_STRING ValueName
;
3149 UNICODE_STRING ValueData
;
3150 ANSI_STRING AnsiString
;
3155 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3156 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3158 if (lpData
!= NULL
&& lpcbData
== NULL
)
3160 return ERROR_INVALID_PARAMETER
;
3165 ValueData
.Length
= 0;
3166 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3167 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3169 ValueData
.MaximumLength
);
3170 if (!ValueData
.Buffer
)
3172 return ERROR_OUTOFMEMORY
;
3177 ValueData
.Buffer
= NULL
;
3178 ValueData
.Length
= 0;
3179 ValueData
.MaximumLength
= 0;
3182 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3183 (LPSTR
)lpValueName
);
3185 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
3186 ErrorCode
= RegQueryValueExW (hKey
,
3190 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
3192 TRACE("ErrorCode %lu\n", ErrorCode
);
3193 RtlFreeUnicodeString(&ValueName
);
3195 if (ErrorCode
== ERROR_SUCCESS
||
3196 ErrorCode
== ERROR_MORE_DATA
)
3203 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
3205 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3207 RtlInitAnsiString(&AnsiString
, NULL
);
3208 AnsiString
.Buffer
= (LPSTR
)lpData
;
3209 AnsiString
.MaximumLength
= *lpcbData
;
3210 ValueData
.Length
= Length
;
3211 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
3212 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
3214 Length
= Length
/ sizeof(WCHAR
);
3216 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3218 if (*lpcbData
< Length
)
3220 ErrorCode
= ERROR_MORE_DATA
;
3224 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
3228 if (lpcbData
!= NULL
)
3234 if (ValueData
.Buffer
!= NULL
)
3236 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
3243 /************************************************************************
3249 RegQueryValueA (HKEY hKey
,
3254 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
3255 UNICODE_STRING SubKeyName
;
3256 UNICODE_STRING Value
;
3257 ANSI_STRING AnsiString
;
3261 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3262 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3264 if (lpValue
!= NULL
&&
3267 return ERROR_INVALID_PARAMETER
;
3270 RtlInitUnicodeString (&SubKeyName
,
3272 RtlInitUnicodeString (&Value
,
3274 if (lpSubKey
!= NULL
&&
3275 strlen(lpSubKey
) != 0)
3277 RtlInitAnsiString (&AnsiString
,
3279 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
3280 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
3281 RtlAnsiStringToUnicodeString (&SubKeyName
,
3286 if (lpValue
!= NULL
)
3288 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
3289 Value
.MaximumLength
= ValueSize
;
3290 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3293 if (Value
.Buffer
== NULL
)
3295 return ERROR_OUTOFMEMORY
;
3303 ErrorCode
= RegQueryValueW (hKey
,
3304 (LPCWSTR
)SubKeyName
.Buffer
,
3307 if (ErrorCode
== ERROR_SUCCESS
)
3309 Value
.Length
= ValueSize
;
3310 RtlInitAnsiString (&AnsiString
,
3312 AnsiString
.Buffer
= lpValue
;
3313 AnsiString
.MaximumLength
= *lpcbValue
;
3314 RtlUnicodeStringToAnsiString (&AnsiString
,
3319 *lpcbValue
= ValueSize
;
3320 if (Value
.Buffer
!= NULL
)
3322 RtlFreeHeap (ProcessHeap
,
3331 /************************************************************************
3337 RegQueryValueW (HKEY hKey
,
3342 OBJECT_ATTRIBUTES ObjectAttributes
;
3343 UNICODE_STRING SubKeyString
;
3350 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3351 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3353 Status
= MapDefaultKey (&KeyHandle
,
3355 if (!NT_SUCCESS(Status
))
3357 return RtlNtStatusToDosError (Status
);
3360 if (lpSubKey
!= NULL
&&
3361 wcslen(lpSubKey
) != 0)
3363 RtlInitUnicodeString (&SubKeyString
,
3365 InitializeObjectAttributes (&ObjectAttributes
,
3367 OBJ_CASE_INSENSITIVE
,
3370 Status
= NtOpenKey (&RealKey
,
3373 if (!NT_SUCCESS(Status
))
3375 ErrorCode
= RtlNtStatusToDosError (Status
);
3378 CloseRealKey
= TRUE
;
3383 CloseRealKey
= FALSE
;
3386 ErrorCode
= RegQueryValueExW (RealKey
,
3391 (LPDWORD
)lpcbValue
);
3398 CloseDefaultKey(KeyHandle
);
3404 /************************************************************************
3410 RegReplaceKeyA (HKEY hKey
,
3415 UNICODE_STRING SubKey
;
3416 UNICODE_STRING NewFile
;
3417 UNICODE_STRING OldFile
;
3420 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
3422 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
3424 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
3427 ErrorCode
= RegReplaceKeyW (hKey
,
3432 RtlFreeUnicodeString (&OldFile
);
3433 RtlFreeUnicodeString (&NewFile
);
3434 RtlFreeUnicodeString (&SubKey
);
3440 /************************************************************************
3446 RegReplaceKeyW (HKEY hKey
,
3451 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3452 OBJECT_ATTRIBUTES NewObjectAttributes
;
3453 OBJECT_ATTRIBUTES OldObjectAttributes
;
3454 UNICODE_STRING SubKeyName
;
3455 UNICODE_STRING NewFileName
;
3456 UNICODE_STRING OldFileName
;
3457 BOOLEAN CloseRealKey
;
3458 HANDLE RealKeyHandle
;
3461 LONG ErrorCode
= ERROR_SUCCESS
;
3463 if (hKey
== HKEY_PERFORMANCE_DATA
)
3465 return ERROR_INVALID_HANDLE
;
3468 Status
= MapDefaultKey (&KeyHandle
,
3470 if (!NT_SUCCESS(Status
))
3472 return RtlNtStatusToDosError (Status
);
3475 /* Open the real key */
3476 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
3478 RtlInitUnicodeString (&SubKeyName
,
3480 InitializeObjectAttributes (&KeyObjectAttributes
,
3482 OBJ_CASE_INSENSITIVE
,
3485 Status
= NtOpenKey (&RealKeyHandle
,
3487 &KeyObjectAttributes
);
3488 if (!NT_SUCCESS(Status
))
3490 ErrorCode
= RtlNtStatusToDosError (Status
);
3493 CloseRealKey
= TRUE
;
3497 RealKeyHandle
= KeyHandle
;
3498 CloseRealKey
= FALSE
;
3501 /* Convert new file name */
3502 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpNewFile
,
3509 NtClose (RealKeyHandle
);
3511 ErrorCode
= ERROR_INVALID_PARAMETER
;
3515 InitializeObjectAttributes (&NewObjectAttributes
,
3517 OBJ_CASE_INSENSITIVE
,
3521 /* Convert old file name */
3522 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpOldFile
,
3527 RtlFreeUnicodeString (&NewFileName
);
3530 NtClose (RealKeyHandle
);
3532 ErrorCode
= ERROR_INVALID_PARAMETER
;
3536 InitializeObjectAttributes (&OldObjectAttributes
,
3538 OBJ_CASE_INSENSITIVE
,
3542 Status
= NtReplaceKey (&NewObjectAttributes
,
3544 &OldObjectAttributes
);
3546 RtlFreeUnicodeString (&OldFileName
);
3547 RtlFreeUnicodeString (&NewFileName
);
3551 NtClose (RealKeyHandle
);
3554 if (!NT_SUCCESS(Status
))
3556 return RtlNtStatusToDosError (Status
);
3560 CloseDefaultKey(KeyHandle
);
3566 /************************************************************************
3572 RegRestoreKeyA (HKEY hKey
,
3576 UNICODE_STRING FileName
;
3579 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3582 ErrorCode
= RegRestoreKeyW (hKey
,
3586 RtlFreeUnicodeString (&FileName
);
3592 /************************************************************************
3598 RegRestoreKeyW (HKEY hKey
,
3602 OBJECT_ATTRIBUTES ObjectAttributes
;
3603 IO_STATUS_BLOCK IoStatusBlock
;
3604 UNICODE_STRING FileName
;
3609 if (hKey
== HKEY_PERFORMANCE_DATA
)
3611 return ERROR_INVALID_HANDLE
;
3614 Status
= MapDefaultKey (&KeyHandle
,
3616 if (!NT_SUCCESS(Status
))
3618 return RtlNtStatusToDosError (Status
);
3621 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpFile
,
3626 Status
= STATUS_INVALID_PARAMETER
;
3630 InitializeObjectAttributes (&ObjectAttributes
,
3632 OBJ_CASE_INSENSITIVE
,
3636 Status
= NtOpenFile (&FileHandle
,
3641 FILE_SYNCHRONOUS_IO_NONALERT
);
3642 RtlFreeUnicodeString (&FileName
);
3643 if (!NT_SUCCESS(Status
))
3648 Status
= NtRestoreKey (KeyHandle
,
3651 NtClose (FileHandle
);
3654 CloseDefaultKey(KeyHandle
);
3656 if (!NT_SUCCESS(Status
))
3658 return RtlNtStatusToDosError (Status
);
3661 return ERROR_SUCCESS
;
3665 /************************************************************************
3671 RegSaveKeyA (HKEY hKey
,
3673 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
3675 UNICODE_STRING FileName
;
3678 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3680 ErrorCode
= RegSaveKeyW (hKey
,
3682 lpSecurityAttributes
);
3683 RtlFreeUnicodeString (&FileName
);
3689 /************************************************************************
3695 RegSaveKeyW (HKEY hKey
,
3697 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
3699 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
3700 OBJECT_ATTRIBUTES ObjectAttributes
;
3701 UNICODE_STRING FileName
;
3702 IO_STATUS_BLOCK IoStatusBlock
;
3707 Status
= MapDefaultKey (&KeyHandle
,
3709 if (!NT_SUCCESS(Status
))
3711 return RtlNtStatusToDosError (Status
);
3714 if (!RtlDosPathNameToNtPathName_U ((PWSTR
)lpFile
,
3719 Status
= STATUS_INVALID_PARAMETER
;
3723 if (lpSecurityAttributes
!= NULL
)
3725 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
3728 InitializeObjectAttributes (&ObjectAttributes
,
3730 OBJ_CASE_INSENSITIVE
,
3732 SecurityDescriptor
);
3733 Status
= NtCreateFile (&FileHandle
,
3734 GENERIC_WRITE
| SYNCHRONIZE
,
3738 FILE_ATTRIBUTE_NORMAL
,
3741 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
3744 RtlFreeUnicodeString (&FileName
);
3745 if (!NT_SUCCESS(Status
))
3750 Status
= NtSaveKey (KeyHandle
,
3752 NtClose (FileHandle
);
3755 CloseDefaultKey(KeyHandle
);
3757 if (!NT_SUCCESS(Status
))
3759 return RtlNtStatusToDosError (Status
);
3762 return ERROR_SUCCESS
;
3766 /************************************************************************
3772 RegSetKeySecurity (HKEY hKey
,
3773 SECURITY_INFORMATION SecurityInformation
,
3774 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
3779 if (hKey
== HKEY_PERFORMANCE_DATA
)
3781 return ERROR_INVALID_HANDLE
;
3784 Status
= MapDefaultKey (&KeyHandle
,
3786 if (!NT_SUCCESS(Status
))
3788 return RtlNtStatusToDosError (Status
);
3791 Status
= NtSetSecurityObject (KeyHandle
,
3792 SecurityInformation
,
3793 pSecurityDescriptor
);
3795 CloseDefaultKey(KeyHandle
);
3797 if (!NT_SUCCESS(Status
))
3799 return RtlNtStatusToDosError (Status
);
3802 return ERROR_SUCCESS
;
3806 /************************************************************************
3812 RegSetValueExA (HKEY hKey
,
3819 UNICODE_STRING ValueName
;
3821 ANSI_STRING AnsiString
;
3822 UNICODE_STRING Data
;
3827 if (lpValueName
!= NULL
&&
3828 strlen(lpValueName
) != 0)
3830 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3832 pValueName
= (LPWSTR
)ValueName
.Buffer
;
3839 if (((dwType
== REG_SZ
) ||
3840 (dwType
== REG_MULTI_SZ
) ||
3841 (dwType
== REG_EXPAND_SZ
)) &&
3844 /* NT adds one if the caller forgot the NULL-termination character */
3845 if (lpData
[cbData
- 1] != '\0')
3850 RtlInitAnsiString (&AnsiString
,
3852 AnsiString
.Buffer
= (PSTR
)lpData
;
3853 AnsiString
.Length
= cbData
- 1;
3854 AnsiString
.MaximumLength
= cbData
;
3855 RtlAnsiStringToUnicodeString (&Data
,
3858 pData
= (LPBYTE
)Data
.Buffer
;
3859 DataSize
= cbData
* sizeof(WCHAR
);
3863 RtlInitUnicodeString (&Data
,
3865 pData
= (LPBYTE
)lpData
;
3869 ErrorCode
= RegSetValueExW (hKey
,
3875 if (pValueName
!= NULL
)
3877 RtlFreeHeap (ProcessHeap
,
3882 if (Data
.Buffer
!= NULL
)
3884 RtlFreeHeap (ProcessHeap
,
3893 /************************************************************************
3899 RegSetValueExW (HKEY hKey
,
3900 LPCWSTR lpValueName
,
3906 UNICODE_STRING ValueName
;
3907 PUNICODE_STRING pValueName
;
3911 Status
= MapDefaultKey (&KeyHandle
,
3913 if (!NT_SUCCESS(Status
))
3915 return RtlNtStatusToDosError (Status
);
3918 if (lpValueName
!= NULL
)
3920 RtlInitUnicodeString (&ValueName
,
3925 RtlInitUnicodeString (&ValueName
, L
"");
3927 pValueName
= &ValueName
;
3929 if (((dwType
== REG_SZ
) ||
3930 (dwType
== REG_MULTI_SZ
) ||
3931 (dwType
== REG_EXPAND_SZ
)) &&
3932 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
3934 /* NT adds one if the caller forgot the NULL-termination character */
3935 cbData
+= sizeof(WCHAR
);
3938 Status
= NtSetValueKey (KeyHandle
,
3945 CloseDefaultKey(KeyHandle
);
3947 if (!NT_SUCCESS(Status
))
3949 return RtlNtStatusToDosError (Status
);
3952 return ERROR_SUCCESS
;
3956 /************************************************************************
3962 RegSetValueA (HKEY hKey
,
3971 if (dwType
!= REG_SZ
)
3973 return ERROR_INVALID_PARAMETER
;
3976 if (lpSubKey
!= NULL
&& lpSubKey
[0] != '\0')
3978 ret
= RegCreateKeyA(hKey
,
3982 if (ret
!= ERROR_SUCCESS
)
3990 ret
= RegSetValueExA(hSubKey
,
3994 (CONST BYTE
*)lpData
,
3995 strlen(lpData
) + 1);
3997 if (hSubKey
!= hKey
)
3999 RegCloseKey(hSubKey
);
4006 /************************************************************************
4012 RegSetValueW (HKEY hKey
,
4018 OBJECT_ATTRIBUTES ObjectAttributes
;
4019 UNICODE_STRING SubKeyString
;
4026 Status
= MapDefaultKey (&KeyHandle
,
4028 if (!NT_SUCCESS(Status
))
4030 return RtlNtStatusToDosError (Status
);
4033 if ((lpSubKey
) && (wcslen(lpSubKey
) != 0))
4035 RtlInitUnicodeString (&SubKeyString
,
4037 InitializeObjectAttributes (&ObjectAttributes
,
4039 OBJ_CASE_INSENSITIVE
,
4042 Status
= NtOpenKey (&RealKey
,
4045 if (!NT_SUCCESS(Status
))
4047 ErrorCode
= RtlNtStatusToDosError (Status
);
4050 CloseRealKey
= TRUE
;
4055 CloseRealKey
= FALSE
;
4058 ErrorCode
= RegSetValueExW (RealKey
,
4064 if (CloseRealKey
== TRUE
)
4070 CloseDefaultKey(KeyHandle
);
4076 /************************************************************************
4082 RegUnLoadKeyA (HKEY hKey
,
4085 UNICODE_STRING KeyName
;
4088 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4091 ErrorCode
= RegUnLoadKeyW (hKey
,
4094 RtlFreeUnicodeString (&KeyName
);
4100 /************************************************************************
4106 RegUnLoadKeyW (HKEY hKey
,
4109 OBJECT_ATTRIBUTES ObjectAttributes
;
4110 UNICODE_STRING KeyName
;
4114 if (hKey
== HKEY_PERFORMANCE_DATA
)
4116 return ERROR_INVALID_HANDLE
;
4119 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4120 if (!NT_SUCCESS(Status
))
4122 return RtlNtStatusToDosError (Status
);
4125 RtlInitUnicodeString (&KeyName
,
4128 InitializeObjectAttributes (&ObjectAttributes
,
4130 OBJ_CASE_INSENSITIVE
,
4134 Status
= NtUnloadKey (&ObjectAttributes
);
4136 CloseDefaultKey(KeyHandle
);
4138 if (!NT_SUCCESS(Status
))
4140 return RtlNtStatusToDosError (Status
);
4143 return ERROR_SUCCESS
;
4147 /************************************************************************
4153 RegLoadMUIStringW(IN HKEY hKey
,
4154 IN LPCWSTR pszValue OPTIONAL
,
4155 OUT LPWSTR pszOutBuf
,
4158 IN LPCWSTR pszDirectory OPTIONAL
)
4160 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4161 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4162 return ERROR_CALL_NOT_IMPLEMENTED
;
4166 /************************************************************************
4172 RegLoadMUIStringA(IN HKEY hKey
,
4173 IN LPCSTR pszValue OPTIONAL
,
4174 OUT LPSTR pszOutBuf
,
4177 IN LPCSTR pszDirectory OPTIONAL
)
4179 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4180 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4181 return ERROR_CALL_NOT_IMPLEMENTED
;