2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
18 #include <wine/debug.h>
20 WINE_DEFAULT_DEBUG_CHANNEL(advapi32
);
22 /* DEFINES ******************************************************************/
24 #define MAX_DEFAULT_HANDLES 6
25 #define REG_MAX_NAME_SIZE 256
26 #define REG_MAX_DATA_SIZE 2048
28 /* GLOBALS ******************************************************************/
30 static RTL_CRITICAL_SECTION HandleTableCS
;
31 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
32 static HANDLE ProcessHeap
;
33 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
34 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
36 /* PROTOTYPES ***************************************************************/
38 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
39 static VOID
CloseDefaultKeys(VOID
);
40 #define ClosePredefKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
44 #define IsPredefKey(HKey) \
45 (((ULONG)(HKey) & 0xF0000000) == 0x80000000)
46 #define GetPredefKeyIndex(HKey) \
47 ((ULONG)(HKey) & 0x0FFFFFFF)
49 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
50 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
52 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
55 /* FUNCTIONS ****************************************************************/
56 /* check if value type needs string conversion (Ansi<->Unicode) */
57 __inline
static int is_string( DWORD type
)
59 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
62 /************************************************************************
63 * RegInitDefaultHandles
68 TRACE("RegInitialize()\n");
70 ProcessHeap
= RtlGetProcessHeap();
71 RtlZeroMemory (DefaultHandleTable
,
72 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
73 RtlInitializeCriticalSection (&HandleTableCS
);
79 /************************************************************************
85 TRACE("RegCleanup()\n");
88 RtlDeleteCriticalSection (&HandleTableCS
);
95 OpenPredefinedKey(IN ULONG Index
,
102 case 0: /* HKEY_CLASSES_ROOT */
103 Status
= OpenClassesRootKey (Handle
);
106 case 1: /* HKEY_CURRENT_USER */
107 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
111 case 2: /* HKEY_LOCAL_MACHINE */
112 Status
= OpenLocalMachineKey (Handle
);
115 case 3: /* HKEY_USERS */
116 Status
= OpenUsersKey (Handle
);
119 case 4: /* HKEY_PERFORMANCE_DATA */
120 Status
= OpenPerformanceDataKey (Handle
);
124 case 5: /* HKEY_CURRENT_CONFIG */
125 Status
= OpenCurrentConfigKey (Handle
);
128 case 6: /* HKEY_DYN_DATA */
129 Status
= STATUS_NOT_IMPLEMENTED
;
133 WARN("MapDefaultHandle() no handle creator\n");
134 Status
= STATUS_INVALID_PARAMETER
;
143 MapDefaultKey (OUT PHANDLE RealKey
,
148 BOOLEAN DoOpen
, DefDisabled
;
149 NTSTATUS Status
= STATUS_SUCCESS
;
151 TRACE("MapDefaultKey (Key %x)\n", Key
);
153 if (!IsPredefKey(Key
))
155 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
156 return STATUS_SUCCESS
;
159 /* Handle special cases here */
160 Index
= GetPredefKeyIndex(Key
);
161 if (Index
>= MAX_DEFAULT_HANDLES
)
163 return STATUS_INVALID_PARAMETER
;
166 RtlEnterCriticalSection (&HandleTableCS
);
168 if (Key
== HKEY_CURRENT_USER
)
169 DefDisabled
= DefaultHandleHKUDisabled
;
171 DefDisabled
= DefaultHandlesDisabled
;
175 Handle
= &DefaultHandleTable
[Index
];
176 DoOpen
= (*Handle
== NULL
);
186 /* create/open the default handle */
187 Status
= OpenPredefinedKey(Index
,
191 if (NT_SUCCESS(Status
))
196 *(PULONG_PTR
)Handle
|= 0x1;
199 RtlLeaveCriticalSection (&HandleTableCS
);
206 CloseDefaultKeys (VOID
)
210 RtlEnterCriticalSection (&HandleTableCS
);
211 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
213 if (DefaultHandleTable
[i
] != NULL
)
215 NtClose (DefaultHandleTable
[i
]);
216 DefaultHandleTable
[i
] = NULL
;
219 RtlLeaveCriticalSection (&HandleTableCS
);
224 OpenClassesRootKey (PHANDLE KeyHandle
)
226 OBJECT_ATTRIBUTES Attributes
;
227 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
229 TRACE("OpenClassesRootKey()\n");
231 InitializeObjectAttributes (&Attributes
,
233 OBJ_CASE_INSENSITIVE
,
236 return NtOpenKey (KeyHandle
,
243 OpenLocalMachineKey (PHANDLE KeyHandle
)
245 OBJECT_ATTRIBUTES Attributes
;
246 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
249 TRACE("OpenLocalMachineKey()\n");
251 InitializeObjectAttributes (&Attributes
,
253 OBJ_CASE_INSENSITIVE
,
256 Status
= NtOpenKey (KeyHandle
,
260 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
266 OpenUsersKey (PHANDLE KeyHandle
)
268 OBJECT_ATTRIBUTES Attributes
;
269 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
271 TRACE("OpenUsersKey()\n");
273 InitializeObjectAttributes (&Attributes
,
275 OBJ_CASE_INSENSITIVE
,
278 return NtOpenKey (KeyHandle
,
285 OpenCurrentConfigKey (PHANDLE KeyHandle
)
287 OBJECT_ATTRIBUTES Attributes
;
288 UNICODE_STRING KeyName
=
289 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
291 TRACE("OpenCurrentConfigKey()\n");
293 InitializeObjectAttributes (&Attributes
,
295 OBJ_CASE_INSENSITIVE
,
298 return NtOpenKey (KeyHandle
,
304 /************************************************************************
305 * RegDisablePredefinedCache
310 RegDisablePredefinedCache(VOID
)
312 RtlEnterCriticalSection (&HandleTableCS
);
313 DefaultHandleHKUDisabled
= TRUE
;
314 RtlLeaveCriticalSection (&HandleTableCS
);
315 return ERROR_SUCCESS
;
319 /************************************************************************
320 * RegDisablePredefinedCacheEx
325 RegDisablePredefinedCacheEx(VOID
)
327 RtlEnterCriticalSection (&HandleTableCS
);
328 DefaultHandlesDisabled
= TRUE
;
329 DefaultHandleHKUDisabled
= TRUE
;
330 RtlLeaveCriticalSection (&HandleTableCS
);
331 return ERROR_SUCCESS
;
335 /************************************************************************
336 * RegOverridePredefKey
341 RegOverridePredefKey(IN HKEY hKey
,
342 IN HKEY hNewHKey OPTIONAL
)
344 LONG ErrorCode
= ERROR_SUCCESS
;
346 if ((hKey
== HKEY_CLASSES_ROOT
||
347 hKey
== HKEY_CURRENT_CONFIG
||
348 hKey
== HKEY_CURRENT_USER
||
349 hKey
== HKEY_LOCAL_MACHINE
||
350 hKey
== HKEY_PERFORMANCE_DATA
||
351 hKey
== HKEY_USERS
) &&
352 !IsPredefKey(hNewHKey
))
357 Index
= GetPredefKeyIndex(hKey
);
358 Handle
= &DefaultHandleTable
[Index
];
360 if (hNewHKey
== NULL
)
362 /* restore the default mapping */
363 NTSTATUS Status
= OpenPredefinedKey(Index
,
365 if (!NT_SUCCESS(Status
))
367 return RtlNtStatusToDosError(Status
);
370 ASSERT(hNewHKey
!= NULL
);
373 RtlEnterCriticalSection (&HandleTableCS
);
375 /* close the currently mapped handle if existing */
381 /* update the mapping */
384 RtlLeaveCriticalSection (&HandleTableCS
);
387 ErrorCode
= ERROR_INVALID_HANDLE
;
393 /************************************************************************
399 RegCloseKey (HKEY hKey
)
403 /* don't close null handle or a pseudo handle */
404 if ((!hKey
) || (((ULONG
)hKey
& 0xF0000000) == 0x80000000))
406 return ERROR_INVALID_HANDLE
;
409 Status
= NtClose (hKey
);
410 if (!NT_SUCCESS(Status
))
412 return RtlNtStatusToDosError (Status
);
415 return ERROR_SUCCESS
;
420 RegpCopyTree(IN HKEY hKeySrc
,
425 LIST_ENTRY ListEntry
;
428 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
430 LIST_ENTRY copyQueueHead
;
431 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
434 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
435 KEY_NODE_INFORMATION
*KeyNode
;
438 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
439 NTSTATUS Status
= STATUS_SUCCESS
;
440 NTSTATUS Status2
= STATUS_SUCCESS
;
442 InitializeListHead(©QueueHead
);
444 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
447 if (Info
.Buffer
== NULL
)
449 return STATUS_INSUFFICIENT_RESOURCES
;
452 copyKeys
= RtlAllocateHeap(ProcessHeap
,
454 sizeof(REGP_COPY_KEYS
));
455 if (copyKeys
!= NULL
)
457 copyKeys
->hKeySrc
= hKeySrc
;
458 copyKeys
->hKeyDest
= hKeyDest
;
459 InsertHeadList(©QueueHead
,
460 ©Keys
->ListEntry
);
462 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
466 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
470 /* enumerate all values and copy them */
474 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
476 KeyValueFullInformation
,
479 &BufferSizeRequired
);
480 if (NT_SUCCESS(Status2
))
482 UNICODE_STRING ValueName
;
485 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
486 ValueName
.Length
= Info
.KeyValue
->NameLength
;
487 ValueName
.MaximumLength
= ValueName
.Length
;
488 ValueName
.Buffer
= Info
.KeyValue
->Name
;
490 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
492 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
494 Info
.KeyValue
->TitleIndex
,
497 Info
.KeyValue
->DataLength
);
499 /* don't break, let's try to copy as many values as possible */
500 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
507 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
511 ASSERT(BufferSize
< BufferSizeRequired
);
513 Buffer
= RtlReAllocateHeap(ProcessHeap
,
519 Info
.Buffer
= Buffer
;
524 /* don't break, let's try to copy as many values as possible */
525 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
528 if (NT_SUCCESS(Status
))
536 /* break to avoid an infinite loop in case of denied access or
538 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
547 /* enumerate all subkeys and open and enqueue them */
551 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
556 &BufferSizeRequired
);
557 if (NT_SUCCESS(Status2
))
559 HANDLE KeyHandle
, NewKeyHandle
;
560 OBJECT_ATTRIBUTES ObjectAttributes
;
561 UNICODE_STRING SubKeyName
, ClassName
;
563 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
564 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
565 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
566 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
567 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
568 ClassName
.MaximumLength
= ClassName
.Length
;
569 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
571 /* open the subkey with sufficient rights */
573 InitializeObjectAttributes(&ObjectAttributes
,
575 OBJ_CASE_INSENSITIVE
,
579 Status2
= NtOpenKey(&KeyHandle
,
580 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
582 if (NT_SUCCESS(Status2
))
584 /* FIXME - attempt to query the security information */
586 InitializeObjectAttributes(&ObjectAttributes
,
588 OBJ_CASE_INSENSITIVE
,
592 Status2
= NtCreateKey(&NewKeyHandle
,
595 Info
.KeyNode
->TitleIndex
,
599 if (NT_SUCCESS(Status2
))
601 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
603 sizeof(REGP_COPY_KEYS
));
604 if (newCopyKeys
!= NULL
)
606 /* save the handles and enqueue the subkey */
607 newCopyKeys
->hKeySrc
= KeyHandle
;
608 newCopyKeys
->hKeyDest
= NewKeyHandle
;
609 InsertTailList(©QueueHead
,
610 &newCopyKeys
->ListEntry
);
615 NtClose(NewKeyHandle
);
617 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
626 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
633 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
637 ASSERT(BufferSize
< BufferSizeRequired
);
639 Buffer
= RtlReAllocateHeap(ProcessHeap
,
645 Info
.Buffer
= Buffer
;
650 /* don't break, let's try to copy as many keys as possible */
651 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
654 if (NT_SUCCESS(Status
))
662 /* break to avoid an infinite loop in case of denied access or
664 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
673 /* close the handles and remove the entry from the list */
674 if (copyKeys
->hKeySrc
!= hKeySrc
)
676 NtClose(copyKeys
->hKeySrc
);
678 if (copyKeys
->hKeyDest
!= hKeyDest
)
680 NtClose(copyKeys
->hKeyDest
);
683 RemoveEntryList(©Keys
->ListEntry
);
685 RtlFreeHeap(ProcessHeap
,
688 } while (!IsListEmpty(©QueueHead
));
691 Status
= STATUS_INSUFFICIENT_RESOURCES
;
693 RtlFreeHeap(ProcessHeap
,
701 /************************************************************************
707 RegCopyTreeW(IN HKEY hKeySrc
,
708 IN LPCWSTR lpSubKey OPTIONAL
,
711 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
714 Status
= MapDefaultKey(&KeyHandle
,
716 if (!NT_SUCCESS(Status
))
718 return RtlNtStatusToDosError(Status
);
721 Status
= MapDefaultKey(&DestKeyHandle
,
723 if (!NT_SUCCESS(Status
))
728 if (lpSubKey
!= NULL
)
730 OBJECT_ATTRIBUTES ObjectAttributes
;
731 UNICODE_STRING SubKeyName
;
733 RtlInitUnicodeString(&SubKeyName
,
736 InitializeObjectAttributes(&ObjectAttributes
,
738 OBJ_CASE_INSENSITIVE
,
742 Status
= NtOpenKey(&SubKeyHandle
,
743 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
745 if (!NT_SUCCESS(Status
))
750 CurKey
= SubKeyHandle
;
755 Status
= RegpCopyTree(CurKey
,
758 if (SubKeyHandle
!= NULL
)
760 NtClose(SubKeyHandle
);
764 ClosePredefKey(DestKeyHandle
);
766 ClosePredefKey(KeyHandle
);
768 if (!NT_SUCCESS(Status
))
770 return RtlNtStatusToDosError(Status
);
773 return ERROR_SUCCESS
;
777 /************************************************************************
783 RegCopyTreeA(IN HKEY hKeySrc
,
784 IN LPCSTR lpSubKey OPTIONAL
,
787 UNICODE_STRING SubKeyName
= {0};
790 if (lpSubKey
!= NULL
&&
791 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
794 return ERROR_NOT_ENOUGH_MEMORY
;
797 Ret
= RegCopyTreeW(hKeySrc
,
801 RtlFreeUnicodeString(&SubKeyName
);
807 /************************************************************************
808 * RegConnectRegistryA
813 RegConnectRegistryA (IN LPCSTR lpMachineName
,
817 UNICODE_STRING MachineName
= {0};
820 if (lpMachineName
!= NULL
&&
821 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
822 (LPSTR
)lpMachineName
))
824 return ERROR_NOT_ENOUGH_MEMORY
;
827 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
831 RtlFreeUnicodeString(&MachineName
);
837 /************************************************************************
838 * RegConnectRegistryW
843 RegConnectRegistryW (LPCWSTR lpMachineName
,
847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
848 return ERROR_CALL_NOT_IMPLEMENTED
;
852 /************************************************************************
855 * Create key and all necessary intermediate keys
858 CreateNestedKey(PHKEY KeyHandle
,
859 POBJECT_ATTRIBUTES ObjectAttributes
,
860 PUNICODE_STRING ClassString
,
863 DWORD
*lpdwDisposition
)
865 OBJECT_ATTRIBUTES LocalObjectAttributes
;
866 UNICODE_STRING LocalKeyName
;
869 ULONG FullNameLength
;
872 HANDLE LocalKeyHandle
;
874 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
880 (PULONG
)lpdwDisposition
);
881 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
882 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
885 /* Copy object attributes */
886 RtlCopyMemory (&LocalObjectAttributes
,
888 sizeof(OBJECT_ATTRIBUTES
));
889 RtlCreateUnicodeString (&LocalKeyName
,
890 ObjectAttributes
->ObjectName
->Buffer
);
891 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
892 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
894 /* Remove the last part of the key name and try to create the key again. */
895 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
897 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
898 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
900 Status
= STATUS_UNSUCCESSFUL
;
904 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
906 Status
= NtCreateKey (&LocalKeyHandle
,
908 &LocalObjectAttributes
,
913 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
916 if (!NT_SUCCESS(Status
))
918 RtlFreeUnicodeString (&LocalKeyName
);
922 /* Add removed parts of the key name and create them too. */
923 Length
= wcslen (LocalKeyName
.Buffer
);
926 NtClose (LocalKeyHandle
);
928 LocalKeyName
.Buffer
[Length
] = L
'\\';
929 Length
= wcslen (LocalKeyName
.Buffer
);
930 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
932 if (Length
== FullNameLength
)
934 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
940 (PULONG
)lpdwDisposition
);
943 Status
= NtCreateKey (&LocalKeyHandle
,
945 &LocalObjectAttributes
,
950 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
951 if (!NT_SUCCESS(Status
))
955 RtlFreeUnicodeString (&LocalKeyName
);
961 /************************************************************************
967 RegCreateKeyExA (HKEY hKey
,
973 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
975 LPDWORD lpdwDisposition
)
977 UNICODE_STRING SubKeyString
;
978 UNICODE_STRING ClassString
;
979 OBJECT_ATTRIBUTES Attributes
;
983 TRACE("RegCreateKeyExA() called\n");
985 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
986 return ERROR_INVALID_USER_BUFFER
;
988 /* get the real parent key */
989 Status
= MapDefaultKey (&ParentKey
,
991 if (!NT_SUCCESS(Status
))
993 return RtlNtStatusToDosError (Status
);
995 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
999 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
1003 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1005 InitializeObjectAttributes (&Attributes
,
1007 OBJ_CASE_INSENSITIVE
,
1009 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1010 Status
= CreateNestedKey(phkResult
,
1012 (lpClass
== NULL
)? NULL
: &ClassString
,
1016 RtlFreeUnicodeString (&SubKeyString
);
1017 if (lpClass
!= NULL
)
1019 RtlFreeUnicodeString (&ClassString
);
1022 ClosePredefKey(ParentKey
);
1024 TRACE("Status %x\n", Status
);
1025 if (!NT_SUCCESS(Status
))
1027 return RtlNtStatusToDosError (Status
);
1030 return ERROR_SUCCESS
;
1034 /************************************************************************
1040 RegCreateKeyExW (HKEY hKey
,
1046 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1048 LPDWORD lpdwDisposition
)
1050 UNICODE_STRING SubKeyString
;
1051 UNICODE_STRING ClassString
;
1052 OBJECT_ATTRIBUTES Attributes
;
1056 TRACE("RegCreateKeyExW() called\n");
1058 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1059 return ERROR_INVALID_USER_BUFFER
;
1061 /* get the real parent key */
1062 Status
= MapDefaultKey (&ParentKey
,
1064 if (!NT_SUCCESS(Status
))
1066 return RtlNtStatusToDosError(Status
);
1068 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
1070 RtlInitUnicodeString (&ClassString
,
1072 RtlInitUnicodeString (&SubKeyString
,
1074 InitializeObjectAttributes (&Attributes
,
1076 OBJ_CASE_INSENSITIVE
,
1078 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1079 Status
= CreateNestedKey(phkResult
,
1081 (lpClass
== NULL
)? NULL
: &ClassString
,
1086 ClosePredefKey(ParentKey
);
1088 TRACE("Status %x\n", Status
);
1089 if (!NT_SUCCESS(Status
))
1091 return RtlNtStatusToDosError (Status
);
1094 return ERROR_SUCCESS
;
1098 /************************************************************************
1104 RegCreateKeyA (HKEY hKey
,
1108 return RegCreateKeyExA (hKey
,
1120 /************************************************************************
1126 RegCreateKeyW (HKEY hKey
,
1130 return RegCreateKeyExW (hKey
,
1142 /************************************************************************
1148 RegDeleteKeyA (HKEY hKey
,
1151 OBJECT_ATTRIBUTES ObjectAttributes
;
1152 UNICODE_STRING SubKeyName
;
1157 Status
= MapDefaultKey (&ParentKey
,
1159 if (!NT_SUCCESS(Status
))
1161 return RtlNtStatusToDosError (Status
);
1164 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
1166 InitializeObjectAttributes(&ObjectAttributes
,
1168 OBJ_CASE_INSENSITIVE
,
1172 Status
= NtOpenKey (&TargetKey
,
1175 RtlFreeUnicodeString (&SubKeyName
);
1176 if (!NT_SUCCESS(Status
))
1181 Status
= NtDeleteKey (TargetKey
);
1182 NtClose (TargetKey
);
1185 ClosePredefKey(ParentKey
);
1187 if (!NT_SUCCESS(Status
))
1189 return RtlNtStatusToDosError(Status
);
1192 return ERROR_SUCCESS
;
1196 /************************************************************************
1202 RegDeleteKeyW (HKEY hKey
,
1205 OBJECT_ATTRIBUTES ObjectAttributes
;
1206 UNICODE_STRING SubKeyName
;
1211 Status
= MapDefaultKey (&ParentKey
,
1213 if (!NT_SUCCESS(Status
))
1215 return RtlNtStatusToDosError (Status
);
1218 RtlInitUnicodeString (&SubKeyName
,
1220 InitializeObjectAttributes (&ObjectAttributes
,
1222 OBJ_CASE_INSENSITIVE
,
1225 Status
= NtOpenKey (&TargetKey
,
1228 if (!NT_SUCCESS(Status
))
1233 Status
= NtDeleteKey (TargetKey
);
1234 NtClose (TargetKey
);
1237 ClosePredefKey(ParentKey
);
1239 if (!NT_SUCCESS(Status
))
1241 return RtlNtStatusToDosError (Status
);
1244 return ERROR_SUCCESS
;
1248 /************************************************************************
1249 * RegDeleteKeyValueW
1254 RegDeleteKeyValueW(IN HKEY hKey
,
1255 IN LPCWSTR lpSubKey OPTIONAL
,
1256 IN LPCWSTR lpValueName OPTIONAL
)
1258 UNICODE_STRING ValueName
;
1259 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1262 Status
= MapDefaultKey(&KeyHandle
,
1264 if (!NT_SUCCESS(Status
))
1266 return RtlNtStatusToDosError(Status
);
1269 if (lpSubKey
!= NULL
)
1271 OBJECT_ATTRIBUTES ObjectAttributes
;
1272 UNICODE_STRING SubKeyName
;
1274 RtlInitUnicodeString(&SubKeyName
,
1277 InitializeObjectAttributes(&ObjectAttributes
,
1279 OBJ_CASE_INSENSITIVE
,
1283 Status
= NtOpenKey(&SubKeyHandle
,
1286 if (!NT_SUCCESS(Status
))
1291 CurKey
= SubKeyHandle
;
1296 RtlInitUnicodeString(&ValueName
,
1297 (LPWSTR
)lpValueName
);
1299 Status
= NtDeleteValueKey(CurKey
,
1302 if (SubKeyHandle
!= NULL
)
1304 NtClose(SubKeyHandle
);
1308 ClosePredefKey(KeyHandle
);
1310 if (!NT_SUCCESS(Status
))
1312 return RtlNtStatusToDosError(Status
);
1315 return ERROR_SUCCESS
;
1319 /************************************************************************
1320 * RegDeleteKeyValueA
1325 RegDeleteKeyValueA(IN HKEY hKey
,
1326 IN LPCSTR lpSubKey OPTIONAL
,
1327 IN LPCSTR lpValueName OPTIONAL
)
1329 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1332 if (lpSubKey
!= NULL
&&
1333 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1336 return ERROR_NOT_ENOUGH_MEMORY
;
1339 if (lpValueName
!= NULL
&&
1340 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1341 (LPSTR
)lpValueName
))
1343 RtlFreeUnicodeString(&SubKey
);
1344 return ERROR_NOT_ENOUGH_MEMORY
;
1347 Ret
= RegDeleteKeyValueW(hKey
,
1351 RtlFreeUnicodeString(&SubKey
);
1352 RtlFreeUnicodeString(&ValueName
);
1359 RegpDeleteTree(IN HKEY hKey
)
1363 LIST_ENTRY ListEntry
;
1365 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1367 LIST_ENTRY delQueueHead
;
1368 PREG_DEL_KEYS delKeys
, newDelKeys
;
1371 PKEY_BASIC_INFORMATION BasicInfo
;
1372 PREG_DEL_KEYS KeyDelRoot
;
1373 NTSTATUS Status
= STATUS_SUCCESS
;
1374 NTSTATUS Status2
= STATUS_SUCCESS
;
1376 InitializeListHead(&delQueueHead
);
1378 ProcessHeap
= RtlGetProcessHeap();
1380 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1381 structure for the root key, we only do that for subkeys as we need to
1382 allocate REGP_DEL_KEYS structures anyway! */
1383 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1385 sizeof(REGP_DEL_KEYS
));
1386 if (KeyDelRoot
!= NULL
)
1388 KeyDelRoot
->KeyHandle
= hKey
;
1389 InsertTailList(&delQueueHead
,
1390 &KeyDelRoot
->ListEntry
);
1394 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1403 /* check if this key contains subkeys and delete them first by queuing
1404 them at the head of the list */
1405 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1407 KeyBasicInformation
,
1412 if (NT_SUCCESS(Status2
))
1414 OBJECT_ATTRIBUTES ObjectAttributes
;
1415 UNICODE_STRING SubKeyName
;
1417 ASSERT(newDelKeys
!= NULL
);
1418 ASSERT(BasicInfo
!= NULL
);
1420 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1421 SubKeyName
.Length
= BasicInfo
->NameLength
;
1422 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1423 SubKeyName
.Buffer
= BasicInfo
->Name
;
1425 InitializeObjectAttributes(&ObjectAttributes
,
1427 OBJ_CASE_INSENSITIVE
,
1431 /* open the subkey */
1432 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1433 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1435 if (!NT_SUCCESS(Status2
))
1440 /* enqueue this key to the head of the deletion queue */
1441 InsertHeadList(&delQueueHead
,
1442 &newDelKeys
->ListEntry
);
1444 /* try again from the head of the list */
1449 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1451 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1453 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1454 if (newDelKeys
!= NULL
)
1456 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1459 goto ReadFirstSubKey
;
1463 /* don't break, let's try to delete as many keys as possible */
1464 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1465 goto SubKeyFailureNoFree
;
1468 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1470 PREG_DEL_KEYS newDelKeys2
;
1472 ASSERT(newDelKeys
!= NULL
);
1474 /* we need more memory to query the key name */
1475 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1478 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1479 if (newDelKeys2
!= NULL
)
1481 newDelKeys
= newDelKeys2
;
1482 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1485 goto ReadFirstSubKey
;
1489 /* don't break, let's try to delete as many keys as possible */
1490 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1493 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1495 /* in some race conditions where another thread would delete
1496 the same tree at the same time, newDelKeys could actually
1498 if (newDelKeys
!= NULL
)
1500 RtlFreeHeap(ProcessHeap
,
1508 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1509 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1510 if (newDelKeys
!= NULL
)
1512 RtlFreeHeap(ProcessHeap
,
1517 SubKeyFailureNoFree
:
1518 /* don't break, let's try to delete as many keys as possible */
1519 if (NT_SUCCESS(Status
))
1525 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1527 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1529 if (!NT_SUCCESS(Status2
))
1531 /* close the key handle so we don't leak handles for keys we were
1532 unable to delete. But only do this for handles not supplied
1535 if (delKeys
->KeyHandle
!= hKey
)
1537 NtClose(delKeys
->KeyHandle
);
1540 if (NT_SUCCESS(Status
))
1542 /* don't break, let's try to delete as many keys as possible */
1547 /* remove the entry from the list */
1548 RemoveEntryList(&delKeys
->ListEntry
);
1550 RtlFreeHeap(ProcessHeap
,
1553 } while (!IsListEmpty(&delQueueHead
));
1556 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1562 /************************************************************************
1568 RegDeleteTreeW(IN HKEY hKey
,
1569 IN LPCWSTR lpSubKey OPTIONAL
)
1571 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1574 Status
= MapDefaultKey(&KeyHandle
,
1576 if (!NT_SUCCESS(Status
))
1578 return RtlNtStatusToDosError(Status
);
1581 if (lpSubKey
!= NULL
)
1583 OBJECT_ATTRIBUTES ObjectAttributes
;
1584 UNICODE_STRING SubKeyName
;
1586 RtlInitUnicodeString(&SubKeyName
,
1589 InitializeObjectAttributes(&ObjectAttributes
,
1591 OBJ_CASE_INSENSITIVE
,
1595 Status
= NtOpenKey(&SubKeyHandle
,
1596 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1598 if (!NT_SUCCESS(Status
))
1603 CurKey
= SubKeyHandle
;
1608 Status
= RegpDeleteTree(CurKey
);
1610 if (NT_SUCCESS(Status
))
1612 /* make sure we only close hKey (KeyHandle) when the caller specified a
1613 subkey, because the handle would be invalid already! */
1614 if (CurKey
!= KeyHandle
)
1616 ClosePredefKey(KeyHandle
);
1619 return ERROR_SUCCESS
;
1623 /* make sure we close all handles we created! */
1624 if (SubKeyHandle
!= NULL
)
1626 NtClose(SubKeyHandle
);
1630 ClosePredefKey(KeyHandle
);
1632 return RtlNtStatusToDosError(Status
);
1637 /************************************************************************
1643 RegDeleteTreeA(IN HKEY hKey
,
1644 IN LPCSTR lpSubKey OPTIONAL
)
1646 UNICODE_STRING SubKeyName
= {0};
1649 if (lpSubKey
!= NULL
&&
1650 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1653 return ERROR_NOT_ENOUGH_MEMORY
;
1656 Ret
= RegDeleteTreeW(hKey
,
1659 RtlFreeUnicodeString(&SubKeyName
);
1665 /************************************************************************
1666 * RegDisableReflectionKey
1671 RegDisableReflectionKey(IN HKEY hBase
)
1673 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1674 return ERROR_CALL_NOT_IMPLEMENTED
;
1678 /************************************************************************
1679 * RegEnableReflectionKey
1684 RegEnableReflectionKey(IN HKEY hBase
)
1686 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1687 return ERROR_CALL_NOT_IMPLEMENTED
;
1690 /******************************************************************************
1691 * RegpApplyRestrictions [internal]
1693 * Helper function for RegGetValueA/W.
1696 RegpApplyRestrictions( DWORD dwFlags
, DWORD dwType
, DWORD cbData
,
1699 /* Check if the type is restricted by the passed flags */
1700 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1706 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1707 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1708 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1709 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1710 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1711 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1712 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1715 if (dwFlags
& dwMask
)
1717 /* Type is not restricted, check for size mismatch */
1718 if (dwType
== REG_BINARY
)
1722 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1724 else if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_QWORD
)
1727 if (cbExpect
&& cbData
!= cbExpect
)
1728 *ret
= ERROR_DATATYPE_MISMATCH
;
1731 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1736 /******************************************************************************
1737 * RegGetValueW [ADVAPI32.@]
1739 * Retrieves the type and data for a value name associated with a key
1740 * optionally expanding it's content and restricting it's type.
1743 * hKey [I] Handle to an open key.
1744 * pszSubKey [I] Name of the subkey of hKey.
1745 * pszValue [I] Name of value under hKey/szSubKey to query.
1746 * dwFlags [I] Flags restricting the value type to retrieve.
1747 * pdwType [O] Destination for the values type, may be NULL.
1748 * pvData [O] Destination for the values content, may be NULL.
1749 * pcbData [I/O] Size of pvData, updated with the size required to
1750 * retrieve the whole content.
1753 * Success: ERROR_SUCCESS
1754 * Failure: nonzero error code from Winerror.h
1757 * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1758 * and REG_SZ is retrieved instead.
1759 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1760 * without RRF_NOEXPAND is thus not allowed.
1763 RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1764 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1767 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1771 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1772 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1773 pvData
, pcbData
, cbData
);
1775 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1776 return ERROR_INVALID_PARAMETER
;
1778 if (pszSubKey
&& pszSubKey
[0])
1780 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1781 if (ret
!= ERROR_SUCCESS
) return ret
;
1784 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1786 /* If we are going to expand we need to read in the whole the value even
1787 * if the passed buffer was too small as the expanded string might be
1788 * smaller than the unexpanded one and could fit into cbData bytes. */
1789 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1790 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1793 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1795 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1798 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1802 if (ret
== ERROR_MORE_DATA
)
1803 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1804 &dwType
, pvBuf
, &cbData
);
1807 /* Even if cbData was large enough we have to copy the
1808 * string since ExpandEnvironmentStrings can't handle
1809 * overlapping buffers. */
1810 CopyMemory(pvBuf
, pvData
, cbData
);
1813 /* Both the type or the value itself could have been modified in
1814 * between so we have to keep retrying until the buffer is large
1815 * enough or we no longer have to expand the value. */
1816 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1818 if (ret
== ERROR_SUCCESS
)
1820 if (dwType
== REG_EXPAND_SZ
)
1822 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1823 pcbData
? *pcbData
: 0);
1825 if(pcbData
&& cbData
> *pcbData
)
1826 ret
= ERROR_MORE_DATA
;
1829 CopyMemory(pvData
, pvBuf
, *pcbData
);
1832 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1835 if (pszSubKey
&& pszSubKey
[0])
1838 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1840 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1841 ZeroMemory(pvData
, *pcbData
);
1843 if (pdwType
) *pdwType
= dwType
;
1844 if (pcbData
) *pcbData
= cbData
;
1850 /******************************************************************************
1851 * RegGetValueA [ADVAPI32.@]
1856 RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1857 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1860 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1864 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1865 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
1868 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1869 return ERROR_INVALID_PARAMETER
;
1871 if (pszSubKey
&& pszSubKey
[0])
1873 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1874 if (ret
!= ERROR_SUCCESS
) return ret
;
1877 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1879 /* If we are going to expand we need to read in the whole the value even
1880 * if the passed buffer was too small as the expanded string might be
1881 * smaller than the unexpanded one and could fit into cbData bytes. */
1882 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1883 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1886 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1888 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1891 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1895 if (ret
== ERROR_MORE_DATA
)
1896 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1897 &dwType
, pvBuf
, &cbData
);
1900 /* Even if cbData was large enough we have to copy the
1901 * string since ExpandEnvironmentStrings can't handle
1902 * overlapping buffers. */
1903 CopyMemory(pvBuf
, pvData
, cbData
);
1906 /* Both the type or the value itself could have been modified in
1907 * between so we have to keep retrying until the buffer is large
1908 * enough or we no longer have to expand the value. */
1909 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1911 if (ret
== ERROR_SUCCESS
)
1913 if (dwType
== REG_EXPAND_SZ
)
1915 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1916 pcbData
? *pcbData
: 0);
1918 if(pcbData
&& cbData
> *pcbData
)
1919 ret
= ERROR_MORE_DATA
;
1922 CopyMemory(pvData
, pvBuf
, *pcbData
);
1925 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1928 if (pszSubKey
&& pszSubKey
[0])
1931 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1933 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1934 ZeroMemory(pvData
, *pcbData
);
1936 if (pdwType
) *pdwType
= dwType
;
1937 if (pcbData
) *pcbData
= cbData
;
1943 /************************************************************************
1949 RegSetKeyValueW(IN HKEY hKey
,
1950 IN LPCWSTR lpSubKey OPTIONAL
,
1951 IN LPCWSTR lpValueName OPTIONAL
,
1953 IN LPCVOID lpData OPTIONAL
,
1956 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1960 Status
= MapDefaultKey(&KeyHandle
,
1962 if (!NT_SUCCESS(Status
))
1964 return RtlNtStatusToDosError(Status
);
1967 if (lpSubKey
!= NULL
)
1969 OBJECT_ATTRIBUTES ObjectAttributes
;
1970 UNICODE_STRING SubKeyName
;
1972 RtlInitUnicodeString(&SubKeyName
,
1975 InitializeObjectAttributes(&ObjectAttributes
,
1977 OBJ_CASE_INSENSITIVE
,
1981 Status
= NtOpenKey(&SubKeyHandle
,
1984 if (!NT_SUCCESS(Status
))
1986 Ret
= RtlNtStatusToDosError(Status
);
1990 CurKey
= SubKeyHandle
;
1995 Ret
= RegSetValueExW(CurKey
,
2002 if (SubKeyHandle
!= NULL
)
2004 NtClose(SubKeyHandle
);
2008 ClosePredefKey(KeyHandle
);
2014 /************************************************************************
2020 RegSetKeyValueA(IN HKEY hKey
,
2021 IN LPCSTR lpSubKey OPTIONAL
,
2022 IN LPCSTR lpValueName OPTIONAL
,
2024 IN LPCVOID lpData OPTIONAL
,
2027 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2031 Status
= MapDefaultKey(&KeyHandle
,
2033 if (!NT_SUCCESS(Status
))
2035 return RtlNtStatusToDosError(Status
);
2038 if (lpSubKey
!= NULL
)
2040 OBJECT_ATTRIBUTES ObjectAttributes
;
2041 UNICODE_STRING SubKeyName
;
2043 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2046 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2050 InitializeObjectAttributes(&ObjectAttributes
,
2052 OBJ_CASE_INSENSITIVE
,
2056 Status
= NtOpenKey(&SubKeyHandle
,
2060 RtlFreeUnicodeString(&SubKeyName
);
2062 if (!NT_SUCCESS(Status
))
2064 Ret
= RtlNtStatusToDosError(Status
);
2068 CurKey
= SubKeyHandle
;
2073 Ret
= RegSetValueExA(CurKey
,
2080 if (SubKeyHandle
!= NULL
)
2082 NtClose(SubKeyHandle
);
2086 ClosePredefKey(KeyHandle
);
2092 /************************************************************************
2098 RegDeleteValueA (HKEY hKey
,
2101 UNICODE_STRING ValueName
;
2105 Status
= MapDefaultKey (&KeyHandle
,
2107 if (!NT_SUCCESS(Status
))
2109 return RtlNtStatusToDosError (Status
);
2112 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
2113 (LPSTR
)lpValueName
);
2114 Status
= NtDeleteValueKey (KeyHandle
,
2116 RtlFreeUnicodeString (&ValueName
);
2118 ClosePredefKey(KeyHandle
);
2120 if (!NT_SUCCESS(Status
))
2122 return RtlNtStatusToDosError (Status
);
2125 return ERROR_SUCCESS
;
2129 /************************************************************************
2135 RegDeleteValueW (HKEY hKey
,
2136 LPCWSTR lpValueName
)
2138 UNICODE_STRING ValueName
;
2142 Status
= MapDefaultKey (&KeyHandle
,
2144 if (!NT_SUCCESS(Status
))
2146 return RtlNtStatusToDosError (Status
);
2149 RtlInitUnicodeString (&ValueName
,
2150 (LPWSTR
)lpValueName
);
2152 Status
= NtDeleteValueKey (KeyHandle
,
2155 ClosePredefKey(KeyHandle
);
2157 if (!NT_SUCCESS(Status
))
2159 return RtlNtStatusToDosError (Status
);
2162 return ERROR_SUCCESS
;
2166 /************************************************************************
2172 RegEnumKeyA (HKEY hKey
,
2180 return RegEnumKeyExA (hKey
,
2191 /************************************************************************
2197 RegEnumKeyW (HKEY hKey
,
2205 return RegEnumKeyExW (hKey
,
2216 /************************************************************************
2222 RegEnumKeyExA (HKEY hKey
,
2229 PFILETIME lpftLastWriteTime
)
2233 KEY_NODE_INFORMATION Node
;
2234 KEY_BASIC_INFORMATION Basic
;
2237 UNICODE_STRING StringU
;
2238 ANSI_STRING StringA
;
2239 LONG ErrorCode
= ERROR_SUCCESS
;
2241 DWORD ClassLength
= 0;
2247 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2248 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2250 if ((lpClass
) && (!lpcbClass
))
2252 return ERROR_INVALID_PARAMETER
;
2255 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2256 if (!NT_SUCCESS(Status
))
2258 return RtlNtStatusToDosError (Status
);
2263 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2274 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2281 /* The class name should start at a dword boundary */
2282 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2286 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2289 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2290 if (KeyInfo
== NULL
)
2292 ErrorCode
= ERROR_OUTOFMEMORY
;
2296 Status
= NtEnumerateKey (KeyHandle
,
2298 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2302 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2303 if (!NT_SUCCESS(Status
))
2305 ErrorCode
= RtlNtStatusToDosError (Status
);
2309 if (lpClass
== NULL
)
2311 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2313 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2317 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2318 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2319 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2324 if (KeyInfo
->Node
.NameLength
> NameLength
||
2325 KeyInfo
->Node
.ClassLength
> ClassLength
)
2327 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2331 StringA
.Buffer
= lpClass
;
2333 StringA
.MaximumLength
= *lpcbClass
;
2334 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2335 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2336 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2337 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2338 lpClass
[StringA
.Length
] = 0;
2339 *lpcbClass
= StringA
.Length
;
2340 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2341 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2342 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2346 if (ErrorCode
== ERROR_SUCCESS
)
2348 StringA
.Buffer
= lpName
;
2350 StringA
.MaximumLength
= *lpcbName
;
2351 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2352 lpName
[StringA
.Length
] = 0;
2353 *lpcbName
= StringA
.Length
;
2354 if (lpftLastWriteTime
!= NULL
)
2356 if (lpClass
== NULL
)
2358 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2359 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2363 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2364 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2370 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
2371 TRACE("Key Namea1 Length %d\n", NameLength
);
2372 TRACE("Key Namea Length %d\n", *lpcbName
);
2373 TRACE("Key Namea %s\n", lpName
);
2375 RtlFreeHeap (ProcessHeap
,
2380 ClosePredefKey(KeyHandle
);
2386 /************************************************************************
2392 RegEnumKeyExW (HKEY hKey
,
2399 PFILETIME lpftLastWriteTime
)
2403 KEY_NODE_INFORMATION Node
;
2404 KEY_BASIC_INFORMATION Basic
;
2410 ULONG ClassLength
= 0;
2412 LONG ErrorCode
= ERROR_SUCCESS
;
2415 Status
= MapDefaultKey(&KeyHandle
,
2417 if (!NT_SUCCESS(Status
))
2419 return RtlNtStatusToDosError (Status
);
2424 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2435 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2442 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2446 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2449 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
2452 if (KeyInfo
== NULL
)
2454 ErrorCode
= ERROR_OUTOFMEMORY
;
2458 Status
= NtEnumerateKey (KeyHandle
,
2460 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2464 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2465 if (!NT_SUCCESS(Status
))
2467 ErrorCode
= RtlNtStatusToDosError (Status
);
2471 if (lpClass
== NULL
)
2473 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2475 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2479 RtlCopyMemory (lpName
,
2480 KeyInfo
->Basic
.Name
,
2481 KeyInfo
->Basic
.NameLength
);
2482 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2483 lpName
[*lpcbName
] = 0;
2488 if (KeyInfo
->Node
.NameLength
> NameLength
||
2489 KeyInfo
->Node
.ClassLength
> ClassLength
)
2491 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2495 RtlCopyMemory (lpName
,
2497 KeyInfo
->Node
.NameLength
);
2498 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2499 lpName
[*lpcbName
] = 0;
2500 RtlCopyMemory (lpClass
,
2501 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2502 KeyInfo
->Node
.ClassLength
);
2503 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2504 lpClass
[*lpcbClass
] = 0;
2508 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2510 if (lpClass
== NULL
)
2512 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2513 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2517 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2518 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2523 RtlFreeHeap (ProcessHeap
,
2528 ClosePredefKey(KeyHandle
);
2533 /************************************************************************
2539 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2540 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2545 char buffer
[256], *buf_ptr
= buffer
;
2546 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2547 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2549 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2550 // hkey, index, value, val_count, reserved, type, data, count );
2552 /* NT only checks count, not val_count */
2553 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2554 status
= MapDefaultKey (&KeyHandle
, hKey
);
2555 if (!NT_SUCCESS(status
))
2557 return RtlNtStatusToDosError (status
);
2560 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2561 if (data
) total_size
+= *count
;
2562 total_size
= min( sizeof(buffer
), total_size
);
2564 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2565 buffer
, total_size
, &total_size
);
2566 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2568 /* we need to fetch the contents for a string type even if not requested,
2569 * because we need to compute the length of the ASCII string. */
2570 if (value
|| data
|| is_string(info
->Type
))
2572 /* retry with a dynamically allocated buffer */
2573 while (status
== STATUS_BUFFER_OVERFLOW
)
2575 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2576 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2578 status
= STATUS_INSUFFICIENT_RESOURCES
;
2581 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2582 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2583 buf_ptr
, total_size
, &total_size
);
2586 if (status
) goto done
;
2588 if (is_string(info
->Type
))
2591 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2592 total_size
- info
->DataOffset
);
2595 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2598 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2599 total_size
- info
->DataOffset
);
2600 /* if the type is REG_SZ and data is not 0-terminated
2601 * and there is enough space in the buffer NT appends a \0 */
2602 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2605 info
->DataLength
= len
;
2609 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2610 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2613 if (value
&& !status
)
2617 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2618 if (len
>= *val_count
)
2620 status
= STATUS_BUFFER_OVERFLOW
;
2623 len
= *val_count
- 1;
2624 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2630 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2636 else status
= STATUS_SUCCESS
;
2638 if (type
) *type
= info
->Type
;
2639 if (count
) *count
= info
->DataLength
;
2642 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2643 ClosePredefKey(KeyHandle
);
2644 return RtlNtStatusToDosError(status
);
2647 /******************************************************************************
2648 * RegEnumValueW [ADVAPI32.@]
2652 * hkey [I] Handle to key to query
2653 * index [I] Index of value to query
2654 * value [O] Value string
2655 * val_count [I/O] Size of value buffer (in wchars)
2656 * reserved [I] Reserved
2657 * type [O] Type code
2658 * data [O] Value data
2659 * count [I/O] Size of data buffer (in bytes)
2662 * Success: ERROR_SUCCESS
2663 * Failure: nonzero error code from Winerror.h
2666 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2667 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2672 char buffer
[256], *buf_ptr
= buffer
;
2673 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2674 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2676 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2677 // hkey, index, value, val_count, reserved, type, data, count );
2679 /* NT only checks count, not val_count */
2680 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2682 status
= MapDefaultKey (&KeyHandle
, hKey
);
2683 if (!NT_SUCCESS(status
))
2685 return RtlNtStatusToDosError (status
);
2688 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2689 if (data
) total_size
+= *count
;
2690 total_size
= min( sizeof(buffer
), total_size
);
2692 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2693 buffer
, total_size
, &total_size
);
2694 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2698 /* retry with a dynamically allocated buffer */
2699 while (status
== STATUS_BUFFER_OVERFLOW
)
2701 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2702 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2704 status
= ERROR_NOT_ENOUGH_MEMORY
;
2707 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2708 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2709 buf_ptr
, total_size
, &total_size
);
2712 if (status
) goto done
;
2716 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2718 status
= STATUS_BUFFER_OVERFLOW
;
2721 memcpy( value
, info
->Name
, info
->NameLength
);
2722 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2723 value
[*val_count
] = 0;
2728 if (total_size
- info
->DataOffset
> *count
)
2730 status
= STATUS_BUFFER_OVERFLOW
;
2733 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2734 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2736 /* if the type is REG_SZ and data is not 0-terminated
2737 * and there is enough space in the buffer NT appends a \0 */
2738 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2739 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2743 else status
= STATUS_SUCCESS
;
2746 if (type
) *type
= info
->Type
;
2747 if (count
) *count
= info
->DataLength
;
2750 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2751 ClosePredefKey(KeyHandle
);
2752 return RtlNtStatusToDosError(status
);
2755 /************************************************************************
2761 RegFlushKey(HKEY hKey
)
2766 if (hKey
== HKEY_PERFORMANCE_DATA
)
2768 return ERROR_SUCCESS
;
2771 Status
= MapDefaultKey (&KeyHandle
,
2773 if (!NT_SUCCESS(Status
))
2775 return RtlNtStatusToDosError (Status
);
2778 Status
= NtFlushKey (KeyHandle
);
2780 ClosePredefKey(KeyHandle
);
2782 if (!NT_SUCCESS(Status
))
2784 return RtlNtStatusToDosError (Status
);
2787 return ERROR_SUCCESS
;
2791 /************************************************************************
2797 RegGetKeySecurity(HKEY hKey
,
2798 SECURITY_INFORMATION SecurityInformation
,
2799 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2800 LPDWORD lpcbSecurityDescriptor
)
2805 if (hKey
== HKEY_PERFORMANCE_DATA
)
2807 return ERROR_INVALID_HANDLE
;
2810 Status
= MapDefaultKey(&KeyHandle
,
2812 if (!NT_SUCCESS(Status
))
2814 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2815 return RtlNtStatusToDosError (Status
);
2818 Status
= NtQuerySecurityObject(KeyHandle
,
2819 SecurityInformation
,
2820 pSecurityDescriptor
,
2821 *lpcbSecurityDescriptor
,
2822 lpcbSecurityDescriptor
);
2825 ClosePredefKey(KeyHandle
);
2827 if (!NT_SUCCESS(Status
))
2829 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
2830 return RtlNtStatusToDosError (Status
);
2833 return ERROR_SUCCESS
;
2837 /************************************************************************
2843 RegLoadKeyA (HKEY hKey
,
2847 UNICODE_STRING FileName
;
2848 UNICODE_STRING KeyName
;
2851 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
2853 RtlCreateUnicodeStringFromAsciiz (&FileName
,
2856 ErrorCode
= RegLoadKeyW (hKey
,
2860 RtlFreeUnicodeString (&FileName
);
2861 RtlFreeUnicodeString (&KeyName
);
2867 /************************************************************************
2873 RegLoadKeyW (HKEY hKey
,
2877 OBJECT_ATTRIBUTES FileObjectAttributes
;
2878 OBJECT_ATTRIBUTES KeyObjectAttributes
;
2879 UNICODE_STRING FileName
;
2880 UNICODE_STRING KeyName
;
2883 LONG ErrorCode
= ERROR_SUCCESS
;
2885 if (hKey
== HKEY_PERFORMANCE_DATA
)
2887 return ERROR_INVALID_HANDLE
;
2890 Status
= MapDefaultKey (&KeyHandle
,
2892 if (!NT_SUCCESS(Status
))
2894 return RtlNtStatusToDosError (Status
);
2897 if (!RtlDosPathNameToNtPathName_U (lpFile
,
2902 ErrorCode
= ERROR_BAD_PATHNAME
;
2906 InitializeObjectAttributes (&FileObjectAttributes
,
2908 OBJ_CASE_INSENSITIVE
,
2912 RtlInitUnicodeString (&KeyName
,
2915 InitializeObjectAttributes (&KeyObjectAttributes
,
2917 OBJ_CASE_INSENSITIVE
,
2921 Status
= NtLoadKey (&KeyObjectAttributes
,
2922 &FileObjectAttributes
);
2924 RtlFreeHeap (RtlGetProcessHeap (),
2928 if (!NT_SUCCESS(Status
))
2930 ErrorCode
= RtlNtStatusToDosError (Status
);
2935 ClosePredefKey(KeyHandle
);
2941 /************************************************************************
2942 * RegNotifyChangeKeyValue
2947 RegNotifyChangeKeyValue (HKEY hKey
,
2949 DWORD dwNotifyFilter
,
2953 IO_STATUS_BLOCK IoStatusBlock
;
2956 LONG ErrorCode
= ERROR_SUCCESS
;
2958 if (hKey
== HKEY_PERFORMANCE_DATA
)
2960 return ERROR_INVALID_HANDLE
;
2963 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
2965 return ERROR_INVALID_PARAMETER
;
2968 Status
= MapDefaultKey (&KeyHandle
,
2970 if (!NT_SUCCESS(Status
))
2972 return RtlNtStatusToDosError (Status
);
2975 /* FIXME: Remote key handles must fail */
2977 Status
= NtNotifyChangeKey (KeyHandle
,
2987 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
2989 ErrorCode
= RtlNtStatusToDosError (Status
);
2992 ClosePredefKey(KeyHandle
);
2998 /************************************************************************
2999 * RegOpenCurrentUser
3004 RegOpenCurrentUser (IN REGSAM samDesired
,
3005 OUT PHKEY phkResult
)
3009 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3010 (PHANDLE
)phkResult
);
3011 if (!NT_SUCCESS(Status
))
3013 /* NOTE - don't set the last error code! just return the error! */
3014 return RtlNtStatusToDosError(Status
);
3017 return ERROR_SUCCESS
;
3021 /************************************************************************
3024 * 20050503 Fireball - imported from WINE
3029 RegOpenKeyA (HKEY hKey
,
3033 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3035 if (!hKey
&& lpSubKey
&& phkResult
)
3037 return ERROR_INVALID_HANDLE
;
3040 if (!lpSubKey
|| !*lpSubKey
)
3043 return ERROR_SUCCESS
;
3046 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3050 /************************************************************************
3055 * 20050503 Fireball - imported from WINE
3060 RegOpenKeyW (HKEY hKey
,
3064 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3066 if (!hKey
&& lpSubKey
&& phkResult
)
3068 return ERROR_INVALID_HANDLE
;
3071 if (!lpSubKey
|| !*lpSubKey
)
3074 return ERROR_SUCCESS
;
3076 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3080 /************************************************************************
3086 RegOpenKeyExA (HKEY hKey
,
3092 OBJECT_ATTRIBUTES ObjectAttributes
;
3093 UNICODE_STRING SubKeyString
;
3096 LONG ErrorCode
= ERROR_SUCCESS
;
3098 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3099 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3101 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3102 if (!NT_SUCCESS(Status
))
3104 return RtlNtStatusToDosError (Status
);
3107 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
3108 InitializeObjectAttributes (&ObjectAttributes
,
3110 OBJ_CASE_INSENSITIVE
,
3114 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3115 RtlFreeUnicodeString (&SubKeyString
);
3116 if (!NT_SUCCESS(Status
))
3118 ErrorCode
= RtlNtStatusToDosError (Status
);
3121 ClosePredefKey(KeyHandle
);
3127 /************************************************************************
3133 RegOpenKeyExW (HKEY hKey
,
3139 OBJECT_ATTRIBUTES ObjectAttributes
;
3140 UNICODE_STRING SubKeyString
;
3143 LONG ErrorCode
= ERROR_SUCCESS
;
3145 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3146 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3148 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3149 if (!NT_SUCCESS(Status
))
3151 return RtlNtStatusToDosError (Status
);
3154 if (lpSubKey
!= NULL
)
3155 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
3157 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
3159 InitializeObjectAttributes (&ObjectAttributes
,
3161 OBJ_CASE_INSENSITIVE
,
3165 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3167 if (!NT_SUCCESS(Status
))
3169 ErrorCode
= RtlNtStatusToDosError (Status
);
3172 ClosePredefKey(KeyHandle
);
3178 /************************************************************************
3179 * RegOpenUserClassesRoot
3184 RegOpenUserClassesRoot (IN HANDLE hToken
,
3186 IN REGSAM samDesired
,
3187 OUT PHKEY phkResult
)
3189 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3190 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3191 PTOKEN_USER TokenUserData
;
3192 ULONG RequiredLength
;
3193 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3194 OBJECT_ATTRIBUTES ObjectAttributes
;
3197 /* check parameters */
3198 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3200 return ERROR_INVALID_PARAMETER
;
3204 * Get the user sid from the token
3208 /* determine how much memory we need */
3209 Status
= NtQueryInformationToken(hToken
,
3214 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3216 /* NOTE - as opposed to all other registry functions windows does indeed
3217 change the last error code in case the caller supplied a invalid
3218 handle for example! */
3219 return RtlNtStatusToDosError (Status
);
3222 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3225 if (TokenUserData
== NULL
)
3227 return ERROR_NOT_ENOUGH_MEMORY
;
3230 /* attempt to read the information */
3231 Status
= NtQueryInformationToken(hToken
,
3236 if (!NT_SUCCESS(Status
))
3238 RtlFreeHeap(ProcessHeap
,
3241 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3243 /* the information appears to have changed?! try again */
3247 /* NOTE - as opposed to all other registry functions windows does indeed
3248 change the last error code in case the caller supplied a invalid
3249 handle for example! */
3250 return RtlNtStatusToDosError (Status
);
3254 * Build the absolute path for the user's registry in the form
3255 * "\Registry\User\<SID>_Classes"
3257 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3258 TokenUserData
->User
.Sid
,
3261 /* we don't need the user data anymore, free it */
3262 RtlFreeHeap(ProcessHeap
,
3266 if (!NT_SUCCESS(Status
))
3268 return RtlNtStatusToDosError (Status
);
3271 /* allocate enough memory for the entire key string */
3272 UserClassesKeyRoot
.Length
= 0;
3273 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3274 sizeof(UserClassesKeyPrefix
) +
3275 sizeof(UserClassesKeySuffix
);
3276 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3278 UserClassesKeyRoot
.MaximumLength
);
3279 if (UserClassesKeyRoot
.Buffer
== NULL
)
3281 RtlFreeUnicodeString(&UserSidString
);
3282 return RtlNtStatusToDosError (Status
);
3285 /* build the string */
3286 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3287 UserClassesKeyPrefix
);
3288 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3290 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3291 UserClassesKeySuffix
);
3293 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3299 InitializeObjectAttributes (&ObjectAttributes
,
3300 &UserClassesKeyRoot
,
3301 OBJ_CASE_INSENSITIVE
,
3305 Status
= NtOpenKey((PHANDLE
)phkResult
,
3309 RtlFreeUnicodeString(&UserSidString
);
3310 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3312 if (!NT_SUCCESS(Status
))
3314 return RtlNtStatusToDosError (Status
);
3317 return ERROR_SUCCESS
;
3321 /************************************************************************
3327 RegQueryInfoKeyA (HKEY hKey
,
3332 LPDWORD lpcbMaxSubKeyLen
,
3333 LPDWORD lpcbMaxClassLen
,
3335 LPDWORD lpcbMaxValueNameLen
,
3336 LPDWORD lpcbMaxValueLen
,
3337 LPDWORD lpcbSecurityDescriptor
,
3338 PFILETIME lpftLastWriteTime
)
3340 WCHAR ClassName
[MAX_PATH
];
3341 UNICODE_STRING UnicodeString
;
3342 ANSI_STRING AnsiString
;
3345 RtlInitUnicodeString (&UnicodeString
,
3347 if (lpClass
!= NULL
)
3349 UnicodeString
.Buffer
= &ClassName
[0];
3350 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3351 AnsiString
.MaximumLength
= *lpcbClass
;
3354 ErrorCode
= RegQueryInfoKeyW (hKey
,
3355 UnicodeString
.Buffer
,
3362 lpcbMaxValueNameLen
,
3364 lpcbSecurityDescriptor
,
3366 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3368 AnsiString
.Buffer
= lpClass
;
3369 AnsiString
.Length
= 0;
3370 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3371 RtlUnicodeStringToAnsiString (&AnsiString
,
3374 *lpcbClass
= AnsiString
.Length
;
3375 lpClass
[AnsiString
.Length
] = 0;
3382 /************************************************************************
3388 RegQueryInfoKeyW (HKEY hKey
,
3393 LPDWORD lpcbMaxSubKeyLen
,
3394 LPDWORD lpcbMaxClassLen
,
3396 LPDWORD lpcbMaxValueNameLen
,
3397 LPDWORD lpcbMaxValueLen
,
3398 LPDWORD lpcbSecurityDescriptor
,
3399 PFILETIME lpftLastWriteTime
)
3401 KEY_FULL_INFORMATION FullInfoBuffer
;
3402 PKEY_FULL_INFORMATION FullInfo
;
3404 ULONG ClassLength
= 0;
3408 LONG ErrorCode
= ERROR_SUCCESS
;
3410 if ((lpClass
) && (!lpcbClass
))
3412 return ERROR_INVALID_PARAMETER
;
3415 Status
= MapDefaultKey (&KeyHandle
,
3417 if (!NT_SUCCESS(Status
))
3419 return RtlNtStatusToDosError (Status
);
3422 if (lpClass
!= NULL
)
3426 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3433 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3434 FullInfo
= RtlAllocateHeap (ProcessHeap
,
3437 if (FullInfo
== NULL
)
3439 ErrorCode
= ERROR_OUTOFMEMORY
;
3443 FullInfo
->ClassLength
= ClassLength
;
3447 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3448 FullInfo
= &FullInfoBuffer
;
3449 FullInfo
->ClassLength
= 0;
3451 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3453 Status
= NtQueryKey (KeyHandle
,
3458 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3459 if (!NT_SUCCESS(Status
))
3461 if (lpClass
!= NULL
)
3463 RtlFreeHeap (ProcessHeap
,
3468 ErrorCode
= RtlNtStatusToDosError (Status
);
3472 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3473 if (lpcSubKeys
!= NULL
)
3475 *lpcSubKeys
= FullInfo
->SubKeys
;
3478 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3479 if (lpcbMaxSubKeyLen
!= NULL
)
3481 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3484 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3485 if (lpcbMaxClassLen
!= NULL
)
3487 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3490 TRACE("Values %lu\n", FullInfo
->Values
);
3491 if (lpcValues
!= NULL
)
3493 *lpcValues
= FullInfo
->Values
;
3496 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3497 if (lpcbMaxValueNameLen
!= NULL
)
3499 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3502 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3503 if (lpcbMaxValueLen
!= NULL
)
3505 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3508 if (lpcbSecurityDescriptor
!= NULL
)
3510 Status
= NtQuerySecurityObject(KeyHandle
,
3511 OWNER_SECURITY_INFORMATION
|
3512 GROUP_SECURITY_INFORMATION
|
3513 DACL_SECURITY_INFORMATION
,
3516 lpcbSecurityDescriptor
);
3517 if (!NT_SUCCESS(Status
))
3519 if (lpClass
!= NULL
)
3521 RtlFreeHeap(ProcessHeap
,
3526 ErrorCode
= RtlNtStatusToDosError (Status
);
3532 if (lpftLastWriteTime
!= NULL
)
3534 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3535 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3538 if (lpClass
!= NULL
)
3540 if (FullInfo
->ClassLength
> ClassLength
)
3542 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3546 RtlCopyMemory (lpClass
,
3548 FullInfo
->ClassLength
);
3549 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3550 lpClass
[*lpcbClass
] = 0;
3553 RtlFreeHeap (ProcessHeap
,
3559 ClosePredefKey(KeyHandle
);
3565 /************************************************************************
3566 * RegQueryMultipleValuesA
3571 RegQueryMultipleValuesA (HKEY hKey
,
3578 DWORD maxBytes
= *ldwTotsize
;
3579 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3582 if (maxBytes
>= (1024*1024))
3583 return ERROR_TRANSFER_TOO_LONG
;
3587 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3588 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3590 for (i
= 0; i
< num_vals
; i
++)
3592 val_list
[i
].ve_valuelen
= 0;
3593 ErrorCode
= RegQueryValueExA (hKey
,
3594 val_list
[i
].ve_valuename
,
3598 &val_list
[i
].ve_valuelen
);
3599 if (ErrorCode
!= ERROR_SUCCESS
)
3604 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3606 ErrorCode
= RegQueryValueExA (hKey
,
3607 val_list
[i
].ve_valuename
,
3609 &val_list
[i
].ve_type
,
3611 &val_list
[i
].ve_valuelen
);
3612 if (ErrorCode
!= ERROR_SUCCESS
)
3617 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3619 bufptr
+= val_list
[i
].ve_valuelen
;
3622 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3625 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3629 /************************************************************************
3630 * RegQueryMultipleValuesW
3635 RegQueryMultipleValuesW (HKEY hKey
,
3642 DWORD maxBytes
= *ldwTotsize
;
3643 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3646 if (maxBytes
>= (1024*1024))
3647 return ERROR_TRANSFER_TOO_LONG
;
3651 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3652 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3654 for (i
= 0; i
< num_vals
; i
++)
3656 val_list
[i
].ve_valuelen
= 0;
3657 ErrorCode
= RegQueryValueExW (hKey
,
3658 val_list
[i
].ve_valuename
,
3662 &val_list
[i
].ve_valuelen
);
3663 if (ErrorCode
!= ERROR_SUCCESS
)
3668 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3670 ErrorCode
= RegQueryValueExW (hKey
,
3671 val_list
[i
].ve_valuename
,
3673 &val_list
[i
].ve_type
,
3675 &val_list
[i
].ve_valuelen
);
3676 if (ErrorCode
!= ERROR_SUCCESS
)
3681 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3683 bufptr
+= val_list
[i
].ve_valuelen
;
3686 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3689 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3693 /************************************************************************
3694 * RegQueryReflectionKey
3699 RegQueryReflectionKey(IN HKEY hBase
,
3700 OUT BOOL
* bIsReflectionDisabled
)
3702 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3703 hBase
, bIsReflectionDisabled
);
3704 return ERROR_CALL_NOT_IMPLEMENTED
;
3708 /************************************************************************
3714 RegQueryValueExW (HKEY hKey
,
3715 LPCWSTR lpValueName
,
3721 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
3722 UNICODE_STRING ValueName
;
3727 LONG ErrorCode
= ERROR_SUCCESS
;
3728 ULONG MaxCopy
= lpcbData
!= NULL
&& lpData
!= NULL
? *lpcbData
: 0;
3730 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3731 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3733 Status
= MapDefaultKey (&KeyHandle
,
3735 if (!NT_SUCCESS(Status
))
3737 return RtlNtStatusToDosError (Status
);
3740 if (lpData
!= NULL
&& lpcbData
== NULL
)
3742 ErrorCode
= ERROR_INVALID_PARAMETER
;
3746 RtlInitUnicodeString (&ValueName
,
3748 BufferSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MaxCopy
;
3749 ValueInfo
= RtlAllocateHeap (ProcessHeap
,
3752 if (ValueInfo
== NULL
)
3754 ErrorCode
= ERROR_OUTOFMEMORY
;
3758 Status
= NtQueryValueKey (KeyHandle
,
3760 KeyValuePartialInformation
,
3764 TRACE("Status 0x%X\n", Status
);
3765 if (Status
== STATUS_BUFFER_OVERFLOW
)
3767 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3769 ErrorCode
= lpData
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
3771 else if (!NT_SUCCESS(Status
))
3773 ErrorCode
= RtlNtStatusToDosError (Status
);
3775 if (lpcbData
!= NULL
)
3777 ResultSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + *lpcbData
;
3783 *lpType
= ValueInfo
->Type
;
3786 if (NT_SUCCESS(Status
) && lpData
!= NULL
)
3788 RtlMoveMemory (lpData
,
3790 min(ValueInfo
->DataLength
, MaxCopy
));
3793 if ((ValueInfo
->Type
== REG_SZ
) ||
3794 (ValueInfo
->Type
== REG_MULTI_SZ
) ||
3795 (ValueInfo
->Type
== REG_EXPAND_SZ
))
3797 if (lpData
!= NULL
&& MaxCopy
> ValueInfo
->DataLength
)
3799 ((PWSTR
)lpData
)[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = 0;
3802 if (lpcbData
!= NULL
)
3804 *lpcbData
= (ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]));
3805 TRACE("(string) Returning Size: %lu\n", *lpcbData
);
3810 if (lpcbData
!= NULL
)
3812 *lpcbData
= ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
3813 TRACE("(other) Returning Size: %lu\n", *lpcbData
);
3817 TRACE("Type %d Size %d\n", ValueInfo
->Type
, ValueInfo
->DataLength
);
3819 RtlFreeHeap (ProcessHeap
,
3824 ClosePredefKey(KeyHandle
);
3830 /************************************************************************
3836 RegQueryValueExA (HKEY hKey
,
3843 UNICODE_STRING ValueName
;
3844 UNICODE_STRING ValueData
;
3845 ANSI_STRING AnsiString
;
3850 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3851 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3853 if (lpData
!= NULL
&& lpcbData
== NULL
)
3855 return ERROR_INVALID_PARAMETER
;
3860 ValueData
.Length
= 0;
3861 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3862 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3864 ValueData
.MaximumLength
);
3865 if (!ValueData
.Buffer
)
3867 return ERROR_OUTOFMEMORY
;
3872 ValueData
.Buffer
= NULL
;
3873 ValueData
.Length
= 0;
3874 ValueData
.MaximumLength
= 0;
3877 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3878 (LPSTR
)lpValueName
);
3880 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
3881 ErrorCode
= RegQueryValueExW (hKey
,
3885 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
3887 TRACE("ErrorCode %lu\n", ErrorCode
);
3888 RtlFreeUnicodeString(&ValueName
);
3890 if (ErrorCode
== ERROR_SUCCESS
||
3891 ErrorCode
== ERROR_MORE_DATA
)
3898 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
3900 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3902 RtlInitAnsiString(&AnsiString
, NULL
);
3903 AnsiString
.Buffer
= (LPSTR
)lpData
;
3904 AnsiString
.MaximumLength
= *lpcbData
;
3905 ValueData
.Length
= Length
;
3906 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
3907 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
3909 Length
= Length
/ sizeof(WCHAR
);
3911 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3913 if (*lpcbData
< Length
)
3915 ErrorCode
= ERROR_MORE_DATA
;
3919 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
3923 if (lpcbData
!= NULL
)
3929 if (ValueData
.Buffer
!= NULL
)
3931 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
3938 /************************************************************************
3944 RegQueryValueA (HKEY hKey
,
3949 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
3950 UNICODE_STRING SubKeyName
;
3951 UNICODE_STRING Value
;
3952 ANSI_STRING AnsiString
;
3956 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3957 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3959 if (lpValue
!= NULL
&&
3962 return ERROR_INVALID_PARAMETER
;
3965 RtlInitUnicodeString (&SubKeyName
,
3967 RtlInitUnicodeString (&Value
,
3969 if (lpSubKey
!= NULL
&&
3970 strlen(lpSubKey
) != 0)
3972 RtlInitAnsiString (&AnsiString
,
3974 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
3975 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
3976 RtlAnsiStringToUnicodeString (&SubKeyName
,
3981 if (lpValue
!= NULL
)
3983 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
3984 Value
.MaximumLength
= ValueSize
;
3985 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3988 if (Value
.Buffer
== NULL
)
3990 return ERROR_OUTOFMEMORY
;
3998 ErrorCode
= RegQueryValueW (hKey
,
3999 (LPCWSTR
)SubKeyName
.Buffer
,
4002 if (ErrorCode
== ERROR_SUCCESS
)
4004 Value
.Length
= ValueSize
;
4005 RtlInitAnsiString (&AnsiString
,
4007 AnsiString
.Buffer
= lpValue
;
4008 AnsiString
.MaximumLength
= *lpcbValue
;
4009 RtlUnicodeStringToAnsiString (&AnsiString
,
4014 *lpcbValue
= ValueSize
;
4015 if (Value
.Buffer
!= NULL
)
4017 RtlFreeHeap (ProcessHeap
,
4026 /************************************************************************
4032 RegQueryValueW (HKEY hKey
,
4037 OBJECT_ATTRIBUTES ObjectAttributes
;
4038 UNICODE_STRING SubKeyString
;
4045 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
4046 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4048 Status
= MapDefaultKey (&KeyHandle
,
4050 if (!NT_SUCCESS(Status
))
4052 return RtlNtStatusToDosError (Status
);
4055 if (lpSubKey
!= NULL
&&
4056 wcslen(lpSubKey
) != 0)
4058 RtlInitUnicodeString (&SubKeyString
,
4060 InitializeObjectAttributes (&ObjectAttributes
,
4062 OBJ_CASE_INSENSITIVE
,
4065 Status
= NtOpenKey (&RealKey
,
4068 if (!NT_SUCCESS(Status
))
4070 ErrorCode
= RtlNtStatusToDosError (Status
);
4073 CloseRealKey
= TRUE
;
4078 CloseRealKey
= FALSE
;
4081 ErrorCode
= RegQueryValueExW (RealKey
,
4086 (LPDWORD
)lpcbValue
);
4093 ClosePredefKey(KeyHandle
);
4099 /************************************************************************
4105 RegReplaceKeyA (HKEY hKey
,
4110 UNICODE_STRING SubKey
;
4111 UNICODE_STRING NewFile
;
4112 UNICODE_STRING OldFile
;
4115 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
4117 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
4119 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
4122 ErrorCode
= RegReplaceKeyW (hKey
,
4127 RtlFreeUnicodeString (&OldFile
);
4128 RtlFreeUnicodeString (&NewFile
);
4129 RtlFreeUnicodeString (&SubKey
);
4135 /************************************************************************
4141 RegReplaceKeyW (HKEY hKey
,
4146 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4147 OBJECT_ATTRIBUTES NewObjectAttributes
;
4148 OBJECT_ATTRIBUTES OldObjectAttributes
;
4149 UNICODE_STRING SubKeyName
;
4150 UNICODE_STRING NewFileName
;
4151 UNICODE_STRING OldFileName
;
4152 BOOLEAN CloseRealKey
;
4153 HANDLE RealKeyHandle
;
4156 LONG ErrorCode
= ERROR_SUCCESS
;
4158 if (hKey
== HKEY_PERFORMANCE_DATA
)
4160 return ERROR_INVALID_HANDLE
;
4163 Status
= MapDefaultKey (&KeyHandle
,
4165 if (!NT_SUCCESS(Status
))
4167 return RtlNtStatusToDosError (Status
);
4170 /* Open the real key */
4171 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4173 RtlInitUnicodeString (&SubKeyName
,
4175 InitializeObjectAttributes (&KeyObjectAttributes
,
4177 OBJ_CASE_INSENSITIVE
,
4180 Status
= NtOpenKey (&RealKeyHandle
,
4182 &KeyObjectAttributes
);
4183 if (!NT_SUCCESS(Status
))
4185 ErrorCode
= RtlNtStatusToDosError (Status
);
4188 CloseRealKey
= TRUE
;
4192 RealKeyHandle
= KeyHandle
;
4193 CloseRealKey
= FALSE
;
4196 /* Convert new file name */
4197 if (!RtlDosPathNameToNtPathName_U (lpNewFile
,
4204 NtClose (RealKeyHandle
);
4206 ErrorCode
= ERROR_INVALID_PARAMETER
;
4210 InitializeObjectAttributes (&NewObjectAttributes
,
4212 OBJ_CASE_INSENSITIVE
,
4216 /* Convert old file name */
4217 if (!RtlDosPathNameToNtPathName_U (lpOldFile
,
4222 RtlFreeHeap (RtlGetProcessHeap (),
4224 NewFileName
.Buffer
);
4227 NtClose (RealKeyHandle
);
4229 ErrorCode
= ERROR_INVALID_PARAMETER
;
4233 InitializeObjectAttributes (&OldObjectAttributes
,
4235 OBJ_CASE_INSENSITIVE
,
4239 Status
= NtReplaceKey (&NewObjectAttributes
,
4241 &OldObjectAttributes
);
4243 RtlFreeHeap (RtlGetProcessHeap (),
4245 OldFileName
.Buffer
);
4246 RtlFreeHeap (RtlGetProcessHeap (),
4248 NewFileName
.Buffer
);
4252 NtClose (RealKeyHandle
);
4255 if (!NT_SUCCESS(Status
))
4257 return RtlNtStatusToDosError (Status
);
4261 ClosePredefKey(KeyHandle
);
4267 /************************************************************************
4273 RegRestoreKeyA (HKEY hKey
,
4277 UNICODE_STRING FileName
;
4280 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4283 ErrorCode
= RegRestoreKeyW (hKey
,
4287 RtlFreeUnicodeString (&FileName
);
4293 /************************************************************************
4299 RegRestoreKeyW (HKEY hKey
,
4303 OBJECT_ATTRIBUTES ObjectAttributes
;
4304 IO_STATUS_BLOCK IoStatusBlock
;
4305 UNICODE_STRING FileName
;
4310 if (hKey
== HKEY_PERFORMANCE_DATA
)
4312 return ERROR_INVALID_HANDLE
;
4315 Status
= MapDefaultKey (&KeyHandle
,
4317 if (!NT_SUCCESS(Status
))
4319 return RtlNtStatusToDosError (Status
);
4322 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4327 Status
= STATUS_INVALID_PARAMETER
;
4331 InitializeObjectAttributes (&ObjectAttributes
,
4333 OBJ_CASE_INSENSITIVE
,
4337 Status
= NtOpenFile (&FileHandle
,
4342 FILE_SYNCHRONOUS_IO_NONALERT
);
4343 RtlFreeHeap (RtlGetProcessHeap(),
4346 if (!NT_SUCCESS(Status
))
4351 Status
= NtRestoreKey (KeyHandle
,
4354 NtClose (FileHandle
);
4357 ClosePredefKey(KeyHandle
);
4359 if (!NT_SUCCESS(Status
))
4361 return RtlNtStatusToDosError (Status
);
4364 return ERROR_SUCCESS
;
4368 /************************************************************************
4374 RegSaveKeyA (HKEY hKey
,
4376 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4378 UNICODE_STRING FileName
;
4381 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4383 ErrorCode
= RegSaveKeyW (hKey
,
4385 lpSecurityAttributes
);
4386 RtlFreeUnicodeString (&FileName
);
4392 /************************************************************************
4398 RegSaveKeyW (HKEY hKey
,
4400 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4402 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4403 OBJECT_ATTRIBUTES ObjectAttributes
;
4404 UNICODE_STRING FileName
;
4405 IO_STATUS_BLOCK IoStatusBlock
;
4410 Status
= MapDefaultKey (&KeyHandle
,
4412 if (!NT_SUCCESS(Status
))
4414 return RtlNtStatusToDosError (Status
);
4417 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4422 Status
= STATUS_INVALID_PARAMETER
;
4426 if (lpSecurityAttributes
!= NULL
)
4428 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4431 InitializeObjectAttributes (&ObjectAttributes
,
4433 OBJ_CASE_INSENSITIVE
,
4435 SecurityDescriptor
);
4436 Status
= NtCreateFile (&FileHandle
,
4437 GENERIC_WRITE
| SYNCHRONIZE
,
4441 FILE_ATTRIBUTE_NORMAL
,
4444 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4447 RtlFreeHeap (RtlGetProcessHeap (),
4450 if (!NT_SUCCESS(Status
))
4455 Status
= NtSaveKey (KeyHandle
,
4457 NtClose (FileHandle
);
4460 ClosePredefKey(KeyHandle
);
4462 if (!NT_SUCCESS(Status
))
4464 return RtlNtStatusToDosError (Status
);
4467 return ERROR_SUCCESS
;
4471 /************************************************************************
4477 RegSetKeySecurity (HKEY hKey
,
4478 SECURITY_INFORMATION SecurityInformation
,
4479 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4484 if (hKey
== HKEY_PERFORMANCE_DATA
)
4486 return ERROR_INVALID_HANDLE
;
4489 Status
= MapDefaultKey (&KeyHandle
,
4491 if (!NT_SUCCESS(Status
))
4493 return RtlNtStatusToDosError (Status
);
4496 Status
= NtSetSecurityObject (KeyHandle
,
4497 SecurityInformation
,
4498 pSecurityDescriptor
);
4500 ClosePredefKey(KeyHandle
);
4502 if (!NT_SUCCESS(Status
))
4504 return RtlNtStatusToDosError (Status
);
4507 return ERROR_SUCCESS
;
4511 /************************************************************************
4517 RegSetValueExA (HKEY hKey
,
4524 UNICODE_STRING ValueName
;
4526 ANSI_STRING AnsiString
;
4527 UNICODE_STRING Data
;
4532 if (lpValueName
!= NULL
&&
4533 strlen(lpValueName
) != 0)
4535 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4537 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4544 if (((dwType
== REG_SZ
) ||
4545 (dwType
== REG_MULTI_SZ
) ||
4546 (dwType
== REG_EXPAND_SZ
)) &&
4549 /* NT adds one if the caller forgot the NULL-termination character */
4550 if (lpData
[cbData
- 1] != '\0')
4555 RtlInitAnsiString (&AnsiString
,
4557 AnsiString
.Buffer
= (PSTR
)lpData
;
4558 AnsiString
.Length
= cbData
- 1;
4559 AnsiString
.MaximumLength
= cbData
;
4560 RtlAnsiStringToUnicodeString (&Data
,
4563 pData
= (LPBYTE
)Data
.Buffer
;
4564 DataSize
= cbData
* sizeof(WCHAR
);
4568 RtlInitUnicodeString (&Data
,
4570 pData
= (LPBYTE
)lpData
;
4574 ErrorCode
= RegSetValueExW (hKey
,
4580 if (pValueName
!= NULL
)
4582 RtlFreeHeap (ProcessHeap
,
4587 if (Data
.Buffer
!= NULL
)
4589 RtlFreeHeap (ProcessHeap
,
4598 /************************************************************************
4604 RegSetValueExW (HKEY hKey
,
4605 LPCWSTR lpValueName
,
4611 UNICODE_STRING ValueName
;
4612 PUNICODE_STRING pValueName
;
4616 Status
= MapDefaultKey (&KeyHandle
,
4618 if (!NT_SUCCESS(Status
))
4620 return RtlNtStatusToDosError (Status
);
4623 if (lpValueName
!= NULL
)
4625 RtlInitUnicodeString (&ValueName
,
4630 RtlInitUnicodeString (&ValueName
, L
"");
4632 pValueName
= &ValueName
;
4634 if (((dwType
== REG_SZ
) ||
4635 (dwType
== REG_MULTI_SZ
) ||
4636 (dwType
== REG_EXPAND_SZ
)) &&
4637 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4639 /* NT adds one if the caller forgot the NULL-termination character */
4640 cbData
+= sizeof(WCHAR
);
4643 Status
= NtSetValueKey (KeyHandle
,
4650 ClosePredefKey(KeyHandle
);
4652 if (!NT_SUCCESS(Status
))
4654 return RtlNtStatusToDosError (Status
);
4657 return ERROR_SUCCESS
;
4661 /************************************************************************
4667 RegSetValueA (HKEY hKey
,
4676 if (dwType
!= REG_SZ
)
4678 return ERROR_INVALID_PARAMETER
;
4681 if (lpSubKey
!= NULL
&& lpSubKey
[0] != '\0')
4683 ret
= RegCreateKeyA(hKey
,
4687 if (ret
!= ERROR_SUCCESS
)
4695 ret
= RegSetValueExA(hSubKey
,
4699 (CONST BYTE
*)lpData
,
4700 strlen(lpData
) + 1);
4702 if (hSubKey
!= hKey
)
4704 RegCloseKey(hSubKey
);
4711 /************************************************************************
4717 RegSetValueW (HKEY hKey
,
4723 OBJECT_ATTRIBUTES ObjectAttributes
;
4724 UNICODE_STRING SubKeyString
;
4731 Status
= MapDefaultKey (&KeyHandle
,
4733 if (!NT_SUCCESS(Status
))
4735 return RtlNtStatusToDosError (Status
);
4738 if ((lpSubKey
) && (wcslen(lpSubKey
) != 0))
4740 RtlInitUnicodeString (&SubKeyString
,
4742 InitializeObjectAttributes (&ObjectAttributes
,
4744 OBJ_CASE_INSENSITIVE
,
4747 Status
= NtOpenKey (&RealKey
,
4750 if (!NT_SUCCESS(Status
))
4752 ErrorCode
= RtlNtStatusToDosError (Status
);
4755 CloseRealKey
= TRUE
;
4760 CloseRealKey
= FALSE
;
4763 ErrorCode
= RegSetValueExW (RealKey
,
4769 if (CloseRealKey
== TRUE
)
4775 ClosePredefKey(KeyHandle
);
4781 /************************************************************************
4787 RegUnLoadKeyA (HKEY hKey
,
4790 UNICODE_STRING KeyName
;
4793 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4796 ErrorCode
= RegUnLoadKeyW (hKey
,
4799 RtlFreeUnicodeString (&KeyName
);
4805 /************************************************************************
4811 RegUnLoadKeyW (HKEY hKey
,
4814 OBJECT_ATTRIBUTES ObjectAttributes
;
4815 UNICODE_STRING KeyName
;
4819 if (hKey
== HKEY_PERFORMANCE_DATA
)
4821 return ERROR_INVALID_HANDLE
;
4824 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4825 if (!NT_SUCCESS(Status
))
4827 return RtlNtStatusToDosError (Status
);
4830 RtlInitUnicodeString (&KeyName
,
4833 InitializeObjectAttributes (&ObjectAttributes
,
4835 OBJ_CASE_INSENSITIVE
,
4839 Status
= NtUnloadKey (&ObjectAttributes
);
4841 ClosePredefKey(KeyHandle
);
4843 if (!NT_SUCCESS(Status
))
4845 return RtlNtStatusToDosError (Status
);
4848 return ERROR_SUCCESS
;
4852 /************************************************************************
4858 RegLoadMUIStringW(IN HKEY hKey
,
4859 IN LPCWSTR pszValue OPTIONAL
,
4860 OUT LPWSTR pszOutBuf
,
4863 IN LPCWSTR pszDirectory OPTIONAL
)
4865 FIXME("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4866 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4867 return ERROR_CALL_NOT_IMPLEMENTED
;
4871 /************************************************************************
4877 RegLoadMUIStringA(IN HKEY hKey
,
4878 IN LPCSTR pszValue OPTIONAL
,
4879 OUT LPSTR pszOutBuf
,
4882 IN LPCSTR pszDirectory OPTIONAL
)
4884 FIXME("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4885 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4886 return ERROR_CALL_NOT_IMPLEMENTED
;