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)
8 * Thomas Weidenmueller <w3seek@reactos.com>
12 * 20050502 Fireball imported some stuff from WINE
15 /* INCLUDES *****************************************************************/
19 #include <wine/debug.h>
21 /* DEFINES ******************************************************************/
23 #define MAX_DEFAULT_HANDLES 6
24 #define REG_MAX_NAME_SIZE 256
25 #define REG_MAX_DATA_SIZE 2048
27 /* GLOBALS ******************************************************************/
29 static RTL_CRITICAL_SECTION HandleTableCS
;
30 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
31 static HANDLE ProcessHeap
;
32 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
34 /* PROTOTYPES ***************************************************************/
36 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
37 static VOID
CloseDefaultKeys(VOID
);
38 #define ClosePredefKey(Handle) \
39 if ((ULONG_PTR)Handle & 0x1) { \
42 #define IsPredefKey(HKey) \
43 (((ULONG)(HKey) & 0xF0000000) == 0x80000000)
44 #define GetPredefKeyIndex(HKey) \
45 ((ULONG)(HKey) & 0x0FFFFFFF)
47 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
48 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
49 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
53 /* FUNCTIONS ****************************************************************/
54 /* check if value type needs string conversion (Ansi<->Unicode) */
55 __inline
static int is_string( DWORD type
)
57 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
60 /************************************************************************
61 * RegInitDefaultHandles
66 TRACE("RegInitialize()\n");
68 ProcessHeap
= RtlGetProcessHeap();
69 RtlZeroMemory (DefaultHandleTable
,
70 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
71 RtlInitializeCriticalSection (&HandleTableCS
);
77 /************************************************************************
83 TRACE("RegCleanup()\n");
86 RtlDeleteCriticalSection (&HandleTableCS
);
93 OpenPredefinedKey(IN ULONG Index
,
100 case 0: /* HKEY_CLASSES_ROOT */
101 Status
= OpenClassesRootKey (Handle
);
104 case 1: /* HKEY_CURRENT_USER */
105 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
109 case 2: /* HKEY_LOCAL_MACHINE */
110 Status
= OpenLocalMachineKey (Handle
);
113 case 3: /* HKEY_USERS */
114 Status
= OpenUsersKey (Handle
);
117 case 4: /* HKEY_PERFORMANCE_DATA */
118 Status
= OpenPerformanceDataKey (Handle
);
122 case 5: /* HKEY_CURRENT_CONFIG */
123 Status
= OpenCurrentConfigKey (Handle
);
126 case 6: /* HKEY_DYN_DATA */
127 Status
= STATUS_NOT_IMPLEMENTED
;
131 WARN("MapDefaultHandle() no handle creator\n");
132 Status
= STATUS_INVALID_PARAMETER
;
141 MapDefaultKey (OUT PHANDLE RealKey
,
147 NTSTATUS Status
= STATUS_SUCCESS
;
149 TRACE("MapDefaultKey (Key %x)\n", Key
);
151 if (!IsPredefKey(Key
))
153 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
154 return STATUS_SUCCESS
;
157 /* Handle special cases here */
158 Index
= GetPredefKeyIndex(Key
);
159 if (Index
>= MAX_DEFAULT_HANDLES
)
161 return STATUS_INVALID_PARAMETER
;
164 RtlEnterCriticalSection (&HandleTableCS
);
166 if (!DefaultHandlesDisabled
)
168 Handle
= &DefaultHandleTable
[Index
];
169 DoOpen
= (*Handle
== NULL
);
179 /* create/open the default handle */
180 Status
= OpenPredefinedKey(Index
,
184 if (NT_SUCCESS(Status
))
186 if (!DefaultHandlesDisabled
)
189 *(PULONG_PTR
)Handle
|= 0x1;
192 RtlLeaveCriticalSection (&HandleTableCS
);
199 CloseDefaultKeys (VOID
)
203 RtlEnterCriticalSection (&HandleTableCS
);
204 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
206 if (DefaultHandleTable
[i
] != NULL
)
208 NtClose (DefaultHandleTable
[i
]);
209 DefaultHandleTable
[i
] = NULL
;
212 RtlLeaveCriticalSection (&HandleTableCS
);
217 OpenClassesRootKey (PHANDLE KeyHandle
)
219 OBJECT_ATTRIBUTES Attributes
;
220 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
222 TRACE("OpenClassesRootKey()\n");
224 InitializeObjectAttributes (&Attributes
,
226 OBJ_CASE_INSENSITIVE
,
229 return NtOpenKey (KeyHandle
,
236 OpenLocalMachineKey (PHANDLE KeyHandle
)
238 OBJECT_ATTRIBUTES Attributes
;
239 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
242 TRACE("OpenLocalMachineKey()\n");
244 InitializeObjectAttributes (&Attributes
,
246 OBJ_CASE_INSENSITIVE
,
249 Status
= NtOpenKey (KeyHandle
,
253 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
259 OpenUsersKey (PHANDLE KeyHandle
)
261 OBJECT_ATTRIBUTES Attributes
;
262 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
264 TRACE("OpenUsersKey()\n");
266 InitializeObjectAttributes (&Attributes
,
268 OBJ_CASE_INSENSITIVE
,
271 return NtOpenKey (KeyHandle
,
278 OpenCurrentConfigKey (PHANDLE KeyHandle
)
280 OBJECT_ATTRIBUTES Attributes
;
281 UNICODE_STRING KeyName
=
282 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
284 TRACE("OpenCurrentConfigKey()\n");
286 InitializeObjectAttributes (&Attributes
,
288 OBJ_CASE_INSENSITIVE
,
291 return NtOpenKey (KeyHandle
,
297 /************************************************************************
298 * RegDisablePredefinedCacheEx
303 RegDisablePredefinedCacheEx(VOID
)
305 RtlEnterCriticalSection (&HandleTableCS
);
306 DefaultHandlesDisabled
= TRUE
;
307 RtlLeaveCriticalSection (&HandleTableCS
);
308 return ERROR_SUCCESS
;
312 /************************************************************************
313 * RegOverridePredefKey
318 RegOverridePredefKey(IN HKEY hKey
,
319 IN HKEY hNewHKey OPTIONAL
)
321 LONG ErrorCode
= ERROR_SUCCESS
;
323 if ((hKey
== HKEY_CLASSES_ROOT
||
324 hKey
== HKEY_CURRENT_CONFIG
||
325 hKey
== HKEY_CURRENT_USER
||
326 hKey
== HKEY_LOCAL_MACHINE
||
327 hKey
== HKEY_PERFORMANCE_DATA
||
328 hKey
== HKEY_USERS
) &&
329 !IsPredefKey(hNewHKey
))
334 Index
= GetPredefKeyIndex(hKey
);
335 Handle
= &DefaultHandleTable
[Index
];
337 if (hNewHKey
== NULL
)
339 /* restore the default mapping */
340 NTSTATUS Status
= OpenPredefinedKey(Index
,
342 if (!NT_SUCCESS(Status
))
344 return RtlNtStatusToDosError(Status
);
347 ASSERT(hNewHKey
!= NULL
);
350 RtlEnterCriticalSection (&HandleTableCS
);
352 /* close the currently mapped handle if existing */
358 /* update the mapping */
361 RtlLeaveCriticalSection (&HandleTableCS
);
364 ErrorCode
= ERROR_INVALID_HANDLE
;
370 /************************************************************************
376 RegCloseKey (HKEY hKey
)
380 /* don't close null handle or a pseudo handle */
381 if ((!hKey
) || (((ULONG
)hKey
& 0xF0000000) == 0x80000000))
383 return ERROR_INVALID_HANDLE
;
386 Status
= NtClose (hKey
);
387 if (!NT_SUCCESS(Status
))
389 return RtlNtStatusToDosError (Status
);
392 return ERROR_SUCCESS
;
397 RegpCopyTree(IN HKEY hKeySrc
,
402 LIST_ENTRY ListEntry
;
405 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
407 LIST_ENTRY copyQueueHead
;
408 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
411 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
412 KEY_NODE_INFORMATION
*KeyNode
;
415 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
416 NTSTATUS Status
= STATUS_SUCCESS
;
417 NTSTATUS Status2
= STATUS_SUCCESS
;
419 InitializeListHead(©QueueHead
);
421 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
424 if (Info
.Buffer
== NULL
)
426 return STATUS_INSUFFICIENT_RESOURCES
;
429 copyKeys
= RtlAllocateHeap(ProcessHeap
,
431 sizeof(REGP_COPY_KEYS
));
432 if (copyKeys
!= NULL
)
434 copyKeys
->hKeySrc
= hKeySrc
;
435 copyKeys
->hKeyDest
= hKeyDest
;
436 InsertHeadList(©QueueHead
,
437 ©Keys
->ListEntry
);
439 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
443 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
447 /* enumerate all values and copy them */
451 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
453 KeyValueFullInformation
,
456 &BufferSizeRequired
);
457 if (NT_SUCCESS(Status2
))
459 UNICODE_STRING ValueName
;
462 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
463 ValueName
.Length
= Info
.KeyValue
->NameLength
;
464 ValueName
.MaximumLength
= ValueName
.Length
;
465 ValueName
.Buffer
= Info
.KeyValue
->Name
;
467 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
469 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
471 Info
.KeyValue
->TitleIndex
,
474 Info
.KeyValue
->DataLength
);
476 /* don't break, let's try to copy as many values as possible */
477 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
484 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
488 ASSERT(BufferSize
< BufferSizeRequired
);
490 Buffer
= RtlReAllocateHeap(ProcessHeap
,
496 Info
.Buffer
= Buffer
;
501 /* don't break, let's try to copy as many values as possible */
502 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
505 if (NT_SUCCESS(Status
))
513 /* break to avoid an infinite loop in case of denied access or
515 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
524 /* enumerate all subkeys and open and enqueue them */
528 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
533 &BufferSizeRequired
);
534 if (NT_SUCCESS(Status2
))
536 HANDLE KeyHandle
, NewKeyHandle
;
537 OBJECT_ATTRIBUTES ObjectAttributes
;
538 UNICODE_STRING SubKeyName
, ClassName
;
540 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
541 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
542 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
543 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
544 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
545 ClassName
.MaximumLength
= ClassName
.Length
;
546 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
548 /* open the subkey with sufficient rights */
550 InitializeObjectAttributes(&ObjectAttributes
,
552 OBJ_CASE_INSENSITIVE
,
556 Status2
= NtOpenKey(&KeyHandle
,
557 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
559 if (NT_SUCCESS(Status2
))
561 /* FIXME - attempt to query the security information */
563 InitializeObjectAttributes(&ObjectAttributes
,
565 OBJ_CASE_INSENSITIVE
,
569 Status2
= NtCreateKey(&NewKeyHandle
,
572 Info
.KeyNode
->TitleIndex
,
576 if (NT_SUCCESS(Status2
))
578 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
580 sizeof(REGP_COPY_KEYS
));
581 if (newCopyKeys
!= NULL
)
583 /* save the handles and enqueue the subkey */
584 newCopyKeys
->hKeySrc
= KeyHandle
;
585 newCopyKeys
->hKeyDest
= NewKeyHandle
;
586 InsertTailList(©QueueHead
,
587 &newCopyKeys
->ListEntry
);
592 NtClose(NewKeyHandle
);
594 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
603 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
610 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
614 ASSERT(BufferSize
< BufferSizeRequired
);
616 Buffer
= RtlReAllocateHeap(ProcessHeap
,
622 Info
.Buffer
= Buffer
;
627 /* don't break, let's try to copy as many keys as possible */
628 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
631 if (NT_SUCCESS(Status
))
639 /* break to avoid an infinite loop in case of denied access or
641 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
650 /* close the handles and remove the entry from the list */
651 if (copyKeys
->hKeySrc
!= hKeySrc
)
653 NtClose(copyKeys
->hKeySrc
);
655 if (copyKeys
->hKeyDest
!= hKeyDest
)
657 NtClose(copyKeys
->hKeyDest
);
660 RemoveEntryList(©Keys
->ListEntry
);
662 RtlFreeHeap(ProcessHeap
,
665 } while (!IsListEmpty(©QueueHead
));
668 Status
= STATUS_INSUFFICIENT_RESOURCES
;
670 RtlFreeHeap(ProcessHeap
,
678 /************************************************************************
684 RegCopyTreeW(IN HKEY hKeySrc
,
685 IN LPCWSTR lpSubKey OPTIONAL
,
688 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
691 Status
= MapDefaultKey(&KeyHandle
,
693 if (!NT_SUCCESS(Status
))
695 return RtlNtStatusToDosError(Status
);
698 Status
= MapDefaultKey(&DestKeyHandle
,
700 if (!NT_SUCCESS(Status
))
705 if (lpSubKey
!= NULL
)
707 OBJECT_ATTRIBUTES ObjectAttributes
;
708 UNICODE_STRING SubKeyName
;
710 RtlInitUnicodeString(&SubKeyName
,
713 InitializeObjectAttributes(&ObjectAttributes
,
715 OBJ_CASE_INSENSITIVE
,
719 Status
= NtOpenKey(&SubKeyHandle
,
720 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
722 if (!NT_SUCCESS(Status
))
727 CurKey
= SubKeyHandle
;
732 Status
= RegpCopyTree(CurKey
,
735 if (SubKeyHandle
!= NULL
)
737 NtClose(SubKeyHandle
);
741 ClosePredefKey(DestKeyHandle
);
743 ClosePredefKey(KeyHandle
);
745 if (!NT_SUCCESS(Status
))
747 return RtlNtStatusToDosError(Status
);
750 return ERROR_SUCCESS
;
754 /************************************************************************
760 RegCopyTreeA(IN HKEY hKeySrc
,
761 IN LPCSTR lpSubKey OPTIONAL
,
764 UNICODE_STRING SubKeyName
= {0};
767 if (lpSubKey
!= NULL
&&
768 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
771 return ERROR_NOT_ENOUGH_MEMORY
;
774 Ret
= RegCopyTreeW(hKeySrc
,
778 RtlFreeUnicodeString(&SubKeyName
);
784 /************************************************************************
785 * RegConnectRegistryA
790 RegConnectRegistryA (IN LPCSTR lpMachineName
,
794 UNICODE_STRING MachineName
= {0};
797 if (lpMachineName
!= NULL
&&
798 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
799 (LPSTR
)lpMachineName
))
801 return ERROR_NOT_ENOUGH_MEMORY
;
804 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
808 RtlFreeUnicodeString(&MachineName
);
814 /************************************************************************
815 * RegConnectRegistryW
820 RegConnectRegistryW (LPCWSTR lpMachineName
,
824 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
825 return ERROR_CALL_NOT_IMPLEMENTED
;
829 /************************************************************************
832 * Create key and all necessary intermediate keys
835 CreateNestedKey(PHKEY KeyHandle
,
836 POBJECT_ATTRIBUTES ObjectAttributes
,
837 PUNICODE_STRING ClassString
,
840 DWORD
*lpdwDisposition
)
842 OBJECT_ATTRIBUTES LocalObjectAttributes
;
843 UNICODE_STRING LocalKeyName
;
846 ULONG FullNameLength
;
849 HANDLE LocalKeyHandle
;
851 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
857 (PULONG
)lpdwDisposition
);
858 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
859 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
862 /* Copy object attributes */
863 RtlCopyMemory (&LocalObjectAttributes
,
865 sizeof(OBJECT_ATTRIBUTES
));
866 RtlCreateUnicodeString (&LocalKeyName
,
867 ObjectAttributes
->ObjectName
->Buffer
);
868 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
869 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
871 /* Remove the last part of the key name and try to create the key again. */
872 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
874 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
875 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
877 Status
= STATUS_UNSUCCESSFUL
;
881 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
883 Status
= NtCreateKey (&LocalKeyHandle
,
885 &LocalObjectAttributes
,
890 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
893 if (!NT_SUCCESS(Status
))
895 RtlFreeUnicodeString (&LocalKeyName
);
899 /* Add removed parts of the key name and create them too. */
900 Length
= wcslen (LocalKeyName
.Buffer
);
903 NtClose (LocalKeyHandle
);
905 LocalKeyName
.Buffer
[Length
] = L
'\\';
906 Length
= wcslen (LocalKeyName
.Buffer
);
907 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
909 if (Length
== FullNameLength
)
911 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
917 (PULONG
)lpdwDisposition
);
920 Status
= NtCreateKey (&LocalKeyHandle
,
922 &LocalObjectAttributes
,
927 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
928 if (!NT_SUCCESS(Status
))
932 RtlFreeUnicodeString (&LocalKeyName
);
938 /************************************************************************
944 RegCreateKeyExA (HKEY hKey
,
950 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
952 LPDWORD lpdwDisposition
)
954 UNICODE_STRING SubKeyString
;
955 UNICODE_STRING ClassString
;
956 OBJECT_ATTRIBUTES Attributes
;
960 TRACE("RegCreateKeyExA() called\n");
962 /* get the real parent key */
963 Status
= MapDefaultKey (&ParentKey
,
965 if (!NT_SUCCESS(Status
))
967 return RtlNtStatusToDosError (Status
);
969 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
973 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
977 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
979 InitializeObjectAttributes (&Attributes
,
981 OBJ_CASE_INSENSITIVE
,
983 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
984 Status
= CreateNestedKey(phkResult
,
986 (lpClass
== NULL
)? NULL
: &ClassString
,
990 RtlFreeUnicodeString (&SubKeyString
);
993 RtlFreeUnicodeString (&ClassString
);
996 ClosePredefKey(ParentKey
);
998 TRACE("Status %x\n", Status
);
999 if (!NT_SUCCESS(Status
))
1001 return RtlNtStatusToDosError (Status
);
1004 return ERROR_SUCCESS
;
1008 /************************************************************************
1014 RegCreateKeyExW (HKEY hKey
,
1020 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1022 LPDWORD lpdwDisposition
)
1024 UNICODE_STRING SubKeyString
;
1025 UNICODE_STRING ClassString
;
1026 OBJECT_ATTRIBUTES Attributes
;
1030 TRACE("RegCreateKeyExW() called\n");
1032 /* get the real parent key */
1033 Status
= MapDefaultKey (&ParentKey
,
1035 if (!NT_SUCCESS(Status
))
1037 return RtlNtStatusToDosError(Status
);
1039 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
1041 RtlInitUnicodeString (&ClassString
,
1043 RtlInitUnicodeString (&SubKeyString
,
1045 InitializeObjectAttributes (&Attributes
,
1047 OBJ_CASE_INSENSITIVE
,
1049 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
1050 Status
= CreateNestedKey(phkResult
,
1052 (lpClass
== NULL
)? NULL
: &ClassString
,
1057 ClosePredefKey(ParentKey
);
1059 TRACE("Status %x\n", Status
);
1060 if (!NT_SUCCESS(Status
))
1062 return RtlNtStatusToDosError (Status
);
1065 return ERROR_SUCCESS
;
1069 /************************************************************************
1075 RegCreateKeyA (HKEY hKey
,
1079 return RegCreateKeyExA (hKey
,
1091 /************************************************************************
1097 RegCreateKeyW (HKEY hKey
,
1101 return RegCreateKeyExW (hKey
,
1113 /************************************************************************
1119 RegDeleteKeyA (HKEY hKey
,
1122 OBJECT_ATTRIBUTES ObjectAttributes
;
1123 UNICODE_STRING SubKeyName
;
1128 Status
= MapDefaultKey (&ParentKey
,
1130 if (!NT_SUCCESS(Status
))
1132 return RtlNtStatusToDosError (Status
);
1135 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
1137 InitializeObjectAttributes(&ObjectAttributes
,
1139 OBJ_CASE_INSENSITIVE
,
1143 Status
= NtOpenKey (&TargetKey
,
1146 RtlFreeUnicodeString (&SubKeyName
);
1147 if (!NT_SUCCESS(Status
))
1152 Status
= NtDeleteKey (TargetKey
);
1153 NtClose (TargetKey
);
1156 ClosePredefKey(ParentKey
);
1158 if (!NT_SUCCESS(Status
))
1160 return RtlNtStatusToDosError(Status
);
1163 return ERROR_SUCCESS
;
1167 /************************************************************************
1173 RegDeleteKeyW (HKEY hKey
,
1176 OBJECT_ATTRIBUTES ObjectAttributes
;
1177 UNICODE_STRING SubKeyName
;
1182 Status
= MapDefaultKey (&ParentKey
,
1184 if (!NT_SUCCESS(Status
))
1186 return RtlNtStatusToDosError (Status
);
1189 RtlInitUnicodeString (&SubKeyName
,
1191 InitializeObjectAttributes (&ObjectAttributes
,
1193 OBJ_CASE_INSENSITIVE
,
1196 Status
= NtOpenKey (&TargetKey
,
1199 if (!NT_SUCCESS(Status
))
1204 Status
= NtDeleteKey (TargetKey
);
1205 NtClose (TargetKey
);
1208 ClosePredefKey(ParentKey
);
1210 if (!NT_SUCCESS(Status
))
1212 return RtlNtStatusToDosError (Status
);
1215 return ERROR_SUCCESS
;
1219 /************************************************************************
1220 * RegDeleteKeyValueW
1225 RegDeleteKeyValueW(IN HKEY hKey
,
1226 IN LPCWSTR lpSubKey OPTIONAL
,
1227 IN LPCWSTR lpValueName OPTIONAL
)
1229 UNICODE_STRING ValueName
;
1230 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1233 Status
= MapDefaultKey(&KeyHandle
,
1235 if (!NT_SUCCESS(Status
))
1237 return RtlNtStatusToDosError(Status
);
1240 if (lpSubKey
!= NULL
)
1242 OBJECT_ATTRIBUTES ObjectAttributes
;
1243 UNICODE_STRING SubKeyName
;
1245 RtlInitUnicodeString(&SubKeyName
,
1248 InitializeObjectAttributes(&ObjectAttributes
,
1250 OBJ_CASE_INSENSITIVE
,
1254 Status
= NtOpenKey(&SubKeyHandle
,
1257 if (!NT_SUCCESS(Status
))
1262 CurKey
= SubKeyHandle
;
1267 RtlInitUnicodeString(&ValueName
,
1268 (LPWSTR
)lpValueName
);
1270 Status
= NtDeleteValueKey(CurKey
,
1273 if (SubKeyHandle
!= NULL
)
1275 NtClose(SubKeyHandle
);
1279 ClosePredefKey(KeyHandle
);
1281 if (!NT_SUCCESS(Status
))
1283 return RtlNtStatusToDosError(Status
);
1286 return ERROR_SUCCESS
;
1290 /************************************************************************
1291 * RegDeleteKeyValueA
1296 RegDeleteKeyValueA(IN HKEY hKey
,
1297 IN LPCSTR lpSubKey OPTIONAL
,
1298 IN LPCSTR lpValueName OPTIONAL
)
1300 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1303 if (lpSubKey
!= NULL
&&
1304 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1307 return ERROR_NOT_ENOUGH_MEMORY
;
1310 if (lpValueName
!= NULL
&&
1311 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1312 (LPSTR
)lpValueName
))
1314 RtlFreeUnicodeString(&SubKey
);
1315 return ERROR_NOT_ENOUGH_MEMORY
;
1318 Ret
= RegDeleteKeyValueW(hKey
,
1322 RtlFreeUnicodeString(&SubKey
);
1323 RtlFreeUnicodeString(&ValueName
);
1330 RegpDeleteTree(IN HKEY hKey
)
1334 LIST_ENTRY ListEntry
;
1336 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1338 LIST_ENTRY delQueueHead
;
1339 PREG_DEL_KEYS delKeys
, newDelKeys
;
1342 PKEY_BASIC_INFORMATION BasicInfo
;
1343 PREG_DEL_KEYS KeyDelRoot
;
1344 NTSTATUS Status
= STATUS_SUCCESS
;
1345 NTSTATUS Status2
= STATUS_SUCCESS
;
1347 InitializeListHead(&delQueueHead
);
1349 ProcessHeap
= RtlGetProcessHeap();
1351 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1352 structure for the root key, we only do that for subkeys as we need to
1353 allocate REGP_DEL_KEYS structures anyway! */
1354 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1356 sizeof(REGP_DEL_KEYS
));
1357 if (KeyDelRoot
!= NULL
)
1359 KeyDelRoot
->KeyHandle
= hKey
;
1360 InsertTailList(&delQueueHead
,
1361 &KeyDelRoot
->ListEntry
);
1365 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1374 /* check if this key contains subkeys and delete them first by queuing
1375 them at the head of the list */
1376 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1378 KeyBasicInformation
,
1383 if (NT_SUCCESS(Status2
))
1385 OBJECT_ATTRIBUTES ObjectAttributes
;
1386 UNICODE_STRING SubKeyName
;
1388 ASSERT(newDelKeys
!= NULL
);
1389 ASSERT(BasicInfo
!= NULL
);
1391 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1392 SubKeyName
.Length
= BasicInfo
->NameLength
;
1393 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1394 SubKeyName
.Buffer
= BasicInfo
->Name
;
1396 InitializeObjectAttributes(&ObjectAttributes
,
1398 OBJ_CASE_INSENSITIVE
,
1402 /* open the subkey */
1403 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1404 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1406 if (!NT_SUCCESS(Status2
))
1411 /* enqueue this key to the head of the deletion queue */
1412 InsertHeadList(&delQueueHead
,
1413 &newDelKeys
->ListEntry
);
1415 /* try again from the head of the list */
1420 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1422 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1424 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1425 if (newDelKeys
!= NULL
)
1427 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1430 goto ReadFirstSubKey
;
1434 /* don't break, let's try to delete as many keys as possible */
1435 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1436 goto SubKeyFailureNoFree
;
1439 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1441 PREG_DEL_KEYS newDelKeys2
;
1443 ASSERT(newDelKeys
!= NULL
);
1445 /* we need more memory to query the key name */
1446 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1449 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1450 if (newDelKeys2
!= NULL
)
1452 newDelKeys
= newDelKeys2
;
1453 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1456 goto ReadFirstSubKey
;
1460 /* don't break, let's try to delete as many keys as possible */
1461 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1464 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1466 /* in some race conditions where another thread would delete
1467 the same tree at the same time, newDelKeys could actually
1469 if (newDelKeys
!= NULL
)
1471 RtlFreeHeap(ProcessHeap
,
1479 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1480 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1481 if (newDelKeys
!= NULL
)
1483 RtlFreeHeap(ProcessHeap
,
1488 SubKeyFailureNoFree
:
1489 /* don't break, let's try to delete as many keys as possible */
1490 if (NT_SUCCESS(Status
))
1496 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1498 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1500 if (!NT_SUCCESS(Status2
))
1502 /* close the key handle so we don't leak handles for keys we were
1503 unable to delete. But only do this for handles not supplied
1506 if (delKeys
->KeyHandle
!= hKey
)
1508 NtClose(delKeys
->KeyHandle
);
1511 if (NT_SUCCESS(Status
))
1513 /* don't break, let's try to delete as many keys as possible */
1518 /* remove the entry from the list */
1519 RemoveEntryList(&delKeys
->ListEntry
);
1521 RtlFreeHeap(ProcessHeap
,
1524 } while (!IsListEmpty(&delQueueHead
));
1527 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1533 /************************************************************************
1539 RegDeleteTreeW(IN HKEY hKey
,
1540 IN LPCWSTR lpSubKey OPTIONAL
)
1542 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1545 Status
= MapDefaultKey(&KeyHandle
,
1547 if (!NT_SUCCESS(Status
))
1549 return RtlNtStatusToDosError(Status
);
1552 if (lpSubKey
!= NULL
)
1554 OBJECT_ATTRIBUTES ObjectAttributes
;
1555 UNICODE_STRING SubKeyName
;
1557 RtlInitUnicodeString(&SubKeyName
,
1560 InitializeObjectAttributes(&ObjectAttributes
,
1562 OBJ_CASE_INSENSITIVE
,
1566 Status
= NtOpenKey(&SubKeyHandle
,
1567 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1569 if (!NT_SUCCESS(Status
))
1574 CurKey
= SubKeyHandle
;
1579 Status
= RegpDeleteTree(CurKey
);
1581 if (NT_SUCCESS(Status
))
1583 /* make sure we only close hKey (KeyHandle) when the caller specified a
1584 subkey, because the handle would be invalid already! */
1585 if (CurKey
!= KeyHandle
)
1587 ClosePredefKey(KeyHandle
);
1590 return ERROR_SUCCESS
;
1594 /* make sure we close all handles we created! */
1595 if (SubKeyHandle
!= NULL
)
1597 NtClose(SubKeyHandle
);
1601 ClosePredefKey(KeyHandle
);
1603 return RtlNtStatusToDosError(Status
);
1608 /************************************************************************
1614 RegDeleteTreeA(IN HKEY hKey
,
1615 IN LPCSTR lpSubKey OPTIONAL
)
1617 UNICODE_STRING SubKeyName
= {0};
1620 if (lpSubKey
!= NULL
&&
1621 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1624 return ERROR_NOT_ENOUGH_MEMORY
;
1627 Ret
= RegDeleteTreeW(hKey
,
1630 RtlFreeUnicodeString(&SubKeyName
);
1636 /************************************************************************
1642 RegSetKeyValueW(IN HKEY hKey
,
1643 IN LPCWSTR lpSubKey OPTIONAL
,
1644 IN LPCWSTR lpValueName OPTIONAL
,
1646 IN LPCVOID lpData OPTIONAL
,
1649 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1653 Status
= MapDefaultKey(&KeyHandle
,
1655 if (!NT_SUCCESS(Status
))
1657 return RtlNtStatusToDosError(Status
);
1660 if (lpSubKey
!= NULL
)
1662 OBJECT_ATTRIBUTES ObjectAttributes
;
1663 UNICODE_STRING SubKeyName
;
1665 RtlInitUnicodeString(&SubKeyName
,
1668 InitializeObjectAttributes(&ObjectAttributes
,
1670 OBJ_CASE_INSENSITIVE
,
1674 Status
= NtOpenKey(&SubKeyHandle
,
1677 if (!NT_SUCCESS(Status
))
1679 Ret
= RtlNtStatusToDosError(Status
);
1683 CurKey
= SubKeyHandle
;
1688 Ret
= RegSetValueExW(CurKey
,
1695 if (SubKeyHandle
!= NULL
)
1697 NtClose(SubKeyHandle
);
1701 ClosePredefKey(KeyHandle
);
1707 /************************************************************************
1713 RegSetKeyValueA(IN HKEY hKey
,
1714 IN LPCSTR lpSubKey OPTIONAL
,
1715 IN LPCSTR lpValueName OPTIONAL
,
1717 IN LPCVOID lpData OPTIONAL
,
1720 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1724 Status
= MapDefaultKey(&KeyHandle
,
1726 if (!NT_SUCCESS(Status
))
1728 return RtlNtStatusToDosError(Status
);
1731 if (lpSubKey
!= NULL
)
1733 OBJECT_ATTRIBUTES ObjectAttributes
;
1734 UNICODE_STRING SubKeyName
;
1736 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1739 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
1743 InitializeObjectAttributes(&ObjectAttributes
,
1745 OBJ_CASE_INSENSITIVE
,
1749 Status
= NtOpenKey(&SubKeyHandle
,
1753 RtlFreeUnicodeString(&SubKeyName
);
1755 if (!NT_SUCCESS(Status
))
1757 Ret
= RtlNtStatusToDosError(Status
);
1761 CurKey
= SubKeyHandle
;
1766 Ret
= RegSetValueExA(CurKey
,
1773 if (SubKeyHandle
!= NULL
)
1775 NtClose(SubKeyHandle
);
1779 ClosePredefKey(KeyHandle
);
1785 /************************************************************************
1791 RegDeleteValueA (HKEY hKey
,
1794 UNICODE_STRING ValueName
;
1798 Status
= MapDefaultKey (&KeyHandle
,
1800 if (!NT_SUCCESS(Status
))
1802 return RtlNtStatusToDosError (Status
);
1805 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
1806 (LPSTR
)lpValueName
);
1807 Status
= NtDeleteValueKey (KeyHandle
,
1809 RtlFreeUnicodeString (&ValueName
);
1811 ClosePredefKey(KeyHandle
);
1813 if (!NT_SUCCESS(Status
))
1815 return RtlNtStatusToDosError (Status
);
1818 return ERROR_SUCCESS
;
1822 /************************************************************************
1828 RegDeleteValueW (HKEY hKey
,
1829 LPCWSTR lpValueName
)
1831 UNICODE_STRING ValueName
;
1835 Status
= MapDefaultKey (&KeyHandle
,
1837 if (!NT_SUCCESS(Status
))
1839 return RtlNtStatusToDosError (Status
);
1842 RtlInitUnicodeString (&ValueName
,
1843 (LPWSTR
)lpValueName
);
1845 Status
= NtDeleteValueKey (KeyHandle
,
1848 ClosePredefKey(KeyHandle
);
1850 if (!NT_SUCCESS(Status
))
1852 return RtlNtStatusToDosError (Status
);
1855 return ERROR_SUCCESS
;
1859 /************************************************************************
1865 RegEnumKeyA (HKEY hKey
,
1873 return RegEnumKeyExA (hKey
,
1884 /************************************************************************
1890 RegEnumKeyW (HKEY hKey
,
1898 return RegEnumKeyExW (hKey
,
1909 /************************************************************************
1915 RegEnumKeyExA (HKEY hKey
,
1922 PFILETIME lpftLastWriteTime
)
1926 KEY_NODE_INFORMATION Node
;
1927 KEY_BASIC_INFORMATION Basic
;
1930 UNICODE_STRING StringU
;
1931 ANSI_STRING StringA
;
1932 LONG ErrorCode
= ERROR_SUCCESS
;
1934 DWORD ClassLength
= 0;
1940 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1941 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
1943 if ((lpClass
) && (!lpcbClass
))
1945 return ERROR_INVALID_PARAMETER
;
1948 Status
= MapDefaultKey(&KeyHandle
, hKey
);
1949 if (!NT_SUCCESS(Status
))
1951 return RtlNtStatusToDosError (Status
);
1956 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1967 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1974 /* The class name should start at a dword boundary */
1975 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1979 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1982 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
1983 if (KeyInfo
== NULL
)
1985 ErrorCode
= ERROR_OUTOFMEMORY
;
1989 Status
= NtEnumerateKey (KeyHandle
,
1991 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
1995 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1996 if (!NT_SUCCESS(Status
))
1998 ErrorCode
= RtlNtStatusToDosError (Status
);
2002 if (lpClass
== NULL
)
2004 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2006 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2010 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2011 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2012 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2017 if (KeyInfo
->Node
.NameLength
> NameLength
||
2018 KeyInfo
->Node
.ClassLength
> ClassLength
)
2020 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2024 StringA
.Buffer
= lpClass
;
2026 StringA
.MaximumLength
= *lpcbClass
;
2027 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2028 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2029 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2030 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2031 lpClass
[StringA
.Length
] = 0;
2032 *lpcbClass
= StringA
.Length
;
2033 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2034 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2035 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2039 if (ErrorCode
== ERROR_SUCCESS
)
2041 StringA
.Buffer
= lpName
;
2043 StringA
.MaximumLength
= *lpcbName
;
2044 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2045 lpName
[StringA
.Length
] = 0;
2046 *lpcbName
= StringA
.Length
;
2047 if (lpftLastWriteTime
!= NULL
)
2049 if (lpClass
== NULL
)
2051 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2052 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2056 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2057 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2063 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
2064 TRACE("Key Namea1 Length %d\n", NameLength
);
2065 TRACE("Key Namea Length %d\n", *lpcbName
);
2066 TRACE("Key Namea %s\n", lpName
);
2068 RtlFreeHeap (ProcessHeap
,
2073 ClosePredefKey(KeyHandle
);
2079 /************************************************************************
2085 RegEnumKeyExW (HKEY hKey
,
2092 PFILETIME lpftLastWriteTime
)
2096 KEY_NODE_INFORMATION Node
;
2097 KEY_BASIC_INFORMATION Basic
;
2103 ULONG ClassLength
= 0;
2105 LONG ErrorCode
= ERROR_SUCCESS
;
2108 Status
= MapDefaultKey(&KeyHandle
,
2110 if (!NT_SUCCESS(Status
))
2112 return RtlNtStatusToDosError (Status
);
2117 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2128 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2135 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2139 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2142 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
2145 if (KeyInfo
== NULL
)
2147 ErrorCode
= ERROR_OUTOFMEMORY
;
2151 Status
= NtEnumerateKey (KeyHandle
,
2153 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2157 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2158 if (!NT_SUCCESS(Status
))
2160 ErrorCode
= RtlNtStatusToDosError (Status
);
2164 if (lpClass
== NULL
)
2166 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2168 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2172 RtlCopyMemory (lpName
,
2173 KeyInfo
->Basic
.Name
,
2174 KeyInfo
->Basic
.NameLength
);
2175 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2176 lpName
[*lpcbName
] = 0;
2181 if (KeyInfo
->Node
.NameLength
> NameLength
||
2182 KeyInfo
->Node
.ClassLength
> ClassLength
)
2184 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2188 RtlCopyMemory (lpName
,
2190 KeyInfo
->Node
.NameLength
);
2191 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2192 lpName
[*lpcbName
] = 0;
2193 RtlCopyMemory (lpClass
,
2194 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2195 KeyInfo
->Node
.ClassLength
);
2196 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2197 lpClass
[*lpcbClass
] = 0;
2201 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2203 if (lpClass
== NULL
)
2205 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2206 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2210 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2211 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2216 RtlFreeHeap (ProcessHeap
,
2221 ClosePredefKey(KeyHandle
);
2226 /************************************************************************
2232 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2233 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2238 char buffer
[256], *buf_ptr
= buffer
;
2239 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2240 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2242 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2243 // hkey, index, value, val_count, reserved, type, data, count );
2245 /* NT only checks count, not val_count */
2246 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2247 status
= MapDefaultKey (&KeyHandle
, hKey
);
2248 if (!NT_SUCCESS(status
))
2250 return RtlNtStatusToDosError (status
);
2253 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2254 if (data
) total_size
+= *count
;
2255 total_size
= min( sizeof(buffer
), total_size
);
2257 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2258 buffer
, total_size
, &total_size
);
2259 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2261 /* we need to fetch the contents for a string type even if not requested,
2262 * because we need to compute the length of the ASCII string. */
2263 if (value
|| data
|| is_string(info
->Type
))
2265 /* retry with a dynamically allocated buffer */
2266 while (status
== STATUS_BUFFER_OVERFLOW
)
2268 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2269 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2271 status
= STATUS_INSUFFICIENT_RESOURCES
;
2274 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2275 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2276 buf_ptr
, total_size
, &total_size
);
2279 if (status
) goto done
;
2281 if (is_string(info
->Type
))
2284 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2285 total_size
- info
->DataOffset
);
2288 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2291 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2292 total_size
- info
->DataOffset
);
2293 /* if the type is REG_SZ and data is not 0-terminated
2294 * and there is enough space in the buffer NT appends a \0 */
2295 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2298 info
->DataLength
= len
;
2302 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2303 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2306 if (value
&& !status
)
2310 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2311 if (len
>= *val_count
)
2313 status
= STATUS_BUFFER_OVERFLOW
;
2316 len
= *val_count
- 1;
2317 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2323 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2329 else status
= STATUS_SUCCESS
;
2331 if (type
) *type
= info
->Type
;
2332 if (count
) *count
= info
->DataLength
;
2335 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2336 ClosePredefKey(KeyHandle
);
2337 return RtlNtStatusToDosError(status
);
2340 /******************************************************************************
2341 * RegEnumValueW [ADVAPI32.@]
2345 * hkey [I] Handle to key to query
2346 * index [I] Index of value to query
2347 * value [O] Value string
2348 * val_count [I/O] Size of value buffer (in wchars)
2349 * reserved [I] Reserved
2350 * type [O] Type code
2351 * data [O] Value data
2352 * count [I/O] Size of data buffer (in bytes)
2355 * Success: ERROR_SUCCESS
2356 * Failure: nonzero error code from Winerror.h
2359 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2360 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2365 char buffer
[256], *buf_ptr
= buffer
;
2366 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2367 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2369 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2370 // hkey, index, value, val_count, reserved, type, data, count );
2372 /* NT only checks count, not val_count */
2373 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2375 status
= MapDefaultKey (&KeyHandle
, hKey
);
2376 if (!NT_SUCCESS(status
))
2378 return RtlNtStatusToDosError (status
);
2381 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2382 if (data
) total_size
+= *count
;
2383 total_size
= min( sizeof(buffer
), total_size
);
2385 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2386 buffer
, total_size
, &total_size
);
2387 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2391 /* retry with a dynamically allocated buffer */
2392 while (status
== STATUS_BUFFER_OVERFLOW
)
2394 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2395 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2397 status
= ERROR_NOT_ENOUGH_MEMORY
;
2400 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2401 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2402 buf_ptr
, total_size
, &total_size
);
2405 if (status
) goto done
;
2409 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2411 status
= STATUS_BUFFER_OVERFLOW
;
2414 memcpy( value
, info
->Name
, info
->NameLength
);
2415 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2416 value
[*val_count
] = 0;
2421 if (total_size
- info
->DataOffset
> *count
)
2423 status
= STATUS_BUFFER_OVERFLOW
;
2426 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2427 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2429 /* if the type is REG_SZ and data is not 0-terminated
2430 * and there is enough space in the buffer NT appends a \0 */
2431 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2432 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2436 else status
= STATUS_SUCCESS
;
2439 if (type
) *type
= info
->Type
;
2440 if (count
) *count
= info
->DataLength
;
2443 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2444 ClosePredefKey(KeyHandle
);
2445 return RtlNtStatusToDosError(status
);
2448 /************************************************************************
2454 RegFlushKey(HKEY hKey
)
2459 if (hKey
== HKEY_PERFORMANCE_DATA
)
2461 return ERROR_SUCCESS
;
2464 Status
= MapDefaultKey (&KeyHandle
,
2466 if (!NT_SUCCESS(Status
))
2468 return RtlNtStatusToDosError (Status
);
2471 Status
= NtFlushKey (KeyHandle
);
2473 ClosePredefKey(KeyHandle
);
2475 if (!NT_SUCCESS(Status
))
2477 return RtlNtStatusToDosError (Status
);
2480 return ERROR_SUCCESS
;
2484 /************************************************************************
2490 RegGetKeySecurity(HKEY hKey
,
2491 SECURITY_INFORMATION SecurityInformation
,
2492 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2493 LPDWORD lpcbSecurityDescriptor
)
2498 if (hKey
== HKEY_PERFORMANCE_DATA
)
2500 return ERROR_INVALID_HANDLE
;
2503 Status
= MapDefaultKey(&KeyHandle
,
2505 if (!NT_SUCCESS(Status
))
2507 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2508 return RtlNtStatusToDosError (Status
);
2511 Status
= NtQuerySecurityObject(KeyHandle
,
2512 SecurityInformation
,
2513 pSecurityDescriptor
,
2514 *lpcbSecurityDescriptor
,
2515 lpcbSecurityDescriptor
);
2518 ClosePredefKey(KeyHandle
);
2520 if (!NT_SUCCESS(Status
))
2522 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
2523 return RtlNtStatusToDosError (Status
);
2526 return ERROR_SUCCESS
;
2530 /************************************************************************
2536 RegLoadKeyA (HKEY hKey
,
2540 UNICODE_STRING FileName
;
2541 UNICODE_STRING KeyName
;
2544 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
2546 RtlCreateUnicodeStringFromAsciiz (&FileName
,
2549 ErrorCode
= RegLoadKeyW (hKey
,
2553 RtlFreeUnicodeString (&FileName
);
2554 RtlFreeUnicodeString (&KeyName
);
2560 /************************************************************************
2566 RegLoadKeyW (HKEY hKey
,
2570 OBJECT_ATTRIBUTES FileObjectAttributes
;
2571 OBJECT_ATTRIBUTES KeyObjectAttributes
;
2572 UNICODE_STRING FileName
;
2573 UNICODE_STRING KeyName
;
2576 LONG ErrorCode
= ERROR_SUCCESS
;
2578 if (hKey
== HKEY_PERFORMANCE_DATA
)
2580 return ERROR_INVALID_HANDLE
;
2583 Status
= MapDefaultKey (&KeyHandle
,
2585 if (!NT_SUCCESS(Status
))
2587 return RtlNtStatusToDosError (Status
);
2590 if (!RtlDosPathNameToNtPathName_U (lpFile
,
2595 ErrorCode
= ERROR_BAD_PATHNAME
;
2599 InitializeObjectAttributes (&FileObjectAttributes
,
2601 OBJ_CASE_INSENSITIVE
,
2605 RtlInitUnicodeString (&KeyName
,
2608 InitializeObjectAttributes (&KeyObjectAttributes
,
2610 OBJ_CASE_INSENSITIVE
,
2614 Status
= NtLoadKey (&KeyObjectAttributes
,
2615 &FileObjectAttributes
);
2617 RtlFreeUnicodeString (&FileName
);
2619 if (!NT_SUCCESS(Status
))
2621 ErrorCode
= RtlNtStatusToDosError (Status
);
2626 ClosePredefKey(KeyHandle
);
2632 /************************************************************************
2633 * RegNotifyChangeKeyValue
2638 RegNotifyChangeKeyValue (HKEY hKey
,
2640 DWORD dwNotifyFilter
,
2644 IO_STATUS_BLOCK IoStatusBlock
;
2647 LONG ErrorCode
= ERROR_SUCCESS
;
2649 if (hKey
== HKEY_PERFORMANCE_DATA
)
2651 return ERROR_INVALID_HANDLE
;
2654 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
2656 return ERROR_INVALID_PARAMETER
;
2659 Status
= MapDefaultKey (&KeyHandle
,
2661 if (!NT_SUCCESS(Status
))
2663 return RtlNtStatusToDosError (Status
);
2666 /* FIXME: Remote key handles must fail */
2668 Status
= NtNotifyChangeKey (KeyHandle
,
2678 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
2680 ErrorCode
= RtlNtStatusToDosError (Status
);
2683 ClosePredefKey(KeyHandle
);
2689 /************************************************************************
2690 * RegOpenCurrentUser
2695 RegOpenCurrentUser (IN REGSAM samDesired
,
2696 OUT PHKEY phkResult
)
2700 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
2701 (PHANDLE
)phkResult
);
2702 if (!NT_SUCCESS(Status
))
2704 /* NOTE - don't set the last error code! just return the error! */
2705 return RtlNtStatusToDosError(Status
);
2708 return ERROR_SUCCESS
;
2712 /************************************************************************
2715 * 20050503 Fireball - imported from WINE
2720 RegOpenKeyA (HKEY hKey
,
2724 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2726 if (!lpSubKey
|| !*lpSubKey
)
2729 return ERROR_SUCCESS
;
2732 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2736 /************************************************************************
2741 * 20050503 Fireball - imported from WINE
2746 RegOpenKeyW (HKEY hKey
,
2750 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2752 if (!lpSubKey
|| !*lpSubKey
)
2755 return ERROR_SUCCESS
;
2757 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2761 /************************************************************************
2767 RegOpenKeyExA (HKEY hKey
,
2773 OBJECT_ATTRIBUTES ObjectAttributes
;
2774 UNICODE_STRING SubKeyString
;
2777 LONG ErrorCode
= ERROR_SUCCESS
;
2779 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2780 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2782 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2783 if (!NT_SUCCESS(Status
))
2785 return RtlNtStatusToDosError (Status
);
2788 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
2789 InitializeObjectAttributes (&ObjectAttributes
,
2791 OBJ_CASE_INSENSITIVE
,
2795 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2796 RtlFreeUnicodeString (&SubKeyString
);
2797 if (!NT_SUCCESS(Status
))
2799 ErrorCode
= RtlNtStatusToDosError (Status
);
2802 ClosePredefKey(KeyHandle
);
2808 /************************************************************************
2814 RegOpenKeyExW (HKEY hKey
,
2820 OBJECT_ATTRIBUTES ObjectAttributes
;
2821 UNICODE_STRING SubKeyString
;
2824 LONG ErrorCode
= ERROR_SUCCESS
;
2826 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2827 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2829 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2830 if (!NT_SUCCESS(Status
))
2832 return RtlNtStatusToDosError (Status
);
2835 if (lpSubKey
!= NULL
)
2836 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
2838 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
2840 InitializeObjectAttributes (&ObjectAttributes
,
2842 OBJ_CASE_INSENSITIVE
,
2846 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2848 if (!NT_SUCCESS(Status
))
2850 ErrorCode
= RtlNtStatusToDosError (Status
);
2853 ClosePredefKey(KeyHandle
);
2859 /************************************************************************
2860 * RegOpenUserClassesRoot
2865 RegOpenUserClassesRoot (IN HANDLE hToken
,
2867 IN REGSAM samDesired
,
2868 OUT PHKEY phkResult
)
2870 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
2871 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
2872 PTOKEN_USER TokenUserData
;
2873 ULONG RequiredLength
;
2874 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
2875 OBJECT_ATTRIBUTES ObjectAttributes
;
2878 /* check parameters */
2879 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
2881 return ERROR_INVALID_PARAMETER
;
2885 * Get the user sid from the token
2889 /* determine how much memory we need */
2890 Status
= NtQueryInformationToken(hToken
,
2895 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
2897 /* NOTE - as opposed to all other registry functions windows does indeed
2898 change the last error code in case the caller supplied a invalid
2899 handle for example! */
2900 return RtlNtStatusToDosError (Status
);
2903 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
2906 if (TokenUserData
== NULL
)
2908 return ERROR_NOT_ENOUGH_MEMORY
;
2911 /* attempt to read the information */
2912 Status
= NtQueryInformationToken(hToken
,
2917 if (!NT_SUCCESS(Status
))
2919 RtlFreeHeap(ProcessHeap
,
2922 if (Status
== STATUS_BUFFER_TOO_SMALL
)
2924 /* the information appears to have changed?! try again */
2928 /* NOTE - as opposed to all other registry functions windows does indeed
2929 change the last error code in case the caller supplied a invalid
2930 handle for example! */
2931 return RtlNtStatusToDosError (Status
);
2935 * Build the absolute path for the user's registry in the form
2936 * "\Registry\User\<SID>_Classes"
2938 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
2939 TokenUserData
->User
.Sid
,
2942 /* we don't need the user data anymore, free it */
2943 RtlFreeHeap(ProcessHeap
,
2947 if (!NT_SUCCESS(Status
))
2949 return RtlNtStatusToDosError (Status
);
2952 /* allocate enough memory for the entire key string */
2953 UserClassesKeyRoot
.Length
= 0;
2954 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
2955 sizeof(UserClassesKeyPrefix
) +
2956 sizeof(UserClassesKeySuffix
);
2957 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
2959 UserClassesKeyRoot
.MaximumLength
);
2960 if (UserClassesKeyRoot
.Buffer
== NULL
)
2962 RtlFreeUnicodeString(&UserSidString
);
2963 return RtlNtStatusToDosError (Status
);
2966 /* build the string */
2967 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2968 UserClassesKeyPrefix
);
2969 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
2971 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2972 UserClassesKeySuffix
);
2974 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
2980 InitializeObjectAttributes (&ObjectAttributes
,
2981 &UserClassesKeyRoot
,
2982 OBJ_CASE_INSENSITIVE
,
2986 Status
= NtOpenKey((PHANDLE
)phkResult
,
2990 RtlFreeUnicodeString(&UserSidString
);
2991 RtlFreeUnicodeString(&UserClassesKeyRoot
);
2993 if (!NT_SUCCESS(Status
))
2995 return RtlNtStatusToDosError (Status
);
2998 return ERROR_SUCCESS
;
3002 /************************************************************************
3008 RegQueryInfoKeyA (HKEY hKey
,
3013 LPDWORD lpcbMaxSubKeyLen
,
3014 LPDWORD lpcbMaxClassLen
,
3016 LPDWORD lpcbMaxValueNameLen
,
3017 LPDWORD lpcbMaxValueLen
,
3018 LPDWORD lpcbSecurityDescriptor
,
3019 PFILETIME lpftLastWriteTime
)
3021 WCHAR ClassName
[MAX_PATH
];
3022 UNICODE_STRING UnicodeString
;
3023 ANSI_STRING AnsiString
;
3026 RtlInitUnicodeString (&UnicodeString
,
3028 if (lpClass
!= NULL
)
3030 UnicodeString
.Buffer
= &ClassName
[0];
3031 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3032 AnsiString
.MaximumLength
= *lpcbClass
;
3035 ErrorCode
= RegQueryInfoKeyW (hKey
,
3036 UnicodeString
.Buffer
,
3043 lpcbMaxValueNameLen
,
3045 lpcbSecurityDescriptor
,
3047 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3049 AnsiString
.Buffer
= lpClass
;
3050 AnsiString
.Length
= 0;
3051 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3052 RtlUnicodeStringToAnsiString (&AnsiString
,
3055 *lpcbClass
= AnsiString
.Length
;
3056 lpClass
[AnsiString
.Length
] = 0;
3063 /************************************************************************
3069 RegQueryInfoKeyW (HKEY hKey
,
3074 LPDWORD lpcbMaxSubKeyLen
,
3075 LPDWORD lpcbMaxClassLen
,
3077 LPDWORD lpcbMaxValueNameLen
,
3078 LPDWORD lpcbMaxValueLen
,
3079 LPDWORD lpcbSecurityDescriptor
,
3080 PFILETIME lpftLastWriteTime
)
3082 KEY_FULL_INFORMATION FullInfoBuffer
;
3083 PKEY_FULL_INFORMATION FullInfo
;
3085 ULONG ClassLength
= 0;
3089 LONG ErrorCode
= ERROR_SUCCESS
;
3091 if ((lpClass
) && (!lpcbClass
))
3093 return ERROR_INVALID_PARAMETER
;
3096 Status
= MapDefaultKey (&KeyHandle
,
3098 if (!NT_SUCCESS(Status
))
3100 return RtlNtStatusToDosError (Status
);
3103 if (lpClass
!= NULL
)
3107 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3114 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3115 FullInfo
= RtlAllocateHeap (ProcessHeap
,
3118 if (FullInfo
== NULL
)
3120 ErrorCode
= ERROR_OUTOFMEMORY
;
3124 FullInfo
->ClassLength
= ClassLength
;
3128 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3129 FullInfo
= &FullInfoBuffer
;
3130 FullInfo
->ClassLength
= 0;
3132 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3134 Status
= NtQueryKey (KeyHandle
,
3139 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3140 if (!NT_SUCCESS(Status
))
3142 if (lpClass
!= NULL
)
3144 RtlFreeHeap (ProcessHeap
,
3149 ErrorCode
= RtlNtStatusToDosError (Status
);
3153 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3154 if (lpcSubKeys
!= NULL
)
3156 *lpcSubKeys
= FullInfo
->SubKeys
;
3159 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3160 if (lpcbMaxSubKeyLen
!= NULL
)
3162 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3165 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3166 if (lpcbMaxClassLen
!= NULL
)
3168 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3171 TRACE("Values %lu\n", FullInfo
->Values
);
3172 if (lpcValues
!= NULL
)
3174 *lpcValues
= FullInfo
->Values
;
3177 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3178 if (lpcbMaxValueNameLen
!= NULL
)
3180 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3183 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3184 if (lpcbMaxValueLen
!= NULL
)
3186 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3189 if (lpcbSecurityDescriptor
!= NULL
)
3191 Status
= NtQuerySecurityObject(KeyHandle
,
3192 OWNER_SECURITY_INFORMATION
|
3193 GROUP_SECURITY_INFORMATION
|
3194 DACL_SECURITY_INFORMATION
,
3197 lpcbSecurityDescriptor
);
3198 if (!NT_SUCCESS(Status
))
3200 if (lpClass
!= NULL
)
3202 RtlFreeHeap(ProcessHeap
,
3207 ErrorCode
= RtlNtStatusToDosError (Status
);
3213 if (lpftLastWriteTime
!= NULL
)
3215 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3216 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3219 if (lpClass
!= NULL
)
3221 if (FullInfo
->ClassLength
> ClassLength
)
3223 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3227 RtlCopyMemory (lpClass
,
3229 FullInfo
->ClassLength
);
3230 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3231 lpClass
[*lpcbClass
] = 0;
3234 RtlFreeHeap (ProcessHeap
,
3240 ClosePredefKey(KeyHandle
);
3246 /************************************************************************
3247 * RegQueryMultipleValuesA
3252 RegQueryMultipleValuesA (HKEY hKey
,
3259 DWORD maxBytes
= *ldwTotsize
;
3260 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3263 if (maxBytes
>= (1024*1024))
3264 return ERROR_TRANSFER_TOO_LONG
;
3268 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3269 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3271 for (i
= 0; i
< num_vals
; i
++)
3273 val_list
[i
].ve_valuelen
= 0;
3274 ErrorCode
= RegQueryValueExA (hKey
,
3275 val_list
[i
].ve_valuename
,
3279 &val_list
[i
].ve_valuelen
);
3280 if (ErrorCode
!= ERROR_SUCCESS
)
3285 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3287 ErrorCode
= RegQueryValueExA (hKey
,
3288 val_list
[i
].ve_valuename
,
3290 &val_list
[i
].ve_type
,
3292 &val_list
[i
].ve_valuelen
);
3293 if (ErrorCode
!= ERROR_SUCCESS
)
3298 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3300 bufptr
+= val_list
[i
].ve_valuelen
;
3303 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3306 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3310 /************************************************************************
3311 * RegQueryMultipleValuesW
3316 RegQueryMultipleValuesW (HKEY hKey
,
3323 DWORD maxBytes
= *ldwTotsize
;
3324 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3327 if (maxBytes
>= (1024*1024))
3328 return ERROR_TRANSFER_TOO_LONG
;
3332 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3333 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3335 for (i
= 0; i
< num_vals
; i
++)
3337 val_list
[i
].ve_valuelen
= 0;
3338 ErrorCode
= RegQueryValueExW (hKey
,
3339 val_list
[i
].ve_valuename
,
3343 &val_list
[i
].ve_valuelen
);
3344 if (ErrorCode
!= ERROR_SUCCESS
)
3349 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3351 ErrorCode
= RegQueryValueExW (hKey
,
3352 val_list
[i
].ve_valuename
,
3354 &val_list
[i
].ve_type
,
3356 &val_list
[i
].ve_valuelen
);
3357 if (ErrorCode
!= ERROR_SUCCESS
)
3362 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3364 bufptr
+= val_list
[i
].ve_valuelen
;
3367 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3370 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3374 /************************************************************************
3380 RegQueryValueExW (HKEY hKey
,
3381 LPCWSTR lpValueName
,
3387 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
3388 UNICODE_STRING ValueName
;
3393 LONG ErrorCode
= ERROR_SUCCESS
;
3394 ULONG MaxCopy
= lpcbData
!= NULL
&& lpData
!= NULL
? *lpcbData
: 0;
3396 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3397 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3399 Status
= MapDefaultKey (&KeyHandle
,
3401 if (!NT_SUCCESS(Status
))
3403 return RtlNtStatusToDosError (Status
);
3406 if (lpData
!= NULL
&& lpcbData
== NULL
)
3408 ErrorCode
= ERROR_INVALID_PARAMETER
;
3412 RtlInitUnicodeString (&ValueName
,
3414 BufferSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MaxCopy
;
3415 ValueInfo
= RtlAllocateHeap (ProcessHeap
,
3418 if (ValueInfo
== NULL
)
3420 ErrorCode
= ERROR_OUTOFMEMORY
;
3424 Status
= NtQueryValueKey (KeyHandle
,
3426 KeyValuePartialInformation
,
3430 TRACE("Status 0x%X\n", Status
);
3431 if (Status
== STATUS_BUFFER_OVERFLOW
)
3433 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3435 ErrorCode
= lpData
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
3437 else if (!NT_SUCCESS(Status
))
3439 ErrorCode
= RtlNtStatusToDosError (Status
);
3441 if (lpcbData
!= NULL
)
3443 ResultSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + *lpcbData
;
3449 *lpType
= ValueInfo
->Type
;
3452 if (NT_SUCCESS(Status
) && lpData
!= NULL
)
3454 RtlMoveMemory (lpData
,
3456 min(ValueInfo
->DataLength
, MaxCopy
));
3459 if ((ValueInfo
->Type
== REG_SZ
) ||
3460 (ValueInfo
->Type
== REG_MULTI_SZ
) ||
3461 (ValueInfo
->Type
== REG_EXPAND_SZ
))
3463 if (lpData
!= NULL
&& MaxCopy
> ValueInfo
->DataLength
)
3465 ((PWSTR
)lpData
)[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = 0;
3468 if (lpcbData
!= NULL
)
3470 *lpcbData
= (ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]));
3471 TRACE("(string) Returning Size: %lu\n", *lpcbData
);
3476 if (lpcbData
!= NULL
)
3478 *lpcbData
= ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
3479 TRACE("(other) Returning Size: %lu\n", *lpcbData
);
3483 TRACE("Type %d Size %d\n", ValueInfo
->Type
, ValueInfo
->DataLength
);
3485 RtlFreeHeap (ProcessHeap
,
3490 ClosePredefKey(KeyHandle
);
3496 /************************************************************************
3502 RegQueryValueExA (HKEY hKey
,
3509 UNICODE_STRING ValueName
;
3510 UNICODE_STRING ValueData
;
3511 ANSI_STRING AnsiString
;
3516 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3517 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3519 if (lpData
!= NULL
&& lpcbData
== NULL
)
3521 return ERROR_INVALID_PARAMETER
;
3526 ValueData
.Length
= 0;
3527 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3528 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3530 ValueData
.MaximumLength
);
3531 if (!ValueData
.Buffer
)
3533 return ERROR_OUTOFMEMORY
;
3538 ValueData
.Buffer
= NULL
;
3539 ValueData
.Length
= 0;
3540 ValueData
.MaximumLength
= 0;
3543 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3544 (LPSTR
)lpValueName
);
3546 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
3547 ErrorCode
= RegQueryValueExW (hKey
,
3551 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
3553 TRACE("ErrorCode %lu\n", ErrorCode
);
3554 RtlFreeUnicodeString(&ValueName
);
3556 if (ErrorCode
== ERROR_SUCCESS
||
3557 ErrorCode
== ERROR_MORE_DATA
)
3564 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
3566 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3568 RtlInitAnsiString(&AnsiString
, NULL
);
3569 AnsiString
.Buffer
= (LPSTR
)lpData
;
3570 AnsiString
.MaximumLength
= *lpcbData
;
3571 ValueData
.Length
= Length
;
3572 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
3573 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
3575 Length
= Length
/ sizeof(WCHAR
);
3577 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3579 if (*lpcbData
< Length
)
3581 ErrorCode
= ERROR_MORE_DATA
;
3585 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
3589 if (lpcbData
!= NULL
)
3595 if (ValueData
.Buffer
!= NULL
)
3597 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
3604 /************************************************************************
3610 RegQueryValueA (HKEY hKey
,
3615 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
3616 UNICODE_STRING SubKeyName
;
3617 UNICODE_STRING Value
;
3618 ANSI_STRING AnsiString
;
3622 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3623 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3625 if (lpValue
!= NULL
&&
3628 return ERROR_INVALID_PARAMETER
;
3631 RtlInitUnicodeString (&SubKeyName
,
3633 RtlInitUnicodeString (&Value
,
3635 if (lpSubKey
!= NULL
&&
3636 strlen(lpSubKey
) != 0)
3638 RtlInitAnsiString (&AnsiString
,
3640 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
3641 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
3642 RtlAnsiStringToUnicodeString (&SubKeyName
,
3647 if (lpValue
!= NULL
)
3649 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
3650 Value
.MaximumLength
= ValueSize
;
3651 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3654 if (Value
.Buffer
== NULL
)
3656 return ERROR_OUTOFMEMORY
;
3664 ErrorCode
= RegQueryValueW (hKey
,
3665 (LPCWSTR
)SubKeyName
.Buffer
,
3668 if (ErrorCode
== ERROR_SUCCESS
)
3670 Value
.Length
= ValueSize
;
3671 RtlInitAnsiString (&AnsiString
,
3673 AnsiString
.Buffer
= lpValue
;
3674 AnsiString
.MaximumLength
= *lpcbValue
;
3675 RtlUnicodeStringToAnsiString (&AnsiString
,
3680 *lpcbValue
= ValueSize
;
3681 if (Value
.Buffer
!= NULL
)
3683 RtlFreeHeap (ProcessHeap
,
3692 /************************************************************************
3698 RegQueryValueW (HKEY hKey
,
3703 OBJECT_ATTRIBUTES ObjectAttributes
;
3704 UNICODE_STRING SubKeyString
;
3711 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3712 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3714 Status
= MapDefaultKey (&KeyHandle
,
3716 if (!NT_SUCCESS(Status
))
3718 return RtlNtStatusToDosError (Status
);
3721 if (lpSubKey
!= NULL
&&
3722 wcslen(lpSubKey
) != 0)
3724 RtlInitUnicodeString (&SubKeyString
,
3726 InitializeObjectAttributes (&ObjectAttributes
,
3728 OBJ_CASE_INSENSITIVE
,
3731 Status
= NtOpenKey (&RealKey
,
3734 if (!NT_SUCCESS(Status
))
3736 ErrorCode
= RtlNtStatusToDosError (Status
);
3739 CloseRealKey
= TRUE
;
3744 CloseRealKey
= FALSE
;
3747 ErrorCode
= RegQueryValueExW (RealKey
,
3752 (LPDWORD
)lpcbValue
);
3759 ClosePredefKey(KeyHandle
);
3765 /************************************************************************
3771 RegReplaceKeyA (HKEY hKey
,
3776 UNICODE_STRING SubKey
;
3777 UNICODE_STRING NewFile
;
3778 UNICODE_STRING OldFile
;
3781 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
3783 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
3785 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
3788 ErrorCode
= RegReplaceKeyW (hKey
,
3793 RtlFreeUnicodeString (&OldFile
);
3794 RtlFreeUnicodeString (&NewFile
);
3795 RtlFreeUnicodeString (&SubKey
);
3801 /************************************************************************
3807 RegReplaceKeyW (HKEY hKey
,
3812 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3813 OBJECT_ATTRIBUTES NewObjectAttributes
;
3814 OBJECT_ATTRIBUTES OldObjectAttributes
;
3815 UNICODE_STRING SubKeyName
;
3816 UNICODE_STRING NewFileName
;
3817 UNICODE_STRING OldFileName
;
3818 BOOLEAN CloseRealKey
;
3819 HANDLE RealKeyHandle
;
3822 LONG ErrorCode
= ERROR_SUCCESS
;
3824 if (hKey
== HKEY_PERFORMANCE_DATA
)
3826 return ERROR_INVALID_HANDLE
;
3829 Status
= MapDefaultKey (&KeyHandle
,
3831 if (!NT_SUCCESS(Status
))
3833 return RtlNtStatusToDosError (Status
);
3836 /* Open the real key */
3837 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
3839 RtlInitUnicodeString (&SubKeyName
,
3841 InitializeObjectAttributes (&KeyObjectAttributes
,
3843 OBJ_CASE_INSENSITIVE
,
3846 Status
= NtOpenKey (&RealKeyHandle
,
3848 &KeyObjectAttributes
);
3849 if (!NT_SUCCESS(Status
))
3851 ErrorCode
= RtlNtStatusToDosError (Status
);
3854 CloseRealKey
= TRUE
;
3858 RealKeyHandle
= KeyHandle
;
3859 CloseRealKey
= FALSE
;
3862 /* Convert new file name */
3863 if (!RtlDosPathNameToNtPathName_U (lpNewFile
,
3870 NtClose (RealKeyHandle
);
3872 ErrorCode
= ERROR_INVALID_PARAMETER
;
3876 InitializeObjectAttributes (&NewObjectAttributes
,
3878 OBJ_CASE_INSENSITIVE
,
3882 /* Convert old file name */
3883 if (!RtlDosPathNameToNtPathName_U (lpOldFile
,
3888 RtlFreeUnicodeString (&NewFileName
);
3891 NtClose (RealKeyHandle
);
3893 ErrorCode
= ERROR_INVALID_PARAMETER
;
3897 InitializeObjectAttributes (&OldObjectAttributes
,
3899 OBJ_CASE_INSENSITIVE
,
3903 Status
= NtReplaceKey (&NewObjectAttributes
,
3905 &OldObjectAttributes
);
3907 RtlFreeUnicodeString (&OldFileName
);
3908 RtlFreeUnicodeString (&NewFileName
);
3912 NtClose (RealKeyHandle
);
3915 if (!NT_SUCCESS(Status
))
3917 return RtlNtStatusToDosError (Status
);
3921 ClosePredefKey(KeyHandle
);
3927 /************************************************************************
3933 RegRestoreKeyA (HKEY hKey
,
3937 UNICODE_STRING FileName
;
3940 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3943 ErrorCode
= RegRestoreKeyW (hKey
,
3947 RtlFreeUnicodeString (&FileName
);
3953 /************************************************************************
3959 RegRestoreKeyW (HKEY hKey
,
3963 OBJECT_ATTRIBUTES ObjectAttributes
;
3964 IO_STATUS_BLOCK IoStatusBlock
;
3965 UNICODE_STRING FileName
;
3970 if (hKey
== HKEY_PERFORMANCE_DATA
)
3972 return ERROR_INVALID_HANDLE
;
3975 Status
= MapDefaultKey (&KeyHandle
,
3977 if (!NT_SUCCESS(Status
))
3979 return RtlNtStatusToDosError (Status
);
3982 if (!RtlDosPathNameToNtPathName_U (lpFile
,
3987 Status
= STATUS_INVALID_PARAMETER
;
3991 InitializeObjectAttributes (&ObjectAttributes
,
3993 OBJ_CASE_INSENSITIVE
,
3997 Status
= NtOpenFile (&FileHandle
,
4002 FILE_SYNCHRONOUS_IO_NONALERT
);
4003 RtlFreeUnicodeString (&FileName
);
4004 if (!NT_SUCCESS(Status
))
4009 Status
= NtRestoreKey (KeyHandle
,
4012 NtClose (FileHandle
);
4015 ClosePredefKey(KeyHandle
);
4017 if (!NT_SUCCESS(Status
))
4019 return RtlNtStatusToDosError (Status
);
4022 return ERROR_SUCCESS
;
4026 /************************************************************************
4032 RegSaveKeyA (HKEY hKey
,
4034 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4036 UNICODE_STRING FileName
;
4039 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4041 ErrorCode
= RegSaveKeyW (hKey
,
4043 lpSecurityAttributes
);
4044 RtlFreeUnicodeString (&FileName
);
4050 /************************************************************************
4056 RegSaveKeyW (HKEY hKey
,
4058 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4060 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4061 OBJECT_ATTRIBUTES ObjectAttributes
;
4062 UNICODE_STRING FileName
;
4063 IO_STATUS_BLOCK IoStatusBlock
;
4068 Status
= MapDefaultKey (&KeyHandle
,
4070 if (!NT_SUCCESS(Status
))
4072 return RtlNtStatusToDosError (Status
);
4075 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4080 Status
= STATUS_INVALID_PARAMETER
;
4084 if (lpSecurityAttributes
!= NULL
)
4086 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4089 InitializeObjectAttributes (&ObjectAttributes
,
4091 OBJ_CASE_INSENSITIVE
,
4093 SecurityDescriptor
);
4094 Status
= NtCreateFile (&FileHandle
,
4095 GENERIC_WRITE
| SYNCHRONIZE
,
4099 FILE_ATTRIBUTE_NORMAL
,
4102 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4105 RtlFreeUnicodeString (&FileName
);
4106 if (!NT_SUCCESS(Status
))
4111 Status
= NtSaveKey (KeyHandle
,
4113 NtClose (FileHandle
);
4116 ClosePredefKey(KeyHandle
);
4118 if (!NT_SUCCESS(Status
))
4120 return RtlNtStatusToDosError (Status
);
4123 return ERROR_SUCCESS
;
4127 /************************************************************************
4133 RegSetKeySecurity (HKEY hKey
,
4134 SECURITY_INFORMATION SecurityInformation
,
4135 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4140 if (hKey
== HKEY_PERFORMANCE_DATA
)
4142 return ERROR_INVALID_HANDLE
;
4145 Status
= MapDefaultKey (&KeyHandle
,
4147 if (!NT_SUCCESS(Status
))
4149 return RtlNtStatusToDosError (Status
);
4152 Status
= NtSetSecurityObject (KeyHandle
,
4153 SecurityInformation
,
4154 pSecurityDescriptor
);
4156 ClosePredefKey(KeyHandle
);
4158 if (!NT_SUCCESS(Status
))
4160 return RtlNtStatusToDosError (Status
);
4163 return ERROR_SUCCESS
;
4167 /************************************************************************
4173 RegSetValueExA (HKEY hKey
,
4180 UNICODE_STRING ValueName
;
4182 ANSI_STRING AnsiString
;
4183 UNICODE_STRING Data
;
4188 if (lpValueName
!= NULL
&&
4189 strlen(lpValueName
) != 0)
4191 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4193 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4200 if (((dwType
== REG_SZ
) ||
4201 (dwType
== REG_MULTI_SZ
) ||
4202 (dwType
== REG_EXPAND_SZ
)) &&
4205 /* NT adds one if the caller forgot the NULL-termination character */
4206 if (lpData
[cbData
- 1] != '\0')
4211 RtlInitAnsiString (&AnsiString
,
4213 AnsiString
.Buffer
= (PSTR
)lpData
;
4214 AnsiString
.Length
= cbData
- 1;
4215 AnsiString
.MaximumLength
= cbData
;
4216 RtlAnsiStringToUnicodeString (&Data
,
4219 pData
= (LPBYTE
)Data
.Buffer
;
4220 DataSize
= cbData
* sizeof(WCHAR
);
4224 RtlInitUnicodeString (&Data
,
4226 pData
= (LPBYTE
)lpData
;
4230 ErrorCode
= RegSetValueExW (hKey
,
4236 if (pValueName
!= NULL
)
4238 RtlFreeHeap (ProcessHeap
,
4243 if (Data
.Buffer
!= NULL
)
4245 RtlFreeHeap (ProcessHeap
,
4254 /************************************************************************
4260 RegSetValueExW (HKEY hKey
,
4261 LPCWSTR lpValueName
,
4267 UNICODE_STRING ValueName
;
4268 PUNICODE_STRING pValueName
;
4272 Status
= MapDefaultKey (&KeyHandle
,
4274 if (!NT_SUCCESS(Status
))
4276 return RtlNtStatusToDosError (Status
);
4279 if (lpValueName
!= NULL
)
4281 RtlInitUnicodeString (&ValueName
,
4286 RtlInitUnicodeString (&ValueName
, L
"");
4288 pValueName
= &ValueName
;
4290 if (((dwType
== REG_SZ
) ||
4291 (dwType
== REG_MULTI_SZ
) ||
4292 (dwType
== REG_EXPAND_SZ
)) &&
4293 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4295 /* NT adds one if the caller forgot the NULL-termination character */
4296 cbData
+= sizeof(WCHAR
);
4299 Status
= NtSetValueKey (KeyHandle
,
4306 ClosePredefKey(KeyHandle
);
4308 if (!NT_SUCCESS(Status
))
4310 return RtlNtStatusToDosError (Status
);
4313 return ERROR_SUCCESS
;
4317 /************************************************************************
4323 RegSetValueA (HKEY hKey
,
4332 if (dwType
!= REG_SZ
)
4334 return ERROR_INVALID_PARAMETER
;
4337 if (lpSubKey
!= NULL
&& lpSubKey
[0] != '\0')
4339 ret
= RegCreateKeyA(hKey
,
4343 if (ret
!= ERROR_SUCCESS
)
4351 ret
= RegSetValueExA(hSubKey
,
4355 (CONST BYTE
*)lpData
,
4356 strlen(lpData
) + 1);
4358 if (hSubKey
!= hKey
)
4360 RegCloseKey(hSubKey
);
4367 /************************************************************************
4373 RegSetValueW (HKEY hKey
,
4379 OBJECT_ATTRIBUTES ObjectAttributes
;
4380 UNICODE_STRING SubKeyString
;
4387 Status
= MapDefaultKey (&KeyHandle
,
4389 if (!NT_SUCCESS(Status
))
4391 return RtlNtStatusToDosError (Status
);
4394 if ((lpSubKey
) && (wcslen(lpSubKey
) != 0))
4396 RtlInitUnicodeString (&SubKeyString
,
4398 InitializeObjectAttributes (&ObjectAttributes
,
4400 OBJ_CASE_INSENSITIVE
,
4403 Status
= NtOpenKey (&RealKey
,
4406 if (!NT_SUCCESS(Status
))
4408 ErrorCode
= RtlNtStatusToDosError (Status
);
4411 CloseRealKey
= TRUE
;
4416 CloseRealKey
= FALSE
;
4419 ErrorCode
= RegSetValueExW (RealKey
,
4425 if (CloseRealKey
== TRUE
)
4431 ClosePredefKey(KeyHandle
);
4437 /************************************************************************
4443 RegUnLoadKeyA (HKEY hKey
,
4446 UNICODE_STRING KeyName
;
4449 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4452 ErrorCode
= RegUnLoadKeyW (hKey
,
4455 RtlFreeUnicodeString (&KeyName
);
4461 /************************************************************************
4467 RegUnLoadKeyW (HKEY hKey
,
4470 OBJECT_ATTRIBUTES ObjectAttributes
;
4471 UNICODE_STRING KeyName
;
4475 if (hKey
== HKEY_PERFORMANCE_DATA
)
4477 return ERROR_INVALID_HANDLE
;
4480 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4481 if (!NT_SUCCESS(Status
))
4483 return RtlNtStatusToDosError (Status
);
4486 RtlInitUnicodeString (&KeyName
,
4489 InitializeObjectAttributes (&ObjectAttributes
,
4491 OBJ_CASE_INSENSITIVE
,
4495 Status
= NtUnloadKey (&ObjectAttributes
);
4497 ClosePredefKey(KeyHandle
);
4499 if (!NT_SUCCESS(Status
))
4501 return RtlNtStatusToDosError (Status
);
4504 return ERROR_SUCCESS
;
4508 /************************************************************************
4514 RegLoadMUIStringW(IN HKEY hKey
,
4515 IN LPCWSTR pszValue OPTIONAL
,
4516 OUT LPWSTR pszOutBuf
,
4519 IN LPCWSTR pszDirectory OPTIONAL
)
4521 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4522 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4523 return ERROR_CALL_NOT_IMPLEMENTED
;
4527 /************************************************************************
4533 RegLoadMUIStringA(IN HKEY hKey
,
4534 IN LPCSTR pszValue OPTIONAL
,
4535 OUT LPSTR pszOutBuf
,
4538 IN LPCSTR pszDirectory OPTIONAL
)
4540 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4541 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4542 return ERROR_CALL_NOT_IMPLEMENTED
;