2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
23 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
25 /* DEFINES ******************************************************************/
27 #define MAX_DEFAULT_HANDLES 6
28 #define REG_MAX_NAME_SIZE 256
29 #define REG_MAX_DATA_SIZE 2048
31 /* GLOBALS ******************************************************************/
33 static RTL_CRITICAL_SECTION HandleTableCS
;
34 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
35 static HANDLE ProcessHeap
;
36 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
37 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
38 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
40 /* PROTOTYPES ***************************************************************/
42 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
43 static VOID
CloseDefaultKeys(VOID
);
44 #define ClosePredefKey(Handle) \
45 if ((ULONG_PTR)Handle & 0x1) { \
48 #define IsPredefKey(HKey) \
49 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey) \
51 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
53 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
54 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
55 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
56 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
59 /* FUNCTIONS ****************************************************************/
60 /* check if value type needs string conversion (Ansi<->Unicode) */
61 __inline
static int is_string( DWORD type
)
63 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
66 /************************************************************************
67 * RegInitDefaultHandles
72 TRACE("RegInitialize()\n");
77 ProcessHeap
= RtlGetProcessHeap();
78 RtlZeroMemory(DefaultHandleTable
,
79 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
80 RtlInitializeCriticalSection(&HandleTableCS
);
82 DllInitialized
= TRUE
;
89 /************************************************************************
95 TRACE("RegCleanup()\n");
98 RtlDeleteCriticalSection(&HandleTableCS
);
105 OpenPredefinedKey(IN ULONG Index
,
112 case 0: /* HKEY_CLASSES_ROOT */
113 Status
= OpenClassesRootKey (Handle
);
116 case 1: /* HKEY_CURRENT_USER */
117 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
121 case 2: /* HKEY_LOCAL_MACHINE */
122 Status
= OpenLocalMachineKey (Handle
);
125 case 3: /* HKEY_USERS */
126 Status
= OpenUsersKey (Handle
);
129 case 4: /* HKEY_PERFORMANCE_DATA */
130 Status
= OpenPerformanceDataKey (Handle
);
134 case 5: /* HKEY_CURRENT_CONFIG */
135 Status
= OpenCurrentConfigKey (Handle
);
138 case 6: /* HKEY_DYN_DATA */
139 Status
= STATUS_NOT_IMPLEMENTED
;
143 WARN("MapDefaultHandle() no handle creator\n");
144 Status
= STATUS_INVALID_PARAMETER
;
153 MapDefaultKey(OUT PHANDLE RealKey
,
158 BOOLEAN DoOpen
, DefDisabled
;
159 NTSTATUS Status
= STATUS_SUCCESS
;
161 TRACE("MapDefaultKey (Key %x)\n", Key
);
163 if (!IsPredefKey(Key
))
165 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
166 return STATUS_SUCCESS
;
169 /* Handle special cases here */
170 Index
= GetPredefKeyIndex(Key
);
171 if (Index
>= MAX_DEFAULT_HANDLES
)
173 return STATUS_INVALID_PARAMETER
;
175 RegInitialize(); /* HACK until delay-loading is implemented */
176 RtlEnterCriticalSection (&HandleTableCS
);
178 if (Key
== HKEY_CURRENT_USER
)
179 DefDisabled
= DefaultHandleHKUDisabled
;
181 DefDisabled
= DefaultHandlesDisabled
;
185 Handle
= &DefaultHandleTable
[Index
];
186 DoOpen
= (*Handle
== NULL
);
196 /* create/open the default handle */
197 Status
= OpenPredefinedKey(Index
,
201 if (NT_SUCCESS(Status
))
206 *(PULONG_PTR
)Handle
|= 0x1;
209 RtlLeaveCriticalSection (&HandleTableCS
);
216 CloseDefaultKeys(VOID
)
219 RegInitialize(); /* HACK until delay-loading is implemented */
220 RtlEnterCriticalSection(&HandleTableCS
);
222 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
224 if (DefaultHandleTable
[i
] != NULL
)
226 NtClose(DefaultHandleTable
[i
]);
227 DefaultHandleTable
[i
] = NULL
;
231 RtlLeaveCriticalSection(&HandleTableCS
);
236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle
)
238 OBJECT_ATTRIBUTES Attributes
;
239 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
242 TRACE("OpenClassesRootKey()\n");
244 InitializeObjectAttributes(&Attributes
,
246 OBJ_CASE_INSENSITIVE
,
249 Status
= NtOpenKey(KeyHandle
,
253 if (!NT_SUCCESS(Status
))
256 /* Mark it as HKCR */
257 MakeHKCRKey((HKEY
*)KeyHandle
);
264 OpenLocalMachineKey(PHANDLE KeyHandle
)
266 OBJECT_ATTRIBUTES Attributes
;
267 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
270 TRACE("OpenLocalMachineKey()\n");
272 InitializeObjectAttributes(&Attributes
,
274 OBJ_CASE_INSENSITIVE
,
277 Status
= NtOpenKey(KeyHandle
,
281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
288 OpenUsersKey(PHANDLE KeyHandle
)
290 OBJECT_ATTRIBUTES Attributes
;
291 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
293 TRACE("OpenUsersKey()\n");
295 InitializeObjectAttributes(&Attributes
,
297 OBJ_CASE_INSENSITIVE
,
300 return NtOpenKey(KeyHandle
,
307 OpenCurrentConfigKey (PHANDLE KeyHandle
)
309 OBJECT_ATTRIBUTES Attributes
;
310 UNICODE_STRING KeyName
=
311 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
313 TRACE("OpenCurrentConfigKey()\n");
315 InitializeObjectAttributes(&Attributes
,
317 OBJ_CASE_INSENSITIVE
,
320 return NtOpenKey(KeyHandle
,
326 /************************************************************************
327 * RegDisablePredefinedCache
332 RegDisablePredefinedCache(VOID
)
334 RegInitialize(); /* HACK until delay-loading is implemented */
335 RtlEnterCriticalSection(&HandleTableCS
);
336 DefaultHandleHKUDisabled
= TRUE
;
337 RtlLeaveCriticalSection(&HandleTableCS
);
338 return ERROR_SUCCESS
;
342 /************************************************************************
343 * RegDisablePredefinedCacheEx
348 RegDisablePredefinedCacheEx(VOID
)
350 RegInitialize(); /* HACK until delay-loading is implemented */
351 RtlEnterCriticalSection(&HandleTableCS
);
352 DefaultHandlesDisabled
= TRUE
;
353 DefaultHandleHKUDisabled
= TRUE
;
354 RtlLeaveCriticalSection(&HandleTableCS
);
355 return ERROR_SUCCESS
;
359 /************************************************************************
360 * RegOverridePredefKey
365 RegOverridePredefKey(IN HKEY hKey
,
366 IN HKEY hNewHKey OPTIONAL
)
368 LONG ErrorCode
= ERROR_SUCCESS
;
370 if ((hKey
== HKEY_CLASSES_ROOT
||
371 hKey
== HKEY_CURRENT_CONFIG
||
372 hKey
== HKEY_CURRENT_USER
||
373 hKey
== HKEY_LOCAL_MACHINE
||
374 hKey
== HKEY_PERFORMANCE_DATA
||
375 hKey
== HKEY_USERS
) &&
376 !IsPredefKey(hNewHKey
))
381 Index
= GetPredefKeyIndex(hKey
);
382 Handle
= &DefaultHandleTable
[Index
];
384 if (hNewHKey
== NULL
)
386 /* restore the default mapping */
387 NTSTATUS Status
= OpenPredefinedKey(Index
,
389 if (!NT_SUCCESS(Status
))
391 return RtlNtStatusToDosError(Status
);
394 ASSERT(hNewHKey
!= NULL
);
396 RegInitialize(); /* HACK until delay-loading is implemented */
397 RtlEnterCriticalSection(&HandleTableCS
);
399 /* close the currently mapped handle if existing */
405 /* update the mapping */
408 RtlLeaveCriticalSection(&HandleTableCS
);
411 ErrorCode
= ERROR_INVALID_HANDLE
;
417 /************************************************************************
423 RegCloseKey(HKEY hKey
)
427 /* don't close null handle or a pseudo handle */
428 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
430 return ERROR_INVALID_HANDLE
;
433 Status
= NtClose(hKey
);
434 if (!NT_SUCCESS(Status
))
436 return RtlNtStatusToDosError(Status
);
439 return ERROR_SUCCESS
;
444 RegpCopyTree(IN HKEY hKeySrc
,
449 LIST_ENTRY ListEntry
;
452 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
454 LIST_ENTRY copyQueueHead
;
455 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
458 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
459 KEY_NODE_INFORMATION
*KeyNode
;
462 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
463 NTSTATUS Status
= STATUS_SUCCESS
;
464 NTSTATUS Status2
= STATUS_SUCCESS
;
466 InitializeListHead(©QueueHead
);
468 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
471 if (Info
.Buffer
== NULL
)
473 return STATUS_INSUFFICIENT_RESOURCES
;
476 copyKeys
= RtlAllocateHeap(ProcessHeap
,
478 sizeof(REGP_COPY_KEYS
));
479 if (copyKeys
!= NULL
)
481 copyKeys
->hKeySrc
= hKeySrc
;
482 copyKeys
->hKeyDest
= hKeyDest
;
483 InsertHeadList(©QueueHead
,
484 ©Keys
->ListEntry
);
486 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
490 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
494 /* enumerate all values and copy them */
498 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
500 KeyValueFullInformation
,
503 &BufferSizeRequired
);
504 if (NT_SUCCESS(Status2
))
506 UNICODE_STRING ValueName
;
509 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
510 ValueName
.Length
= Info
.KeyValue
->NameLength
;
511 ValueName
.MaximumLength
= ValueName
.Length
;
512 ValueName
.Buffer
= Info
.KeyValue
->Name
;
514 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
516 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
518 Info
.KeyValue
->TitleIndex
,
521 Info
.KeyValue
->DataLength
);
523 /* don't break, let's try to copy as many values as possible */
524 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
531 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
535 ASSERT(BufferSize
< BufferSizeRequired
);
537 Buffer
= RtlReAllocateHeap(ProcessHeap
,
543 Info
.Buffer
= Buffer
;
548 /* don't break, let's try to copy as many values as possible */
549 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
552 if (NT_SUCCESS(Status
))
560 /* break to avoid an infinite loop in case of denied access or
562 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
571 /* enumerate all subkeys and open and enqueue them */
575 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
580 &BufferSizeRequired
);
581 if (NT_SUCCESS(Status2
))
583 HANDLE KeyHandle
, NewKeyHandle
;
584 OBJECT_ATTRIBUTES ObjectAttributes
;
585 UNICODE_STRING SubKeyName
, ClassName
;
587 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
588 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
589 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
590 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
591 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
592 ClassName
.MaximumLength
= ClassName
.Length
;
593 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
595 /* open the subkey with sufficient rights */
597 InitializeObjectAttributes(&ObjectAttributes
,
599 OBJ_CASE_INSENSITIVE
,
603 Status2
= NtOpenKey(&KeyHandle
,
604 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
606 if (NT_SUCCESS(Status2
))
608 /* FIXME - attempt to query the security information */
610 InitializeObjectAttributes(&ObjectAttributes
,
612 OBJ_CASE_INSENSITIVE
,
616 Status2
= NtCreateKey(&NewKeyHandle
,
619 Info
.KeyNode
->TitleIndex
,
623 if (NT_SUCCESS(Status2
))
625 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
627 sizeof(REGP_COPY_KEYS
));
628 if (newCopyKeys
!= NULL
)
630 /* save the handles and enqueue the subkey */
631 newCopyKeys
->hKeySrc
= KeyHandle
;
632 newCopyKeys
->hKeyDest
= NewKeyHandle
;
633 InsertTailList(©QueueHead
,
634 &newCopyKeys
->ListEntry
);
639 NtClose(NewKeyHandle
);
641 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
650 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
657 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
661 ASSERT(BufferSize
< BufferSizeRequired
);
663 Buffer
= RtlReAllocateHeap(ProcessHeap
,
669 Info
.Buffer
= Buffer
;
674 /* don't break, let's try to copy as many keys as possible */
675 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
678 if (NT_SUCCESS(Status
))
686 /* break to avoid an infinite loop in case of denied access or
688 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
697 /* close the handles and remove the entry from the list */
698 if (copyKeys
->hKeySrc
!= hKeySrc
)
700 NtClose(copyKeys
->hKeySrc
);
702 if (copyKeys
->hKeyDest
!= hKeyDest
)
704 NtClose(copyKeys
->hKeyDest
);
707 RemoveEntryList(©Keys
->ListEntry
);
709 RtlFreeHeap(ProcessHeap
,
712 } while (!IsListEmpty(©QueueHead
));
715 Status
= STATUS_INSUFFICIENT_RESOURCES
;
717 RtlFreeHeap(ProcessHeap
,
725 /************************************************************************
731 RegCopyTreeW(IN HKEY hKeySrc
,
732 IN LPCWSTR lpSubKey OPTIONAL
,
735 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
738 Status
= MapDefaultKey(&KeyHandle
,
740 if (!NT_SUCCESS(Status
))
742 return RtlNtStatusToDosError(Status
);
745 Status
= MapDefaultKey(&DestKeyHandle
,
747 if (!NT_SUCCESS(Status
))
752 if (lpSubKey
!= NULL
)
754 OBJECT_ATTRIBUTES ObjectAttributes
;
755 UNICODE_STRING SubKeyName
;
757 RtlInitUnicodeString(&SubKeyName
,
760 InitializeObjectAttributes(&ObjectAttributes
,
762 OBJ_CASE_INSENSITIVE
,
766 Status
= NtOpenKey(&SubKeyHandle
,
767 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
769 if (!NT_SUCCESS(Status
))
774 CurKey
= SubKeyHandle
;
779 Status
= RegpCopyTree(CurKey
,
782 if (SubKeyHandle
!= NULL
)
784 NtClose(SubKeyHandle
);
788 ClosePredefKey(DestKeyHandle
);
790 ClosePredefKey(KeyHandle
);
792 if (!NT_SUCCESS(Status
))
794 return RtlNtStatusToDosError(Status
);
797 return ERROR_SUCCESS
;
801 /************************************************************************
807 RegCopyTreeA(IN HKEY hKeySrc
,
808 IN LPCSTR lpSubKey OPTIONAL
,
811 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
814 if (lpSubKey
!= NULL
&&
815 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
818 return ERROR_NOT_ENOUGH_MEMORY
;
821 Ret
= RegCopyTreeW(hKeySrc
,
825 RtlFreeUnicodeString(&SubKeyName
);
831 /************************************************************************
832 * RegConnectRegistryA
837 RegConnectRegistryA(IN LPCSTR lpMachineName
,
841 UNICODE_STRING MachineName
= { 0, 0, NULL
};
844 if (lpMachineName
!= NULL
&&
845 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
846 (LPSTR
)lpMachineName
))
848 return ERROR_NOT_ENOUGH_MEMORY
;
851 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
855 RtlFreeUnicodeString(&MachineName
);
861 /************************************************************************
862 * RegConnectRegistryW
867 RegConnectRegistryW(LPCWSTR lpMachineName
,
873 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
875 if (!lpMachineName
|| !*lpMachineName
)
877 /* Use the local machine name */
878 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
882 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
883 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
885 /* MSDN says lpMachineName must start with \\ : not so */
886 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
889 if (GetComputerNameW(compName
, &len
))
891 if (!_wcsicmp(lpMachineName
, compName
))
892 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
895 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
896 ret
= ERROR_BAD_NETPATH
;
900 ret
= GetLastError();
907 /************************************************************************
910 * Create key and all necessary intermediate keys
913 CreateNestedKey(PHKEY KeyHandle
,
914 POBJECT_ATTRIBUTES ObjectAttributes
,
915 PUNICODE_STRING ClassString
,
918 DWORD
*lpdwDisposition
)
920 OBJECT_ATTRIBUTES LocalObjectAttributes
;
921 UNICODE_STRING LocalKeyName
;
924 ULONG FullNameLength
;
927 HANDLE LocalKeyHandle
;
929 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
935 (PULONG
)lpdwDisposition
);
936 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
937 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
940 /* Copy object attributes */
941 RtlCopyMemory(&LocalObjectAttributes
,
943 sizeof(OBJECT_ATTRIBUTES
));
944 RtlCreateUnicodeString(&LocalKeyName
,
945 ObjectAttributes
->ObjectName
->Buffer
);
946 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
947 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
949 LocalKeyHandle
= NULL
;
951 /* Remove the last part of the key name and try to create the key again. */
952 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
954 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
955 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
957 Status
= STATUS_UNSUCCESSFUL
;
962 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
964 Status
= NtCreateKey(&LocalKeyHandle
,
966 &LocalObjectAttributes
,
971 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
974 if (!NT_SUCCESS(Status
))
976 RtlFreeUnicodeString(&LocalKeyName
);
980 /* Add removed parts of the key name and create them too. */
981 Length
= wcslen(LocalKeyName
.Buffer
);
985 NtClose (LocalKeyHandle
);
987 LocalKeyName
.Buffer
[Length
] = L
'\\';
988 Length
= wcslen (LocalKeyName
.Buffer
);
989 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
991 if (Length
== FullNameLength
)
993 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
999 (PULONG
)lpdwDisposition
);
1003 Status
= NtCreateKey(&LocalKeyHandle
,
1005 &LocalObjectAttributes
,
1010 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
1011 if (!NT_SUCCESS(Status
))
1015 RtlFreeUnicodeString(&LocalKeyName
);
1021 /************************************************************************
1029 _In_ LPCSTR lpSubKey
,
1030 _In_ DWORD Reserved
,
1032 _In_ DWORD dwOptions
,
1033 _In_ REGSAM samDesired
,
1034 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1035 _Out_ PHKEY phkResult
,
1036 _Out_ LPDWORD lpdwDisposition
)
1038 UNICODE_STRING SubKeyString
;
1039 UNICODE_STRING ClassString
;
1042 RtlCreateUnicodeStringFromAsciiz(&ClassString
, lpClass
);
1043 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, (LPSTR
)lpSubKey
);
1045 ErrorCode
= RegCreateKeyExW(
1047 SubKeyString
.Buffer
,
1052 lpSecurityAttributes
,
1056 RtlFreeUnicodeString(&SubKeyString
);
1057 RtlFreeUnicodeString(&ClassString
);
1063 /************************************************************************
1069 RegCreateKeyExW(HKEY hKey
,
1075 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1077 LPDWORD lpdwDisposition
)
1079 UNICODE_STRING SubKeyString
;
1080 UNICODE_STRING ClassString
;
1081 OBJECT_ATTRIBUTES ObjectAttributes
;
1083 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1086 TRACE("RegCreateKeyExW() called\n");
1088 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1089 return ERROR_INVALID_USER_BUFFER
;
1091 /* get the real parent key */
1092 Status
= MapDefaultKey(&ParentKey
,
1094 if (!NT_SUCCESS(Status
))
1096 return RtlNtStatusToDosError(Status
);
1099 TRACE("ParentKey %p\n", ParentKey
);
1101 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1102 Attributes
|= OBJ_OPENLINK
;
1104 RtlInitUnicodeString(&ClassString
,
1106 RtlInitUnicodeString(&SubKeyString
,
1108 InitializeObjectAttributes(&ObjectAttributes
,
1112 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1113 Status
= CreateNestedKey(phkResult
,
1115 (lpClass
== NULL
)? NULL
: &ClassString
,
1120 ClosePredefKey(ParentKey
);
1122 TRACE("Status %x\n", Status
);
1123 if (!NT_SUCCESS(Status
))
1125 return RtlNtStatusToDosError(Status
);
1128 return ERROR_SUCCESS
;
1132 /************************************************************************
1138 RegCreateKeyA(HKEY hKey
,
1142 return RegCreateKeyExA(hKey
,
1154 /************************************************************************
1160 RegCreateKeyW(HKEY hKey
,
1164 return RegCreateKeyExW(hKey
,
1176 /************************************************************************
1182 RegDeleteKeyA(HKEY hKey
,
1185 OBJECT_ATTRIBUTES ObjectAttributes
;
1186 UNICODE_STRING SubKeyName
;
1191 /* Make sure we got a subkey */
1195 return ERROR_INVALID_PARAMETER
;
1198 Status
= MapDefaultKey(&ParentKey
,
1200 if (!NT_SUCCESS(Status
))
1202 return RtlNtStatusToDosError(Status
);
1205 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1207 InitializeObjectAttributes(&ObjectAttributes
,
1209 OBJ_CASE_INSENSITIVE
,
1213 Status
= NtOpenKey(&TargetKey
,
1216 RtlFreeUnicodeString(&SubKeyName
);
1217 if (!NT_SUCCESS(Status
))
1222 Status
= NtDeleteKey(TargetKey
);
1223 NtClose (TargetKey
);
1226 ClosePredefKey(ParentKey
);
1228 if (!NT_SUCCESS(Status
))
1230 return RtlNtStatusToDosError(Status
);
1233 return ERROR_SUCCESS
;
1237 /************************************************************************
1243 RegDeleteKeyW(HKEY hKey
,
1246 OBJECT_ATTRIBUTES ObjectAttributes
;
1247 UNICODE_STRING SubKeyName
;
1252 /* Make sure we got a subkey */
1256 return ERROR_INVALID_PARAMETER
;
1259 Status
= MapDefaultKey(&ParentKey
,
1261 if (!NT_SUCCESS(Status
))
1263 return RtlNtStatusToDosError(Status
);
1266 RtlInitUnicodeString(&SubKeyName
,
1268 InitializeObjectAttributes(&ObjectAttributes
,
1270 OBJ_CASE_INSENSITIVE
,
1273 Status
= NtOpenKey(&TargetKey
,
1276 if (!NT_SUCCESS(Status
))
1281 Status
= NtDeleteKey(TargetKey
);
1285 ClosePredefKey(ParentKey
);
1287 if (!NT_SUCCESS(Status
))
1289 return RtlNtStatusToDosError(Status
);
1292 return ERROR_SUCCESS
;
1296 /************************************************************************
1303 RegDeleteKeyExA(HKEY hKey
,
1308 OBJECT_ATTRIBUTES ObjectAttributes
;
1309 UNICODE_STRING SubKeyName
;
1314 /* Make sure we got a subkey */
1318 return ERROR_INVALID_PARAMETER
;
1321 Status
= MapDefaultKey(&ParentKey
,
1323 if (!NT_SUCCESS(Status
))
1325 return RtlNtStatusToDosError(Status
);
1328 if (samDesired
& KEY_WOW64_32KEY
)
1329 ERR("Wow64 not yet supported!\n");
1331 if (samDesired
& KEY_WOW64_64KEY
)
1332 ERR("Wow64 not yet supported!\n");
1334 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1336 InitializeObjectAttributes(&ObjectAttributes
,
1338 OBJ_CASE_INSENSITIVE
,
1342 Status
= NtOpenKey(&TargetKey
,
1345 RtlFreeUnicodeString(&SubKeyName
);
1346 if (!NT_SUCCESS(Status
))
1351 Status
= NtDeleteKey(TargetKey
);
1352 NtClose (TargetKey
);
1355 ClosePredefKey(ParentKey
);
1357 if (!NT_SUCCESS(Status
))
1359 return RtlNtStatusToDosError(Status
);
1362 return ERROR_SUCCESS
;
1366 /************************************************************************
1373 RegDeleteKeyExW(HKEY hKey
,
1378 OBJECT_ATTRIBUTES ObjectAttributes
;
1379 UNICODE_STRING SubKeyName
;
1384 /* Make sure we got a subkey */
1388 return ERROR_INVALID_PARAMETER
;
1391 Status
= MapDefaultKey(&ParentKey
,
1393 if (!NT_SUCCESS(Status
))
1395 return RtlNtStatusToDosError(Status
);
1398 if (samDesired
& KEY_WOW64_32KEY
)
1399 ERR("Wow64 not yet supported!\n");
1401 if (samDesired
& KEY_WOW64_64KEY
)
1402 ERR("Wow64 not yet supported!\n");
1405 RtlInitUnicodeString(&SubKeyName
,
1407 InitializeObjectAttributes(&ObjectAttributes
,
1409 OBJ_CASE_INSENSITIVE
,
1412 Status
= NtOpenKey(&TargetKey
,
1415 if (!NT_SUCCESS(Status
))
1420 Status
= NtDeleteKey(TargetKey
);
1424 ClosePredefKey(ParentKey
);
1426 if (!NT_SUCCESS(Status
))
1428 return RtlNtStatusToDosError(Status
);
1431 return ERROR_SUCCESS
;
1435 /************************************************************************
1436 * RegDeleteKeyValueW
1441 RegDeleteKeyValueW(IN HKEY hKey
,
1442 IN LPCWSTR lpSubKey OPTIONAL
,
1443 IN LPCWSTR lpValueName OPTIONAL
)
1445 UNICODE_STRING ValueName
;
1446 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1449 Status
= MapDefaultKey(&KeyHandle
,
1451 if (!NT_SUCCESS(Status
))
1453 return RtlNtStatusToDosError(Status
);
1456 if (lpSubKey
!= NULL
)
1458 OBJECT_ATTRIBUTES ObjectAttributes
;
1459 UNICODE_STRING SubKeyName
;
1461 RtlInitUnicodeString(&SubKeyName
,
1464 InitializeObjectAttributes(&ObjectAttributes
,
1466 OBJ_CASE_INSENSITIVE
,
1470 Status
= NtOpenKey(&SubKeyHandle
,
1473 if (!NT_SUCCESS(Status
))
1478 CurKey
= SubKeyHandle
;
1483 RtlInitUnicodeString(&ValueName
,
1484 (LPWSTR
)lpValueName
);
1486 Status
= NtDeleteValueKey(CurKey
,
1489 if (SubKeyHandle
!= NULL
)
1491 NtClose(SubKeyHandle
);
1495 ClosePredefKey(KeyHandle
);
1497 if (!NT_SUCCESS(Status
))
1499 return RtlNtStatusToDosError(Status
);
1502 return ERROR_SUCCESS
;
1506 /************************************************************************
1507 * RegDeleteKeyValueA
1512 RegDeleteKeyValueA(IN HKEY hKey
,
1513 IN LPCSTR lpSubKey OPTIONAL
,
1514 IN LPCSTR lpValueName OPTIONAL
)
1516 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1519 if (lpSubKey
!= NULL
&&
1520 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1523 return ERROR_NOT_ENOUGH_MEMORY
;
1526 if (lpValueName
!= NULL
&&
1527 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1528 (LPSTR
)lpValueName
))
1530 RtlFreeUnicodeString(&SubKey
);
1531 return ERROR_NOT_ENOUGH_MEMORY
;
1534 Ret
= RegDeleteKeyValueW(hKey
,
1538 RtlFreeUnicodeString(&SubKey
);
1539 RtlFreeUnicodeString(&ValueName
);
1545 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1547 RegpDeleteTree(IN HKEY hKey
)
1551 LIST_ENTRY ListEntry
;
1553 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1555 LIST_ENTRY delQueueHead
;
1556 PREG_DEL_KEYS delKeys
, newDelKeys
;
1559 PKEY_BASIC_INFORMATION BasicInfo
;
1560 PREG_DEL_KEYS KeyDelRoot
;
1561 NTSTATUS Status
= STATUS_SUCCESS
;
1562 NTSTATUS Status2
= STATUS_SUCCESS
;
1564 InitializeListHead(&delQueueHead
);
1566 ProcessHeap
= RtlGetProcessHeap();
1568 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1569 structure for the root key, we only do that for subkeys as we need to
1570 allocate REGP_DEL_KEYS structures anyway! */
1571 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1573 sizeof(REGP_DEL_KEYS
));
1574 if (KeyDelRoot
!= NULL
)
1576 KeyDelRoot
->KeyHandle
= hKey
;
1577 InsertTailList(&delQueueHead
,
1578 &KeyDelRoot
->ListEntry
);
1582 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1591 /* check if this key contains subkeys and delete them first by queuing
1592 them at the head of the list */
1593 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1595 KeyBasicInformation
,
1600 if (NT_SUCCESS(Status2
))
1602 OBJECT_ATTRIBUTES ObjectAttributes
;
1603 UNICODE_STRING SubKeyName
;
1605 ASSERT(newDelKeys
!= NULL
);
1606 ASSERT(BasicInfo
!= NULL
);
1608 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1609 SubKeyName
.Length
= BasicInfo
->NameLength
;
1610 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1611 SubKeyName
.Buffer
= BasicInfo
->Name
;
1613 InitializeObjectAttributes(&ObjectAttributes
,
1615 OBJ_CASE_INSENSITIVE
,
1619 /* open the subkey */
1620 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1621 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1623 if (!NT_SUCCESS(Status2
))
1628 /* enqueue this key to the head of the deletion queue */
1629 InsertHeadList(&delQueueHead
,
1630 &newDelKeys
->ListEntry
);
1632 /* try again from the head of the list */
1637 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1639 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1641 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1642 if (newDelKeys
!= NULL
)
1644 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1647 goto ReadFirstSubKey
;
1651 /* don't break, let's try to delete as many keys as possible */
1652 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1653 goto SubKeyFailureNoFree
;
1656 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1658 PREG_DEL_KEYS newDelKeys2
;
1660 ASSERT(newDelKeys
!= NULL
);
1662 /* we need more memory to query the key name */
1663 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1666 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1667 if (newDelKeys2
!= NULL
)
1669 newDelKeys
= newDelKeys2
;
1670 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1673 goto ReadFirstSubKey
;
1677 /* don't break, let's try to delete as many keys as possible */
1678 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1681 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1683 /* in some race conditions where another thread would delete
1684 the same tree at the same time, newDelKeys could actually
1686 if (newDelKeys
!= NULL
)
1688 RtlFreeHeap(ProcessHeap
,
1696 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1697 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1698 if (newDelKeys
!= NULL
)
1700 RtlFreeHeap(ProcessHeap
,
1705 SubKeyFailureNoFree
:
1706 /* don't break, let's try to delete as many keys as possible */
1707 if (NT_SUCCESS(Status
))
1713 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1715 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1717 if (!NT_SUCCESS(Status2
))
1719 /* close the key handle so we don't leak handles for keys we were
1720 unable to delete. But only do this for handles not supplied
1723 if (delKeys
->KeyHandle
!= hKey
)
1725 NtClose(delKeys
->KeyHandle
);
1728 if (NT_SUCCESS(Status
))
1730 /* don't break, let's try to delete as many keys as possible */
1735 /* remove the entry from the list */
1736 RemoveEntryList(&delKeys
->ListEntry
);
1738 RtlFreeHeap(ProcessHeap
,
1741 } while (!IsListEmpty(&delQueueHead
));
1744 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1750 /************************************************************************
1756 RegDeleteTreeW(IN HKEY hKey
,
1757 IN LPCWSTR lpSubKey OPTIONAL
)
1759 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1762 Status
= MapDefaultKey(&KeyHandle
,
1764 if (!NT_SUCCESS(Status
))
1766 return RtlNtStatusToDosError(Status
);
1769 if (lpSubKey
!= NULL
)
1771 OBJECT_ATTRIBUTES ObjectAttributes
;
1772 UNICODE_STRING SubKeyName
;
1774 RtlInitUnicodeString(&SubKeyName
,
1777 InitializeObjectAttributes(&ObjectAttributes
,
1779 OBJ_CASE_INSENSITIVE
,
1783 Status
= NtOpenKey(&SubKeyHandle
,
1784 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1786 if (!NT_SUCCESS(Status
))
1791 CurKey
= SubKeyHandle
;
1796 Status
= RegpDeleteTree(CurKey
);
1798 if (NT_SUCCESS(Status
))
1800 /* make sure we only close hKey (KeyHandle) when the caller specified a
1801 subkey, because the handle would be invalid already! */
1802 if (CurKey
!= KeyHandle
)
1804 ClosePredefKey(KeyHandle
);
1807 return ERROR_SUCCESS
;
1811 /* make sure we close all handles we created! */
1812 if (SubKeyHandle
!= NULL
)
1814 NtClose(SubKeyHandle
);
1818 ClosePredefKey(KeyHandle
);
1820 return RtlNtStatusToDosError(Status
);
1826 /************************************************************************
1833 RegDeleteTreeW(HKEY hKey
,
1837 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1838 DWORD dwMaxLen
, dwSize
;
1842 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1844 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1846 Status
= MapDefaultKey(&KeyHandle
,
1848 if (!NT_SUCCESS(Status
))
1850 return RtlNtStatusToDosError(Status
);
1853 hSubKey
= KeyHandle
;
1857 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1860 ClosePredefKey(KeyHandle
);
1865 /* Get highest length for keys, values */
1866 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1867 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1868 if (ret
) goto cleanup
;
1872 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1873 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1875 /* Name too big: alloc a buffer for it */
1876 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1878 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1884 /* Recursively delete all the subkeys */
1888 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1889 NULL
, NULL
, NULL
)) break;
1891 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1892 if (ret
) goto cleanup
;
1896 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1901 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1902 NULL
, NULL
, NULL
, NULL
)) break;
1904 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1905 if (ret
) goto cleanup
;
1909 /* Free buffer if allocated */
1910 if (lpszName
!= szNameBuf
)
1911 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1913 RegCloseKey(hSubKey
);
1915 ClosePredefKey(KeyHandle
);
1921 /************************************************************************
1927 RegDeleteTreeA(IN HKEY hKey
,
1928 IN LPCSTR lpSubKey OPTIONAL
)
1930 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1933 if (lpSubKey
!= NULL
&&
1934 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1937 return ERROR_NOT_ENOUGH_MEMORY
;
1940 Ret
= RegDeleteTreeW(hKey
,
1943 RtlFreeUnicodeString(&SubKeyName
);
1949 /************************************************************************
1950 * RegDisableReflectionKey
1955 RegDisableReflectionKey(IN HKEY hBase
)
1957 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1958 return ERROR_CALL_NOT_IMPLEMENTED
;
1962 /************************************************************************
1963 * RegEnableReflectionKey
1968 RegEnableReflectionKey(IN HKEY hBase
)
1970 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1971 return ERROR_CALL_NOT_IMPLEMENTED
;
1975 /******************************************************************************
1976 * RegpApplyRestrictions [internal]
1978 * Helper function for RegGetValueA/W.
1981 RegpApplyRestrictions(DWORD dwFlags
,
1986 /* Check if the type is restricted by the passed flags */
1987 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1993 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1994 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1995 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1996 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1997 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1998 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1999 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
2002 if (dwFlags
& dwMask
)
2004 /* Type is not restricted, check for size mismatch */
2005 if (dwType
== REG_BINARY
)
2009 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2011 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2014 if (cbExpect
&& cbData
!= cbExpect
)
2015 *ret
= ERROR_DATATYPE_MISMATCH
;
2018 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2023 /******************************************************************************
2024 * RegGetValueW [ADVAPI32.@]
2026 * Retrieves the type and data for a value name associated with a key,
2027 * optionally expanding its content and restricting its type.
2030 * hKey [I] Handle to an open key.
2031 * pszSubKey [I] Name of the subkey of hKey.
2032 * pszValue [I] Name of value under hKey/szSubKey to query.
2033 * dwFlags [I] Flags restricting the value type to retrieve.
2034 * pdwType [O] Destination for the values type, may be NULL.
2035 * pvData [O] Destination for the values content, may be NULL.
2036 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2037 * retrieve the whole content, including the trailing '\0'
2041 * Success: ERROR_SUCCESS
2042 * Failure: nonzero error code from Winerror.h
2045 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2046 * expanded and pdwType is set to REG_SZ instead.
2047 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2048 * without RRF_NOEXPAND is thus not allowed.
2049 * An exception is the case where RRF_RT_ANY is specified, because then
2050 * RRF_NOEXPAND is allowed.
2053 RegGetValueW(HKEY hKey
,
2061 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2065 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2066 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2067 pvData
, pcbData
, cbData
);
2069 if (pvData
&& !pcbData
)
2070 return ERROR_INVALID_PARAMETER
;
2071 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2072 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2073 return ERROR_INVALID_PARAMETER
;
2075 if (pszSubKey
&& pszSubKey
[0])
2077 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2078 if (ret
!= ERROR_SUCCESS
) return ret
;
2081 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2083 /* If we are going to expand we need to read in the whole the value even
2084 * if the passed buffer was too small as the expanded string might be
2085 * smaller than the unexpanded one and could fit into cbData bytes. */
2086 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2087 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2091 HeapFree(GetProcessHeap(), 0, pvBuf
);
2093 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2096 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2100 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2101 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2102 &dwType
, pvBuf
, &cbData
);
2105 /* Even if cbData was large enough we have to copy the
2106 * string since ExpandEnvironmentStrings can't handle
2107 * overlapping buffers. */
2108 CopyMemory(pvBuf
, pvData
, cbData
);
2111 /* Both the type or the value itself could have been modified in
2112 * between so we have to keep retrying until the buffer is large
2113 * enough or we no longer have to expand the value. */
2115 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2117 if (ret
== ERROR_SUCCESS
)
2119 /* Recheck dwType in case it changed since the first call */
2120 if (dwType
== REG_EXPAND_SZ
)
2122 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2123 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2125 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2126 ret
= ERROR_MORE_DATA
;
2129 CopyMemory(pvData
, pvBuf
, *pcbData
);
2132 HeapFree(GetProcessHeap(), 0, pvBuf
);
2135 if (pszSubKey
&& pszSubKey
[0])
2138 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2140 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2141 ZeroMemory(pvData
, *pcbData
);
2153 /******************************************************************************
2154 * RegGetValueA [ADVAPI32.@]
2159 RegGetValueA(HKEY hKey
,
2167 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2171 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2172 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2175 if (pvData
&& !pcbData
)
2176 return ERROR_INVALID_PARAMETER
;
2177 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2178 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2179 return ERROR_INVALID_PARAMETER
;
2181 if (pszSubKey
&& pszSubKey
[0])
2183 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2184 if (ret
!= ERROR_SUCCESS
) return ret
;
2187 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2189 /* If we are going to expand we need to read in the whole the value even
2190 * if the passed buffer was too small as the expanded string might be
2191 * smaller than the unexpanded one and could fit into cbData bytes. */
2192 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2193 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2196 HeapFree(GetProcessHeap(), 0, pvBuf
);
2198 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2201 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2205 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2206 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2207 &dwType
, pvBuf
, &cbData
);
2210 /* Even if cbData was large enough we have to copy the
2211 * string since ExpandEnvironmentStrings can't handle
2212 * overlapping buffers. */
2213 CopyMemory(pvBuf
, pvData
, cbData
);
2216 /* Both the type or the value itself could have been modified in
2217 * between so we have to keep retrying until the buffer is large
2218 * enough or we no longer have to expand the value. */
2219 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2221 if (ret
== ERROR_SUCCESS
)
2223 /* Recheck dwType in case it changed since the first call */
2224 if (dwType
== REG_EXPAND_SZ
)
2226 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2227 pcbData
? *pcbData
: 0);
2229 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2230 ret
= ERROR_MORE_DATA
;
2233 CopyMemory(pvData
, pvBuf
, *pcbData
);
2236 HeapFree(GetProcessHeap(), 0, pvBuf
);
2239 if (pszSubKey
&& pszSubKey
[0])
2242 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2244 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2245 ZeroMemory(pvData
, *pcbData
);
2247 if (pdwType
) *pdwType
= dwType
;
2248 if (pcbData
) *pcbData
= cbData
;
2254 /************************************************************************
2260 RegSetKeyValueW(IN HKEY hKey
,
2261 IN LPCWSTR lpSubKey OPTIONAL
,
2262 IN LPCWSTR lpValueName OPTIONAL
,
2264 IN LPCVOID lpData OPTIONAL
,
2267 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2271 Status
= MapDefaultKey(&KeyHandle
,
2273 if (!NT_SUCCESS(Status
))
2275 return RtlNtStatusToDosError(Status
);
2278 if (lpSubKey
!= NULL
)
2280 OBJECT_ATTRIBUTES ObjectAttributes
;
2281 UNICODE_STRING SubKeyName
;
2283 RtlInitUnicodeString(&SubKeyName
,
2286 InitializeObjectAttributes(&ObjectAttributes
,
2288 OBJ_CASE_INSENSITIVE
,
2292 Status
= NtOpenKey(&SubKeyHandle
,
2295 if (!NT_SUCCESS(Status
))
2297 Ret
= RtlNtStatusToDosError(Status
);
2301 CurKey
= SubKeyHandle
;
2306 Ret
= RegSetValueExW(CurKey
,
2313 if (SubKeyHandle
!= NULL
)
2315 NtClose(SubKeyHandle
);
2319 ClosePredefKey(KeyHandle
);
2325 /************************************************************************
2331 RegSetKeyValueA(IN HKEY hKey
,
2332 IN LPCSTR lpSubKey OPTIONAL
,
2333 IN LPCSTR lpValueName OPTIONAL
,
2335 IN LPCVOID lpData OPTIONAL
,
2338 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2342 Status
= MapDefaultKey(&KeyHandle
,
2344 if (!NT_SUCCESS(Status
))
2346 return RtlNtStatusToDosError(Status
);
2349 if (lpSubKey
!= NULL
)
2351 OBJECT_ATTRIBUTES ObjectAttributes
;
2352 UNICODE_STRING SubKeyName
;
2354 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2357 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2361 InitializeObjectAttributes(&ObjectAttributes
,
2363 OBJ_CASE_INSENSITIVE
,
2367 Status
= NtOpenKey(&SubKeyHandle
,
2371 RtlFreeUnicodeString(&SubKeyName
);
2373 if (!NT_SUCCESS(Status
))
2375 Ret
= RtlNtStatusToDosError(Status
);
2379 CurKey
= SubKeyHandle
;
2384 Ret
= RegSetValueExA(CurKey
,
2391 if (SubKeyHandle
!= NULL
)
2393 NtClose(SubKeyHandle
);
2397 ClosePredefKey(KeyHandle
);
2403 /************************************************************************
2409 RegDeleteValueA(HKEY hKey
,
2412 UNICODE_STRING ValueName
;
2416 Status
= MapDefaultKey(&KeyHandle
,
2418 if (!NT_SUCCESS(Status
))
2420 return RtlNtStatusToDosError(Status
);
2423 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2424 (LPSTR
)lpValueName
);
2425 Status
= NtDeleteValueKey(KeyHandle
,
2427 RtlFreeUnicodeString (&ValueName
);
2429 ClosePredefKey(KeyHandle
);
2431 if (!NT_SUCCESS(Status
))
2433 return RtlNtStatusToDosError(Status
);
2436 return ERROR_SUCCESS
;
2440 /************************************************************************
2446 RegDeleteValueW(HKEY hKey
,
2447 LPCWSTR lpValueName
)
2449 UNICODE_STRING ValueName
;
2453 Status
= MapDefaultKey(&KeyHandle
,
2455 if (!NT_SUCCESS(Status
))
2457 return RtlNtStatusToDosError(Status
);
2460 RtlInitUnicodeString(&ValueName
,
2461 (LPWSTR
)lpValueName
);
2463 Status
= NtDeleteValueKey(KeyHandle
,
2466 ClosePredefKey(KeyHandle
);
2468 if (!NT_SUCCESS(Status
))
2470 return RtlNtStatusToDosError(Status
);
2473 return ERROR_SUCCESS
;
2477 /************************************************************************
2483 RegEnumKeyA(HKEY hKey
,
2491 return RegEnumKeyExA(hKey
,
2502 /************************************************************************
2508 RegEnumKeyW(HKEY hKey
,
2516 return RegEnumKeyExW(hKey
,
2527 /************************************************************************
2533 RegEnumKeyExA(HKEY hKey
,
2540 PFILETIME lpftLastWriteTime
)
2544 KEY_NODE_INFORMATION Node
;
2545 KEY_BASIC_INFORMATION Basic
;
2548 UNICODE_STRING StringU
;
2549 ANSI_STRING StringA
;
2550 LONG ErrorCode
= ERROR_SUCCESS
;
2552 DWORD ClassLength
= 0;
2558 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2559 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2561 if ((lpClass
) && (!lpcbClass
))
2563 return ERROR_INVALID_PARAMETER
;
2566 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2567 if (!NT_SUCCESS(Status
))
2569 return RtlNtStatusToDosError(Status
);
2574 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2585 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2592 /* The class name should start at a dword boundary */
2593 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2597 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2600 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2601 if (KeyInfo
== NULL
)
2603 ErrorCode
= ERROR_OUTOFMEMORY
;
2607 Status
= NtEnumerateKey(KeyHandle
,
2609 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2613 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2614 if (!NT_SUCCESS(Status
))
2616 ErrorCode
= RtlNtStatusToDosError (Status
);
2620 if (lpClass
== NULL
)
2622 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2624 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2628 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2629 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2630 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2635 if (KeyInfo
->Node
.NameLength
> NameLength
||
2636 KeyInfo
->Node
.ClassLength
> ClassLength
)
2638 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2642 StringA
.Buffer
= lpClass
;
2644 StringA
.MaximumLength
= *lpcbClass
;
2645 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2646 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2647 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2648 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2649 lpClass
[StringA
.Length
] = 0;
2650 *lpcbClass
= StringA
.Length
;
2651 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2652 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2653 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2657 if (ErrorCode
== ERROR_SUCCESS
)
2659 StringA
.Buffer
= lpName
;
2661 StringA
.MaximumLength
= *lpcbName
;
2662 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2663 lpName
[StringA
.Length
] = 0;
2664 *lpcbName
= StringA
.Length
;
2665 if (lpftLastWriteTime
!= NULL
)
2667 if (lpClass
== NULL
)
2669 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2670 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2674 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2675 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2681 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2682 TRACE("Key Name1 Length %d\n", NameLength
);
2683 TRACE("Key Name Length %d\n", *lpcbName
);
2684 TRACE("Key Name %s\n", lpName
);
2686 RtlFreeHeap(ProcessHeap
,
2691 ClosePredefKey(KeyHandle
);
2697 /************************************************************************
2703 RegEnumKeyExW(HKEY hKey
,
2710 PFILETIME lpftLastWriteTime
)
2714 KEY_NODE_INFORMATION Node
;
2715 KEY_BASIC_INFORMATION Basic
;
2721 ULONG ClassLength
= 0;
2723 LONG ErrorCode
= ERROR_SUCCESS
;
2726 Status
= MapDefaultKey(&KeyHandle
,
2728 if (!NT_SUCCESS(Status
))
2730 return RtlNtStatusToDosError(Status
);
2735 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2746 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2753 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2757 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2760 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2763 if (KeyInfo
== NULL
)
2765 ErrorCode
= ERROR_OUTOFMEMORY
;
2769 Status
= NtEnumerateKey(KeyHandle
,
2771 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2775 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2776 if (!NT_SUCCESS(Status
))
2778 ErrorCode
= RtlNtStatusToDosError (Status
);
2782 if (lpClass
== NULL
)
2784 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2786 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2790 RtlCopyMemory(lpName
,
2791 KeyInfo
->Basic
.Name
,
2792 KeyInfo
->Basic
.NameLength
);
2793 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2794 lpName
[*lpcbName
] = 0;
2799 if (KeyInfo
->Node
.NameLength
> NameLength
||
2800 KeyInfo
->Node
.ClassLength
> ClassLength
)
2802 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2806 RtlCopyMemory(lpName
,
2808 KeyInfo
->Node
.NameLength
);
2809 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2810 lpName
[*lpcbName
] = 0;
2811 RtlCopyMemory(lpClass
,
2812 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2813 KeyInfo
->Node
.ClassLength
);
2814 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2815 lpClass
[*lpcbClass
] = 0;
2819 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2821 if (lpClass
== NULL
)
2823 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2824 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2828 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2829 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2834 RtlFreeHeap(ProcessHeap
,
2839 ClosePredefKey(KeyHandle
);
2845 /************************************************************************
2851 RegEnumValueA(HKEY hKey
,
2863 char buffer
[256], *buf_ptr
= buffer
;
2864 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2865 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2867 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2868 // hkey, index, value, val_count, reserved, type, data, count );
2870 /* NT only checks count, not val_count */
2871 if ((data
&& !count
) || reserved
)
2872 return ERROR_INVALID_PARAMETER
;
2874 status
= MapDefaultKey(&KeyHandle
, hKey
);
2875 if (!NT_SUCCESS(status
))
2877 return RtlNtStatusToDosError(status
);
2880 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2881 if (data
) total_size
+= *count
;
2882 total_size
= min( sizeof(buffer
), total_size
);
2884 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2885 buffer
, total_size
, &total_size
);
2886 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2888 /* we need to fetch the contents for a string type even if not requested,
2889 * because we need to compute the length of the ASCII string. */
2890 if (value
|| data
|| is_string(info
->Type
))
2892 /* retry with a dynamically allocated buffer */
2893 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2895 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2896 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2898 status
= STATUS_INSUFFICIENT_RESOURCES
;
2901 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2902 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2903 buf_ptr
, total_size
, &total_size
);
2906 if (status
) goto done
;
2908 if (is_string(info
->Type
))
2911 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2915 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2918 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2920 /* if the type is REG_SZ and data is not 0-terminated
2921 * and there is enough space in the buffer NT appends a \0 */
2922 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2925 info
->DataLength
= len
;
2929 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2930 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2933 if (value
&& !status
)
2937 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2938 if (len
>= *val_count
)
2940 status
= STATUS_BUFFER_OVERFLOW
;
2943 len
= *val_count
- 1;
2944 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2950 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2956 else status
= STATUS_SUCCESS
;
2958 if (type
) *type
= info
->Type
;
2959 if (count
) *count
= info
->DataLength
;
2962 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2963 ClosePredefKey(KeyHandle
);
2964 return RtlNtStatusToDosError(status
);
2968 /******************************************************************************
2969 * RegEnumValueW [ADVAPI32.@]
2973 * hkey [I] Handle to key to query
2974 * index [I] Index of value to query
2975 * value [O] Value string
2976 * val_count [I/O] Size of value buffer (in wchars)
2977 * reserved [I] Reserved
2978 * type [O] Type code
2979 * data [O] Value data
2980 * count [I/O] Size of data buffer (in bytes)
2983 * Success: ERROR_SUCCESS
2984 * Failure: nonzero error code from Winerror.h
2987 RegEnumValueW(HKEY hKey
,
2999 char buffer
[256], *buf_ptr
= buffer
;
3000 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
3001 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
3003 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
3004 // hkey, index, value, val_count, reserved, type, data, count );
3006 /* NT only checks count, not val_count */
3007 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3009 status
= MapDefaultKey(&KeyHandle
, hKey
);
3010 if (!NT_SUCCESS(status
))
3012 return RtlNtStatusToDosError(status
);
3015 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
3016 if (data
) total_size
+= *count
;
3017 total_size
= min( sizeof(buffer
), total_size
);
3019 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3020 buffer
, total_size
, &total_size
);
3021 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
3025 /* retry with a dynamically allocated buffer */
3026 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
3028 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3029 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3031 status
= ERROR_NOT_ENOUGH_MEMORY
;
3034 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
3035 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3036 buf_ptr
, total_size
, &total_size
);
3039 if (status
) goto done
;
3043 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3045 status
= STATUS_BUFFER_OVERFLOW
;
3048 memcpy( value
, info
->Name
, info
->NameLength
);
3049 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3050 value
[*val_count
] = 0;
3055 if (info
->DataLength
> *count
)
3057 status
= STATUS_BUFFER_OVERFLOW
;
3060 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3061 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3063 /* if the type is REG_SZ and data is not 0-terminated
3064 * and there is enough space in the buffer NT appends a \0 */
3065 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3066 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3070 else status
= STATUS_SUCCESS
;
3073 if (type
) *type
= info
->Type
;
3074 if (count
) *count
= info
->DataLength
;
3077 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3078 ClosePredefKey(KeyHandle
);
3079 return RtlNtStatusToDosError(status
);
3083 /************************************************************************
3089 RegFlushKey(HKEY hKey
)
3094 if (hKey
== HKEY_PERFORMANCE_DATA
)
3096 return ERROR_SUCCESS
;
3099 Status
= MapDefaultKey(&KeyHandle
,
3101 if (!NT_SUCCESS(Status
))
3103 return RtlNtStatusToDosError(Status
);
3106 Status
= NtFlushKey(KeyHandle
);
3108 ClosePredefKey(KeyHandle
);
3110 if (!NT_SUCCESS(Status
))
3112 return RtlNtStatusToDosError(Status
);
3115 return ERROR_SUCCESS
;
3119 /************************************************************************
3125 RegGetKeySecurity(HKEY hKey
,
3126 SECURITY_INFORMATION SecurityInformation
,
3127 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3128 LPDWORD lpcbSecurityDescriptor
)
3133 if (hKey
== HKEY_PERFORMANCE_DATA
)
3135 return ERROR_INVALID_HANDLE
;
3138 Status
= MapDefaultKey(&KeyHandle
,
3140 if (!NT_SUCCESS(Status
))
3142 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3143 return RtlNtStatusToDosError(Status
);
3146 Status
= NtQuerySecurityObject(KeyHandle
,
3147 SecurityInformation
,
3148 pSecurityDescriptor
,
3149 *lpcbSecurityDescriptor
,
3150 lpcbSecurityDescriptor
);
3152 ClosePredefKey(KeyHandle
);
3154 if (!NT_SUCCESS(Status
))
3156 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3157 return RtlNtStatusToDosError(Status
);
3160 return ERROR_SUCCESS
;
3164 /************************************************************************
3170 RegLoadKeyA(HKEY hKey
,
3174 UNICODE_STRING FileName
;
3175 UNICODE_STRING KeyName
;
3178 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3180 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3183 ErrorCode
= RegLoadKeyW(hKey
,
3187 RtlFreeUnicodeString(&FileName
);
3188 RtlFreeUnicodeString(&KeyName
);
3194 /************************************************************************
3200 RegLoadKeyW(HKEY hKey
,
3204 OBJECT_ATTRIBUTES FileObjectAttributes
;
3205 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3206 UNICODE_STRING FileName
;
3207 UNICODE_STRING KeyName
;
3210 LONG ErrorCode
= ERROR_SUCCESS
;
3212 if (hKey
== HKEY_PERFORMANCE_DATA
)
3214 return ERROR_INVALID_HANDLE
;
3217 Status
= MapDefaultKey(&KeyHandle
,
3219 if (!NT_SUCCESS(Status
))
3221 return RtlNtStatusToDosError(Status
);
3224 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3229 ErrorCode
= ERROR_BAD_PATHNAME
;
3233 InitializeObjectAttributes(&FileObjectAttributes
,
3235 OBJ_CASE_INSENSITIVE
,
3239 RtlInitUnicodeString(&KeyName
,
3242 InitializeObjectAttributes(&KeyObjectAttributes
,
3244 OBJ_CASE_INSENSITIVE
,
3248 Status
= NtLoadKey(&KeyObjectAttributes
,
3249 &FileObjectAttributes
);
3251 RtlFreeHeap(RtlGetProcessHeap(),
3255 if (!NT_SUCCESS(Status
))
3257 ErrorCode
= RtlNtStatusToDosError(Status
);
3262 ClosePredefKey(KeyHandle
);
3268 /************************************************************************
3269 * RegNotifyChangeKeyValue
3274 RegNotifyChangeKeyValue(HKEY hKey
,
3276 DWORD dwNotifyFilter
,
3280 IO_STATUS_BLOCK IoStatusBlock
;
3283 LONG ErrorCode
= ERROR_SUCCESS
;
3285 if (hKey
== HKEY_PERFORMANCE_DATA
)
3287 return ERROR_INVALID_HANDLE
;
3290 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3292 return ERROR_INVALID_PARAMETER
;
3295 Status
= MapDefaultKey(&KeyHandle
,
3297 if (!NT_SUCCESS(Status
))
3299 return RtlNtStatusToDosError(Status
);
3302 /* FIXME: Remote key handles must fail */
3304 Status
= NtNotifyChangeKey(KeyHandle
,
3314 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3316 ErrorCode
= RtlNtStatusToDosError(Status
);
3319 ClosePredefKey(KeyHandle
);
3325 /************************************************************************
3326 * RegOpenCurrentUser
3331 RegOpenCurrentUser(IN REGSAM samDesired
,
3332 OUT PHKEY phkResult
)
3336 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3337 (PHANDLE
)phkResult
);
3338 if (!NT_SUCCESS(Status
))
3340 /* NOTE - don't set the last error code! just return the error! */
3341 return RtlNtStatusToDosError(Status
);
3344 return ERROR_SUCCESS
;
3348 /************************************************************************
3351 * 20050503 Fireball - imported from WINE
3356 RegOpenKeyA(HKEY hKey
,
3360 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3361 hKey
, lpSubKey
, phkResult
);
3364 return ERROR_INVALID_PARAMETER
;
3366 if (!hKey
&& lpSubKey
&& phkResult
)
3368 return ERROR_INVALID_HANDLE
;
3371 if (!lpSubKey
|| !*lpSubKey
)
3374 return ERROR_SUCCESS
;
3377 return RegOpenKeyExA(hKey
,
3385 /************************************************************************
3390 * 20050503 Fireball - imported from WINE
3395 RegOpenKeyW(HKEY hKey
,
3399 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3400 hKey
, lpSubKey
, phkResult
);
3403 return ERROR_INVALID_PARAMETER
;
3405 if (!hKey
&& lpSubKey
&& phkResult
)
3407 return ERROR_INVALID_HANDLE
;
3410 if (!lpSubKey
|| !*lpSubKey
)
3413 return ERROR_SUCCESS
;
3416 return RegOpenKeyExW(hKey
,
3424 /************************************************************************