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 /* FIXME: should go into msvcrt.h header? */
28 #define offsetof(s,m) (size_t)&(((s*)NULL)->m)
30 /* GLOBALS ******************************************************************/
32 static RTL_CRITICAL_SECTION HandleTableCS
;
33 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
34 static HANDLE ProcessHeap
;
35 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
37 /* PROTOTYPES ***************************************************************/
39 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
40 static VOID
CloseDefaultKeys(VOID
);
41 #define CloseDefaultKey(Handle) \
42 if ((ULONG_PTR)Handle & 0x1) { \
46 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
47 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
48 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
49 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
52 /* FUNCTIONS ****************************************************************/
53 /* check if value type needs string conversion (Ansi<->Unicode) */
54 inline static int is_string( DWORD type
)
56 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
59 /************************************************************************
60 * RegInitDefaultHandles
65 TRACE("RegInitialize()\n");
67 ProcessHeap
= RtlGetProcessHeap();
68 RtlZeroMemory (DefaultHandleTable
,
69 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
70 RtlInitializeCriticalSection (&HandleTableCS
);
76 /************************************************************************
82 TRACE("RegCleanup()\n");
85 RtlDeleteCriticalSection (&HandleTableCS
);
92 OpenPredefinedKey(IN ULONG Index
,
99 case 0: /* HKEY_CLASSES_ROOT */
100 Status
= OpenClassesRootKey (Handle
);
103 case 1: /* HKEY_CURRENT_USER */
104 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
108 case 2: /* HKEY_LOCAL_MACHINE */
109 Status
= OpenLocalMachineKey (Handle
);
112 case 3: /* HKEY_USERS */
113 Status
= OpenUsersKey (Handle
);
116 case 4: /* HKEY_PERFORMANCE_DATA */
117 Status
= OpenPerformanceDataKey (Handle
);
121 case 5: /* HKEY_CURRENT_CONFIG */
122 Status
= OpenCurrentConfigKey (Handle
);
125 case 6: /* HKEY_DYN_DATA */
126 Status
= STATUS_NOT_IMPLEMENTED
;
130 WARN("MapDefaultHandle() no handle creator\n");
131 Status
= STATUS_INVALID_PARAMETER
;
140 MapDefaultKey (OUT PHANDLE RealKey
,
146 NTSTATUS Status
= STATUS_SUCCESS
;
148 TRACE("MapDefaultKey (Key %x)\n", Key
);
150 if (((ULONG
)Key
& 0xF0000000) != 0x80000000)
152 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
153 return STATUS_SUCCESS
;
156 /* Handle special cases here */
157 Index
= (ULONG
)Key
& 0x0FFFFFFF;
158 if (Index
>= MAX_DEFAULT_HANDLES
)
160 return STATUS_INVALID_PARAMETER
;
163 RtlEnterCriticalSection (&HandleTableCS
);
165 if (!DefaultHandlesDisabled
)
167 Handle
= &DefaultHandleTable
[Index
];
168 DoOpen
= (*Handle
== NULL
);
178 /* create/open the default handle */
179 Status
= OpenPredefinedKey(Index
,
183 if (NT_SUCCESS(Status
))
185 if (!DefaultHandlesDisabled
)
188 *(PULONG_PTR
)Handle
|= 0x1;
191 RtlLeaveCriticalSection (&HandleTableCS
);
198 CloseDefaultKeys (VOID
)
202 RtlEnterCriticalSection (&HandleTableCS
);
203 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
205 if (DefaultHandleTable
[i
] != NULL
)
207 NtClose (DefaultHandleTable
[i
]);
208 DefaultHandleTable
[i
] = NULL
;
211 RtlLeaveCriticalSection (&HandleTableCS
);
216 OpenClassesRootKey (PHANDLE KeyHandle
)
218 OBJECT_ATTRIBUTES Attributes
;
219 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
221 TRACE("OpenClassesRootKey()\n");
223 InitializeObjectAttributes (&Attributes
,
225 OBJ_CASE_INSENSITIVE
,
228 return NtOpenKey (KeyHandle
,
235 OpenLocalMachineKey (PHANDLE KeyHandle
)
237 OBJECT_ATTRIBUTES Attributes
;
238 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
241 TRACE("OpenLocalMachineKey()\n");
243 InitializeObjectAttributes (&Attributes
,
245 OBJ_CASE_INSENSITIVE
,
248 Status
= NtOpenKey (KeyHandle
,
252 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
258 OpenUsersKey (PHANDLE KeyHandle
)
260 OBJECT_ATTRIBUTES Attributes
;
261 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
263 TRACE("OpenUsersKey()\n");
265 InitializeObjectAttributes (&Attributes
,
267 OBJ_CASE_INSENSITIVE
,
270 return NtOpenKey (KeyHandle
,
277 OpenCurrentConfigKey (PHANDLE KeyHandle
)
279 OBJECT_ATTRIBUTES Attributes
;
280 UNICODE_STRING KeyName
=
281 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
283 TRACE("OpenCurrentConfigKey()\n");
285 InitializeObjectAttributes (&Attributes
,
287 OBJ_CASE_INSENSITIVE
,
290 return NtOpenKey (KeyHandle
,
296 /************************************************************************
297 * RegDisablePredefinedCacheEx
302 RegDisablePredefinedCacheEx(VOID
)
304 RtlEnterCriticalSection (&HandleTableCS
);
305 DefaultHandlesDisabled
= TRUE
;
306 RtlLeaveCriticalSection (&HandleTableCS
);
307 return ERROR_SUCCESS
;
311 /************************************************************************
312 * RegOverridePredefKey
317 RegOverridePredefKey(IN HKEY hKey
,
318 IN HKEY hNewHKey OPTIONAL
)
320 LONG ErrorCode
= ERROR_SUCCESS
;
322 if (hKey
== HKEY_CLASSES_ROOT
||
323 hKey
== HKEY_CURRENT_CONFIG
||
324 hKey
== HKEY_CURRENT_USER
||
325 hKey
== HKEY_LOCAL_MACHINE
||
326 hKey
== HKEY_PERFORMANCE_DATA
||
332 Index
= (ULONG
)hKey
& 0x0FFFFFFF;
333 Handle
= &DefaultHandleTable
[Index
];
335 if (hNewHKey
== NULL
)
337 /* restore the default mapping */
338 NTSTATUS Status
= OpenPredefinedKey(Index
,
340 if (!NT_SUCCESS(Status
))
342 return RtlNtStatusToDosError(Status
);
345 ASSERT(hNewHKey
!= NULL
);
348 RtlEnterCriticalSection (&HandleTableCS
);
350 /* close the currently mapped handle if existing */
356 /* update the mapping */
359 RtlLeaveCriticalSection (&HandleTableCS
);
362 ErrorCode
= ERROR_INVALID_HANDLE
;
368 /************************************************************************
374 RegCloseKey (HKEY hKey
)
378 /* don't close null handle or a pseudo handle */
379 if ((!hKey
) || (((ULONG
)hKey
& 0xF0000000) == 0x80000000))
381 return ERROR_INVALID_HANDLE
;
384 Status
= NtClose (hKey
);
385 if (!NT_SUCCESS(Status
))
387 return RtlNtStatusToDosError (Status
);
390 return ERROR_SUCCESS
;
395 RegpCopyTree(IN HKEY hKeySrc
,
400 LIST_ENTRY ListEntry
;
403 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
405 LIST_ENTRY copyQueueHead
;
406 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
409 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
410 KEY_NODE_INFORMATION
*KeyNode
;
413 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
414 NTSTATUS Status
= STATUS_SUCCESS
;
415 NTSTATUS Status2
= STATUS_SUCCESS
;
417 InitializeListHead(©QueueHead
);
419 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
422 if (Info
.Buffer
== NULL
)
424 return STATUS_INSUFFICIENT_RESOURCES
;
427 copyKeys
= RtlAllocateHeap(ProcessHeap
,
429 sizeof(REGP_COPY_KEYS
));
430 if (copyKeys
!= NULL
)
432 copyKeys
->hKeySrc
= hKeySrc
;
433 copyKeys
->hKeyDest
= hKeyDest
;
434 InsertHeadList(©QueueHead
,
435 ©Keys
->ListEntry
);
437 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
441 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
445 /* enumerate all values and copy them */
449 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
451 KeyValueFullInformation
,
454 &BufferSizeRequired
);
455 if (NT_SUCCESS(Status2
))
457 UNICODE_STRING ValueName
;
460 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
461 ValueName
.Length
= Info
.KeyValue
->NameLength
;
462 ValueName
.MaximumLength
= ValueName
.Length
;
463 ValueName
.Buffer
= Info
.KeyValue
->Name
;
465 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
467 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
469 Info
.KeyValue
->TitleIndex
,
472 Info
.KeyValue
->DataLength
);
474 /* don't break, let's try to copy as many values as possible */
475 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
482 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
486 ASSERT(BufferSize
< BufferSizeRequired
);
488 Buffer
= RtlReAllocateHeap(ProcessHeap
,
494 Info
.Buffer
= Buffer
;
499 /* don't break, let's try to copy as many values as possible */
500 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
503 if (NT_SUCCESS(Status
))
511 /* break to avoid an infinite loop in case of denied access or
513 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
522 /* enumerate all subkeys and open and enqueue them */
526 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
531 &BufferSizeRequired
);
532 if (NT_SUCCESS(Status2
))
534 HANDLE KeyHandle
, NewKeyHandle
;
535 OBJECT_ATTRIBUTES ObjectAttributes
;
536 UNICODE_STRING SubKeyName
, ClassName
;
538 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
539 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
540 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
541 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
542 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
543 ClassName
.MaximumLength
= ClassName
.Length
;
544 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
546 /* open the subkey with sufficient rights */
548 InitializeObjectAttributes(&ObjectAttributes
,
550 OBJ_CASE_INSENSITIVE
,
554 Status2
= NtOpenKey(&KeyHandle
,
555 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
557 if (NT_SUCCESS(Status2
))
559 /* FIXME - attempt to query the security information */
561 InitializeObjectAttributes(&ObjectAttributes
,
563 OBJ_CASE_INSENSITIVE
,
567 Status2
= NtCreateKey(&NewKeyHandle
,
570 Info
.KeyNode
->TitleIndex
,
574 if (NT_SUCCESS(Status2
))
576 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
578 sizeof(REGP_COPY_KEYS
));
579 if (newCopyKeys
!= NULL
)
581 /* save the handles and enqueue the subkey */
582 newCopyKeys
->hKeySrc
= KeyHandle
;
583 newCopyKeys
->hKeyDest
= NewKeyHandle
;
584 InsertTailList(©QueueHead
,
585 &newCopyKeys
->ListEntry
);
590 NtClose(NewKeyHandle
);
592 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
601 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
608 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
612 ASSERT(BufferSize
< BufferSizeRequired
);
614 Buffer
= RtlReAllocateHeap(ProcessHeap
,
620 Info
.Buffer
= Buffer
;
625 /* don't break, let's try to copy as many keys as possible */
626 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
629 if (NT_SUCCESS(Status
))
637 /* break to avoid an infinite loop in case of denied access or
639 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
648 /* close the handles and remove the entry from the list */
649 if (copyKeys
->hKeySrc
!= hKeySrc
)
651 NtClose(copyKeys
->hKeySrc
);
653 if (copyKeys
->hKeyDest
!= hKeyDest
)
655 NtClose(copyKeys
->hKeyDest
);
658 RemoveEntryList(©Keys
->ListEntry
);
660 RtlFreeHeap(ProcessHeap
,
663 } while (!IsListEmpty(©QueueHead
));
666 Status
= STATUS_INSUFFICIENT_RESOURCES
;
668 RtlFreeHeap(ProcessHeap
,
676 /************************************************************************
682 RegCopyTreeW(IN HKEY hKeySrc
,
683 IN LPCWSTR lpSubKey OPTIONAL
,
686 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
689 Status
= MapDefaultKey(&KeyHandle
,
691 if (!NT_SUCCESS(Status
))
693 return RtlNtStatusToDosError(Status
);
696 Status
= MapDefaultKey(&DestKeyHandle
,
698 if (!NT_SUCCESS(Status
))
703 if (lpSubKey
!= NULL
)
705 OBJECT_ATTRIBUTES ObjectAttributes
;
706 UNICODE_STRING SubKeyName
;
708 RtlInitUnicodeString(&SubKeyName
,
711 InitializeObjectAttributes(&ObjectAttributes
,
713 OBJ_CASE_INSENSITIVE
,
717 Status
= NtOpenKey(&SubKeyHandle
,
718 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
720 if (!NT_SUCCESS(Status
))
725 CurKey
= SubKeyHandle
;
730 Status
= RegpCopyTree(CurKey
,
733 if (SubKeyHandle
!= NULL
)
735 NtClose(SubKeyHandle
);
739 CloseDefaultKey(DestKeyHandle
);
741 CloseDefaultKey(KeyHandle
);
743 if (!NT_SUCCESS(Status
))
745 return RtlNtStatusToDosError(Status
);
748 return ERROR_SUCCESS
;
752 /************************************************************************
758 RegCopyTreeA(IN HKEY hKeySrc
,
759 IN LPCSTR lpSubKey OPTIONAL
,
762 UNICODE_STRING SubKeyName
= {0};
765 if (lpSubKey
!= NULL
&&
766 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
769 return ERROR_NOT_ENOUGH_MEMORY
;
772 Ret
= RegCopyTreeW(hKeySrc
,
776 RtlFreeUnicodeString(&SubKeyName
);
782 /************************************************************************
783 * RegConnectRegistryA
788 RegConnectRegistryA (IN LPCSTR lpMachineName
,
792 UNICODE_STRING MachineName
= {0};
795 if (lpMachineName
!= NULL
&&
796 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
797 (LPSTR
)lpMachineName
))
799 return ERROR_NOT_ENOUGH_MEMORY
;
802 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
806 RtlFreeUnicodeString(&MachineName
);
812 /************************************************************************
813 * RegConnectRegistryW
818 RegConnectRegistryW (LPCWSTR lpMachineName
,
822 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
823 return ERROR_CALL_NOT_IMPLEMENTED
;
827 /************************************************************************
830 * Create key and all necessary intermediate keys
833 CreateNestedKey(PHKEY KeyHandle
,
834 POBJECT_ATTRIBUTES ObjectAttributes
,
835 PUNICODE_STRING ClassString
,
838 DWORD
*lpdwDisposition
)
840 OBJECT_ATTRIBUTES LocalObjectAttributes
;
841 UNICODE_STRING LocalKeyName
;
844 ULONG FullNameLength
;
847 HANDLE LocalKeyHandle
;
849 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
855 (PULONG
)lpdwDisposition
);
856 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
857 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
860 /* Copy object attributes */
861 RtlCopyMemory (&LocalObjectAttributes
,
863 sizeof(OBJECT_ATTRIBUTES
));
864 RtlCreateUnicodeString (&LocalKeyName
,
865 ObjectAttributes
->ObjectName
->Buffer
);
866 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
867 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
869 /* Remove the last part of the key name and try to create the key again. */
870 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
872 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
873 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
875 Status
= STATUS_UNSUCCESSFUL
;
879 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
881 Status
= NtCreateKey (&LocalKeyHandle
,
883 &LocalObjectAttributes
,
888 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
891 if (!NT_SUCCESS(Status
))
893 RtlFreeUnicodeString (&LocalKeyName
);
897 /* Add removed parts of the key name and create them too. */
898 Length
= wcslen (LocalKeyName
.Buffer
);
901 NtClose (LocalKeyHandle
);
903 LocalKeyName
.Buffer
[Length
] = L
'\\';
904 Length
= wcslen (LocalKeyName
.Buffer
);
905 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
907 if (Length
== FullNameLength
)
909 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
915 (PULONG
)lpdwDisposition
);
918 Status
= NtCreateKey (&LocalKeyHandle
,
920 &LocalObjectAttributes
,
925 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
926 if (!NT_SUCCESS(Status
))
930 RtlFreeUnicodeString (&LocalKeyName
);
936 /************************************************************************
942 RegCreateKeyExA (HKEY hKey
,
948 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
950 LPDWORD lpdwDisposition
)
952 UNICODE_STRING SubKeyString
;
953 UNICODE_STRING ClassString
;
954 OBJECT_ATTRIBUTES Attributes
;
958 TRACE("RegCreateKeyExA() called\n");
960 /* get the real parent key */
961 Status
= MapDefaultKey (&ParentKey
,
963 if (!NT_SUCCESS(Status
))
965 return RtlNtStatusToDosError (Status
);
967 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
971 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
975 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
977 InitializeObjectAttributes (&Attributes
,
979 OBJ_CASE_INSENSITIVE
,
981 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
982 Status
= CreateNestedKey(phkResult
,
984 (lpClass
== NULL
)? NULL
: &ClassString
,
988 RtlFreeUnicodeString (&SubKeyString
);
991 RtlFreeUnicodeString (&ClassString
);
994 CloseDefaultKey(ParentKey
);
996 TRACE("Status %x\n", Status
);
997 if (!NT_SUCCESS(Status
))
999 return RtlNtStatusToDosError (Status
);
1002 return ERROR_SUCCESS
;
1006 /************************************************************************
1012 RegCreateKeyExW (HKEY hKey
,
1018 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1020 LPDWORD lpdwDisposition
)
1022 UNICODE_STRING SubKeyString
;
1023 UNICODE_STRING ClassString
;
1024 OBJECT_ATTRIBUTES Attributes
;
1028 TRACE("RegCreateKeyExW() called\n");
1030 /* get the real parent key */
1031 Status
= MapDefaultKey (&ParentKey
,
1033 if (!NT_SUCCESS(Status
))
1035 return RtlNtStatusToDosError(Status
);
1037 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
1039 RtlInitUnicodeString (&ClassString
,
1041 RtlInitUnicodeString (&SubKeyString
,
1043 InitializeObjectAttributes (&Attributes
,
1045 OBJ_CASE_INSENSITIVE
,
1047 (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
);
1048 Status
= CreateNestedKey(phkResult
,
1050 (lpClass
== NULL
)? NULL
: &ClassString
,
1055 CloseDefaultKey(ParentKey
);
1057 TRACE("Status %x\n", Status
);
1058 if (!NT_SUCCESS(Status
))
1060 return RtlNtStatusToDosError (Status
);
1063 return ERROR_SUCCESS
;
1067 /************************************************************************
1073 RegCreateKeyA (HKEY hKey
,
1077 return RegCreateKeyExA (hKey
,
1089 /************************************************************************
1095 RegCreateKeyW (HKEY hKey
,
1099 return RegCreateKeyExW (hKey
,
1111 /************************************************************************
1117 RegDeleteKeyA (HKEY hKey
,
1120 OBJECT_ATTRIBUTES ObjectAttributes
;
1121 UNICODE_STRING SubKeyName
;
1126 Status
= MapDefaultKey (&ParentKey
,
1128 if (!NT_SUCCESS(Status
))
1130 return RtlNtStatusToDosError (Status
);
1133 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
1135 InitializeObjectAttributes(&ObjectAttributes
,
1137 OBJ_CASE_INSENSITIVE
,
1141 Status
= NtOpenKey (&TargetKey
,
1144 RtlFreeUnicodeString (&SubKeyName
);
1145 if (!NT_SUCCESS(Status
))
1150 Status
= NtDeleteKey (TargetKey
);
1151 NtClose (TargetKey
);
1154 CloseDefaultKey(ParentKey
);
1156 if (!NT_SUCCESS(Status
))
1158 return RtlNtStatusToDosError(Status
);
1161 return ERROR_SUCCESS
;
1165 /************************************************************************
1171 RegDeleteKeyW (HKEY hKey
,
1174 OBJECT_ATTRIBUTES ObjectAttributes
;
1175 UNICODE_STRING SubKeyName
;
1180 Status
= MapDefaultKey (&ParentKey
,
1182 if (!NT_SUCCESS(Status
))
1184 return RtlNtStatusToDosError (Status
);
1187 RtlInitUnicodeString (&SubKeyName
,
1189 InitializeObjectAttributes (&ObjectAttributes
,
1191 OBJ_CASE_INSENSITIVE
,
1194 Status
= NtOpenKey (&TargetKey
,
1197 if (!NT_SUCCESS(Status
))
1202 Status
= NtDeleteKey (TargetKey
);
1203 NtClose (TargetKey
);
1206 CloseDefaultKey(ParentKey
);
1208 if (!NT_SUCCESS(Status
))
1210 return RtlNtStatusToDosError (Status
);
1213 return ERROR_SUCCESS
;
1217 /************************************************************************
1218 * RegDeleteKeyValueW
1223 RegDeleteKeyValueW(IN HKEY hKey
,
1224 IN LPCWSTR lpSubKey OPTIONAL
,
1225 IN LPCWSTR lpValueName OPTIONAL
)
1227 UNICODE_STRING ValueName
;
1228 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1231 Status
= MapDefaultKey(&KeyHandle
,
1233 if (!NT_SUCCESS(Status
))
1235 return RtlNtStatusToDosError(Status
);
1238 if (lpSubKey
!= NULL
)
1240 OBJECT_ATTRIBUTES ObjectAttributes
;
1241 UNICODE_STRING SubKeyName
;
1243 RtlInitUnicodeString(&SubKeyName
,
1246 InitializeObjectAttributes(&ObjectAttributes
,
1248 OBJ_CASE_INSENSITIVE
,
1252 Status
= NtOpenKey(&SubKeyHandle
,
1255 if (!NT_SUCCESS(Status
))
1260 CurKey
= SubKeyHandle
;
1265 RtlInitUnicodeString(&ValueName
,
1266 (LPWSTR
)lpValueName
);
1268 Status
= NtDeleteValueKey(CurKey
,
1271 if (SubKeyHandle
!= NULL
)
1273 NtClose(SubKeyHandle
);
1277 CloseDefaultKey(KeyHandle
);
1279 if (!NT_SUCCESS(Status
))
1281 return RtlNtStatusToDosError(Status
);
1284 return ERROR_SUCCESS
;
1288 /************************************************************************
1289 * RegDeleteKeyValueA
1294 RegDeleteKeyValueA(IN HKEY hKey
,
1295 IN LPCSTR lpSubKey OPTIONAL
,
1296 IN LPCSTR lpValueName OPTIONAL
)
1298 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1301 if (lpSubKey
!= NULL
&&
1302 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1305 return ERROR_NOT_ENOUGH_MEMORY
;
1308 if (lpValueName
!= NULL
&&
1309 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1310 (LPSTR
)lpValueName
))
1312 RtlFreeUnicodeString(&SubKey
);
1313 return ERROR_NOT_ENOUGH_MEMORY
;
1316 Ret
= RegDeleteKeyValueW(hKey
,
1320 RtlFreeUnicodeString(&SubKey
);
1321 RtlFreeUnicodeString(&ValueName
);
1328 RegpDeleteTree(IN HKEY hKey
)
1332 LIST_ENTRY ListEntry
;
1334 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1336 LIST_ENTRY delQueueHead
;
1337 PREG_DEL_KEYS delKeys
, newDelKeys
;
1340 PKEY_BASIC_INFORMATION BasicInfo
;
1341 PREG_DEL_KEYS KeyDelRoot
;
1342 NTSTATUS Status
= STATUS_SUCCESS
;
1343 NTSTATUS Status2
= STATUS_SUCCESS
;
1345 InitializeListHead(&delQueueHead
);
1347 ProcessHeap
= RtlGetProcessHeap();
1349 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1350 structure for the root key, we only do that for subkeys as we need to
1351 allocate REGP_DEL_KEYS structures anyway! */
1352 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1354 sizeof(REGP_DEL_KEYS
));
1355 if (KeyDelRoot
!= NULL
)
1357 KeyDelRoot
->KeyHandle
= hKey
;
1358 InsertTailList(&delQueueHead
,
1359 &KeyDelRoot
->ListEntry
);
1363 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1372 /* check if this key contains subkeys and delete them first by queuing
1373 them at the head of the list */
1374 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1376 KeyBasicInformation
,
1381 if (NT_SUCCESS(Status2
))
1383 OBJECT_ATTRIBUTES ObjectAttributes
;
1384 UNICODE_STRING SubKeyName
;
1386 ASSERT(newDelKeys
!= NULL
);
1387 ASSERT(BasicInfo
!= NULL
);
1389 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1390 SubKeyName
.Length
= BasicInfo
->NameLength
;
1391 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1392 SubKeyName
.Buffer
= BasicInfo
->Name
;
1394 InitializeObjectAttributes(&ObjectAttributes
,
1396 OBJ_CASE_INSENSITIVE
,
1400 /* open the subkey */
1401 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1402 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1404 if (!NT_SUCCESS(Status2
))
1409 /* enqueue this key to the head of the deletion queue */
1410 InsertHeadList(&delQueueHead
,
1411 &newDelKeys
->ListEntry
);
1413 /* try again from the head of the list */
1418 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1420 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1422 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1423 if (newDelKeys
!= NULL
)
1425 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1428 goto ReadFirstSubKey
;
1432 /* don't break, let's try to delete as many keys as possible */
1433 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1434 goto SubKeyFailureNoFree
;
1437 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1439 PREG_DEL_KEYS newDelKeys2
;
1441 ASSERT(newDelKeys
!= NULL
);
1443 /* we need more memory to query the key name */
1444 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1447 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1448 if (newDelKeys2
!= NULL
)
1450 newDelKeys
= newDelKeys2
;
1451 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1454 goto ReadFirstSubKey
;
1458 /* don't break, let's try to delete as many keys as possible */
1459 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1464 ASSERT(newDelKeys
!= NULL
);
1465 RtlFreeHeap(ProcessHeap
,
1469 SubKeyFailureNoFree
:
1470 /* don't break, let's try to delete as many keys as possible */
1471 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
1477 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1479 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1481 if (!NT_SUCCESS(Status2
))
1483 /* close the key handle so we don't leak handles for keys we were
1484 unable to delete. But only do this for handles not supplied
1487 if (delKeys
->KeyHandle
!= hKey
)
1489 NtClose(delKeys
->KeyHandle
);
1492 if (NT_SUCCESS(Status
))
1494 /* don't break, let's try to delete as many keys as possible */
1499 /* remove the entry from the list */
1500 RemoveEntryList(&delKeys
->ListEntry
);
1502 RtlFreeHeap(ProcessHeap
,
1505 } while (!IsListEmpty(&delQueueHead
));
1508 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1514 /************************************************************************
1520 RegDeleteTreeW(IN HKEY hKey
,
1521 IN LPCWSTR lpSubKey OPTIONAL
)
1523 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1526 Status
= MapDefaultKey(&KeyHandle
,
1528 if (!NT_SUCCESS(Status
))
1530 return RtlNtStatusToDosError(Status
);
1533 if (lpSubKey
!= NULL
)
1535 OBJECT_ATTRIBUTES ObjectAttributes
;
1536 UNICODE_STRING SubKeyName
;
1538 RtlInitUnicodeString(&SubKeyName
,
1541 InitializeObjectAttributes(&ObjectAttributes
,
1543 OBJ_CASE_INSENSITIVE
,
1547 Status
= NtOpenKey(&SubKeyHandle
,
1548 DELETE
| KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
1550 if (!NT_SUCCESS(Status
))
1555 CurKey
= SubKeyHandle
;
1560 Status
= RegpDeleteTree(CurKey
);
1562 if (NT_SUCCESS(Status
))
1564 /* make sure we only close hKey (KeyHandle) when the caller specified a
1565 subkey, because the handle would be invalid already! */
1566 if (CurKey
!= KeyHandle
)
1568 CloseDefaultKey(KeyHandle
);
1571 return ERROR_SUCCESS
;
1575 /* make sure we close all handles we created! */
1576 if (SubKeyHandle
!= NULL
)
1578 NtClose(SubKeyHandle
);
1582 CloseDefaultKey(KeyHandle
);
1584 return RtlNtStatusToDosError(Status
);
1589 /************************************************************************
1595 RegDeleteTreeA(IN HKEY hKey
,
1596 IN LPCSTR lpSubKey OPTIONAL
)
1598 UNICODE_STRING SubKeyName
= {0};
1601 if (lpSubKey
!= NULL
&&
1602 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1605 return ERROR_NOT_ENOUGH_MEMORY
;
1608 Ret
= RegDeleteTreeW(hKey
,
1611 RtlFreeUnicodeString(&SubKeyName
);
1617 /************************************************************************
1623 RegSetKeyValueW(IN HKEY hKey
,
1624 IN LPCWSTR lpSubKey OPTIONAL
,
1625 IN LPCWSTR lpValueName OPTIONAL
,
1627 IN LPCVOID lpData OPTIONAL
,
1630 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1634 Status
= MapDefaultKey(&KeyHandle
,
1636 if (!NT_SUCCESS(Status
))
1638 return RtlNtStatusToDosError(Status
);
1641 if (lpSubKey
!= NULL
)
1643 OBJECT_ATTRIBUTES ObjectAttributes
;
1644 UNICODE_STRING SubKeyName
;
1646 RtlInitUnicodeString(&SubKeyName
,
1649 InitializeObjectAttributes(&ObjectAttributes
,
1651 OBJ_CASE_INSENSITIVE
,
1655 Status
= NtOpenKey(&SubKeyHandle
,
1658 if (!NT_SUCCESS(Status
))
1660 Ret
= RtlNtStatusToDosError(Status
);
1664 CurKey
= SubKeyHandle
;
1669 Ret
= RegSetValueExW(CurKey
,
1676 if (SubKeyHandle
!= NULL
)
1678 NtClose(SubKeyHandle
);
1682 CloseDefaultKey(KeyHandle
);
1688 /************************************************************************
1694 RegSetKeyValueA(IN HKEY hKey
,
1695 IN LPCSTR lpSubKey OPTIONAL
,
1696 IN LPCSTR lpValueName OPTIONAL
,
1698 IN LPCVOID lpData OPTIONAL
,
1701 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1705 Status
= MapDefaultKey(&KeyHandle
,
1707 if (!NT_SUCCESS(Status
))
1709 return RtlNtStatusToDosError(Status
);
1712 if (lpSubKey
!= NULL
)
1714 OBJECT_ATTRIBUTES ObjectAttributes
;
1715 UNICODE_STRING SubKeyName
;
1717 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1720 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
1724 InitializeObjectAttributes(&ObjectAttributes
,
1726 OBJ_CASE_INSENSITIVE
,
1730 Status
= NtOpenKey(&SubKeyHandle
,
1734 RtlFreeUnicodeString(&SubKeyName
);
1736 if (!NT_SUCCESS(Status
))
1738 Ret
= RtlNtStatusToDosError(Status
);
1742 CurKey
= SubKeyHandle
;
1747 Ret
= RegSetValueExA(CurKey
,
1754 if (SubKeyHandle
!= NULL
)
1756 NtClose(SubKeyHandle
);
1760 CloseDefaultKey(KeyHandle
);
1766 /************************************************************************
1772 RegDeleteValueA (HKEY hKey
,
1775 UNICODE_STRING ValueName
;
1779 Status
= MapDefaultKey (&KeyHandle
,
1781 if (!NT_SUCCESS(Status
))
1783 return RtlNtStatusToDosError (Status
);
1786 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
1787 (LPSTR
)lpValueName
);
1788 Status
= NtDeleteValueKey (KeyHandle
,
1790 RtlFreeUnicodeString (&ValueName
);
1792 CloseDefaultKey(KeyHandle
);
1794 if (!NT_SUCCESS(Status
))
1796 return RtlNtStatusToDosError (Status
);
1799 return ERROR_SUCCESS
;
1803 /************************************************************************
1809 RegDeleteValueW (HKEY hKey
,
1810 LPCWSTR lpValueName
)
1812 UNICODE_STRING ValueName
;
1816 Status
= MapDefaultKey (&KeyHandle
,
1818 if (!NT_SUCCESS(Status
))
1820 return RtlNtStatusToDosError (Status
);
1823 RtlInitUnicodeString (&ValueName
,
1824 (LPWSTR
)lpValueName
);
1826 Status
= NtDeleteValueKey (KeyHandle
,
1829 CloseDefaultKey(KeyHandle
);
1831 if (!NT_SUCCESS(Status
))
1833 return RtlNtStatusToDosError (Status
);
1836 return ERROR_SUCCESS
;
1840 /************************************************************************
1846 RegEnumKeyA (HKEY hKey
,
1854 return RegEnumKeyExA (hKey
,
1865 /************************************************************************
1871 RegEnumKeyW (HKEY hKey
,
1879 return RegEnumKeyExW (hKey
,
1890 /************************************************************************
1896 RegEnumKeyExA (HKEY hKey
,
1903 PFILETIME lpftLastWriteTime
)
1907 KEY_NODE_INFORMATION Node
;
1908 KEY_BASIC_INFORMATION Basic
;
1911 UNICODE_STRING StringU
;
1912 ANSI_STRING StringA
;
1913 LONG ErrorCode
= ERROR_SUCCESS
;
1915 DWORD ClassLength
= 0;
1921 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
1922 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
1924 if ((lpClass
) && (!lpcbClass
))
1926 return ERROR_INVALID_PARAMETER
;
1929 Status
= MapDefaultKey(&KeyHandle
, hKey
);
1930 if (!NT_SUCCESS(Status
))
1932 return RtlNtStatusToDosError (Status
);
1937 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
1948 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
1955 /* The class name should start at a dword boundary */
1956 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
1960 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
1963 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
1964 if (KeyInfo
== NULL
)
1966 ErrorCode
= ERROR_OUTOFMEMORY
;
1970 Status
= NtEnumerateKey (KeyHandle
,
1972 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
1976 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
1977 if (!NT_SUCCESS(Status
))
1979 ErrorCode
= RtlNtStatusToDosError (Status
);
1983 if (lpClass
== NULL
)
1985 if (KeyInfo
->Basic
.NameLength
> NameLength
)
1987 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
1991 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
1992 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
1993 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
1998 if (KeyInfo
->Node
.NameLength
> NameLength
||
1999 KeyInfo
->Node
.ClassLength
> ClassLength
)
2001 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2005 StringA
.Buffer
= lpClass
;
2007 StringA
.MaximumLength
= *lpcbClass
;
2008 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2009 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2010 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2011 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2012 lpClass
[StringA
.Length
] = 0;
2013 *lpcbClass
= StringA
.Length
;
2014 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2015 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2016 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2020 if (ErrorCode
== ERROR_SUCCESS
)
2022 StringA
.Buffer
= lpName
;
2024 StringA
.MaximumLength
= *lpcbName
;
2025 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2026 lpName
[StringA
.Length
] = 0;
2027 *lpcbName
= StringA
.Length
;
2028 if (lpftLastWriteTime
!= NULL
)
2030 if (lpClass
== NULL
)
2032 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2033 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2037 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2038 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2044 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
2045 TRACE("Key Namea1 Length %d\n", NameLength
);
2046 TRACE("Key Namea Length %d\n", *lpcbName
);
2047 TRACE("Key Namea %s\n", lpName
);
2049 RtlFreeHeap (ProcessHeap
,
2054 CloseDefaultKey(KeyHandle
);
2060 /************************************************************************
2066 RegEnumKeyExW (HKEY hKey
,
2073 PFILETIME lpftLastWriteTime
)
2077 KEY_NODE_INFORMATION Node
;
2078 KEY_BASIC_INFORMATION Basic
;
2084 ULONG ClassLength
= 0;
2086 LONG ErrorCode
= ERROR_SUCCESS
;
2089 Status
= MapDefaultKey(&KeyHandle
,
2091 if (!NT_SUCCESS(Status
))
2093 return RtlNtStatusToDosError (Status
);
2098 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2109 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2116 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2120 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2123 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
2126 if (KeyInfo
== NULL
)
2128 ErrorCode
= ERROR_OUTOFMEMORY
;
2132 Status
= NtEnumerateKey (KeyHandle
,
2134 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2138 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2139 if (!NT_SUCCESS(Status
))
2141 ErrorCode
= RtlNtStatusToDosError (Status
);
2145 if (lpClass
== NULL
)
2147 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2149 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2153 RtlCopyMemory (lpName
,
2154 KeyInfo
->Basic
.Name
,
2155 KeyInfo
->Basic
.NameLength
);
2156 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2157 lpName
[*lpcbName
] = 0;
2162 if (KeyInfo
->Node
.NameLength
> NameLength
||
2163 KeyInfo
->Node
.ClassLength
> ClassLength
)
2165 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2169 RtlCopyMemory (lpName
,
2171 KeyInfo
->Node
.NameLength
);
2172 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2173 lpName
[*lpcbName
] = 0;
2174 RtlCopyMemory (lpClass
,
2175 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2176 KeyInfo
->Node
.ClassLength
);
2177 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2178 lpClass
[*lpcbClass
] = 0;
2182 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2184 if (lpClass
== NULL
)
2186 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2187 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2191 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2192 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2197 RtlFreeHeap (ProcessHeap
,
2202 CloseDefaultKey(KeyHandle
);
2207 /************************************************************************
2213 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2214 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2219 char buffer
[256], *buf_ptr
= buffer
;
2220 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2221 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2223 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2224 // hkey, index, value, val_count, reserved, type, data, count );
2226 /* NT only checks count, not val_count */
2227 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2228 status
= MapDefaultKey (&KeyHandle
, hKey
);
2229 if (!NT_SUCCESS(status
))
2231 return RtlNtStatusToDosError (status
);
2234 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2235 if (data
) total_size
+= *count
;
2236 total_size
= min( sizeof(buffer
), total_size
);
2238 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2239 buffer
, total_size
, &total_size
);
2240 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2242 /* we need to fetch the contents for a string type even if not requested,
2243 * because we need to compute the length of the ASCII string. */
2244 if (value
|| data
|| is_string(info
->Type
))
2246 /* retry with a dynamically allocated buffer */
2247 while (status
== STATUS_BUFFER_OVERFLOW
)
2249 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2250 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2252 status
= STATUS_INSUFFICIENT_RESOURCES
;
2255 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2256 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2257 buf_ptr
, total_size
, &total_size
);
2260 if (status
) goto done
;
2262 if (is_string(info
->Type
))
2265 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2266 total_size
- info
->DataOffset
);
2269 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2272 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2273 total_size
- info
->DataOffset
);
2274 /* if the type is REG_SZ and data is not 0-terminated
2275 * and there is enough space in the buffer NT appends a \0 */
2276 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2279 info
->DataLength
= len
;
2283 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2284 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2287 if (value
&& !status
)
2291 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2292 if (len
>= *val_count
)
2294 status
= STATUS_BUFFER_OVERFLOW
;
2297 len
= *val_count
- 1;
2298 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2304 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2310 else status
= STATUS_SUCCESS
;
2312 if (type
) *type
= info
->Type
;
2313 if (count
) *count
= info
->DataLength
;
2316 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2317 CloseDefaultKey(KeyHandle
);
2318 return RtlNtStatusToDosError(status
);
2321 /******************************************************************************
2322 * RegEnumValueW [ADVAPI32.@]
2326 * hkey [I] Handle to key to query
2327 * index [I] Index of value to query
2328 * value [O] Value string
2329 * val_count [I/O] Size of value buffer (in wchars)
2330 * reserved [I] Reserved
2331 * type [O] Type code
2332 * data [O] Value data
2333 * count [I/O] Size of data buffer (in bytes)
2336 * Success: ERROR_SUCCESS
2337 * Failure: nonzero error code from Winerror.h
2340 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2341 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2346 char buffer
[256], *buf_ptr
= buffer
;
2347 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2348 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2350 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2351 // hkey, index, value, val_count, reserved, type, data, count );
2353 /* NT only checks count, not val_count */
2354 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2356 status
= MapDefaultKey (&KeyHandle
, hKey
);
2357 if (!NT_SUCCESS(status
))
2359 return RtlNtStatusToDosError (status
);
2362 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2363 if (data
) total_size
+= *count
;
2364 total_size
= min( sizeof(buffer
), total_size
);
2366 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2367 buffer
, total_size
, &total_size
);
2368 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2372 /* retry with a dynamically allocated buffer */
2373 while (status
== STATUS_BUFFER_OVERFLOW
)
2375 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2376 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2378 status
= ERROR_NOT_ENOUGH_MEMORY
;
2381 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2382 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2383 buf_ptr
, total_size
, &total_size
);
2386 if (status
) goto done
;
2390 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2392 status
= STATUS_BUFFER_OVERFLOW
;
2395 memcpy( value
, info
->Name
, info
->NameLength
);
2396 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2397 value
[*val_count
] = 0;
2402 if (total_size
- info
->DataOffset
> *count
)
2404 status
= STATUS_BUFFER_OVERFLOW
;
2407 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2408 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2410 /* if the type is REG_SZ and data is not 0-terminated
2411 * and there is enough space in the buffer NT appends a \0 */
2412 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2413 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2417 else status
= STATUS_SUCCESS
;
2420 if (type
) *type
= info
->Type
;
2421 if (count
) *count
= info
->DataLength
;
2424 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2425 CloseDefaultKey(KeyHandle
);
2426 return RtlNtStatusToDosError(status
);
2429 /************************************************************************
2435 RegFlushKey(HKEY hKey
)
2440 if (hKey
== HKEY_PERFORMANCE_DATA
)
2442 return ERROR_SUCCESS
;
2445 Status
= MapDefaultKey (&KeyHandle
,
2447 if (!NT_SUCCESS(Status
))
2449 return RtlNtStatusToDosError (Status
);
2452 Status
= NtFlushKey (KeyHandle
);
2454 CloseDefaultKey(KeyHandle
);
2456 if (!NT_SUCCESS(Status
))
2458 return RtlNtStatusToDosError (Status
);
2461 return ERROR_SUCCESS
;
2465 /************************************************************************
2471 RegGetKeySecurity(HKEY hKey
,
2472 SECURITY_INFORMATION SecurityInformation
,
2473 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2474 LPDWORD lpcbSecurityDescriptor
)
2479 if (hKey
== HKEY_PERFORMANCE_DATA
)
2481 return ERROR_INVALID_HANDLE
;
2484 Status
= MapDefaultKey(&KeyHandle
,
2486 if (!NT_SUCCESS(Status
))
2488 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2489 return RtlNtStatusToDosError (Status
);
2492 Status
= NtQuerySecurityObject(KeyHandle
,
2493 SecurityInformation
,
2494 pSecurityDescriptor
,
2495 *lpcbSecurityDescriptor
,
2496 lpcbSecurityDescriptor
);
2498 CloseDefaultKey(KeyHandle
);
2500 if (!NT_SUCCESS(Status
))
2502 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
2503 return RtlNtStatusToDosError (Status
);
2506 return ERROR_SUCCESS
;
2510 /************************************************************************
2516 RegLoadKeyA (HKEY hKey
,
2520 UNICODE_STRING FileName
;
2521 UNICODE_STRING KeyName
;
2524 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
2526 RtlCreateUnicodeStringFromAsciiz (&FileName
,
2529 ErrorCode
= RegLoadKeyW (hKey
,
2533 RtlFreeUnicodeString (&FileName
);
2534 RtlFreeUnicodeString (&KeyName
);
2540 /************************************************************************
2546 RegLoadKeyW (HKEY hKey
,
2550 OBJECT_ATTRIBUTES FileObjectAttributes
;
2551 OBJECT_ATTRIBUTES KeyObjectAttributes
;
2552 UNICODE_STRING FileName
;
2553 UNICODE_STRING KeyName
;
2556 LONG ErrorCode
= ERROR_SUCCESS
;
2558 if (hKey
== HKEY_PERFORMANCE_DATA
)
2560 return ERROR_INVALID_HANDLE
;
2563 Status
= MapDefaultKey (&KeyHandle
,
2565 if (!NT_SUCCESS(Status
))
2567 return RtlNtStatusToDosError (Status
);
2570 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpFile
,
2575 ErrorCode
= ERROR_BAD_PATHNAME
;
2579 InitializeObjectAttributes (&FileObjectAttributes
,
2581 OBJ_CASE_INSENSITIVE
,
2585 RtlInitUnicodeString (&KeyName
,
2588 InitializeObjectAttributes (&KeyObjectAttributes
,
2590 OBJ_CASE_INSENSITIVE
,
2594 Status
= NtLoadKey (&KeyObjectAttributes
,
2595 &FileObjectAttributes
);
2597 RtlFreeUnicodeString (&FileName
);
2599 if (!NT_SUCCESS(Status
))
2601 ErrorCode
= RtlNtStatusToDosError (Status
);
2606 CloseDefaultKey(KeyHandle
);
2612 /************************************************************************
2613 * RegNotifyChangeKeyValue
2618 RegNotifyChangeKeyValue (HKEY hKey
,
2620 DWORD dwNotifyFilter
,
2624 IO_STATUS_BLOCK IoStatusBlock
;
2627 LONG ErrorCode
= ERROR_SUCCESS
;
2629 if (hKey
== HKEY_PERFORMANCE_DATA
)
2631 return ERROR_INVALID_HANDLE
;
2634 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
2636 return ERROR_INVALID_PARAMETER
;
2639 Status
= MapDefaultKey (&KeyHandle
,
2641 if (!NT_SUCCESS(Status
))
2643 return RtlNtStatusToDosError (Status
);
2646 /* FIXME: Remote key handles must fail */
2648 Status
= NtNotifyChangeKey (KeyHandle
,
2658 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
2660 ErrorCode
= RtlNtStatusToDosError (Status
);
2663 CloseDefaultKey(KeyHandle
);
2669 /************************************************************************
2670 * RegOpenCurrentUser
2675 RegOpenCurrentUser (IN REGSAM samDesired
,
2676 OUT PHKEY phkResult
)
2680 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
2681 (PHANDLE
)phkResult
);
2682 if (!NT_SUCCESS(Status
))
2684 /* NOTE - don't set the last error code! just return the error! */
2685 return RtlNtStatusToDosError(Status
);
2688 return ERROR_SUCCESS
;
2692 /************************************************************************
2695 * 20050503 Fireball - imported from WINE
2700 RegOpenKeyA (HKEY hKey
,
2704 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2706 if (!lpSubKey
|| !*lpSubKey
)
2709 return ERROR_SUCCESS
;
2712 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2716 /************************************************************************
2721 * 20050503 Fireball - imported from WINE
2726 RegOpenKeyW (HKEY hKey
,
2730 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
2732 if (!lpSubKey
|| !*lpSubKey
)
2735 return ERROR_SUCCESS
;
2737 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
2741 /************************************************************************
2747 RegOpenKeyExA (HKEY hKey
,
2753 OBJECT_ATTRIBUTES ObjectAttributes
;
2754 UNICODE_STRING SubKeyString
;
2757 LONG ErrorCode
= ERROR_SUCCESS
;
2759 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2760 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2762 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2763 if (!NT_SUCCESS(Status
))
2765 return RtlNtStatusToDosError (Status
);
2768 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
2769 InitializeObjectAttributes (&ObjectAttributes
,
2771 OBJ_CASE_INSENSITIVE
,
2775 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2776 RtlFreeUnicodeString (&SubKeyString
);
2777 if (!NT_SUCCESS(Status
))
2779 ErrorCode
= RtlNtStatusToDosError (Status
);
2782 CloseDefaultKey(KeyHandle
);
2788 /************************************************************************
2794 RegOpenKeyExW (HKEY hKey
,
2800 OBJECT_ATTRIBUTES ObjectAttributes
;
2801 UNICODE_STRING SubKeyString
;
2804 LONG ErrorCode
= ERROR_SUCCESS
;
2806 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
2807 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
2809 Status
= MapDefaultKey (&KeyHandle
, hKey
);
2810 if (!NT_SUCCESS(Status
))
2812 return RtlNtStatusToDosError (Status
);
2815 if (lpSubKey
!= NULL
)
2816 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
2818 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
2820 InitializeObjectAttributes (&ObjectAttributes
,
2822 OBJ_CASE_INSENSITIVE
,
2826 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
2828 if (!NT_SUCCESS(Status
))
2830 ErrorCode
= RtlNtStatusToDosError (Status
);
2833 CloseDefaultKey(KeyHandle
);
2839 /************************************************************************
2840 * RegOpenUserClassesRoot
2845 RegOpenUserClassesRoot (IN HANDLE hToken
,
2847 IN REGSAM samDesired
,
2848 OUT PHKEY phkResult
)
2850 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
2851 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
2852 PTOKEN_USER TokenUserData
;
2853 ULONG RequiredLength
;
2854 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
2855 OBJECT_ATTRIBUTES ObjectAttributes
;
2858 /* check parameters */
2859 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
2861 return ERROR_INVALID_PARAMETER
;
2865 * Get the user sid from the token
2869 /* determine how much memory we need */
2870 Status
= NtQueryInformationToken(hToken
,
2875 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
2877 /* NOTE - as opposed to all other registry functions windows does indeed
2878 change the last error code in case the caller supplied a invalid
2879 handle for example! */
2880 return RtlNtStatusToDosError (Status
);
2883 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
2886 if (TokenUserData
== NULL
)
2888 return ERROR_NOT_ENOUGH_MEMORY
;
2891 /* attempt to read the information */
2892 Status
= NtQueryInformationToken(hToken
,
2897 if (!NT_SUCCESS(Status
))
2899 RtlFreeHeap(ProcessHeap
,
2902 if (Status
== STATUS_BUFFER_TOO_SMALL
)
2904 /* the information appears to have changed?! try again */
2908 /* NOTE - as opposed to all other registry functions windows does indeed
2909 change the last error code in case the caller supplied a invalid
2910 handle for example! */
2911 return RtlNtStatusToDosError (Status
);
2915 * Build the absolute path for the user's registry in the form
2916 * "\Registry\User\<SID>_Classes"
2918 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
2919 TokenUserData
->User
.Sid
,
2922 /* we don't need the user data anymore, free it */
2923 RtlFreeHeap(ProcessHeap
,
2927 if (!NT_SUCCESS(Status
))
2929 return RtlNtStatusToDosError (Status
);
2932 /* allocate enough memory for the entire key string */
2933 UserClassesKeyRoot
.Length
= 0;
2934 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
2935 sizeof(UserClassesKeyPrefix
) +
2936 sizeof(UserClassesKeySuffix
);
2937 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
2939 UserClassesKeyRoot
.MaximumLength
);
2940 if (UserClassesKeyRoot
.Buffer
== NULL
)
2942 RtlFreeUnicodeString(&UserSidString
);
2943 return RtlNtStatusToDosError (Status
);
2946 /* build the string */
2947 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2948 UserClassesKeyPrefix
);
2949 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
2951 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
2952 UserClassesKeySuffix
);
2954 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
2960 InitializeObjectAttributes (&ObjectAttributes
,
2961 &UserClassesKeyRoot
,
2962 OBJ_CASE_INSENSITIVE
,
2966 Status
= NtOpenKey((PHANDLE
)phkResult
,
2970 RtlFreeUnicodeString(&UserSidString
);
2971 RtlFreeUnicodeString(&UserClassesKeyRoot
);
2973 if (!NT_SUCCESS(Status
))
2975 return RtlNtStatusToDosError (Status
);
2978 return ERROR_SUCCESS
;
2982 /************************************************************************
2988 RegQueryInfoKeyA (HKEY hKey
,
2993 LPDWORD lpcbMaxSubKeyLen
,
2994 LPDWORD lpcbMaxClassLen
,
2996 LPDWORD lpcbMaxValueNameLen
,
2997 LPDWORD lpcbMaxValueLen
,
2998 LPDWORD lpcbSecurityDescriptor
,
2999 PFILETIME lpftLastWriteTime
)
3001 WCHAR ClassName
[MAX_PATH
];
3002 UNICODE_STRING UnicodeString
;
3003 ANSI_STRING AnsiString
;
3006 RtlInitUnicodeString (&UnicodeString
,
3008 if (lpClass
!= NULL
)
3010 UnicodeString
.Buffer
= &ClassName
[0];
3011 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3012 AnsiString
.MaximumLength
= *lpcbClass
;
3015 ErrorCode
= RegQueryInfoKeyW (hKey
,
3016 UnicodeString
.Buffer
,
3023 lpcbMaxValueNameLen
,
3025 lpcbSecurityDescriptor
,
3027 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3029 AnsiString
.Buffer
= lpClass
;
3030 AnsiString
.Length
= 0;
3031 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3032 RtlUnicodeStringToAnsiString (&AnsiString
,
3035 *lpcbClass
= AnsiString
.Length
;
3036 lpClass
[AnsiString
.Length
] = 0;
3043 /************************************************************************
3049 RegQueryInfoKeyW (HKEY hKey
,
3054 LPDWORD lpcbMaxSubKeyLen
,
3055 LPDWORD lpcbMaxClassLen
,
3057 LPDWORD lpcbMaxValueNameLen
,
3058 LPDWORD lpcbMaxValueLen
,
3059 LPDWORD lpcbSecurityDescriptor
,
3060 PFILETIME lpftLastWriteTime
)
3062 KEY_FULL_INFORMATION FullInfoBuffer
;
3063 PKEY_FULL_INFORMATION FullInfo
;
3065 ULONG ClassLength
= 0;
3069 LONG ErrorCode
= ERROR_SUCCESS
;
3071 if ((lpClass
) && (!lpcbClass
))
3073 return ERROR_INVALID_PARAMETER
;
3076 Status
= MapDefaultKey (&KeyHandle
,
3078 if (!NT_SUCCESS(Status
))
3080 return RtlNtStatusToDosError (Status
);
3083 if (lpClass
!= NULL
)
3087 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3094 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3095 FullInfo
= RtlAllocateHeap (ProcessHeap
,
3098 if (FullInfo
== NULL
)
3100 ErrorCode
= ERROR_OUTOFMEMORY
;
3104 FullInfo
->ClassLength
= ClassLength
;
3108 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3109 FullInfo
= &FullInfoBuffer
;
3110 FullInfo
->ClassLength
= 0;
3112 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3114 Status
= NtQueryKey (KeyHandle
,
3119 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3120 if (!NT_SUCCESS(Status
))
3122 if (lpClass
!= NULL
)
3124 RtlFreeHeap (ProcessHeap
,
3129 ErrorCode
= RtlNtStatusToDosError (Status
);
3133 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3134 if (lpcSubKeys
!= NULL
)
3136 *lpcSubKeys
= FullInfo
->SubKeys
;
3139 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3140 if (lpcbMaxSubKeyLen
!= NULL
)
3142 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3145 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3146 if (lpcbMaxClassLen
!= NULL
)
3148 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3151 TRACE("Values %lu\n", FullInfo
->Values
);
3152 if (lpcValues
!= NULL
)
3154 *lpcValues
= FullInfo
->Values
;
3157 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3158 if (lpcbMaxValueNameLen
!= NULL
)
3160 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3163 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3164 if (lpcbMaxValueLen
!= NULL
)
3166 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3169 if (lpcbSecurityDescriptor
!= NULL
)
3171 Status
= NtQuerySecurityObject(KeyHandle
,
3172 OWNER_SECURITY_INFORMATION
|
3173 GROUP_SECURITY_INFORMATION
|
3174 DACL_SECURITY_INFORMATION
,
3177 lpcbSecurityDescriptor
);
3178 if (!NT_SUCCESS(Status
))
3180 if (lpClass
!= NULL
)
3182 RtlFreeHeap(ProcessHeap
,
3187 ErrorCode
= RtlNtStatusToDosError (Status
);
3192 if (lpftLastWriteTime
!= NULL
)
3194 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3195 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3198 if (lpClass
!= NULL
)
3200 if (FullInfo
->ClassLength
> ClassLength
)
3202 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3206 RtlCopyMemory (lpClass
,
3208 FullInfo
->ClassLength
);
3209 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3210 lpClass
[*lpcbClass
] = 0;
3213 RtlFreeHeap (ProcessHeap
,
3219 CloseDefaultKey(KeyHandle
);
3225 /************************************************************************
3226 * RegQueryMultipleValuesA
3231 RegQueryMultipleValuesA (HKEY hKey
,
3238 DWORD maxBytes
= *ldwTotsize
;
3239 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3242 if (maxBytes
>= (1024*1024))
3243 return ERROR_TRANSFER_TOO_LONG
;
3247 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3248 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3250 for (i
= 0; i
< num_vals
; i
++)
3252 val_list
[i
].ve_valuelen
= 0;
3253 ErrorCode
= RegQueryValueExA (hKey
,
3254 val_list
[i
].ve_valuename
,
3258 &val_list
[i
].ve_valuelen
);
3259 if (ErrorCode
!= ERROR_SUCCESS
)
3264 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3266 ErrorCode
= RegQueryValueExA (hKey
,
3267 val_list
[i
].ve_valuename
,
3269 &val_list
[i
].ve_type
,
3271 &val_list
[i
].ve_valuelen
);
3272 if (ErrorCode
!= ERROR_SUCCESS
)
3277 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3279 bufptr
+= val_list
[i
].ve_valuelen
;
3282 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3285 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3289 /************************************************************************
3290 * RegQueryMultipleValuesW
3295 RegQueryMultipleValuesW (HKEY hKey
,
3302 DWORD maxBytes
= *ldwTotsize
;
3303 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3306 if (maxBytes
>= (1024*1024))
3307 return ERROR_TRANSFER_TOO_LONG
;
3311 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3312 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3314 for (i
= 0; i
< num_vals
; i
++)
3316 val_list
[i
].ve_valuelen
= 0;
3317 ErrorCode
= RegQueryValueExW (hKey
,
3318 val_list
[i
].ve_valuename
,
3322 &val_list
[i
].ve_valuelen
);
3323 if (ErrorCode
!= ERROR_SUCCESS
)
3328 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3330 ErrorCode
= RegQueryValueExW (hKey
,
3331 val_list
[i
].ve_valuename
,
3333 &val_list
[i
].ve_type
,
3335 &val_list
[i
].ve_valuelen
);
3336 if (ErrorCode
!= ERROR_SUCCESS
)
3341 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3343 bufptr
+= val_list
[i
].ve_valuelen
;
3346 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3349 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3353 /************************************************************************
3359 RegQueryValueExW (HKEY hKey
,
3360 LPCWSTR lpValueName
,
3366 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
3367 UNICODE_STRING ValueName
;
3372 LONG ErrorCode
= ERROR_SUCCESS
;
3373 ULONG MaxCopy
= lpcbData
!= NULL
&& lpData
!= NULL
? *lpcbData
: 0;
3375 TRACE("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
3376 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3378 Status
= MapDefaultKey (&KeyHandle
,
3380 if (!NT_SUCCESS(Status
))
3382 return RtlNtStatusToDosError (Status
);
3385 if (lpData
!= NULL
&& lpcbData
== NULL
)
3387 ErrorCode
= ERROR_INVALID_PARAMETER
;
3391 RtlInitUnicodeString (&ValueName
,
3393 BufferSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MaxCopy
;
3394 ValueInfo
= RtlAllocateHeap (ProcessHeap
,
3397 if (ValueInfo
== NULL
)
3399 ErrorCode
= ERROR_OUTOFMEMORY
;
3403 Status
= NtQueryValueKey (KeyHandle
,
3405 KeyValuePartialInformation
,
3409 TRACE("Status 0x%X\n", Status
);
3410 if (Status
== STATUS_BUFFER_OVERFLOW
)
3412 /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
3414 ErrorCode
= lpData
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
3416 else if (!NT_SUCCESS(Status
))
3418 ErrorCode
= RtlNtStatusToDosError (Status
);
3420 if (lpcbData
!= NULL
)
3422 ResultSize
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + *lpcbData
;
3428 *lpType
= ValueInfo
->Type
;
3431 if (NT_SUCCESS(Status
) && lpData
!= NULL
)
3433 RtlMoveMemory (lpData
,
3435 min(ValueInfo
->DataLength
, MaxCopy
));
3438 if ((ValueInfo
->Type
== REG_SZ
) ||
3439 (ValueInfo
->Type
== REG_MULTI_SZ
) ||
3440 (ValueInfo
->Type
== REG_EXPAND_SZ
))
3442 if (lpData
!= NULL
&& MaxCopy
> ValueInfo
->DataLength
)
3444 ((PWSTR
)lpData
)[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = 0;
3447 if (lpcbData
!= NULL
)
3449 *lpcbData
= (ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]));
3450 TRACE("(string) Returning Size: %lu\n", *lpcbData
);
3455 if (lpcbData
!= NULL
)
3457 *lpcbData
= ResultSize
- FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
3458 TRACE("(other) Returning Size: %lu\n", *lpcbData
);
3462 TRACE("Type %d Size %d\n", ValueInfo
->Type
, ValueInfo
->DataLength
);
3464 RtlFreeHeap (ProcessHeap
,
3469 CloseDefaultKey(KeyHandle
);
3475 /************************************************************************
3481 RegQueryValueExA (HKEY hKey
,
3488 UNICODE_STRING ValueName
;
3489 UNICODE_STRING ValueData
;
3490 ANSI_STRING AnsiString
;
3495 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3496 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3498 if (lpData
!= NULL
&& lpcbData
== NULL
)
3500 return ERROR_INVALID_PARAMETER
;
3505 ValueData
.Length
= 0;
3506 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3507 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3509 ValueData
.MaximumLength
);
3510 if (!ValueData
.Buffer
)
3512 return ERROR_OUTOFMEMORY
;
3517 ValueData
.Buffer
= NULL
;
3518 ValueData
.Length
= 0;
3519 ValueData
.MaximumLength
= 0;
3522 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
3523 (LPSTR
)lpValueName
);
3525 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
3526 ErrorCode
= RegQueryValueExW (hKey
,
3530 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
3532 TRACE("ErrorCode %lu\n", ErrorCode
);
3533 RtlFreeUnicodeString(&ValueName
);
3535 if (ErrorCode
== ERROR_SUCCESS
||
3536 ErrorCode
== ERROR_MORE_DATA
)
3543 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
3545 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3547 RtlInitAnsiString(&AnsiString
, NULL
);
3548 AnsiString
.Buffer
= (LPSTR
)lpData
;
3549 AnsiString
.MaximumLength
= *lpcbData
;
3550 ValueData
.Length
= Length
;
3551 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
3552 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
3554 Length
= Length
/ sizeof(WCHAR
);
3556 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
3558 if (*lpcbData
< Length
)
3560 ErrorCode
= ERROR_MORE_DATA
;
3564 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
3568 if (lpcbData
!= NULL
)
3574 if (ValueData
.Buffer
!= NULL
)
3576 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
3583 /************************************************************************
3589 RegQueryValueA (HKEY hKey
,
3594 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
3595 UNICODE_STRING SubKeyName
;
3596 UNICODE_STRING Value
;
3597 ANSI_STRING AnsiString
;
3601 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
3602 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3604 if (lpValue
!= NULL
&&
3607 return ERROR_INVALID_PARAMETER
;
3610 RtlInitUnicodeString (&SubKeyName
,
3612 RtlInitUnicodeString (&Value
,
3614 if (lpSubKey
!= NULL
&&
3615 strlen(lpSubKey
) != 0)
3617 RtlInitAnsiString (&AnsiString
,
3619 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
3620 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
3621 RtlAnsiStringToUnicodeString (&SubKeyName
,
3626 if (lpValue
!= NULL
)
3628 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
3629 Value
.MaximumLength
= ValueSize
;
3630 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
3633 if (Value
.Buffer
== NULL
)
3635 return ERROR_OUTOFMEMORY
;
3643 ErrorCode
= RegQueryValueW (hKey
,
3644 (LPCWSTR
)SubKeyName
.Buffer
,
3647 if (ErrorCode
== ERROR_SUCCESS
)
3649 Value
.Length
= ValueSize
;
3650 RtlInitAnsiString (&AnsiString
,
3652 AnsiString
.Buffer
= lpValue
;
3653 AnsiString
.MaximumLength
= *lpcbValue
;
3654 RtlUnicodeStringToAnsiString (&AnsiString
,
3659 *lpcbValue
= ValueSize
;
3660 if (Value
.Buffer
!= NULL
)
3662 RtlFreeHeap (ProcessHeap
,
3671 /************************************************************************
3677 RegQueryValueW (HKEY hKey
,
3682 OBJECT_ATTRIBUTES ObjectAttributes
;
3683 UNICODE_STRING SubKeyString
;
3690 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
3691 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
3693 Status
= MapDefaultKey (&KeyHandle
,
3695 if (!NT_SUCCESS(Status
))
3697 return RtlNtStatusToDosError (Status
);
3700 if (lpSubKey
!= NULL
&&
3701 wcslen(lpSubKey
) != 0)
3703 RtlInitUnicodeString (&SubKeyString
,
3705 InitializeObjectAttributes (&ObjectAttributes
,
3707 OBJ_CASE_INSENSITIVE
,
3710 Status
= NtOpenKey (&RealKey
,
3713 if (!NT_SUCCESS(Status
))
3715 ErrorCode
= RtlNtStatusToDosError (Status
);
3718 CloseRealKey
= TRUE
;
3723 CloseRealKey
= FALSE
;
3726 ErrorCode
= RegQueryValueExW (RealKey
,
3731 (LPDWORD
)lpcbValue
);
3738 CloseDefaultKey(KeyHandle
);
3744 /************************************************************************
3750 RegReplaceKeyA (HKEY hKey
,
3755 UNICODE_STRING SubKey
;
3756 UNICODE_STRING NewFile
;
3757 UNICODE_STRING OldFile
;
3760 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
3762 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
3764 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
3767 ErrorCode
= RegReplaceKeyW (hKey
,
3772 RtlFreeUnicodeString (&OldFile
);
3773 RtlFreeUnicodeString (&NewFile
);
3774 RtlFreeUnicodeString (&SubKey
);
3780 /************************************************************************
3786 RegReplaceKeyW (HKEY hKey
,
3791 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3792 OBJECT_ATTRIBUTES NewObjectAttributes
;
3793 OBJECT_ATTRIBUTES OldObjectAttributes
;
3794 UNICODE_STRING SubKeyName
;
3795 UNICODE_STRING NewFileName
;
3796 UNICODE_STRING OldFileName
;
3797 BOOLEAN CloseRealKey
;
3798 HANDLE RealKeyHandle
;
3801 LONG ErrorCode
= ERROR_SUCCESS
;
3803 if (hKey
== HKEY_PERFORMANCE_DATA
)
3805 return ERROR_INVALID_HANDLE
;
3808 Status
= MapDefaultKey (&KeyHandle
,
3810 if (!NT_SUCCESS(Status
))
3812 return RtlNtStatusToDosError (Status
);
3815 /* Open the real key */
3816 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
3818 RtlInitUnicodeString (&SubKeyName
,
3820 InitializeObjectAttributes (&KeyObjectAttributes
,
3822 OBJ_CASE_INSENSITIVE
,
3825 Status
= NtOpenKey (&RealKeyHandle
,
3827 &KeyObjectAttributes
);
3828 if (!NT_SUCCESS(Status
))
3830 ErrorCode
= RtlNtStatusToDosError (Status
);
3833 CloseRealKey
= TRUE
;
3837 RealKeyHandle
= KeyHandle
;
3838 CloseRealKey
= FALSE
;
3841 /* Convert new file name */
3842 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpNewFile
,
3849 NtClose (RealKeyHandle
);
3851 ErrorCode
= ERROR_INVALID_PARAMETER
;
3855 InitializeObjectAttributes (&NewObjectAttributes
,
3857 OBJ_CASE_INSENSITIVE
,
3861 /* Convert old file name */
3862 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpOldFile
,
3867 RtlFreeUnicodeString (&NewFileName
);
3870 NtClose (RealKeyHandle
);
3872 ErrorCode
= ERROR_INVALID_PARAMETER
;
3876 InitializeObjectAttributes (&OldObjectAttributes
,
3878 OBJ_CASE_INSENSITIVE
,
3882 Status
= NtReplaceKey (&NewObjectAttributes
,
3884 &OldObjectAttributes
);
3886 RtlFreeUnicodeString (&OldFileName
);
3887 RtlFreeUnicodeString (&NewFileName
);
3891 NtClose (RealKeyHandle
);
3894 if (!NT_SUCCESS(Status
))
3896 return RtlNtStatusToDosError (Status
);
3900 CloseDefaultKey(KeyHandle
);
3906 /************************************************************************
3912 RegRestoreKeyA (HKEY hKey
,
3916 UNICODE_STRING FileName
;
3919 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3922 ErrorCode
= RegRestoreKeyW (hKey
,
3926 RtlFreeUnicodeString (&FileName
);
3932 /************************************************************************
3938 RegRestoreKeyW (HKEY hKey
,
3942 OBJECT_ATTRIBUTES ObjectAttributes
;
3943 IO_STATUS_BLOCK IoStatusBlock
;
3944 UNICODE_STRING FileName
;
3949 if (hKey
== HKEY_PERFORMANCE_DATA
)
3951 return ERROR_INVALID_HANDLE
;
3954 Status
= MapDefaultKey (&KeyHandle
,
3956 if (!NT_SUCCESS(Status
))
3958 return RtlNtStatusToDosError (Status
);
3961 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpFile
,
3966 Status
= STATUS_INVALID_PARAMETER
;
3970 InitializeObjectAttributes (&ObjectAttributes
,
3972 OBJ_CASE_INSENSITIVE
,
3976 Status
= NtOpenFile (&FileHandle
,
3981 FILE_SYNCHRONOUS_IO_NONALERT
);
3982 RtlFreeUnicodeString (&FileName
);
3983 if (!NT_SUCCESS(Status
))
3988 Status
= NtRestoreKey (KeyHandle
,
3991 NtClose (FileHandle
);
3994 CloseDefaultKey(KeyHandle
);
3996 if (!NT_SUCCESS(Status
))
3998 return RtlNtStatusToDosError (Status
);
4001 return ERROR_SUCCESS
;
4005 /************************************************************************
4011 RegSaveKeyA (HKEY hKey
,
4013 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4015 UNICODE_STRING FileName
;
4018 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4020 ErrorCode
= RegSaveKeyW (hKey
,
4022 lpSecurityAttributes
);
4023 RtlFreeUnicodeString (&FileName
);
4029 /************************************************************************
4035 RegSaveKeyW (HKEY hKey
,
4037 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4039 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4040 OBJECT_ATTRIBUTES ObjectAttributes
;
4041 UNICODE_STRING FileName
;
4042 IO_STATUS_BLOCK IoStatusBlock
;
4047 Status
= MapDefaultKey (&KeyHandle
,
4049 if (!NT_SUCCESS(Status
))
4051 return RtlNtStatusToDosError (Status
);
4054 if (!RtlDosPathNameToNtPathName_U ((PWSTR
)lpFile
,
4059 Status
= STATUS_INVALID_PARAMETER
;
4063 if (lpSecurityAttributes
!= NULL
)
4065 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4068 InitializeObjectAttributes (&ObjectAttributes
,
4070 OBJ_CASE_INSENSITIVE
,
4072 SecurityDescriptor
);
4073 Status
= NtCreateFile (&FileHandle
,
4074 GENERIC_WRITE
| SYNCHRONIZE
,
4078 FILE_ATTRIBUTE_NORMAL
,
4081 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4084 RtlFreeUnicodeString (&FileName
);
4085 if (!NT_SUCCESS(Status
))
4090 Status
= NtSaveKey (KeyHandle
,
4092 NtClose (FileHandle
);
4095 CloseDefaultKey(KeyHandle
);
4097 if (!NT_SUCCESS(Status
))
4099 return RtlNtStatusToDosError (Status
);
4102 return ERROR_SUCCESS
;
4106 /************************************************************************
4112 RegSetKeySecurity (HKEY hKey
,
4113 SECURITY_INFORMATION SecurityInformation
,
4114 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4119 if (hKey
== HKEY_PERFORMANCE_DATA
)
4121 return ERROR_INVALID_HANDLE
;
4124 Status
= MapDefaultKey (&KeyHandle
,
4126 if (!NT_SUCCESS(Status
))
4128 return RtlNtStatusToDosError (Status
);
4131 Status
= NtSetSecurityObject (KeyHandle
,
4132 SecurityInformation
,
4133 pSecurityDescriptor
);
4135 CloseDefaultKey(KeyHandle
);
4137 if (!NT_SUCCESS(Status
))
4139 return RtlNtStatusToDosError (Status
);
4142 return ERROR_SUCCESS
;
4146 /************************************************************************
4152 RegSetValueExA (HKEY hKey
,
4159 UNICODE_STRING ValueName
;
4161 ANSI_STRING AnsiString
;
4162 UNICODE_STRING Data
;
4167 if (lpValueName
!= NULL
&&
4168 strlen(lpValueName
) != 0)
4170 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4172 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4179 if (((dwType
== REG_SZ
) ||
4180 (dwType
== REG_MULTI_SZ
) ||
4181 (dwType
== REG_EXPAND_SZ
)) &&
4184 /* NT adds one if the caller forgot the NULL-termination character */
4185 if (lpData
[cbData
- 1] != '\0')
4190 RtlInitAnsiString (&AnsiString
,
4192 AnsiString
.Buffer
= (PSTR
)lpData
;
4193 AnsiString
.Length
= cbData
- 1;
4194 AnsiString
.MaximumLength
= cbData
;
4195 RtlAnsiStringToUnicodeString (&Data
,
4198 pData
= (LPBYTE
)Data
.Buffer
;
4199 DataSize
= cbData
* sizeof(WCHAR
);
4203 RtlInitUnicodeString (&Data
,
4205 pData
= (LPBYTE
)lpData
;
4209 ErrorCode
= RegSetValueExW (hKey
,
4215 if (pValueName
!= NULL
)
4217 RtlFreeHeap (ProcessHeap
,
4222 if (Data
.Buffer
!= NULL
)
4224 RtlFreeHeap (ProcessHeap
,
4233 /************************************************************************
4239 RegSetValueExW (HKEY hKey
,
4240 LPCWSTR lpValueName
,
4246 UNICODE_STRING ValueName
;
4247 PUNICODE_STRING pValueName
;
4251 Status
= MapDefaultKey (&KeyHandle
,
4253 if (!NT_SUCCESS(Status
))
4255 return RtlNtStatusToDosError (Status
);
4258 if (lpValueName
!= NULL
)
4260 RtlInitUnicodeString (&ValueName
,
4265 RtlInitUnicodeString (&ValueName
, L
"");
4267 pValueName
= &ValueName
;
4269 if (((dwType
== REG_SZ
) ||
4270 (dwType
== REG_MULTI_SZ
) ||
4271 (dwType
== REG_EXPAND_SZ
)) &&
4272 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4274 /* NT adds one if the caller forgot the NULL-termination character */
4275 cbData
+= sizeof(WCHAR
);
4278 Status
= NtSetValueKey (KeyHandle
,
4285 CloseDefaultKey(KeyHandle
);
4287 if (!NT_SUCCESS(Status
))
4289 return RtlNtStatusToDosError (Status
);
4292 return ERROR_SUCCESS
;
4296 /************************************************************************
4302 RegSetValueA (HKEY hKey
,
4311 if (dwType
!= REG_SZ
)
4313 return ERROR_INVALID_PARAMETER
;
4316 if (lpSubKey
!= NULL
&& lpSubKey
[0] != '\0')
4318 ret
= RegCreateKeyA(hKey
,
4322 if (ret
!= ERROR_SUCCESS
)
4330 ret
= RegSetValueExA(hSubKey
,
4334 (CONST BYTE
*)lpData
,
4335 strlen(lpData
) + 1);
4337 if (hSubKey
!= hKey
)
4339 RegCloseKey(hSubKey
);
4346 /************************************************************************
4352 RegSetValueW (HKEY hKey
,
4358 OBJECT_ATTRIBUTES ObjectAttributes
;
4359 UNICODE_STRING SubKeyString
;
4366 Status
= MapDefaultKey (&KeyHandle
,
4368 if (!NT_SUCCESS(Status
))
4370 return RtlNtStatusToDosError (Status
);
4373 if ((lpSubKey
) && (wcslen(lpSubKey
) != 0))
4375 RtlInitUnicodeString (&SubKeyString
,
4377 InitializeObjectAttributes (&ObjectAttributes
,
4379 OBJ_CASE_INSENSITIVE
,
4382 Status
= NtOpenKey (&RealKey
,
4385 if (!NT_SUCCESS(Status
))
4387 ErrorCode
= RtlNtStatusToDosError (Status
);
4390 CloseRealKey
= TRUE
;
4395 CloseRealKey
= FALSE
;
4398 ErrorCode
= RegSetValueExW (RealKey
,
4404 if (CloseRealKey
== TRUE
)
4410 CloseDefaultKey(KeyHandle
);
4416 /************************************************************************
4422 RegUnLoadKeyA (HKEY hKey
,
4425 UNICODE_STRING KeyName
;
4428 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4431 ErrorCode
= RegUnLoadKeyW (hKey
,
4434 RtlFreeUnicodeString (&KeyName
);
4440 /************************************************************************
4446 RegUnLoadKeyW (HKEY hKey
,
4449 OBJECT_ATTRIBUTES ObjectAttributes
;
4450 UNICODE_STRING KeyName
;
4454 if (hKey
== HKEY_PERFORMANCE_DATA
)
4456 return ERROR_INVALID_HANDLE
;
4459 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4460 if (!NT_SUCCESS(Status
))
4462 return RtlNtStatusToDosError (Status
);
4465 RtlInitUnicodeString (&KeyName
,
4468 InitializeObjectAttributes (&ObjectAttributes
,
4470 OBJ_CASE_INSENSITIVE
,
4474 Status
= NtUnloadKey (&ObjectAttributes
);
4476 CloseDefaultKey(KeyHandle
);
4478 if (!NT_SUCCESS(Status
))
4480 return RtlNtStatusToDosError (Status
);
4483 return ERROR_SUCCESS
;
4487 /************************************************************************
4493 RegLoadMUIStringW(IN HKEY hKey
,
4494 IN LPCWSTR pszValue OPTIONAL
,
4495 OUT LPWSTR pszOutBuf
,
4498 IN LPCWSTR pszDirectory OPTIONAL
)
4500 DPRINT1("RegLoadMUIStringW(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4501 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4502 return ERROR_CALL_NOT_IMPLEMENTED
;
4506 /************************************************************************
4512 RegLoadMUIStringA(IN HKEY hKey
,
4513 IN LPCSTR pszValue OPTIONAL
,
4514 OUT LPSTR pszOutBuf
,
4517 IN LPCSTR pszDirectory OPTIONAL
)
4519 DPRINT1("RegLoadMUIStringA(0x%p, 0x%p, 0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
4520 hKey
, pszValue
, pszOutBuf
, cbOutBuf
, Reserved
, pszDirectory
);
4521 return ERROR_CALL_NOT_IMPLEMENTED
;