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 *****************************************************************/
17 #include <pseh/pseh2.h>
18 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
20 /* DEFINES ******************************************************************/
22 #define MAX_DEFAULT_HANDLES 6
23 #define REG_MAX_NAME_SIZE 256
24 #define REG_MAX_DATA_SIZE 2048
26 /* GLOBALS ******************************************************************/
28 static RTL_CRITICAL_SECTION HandleTableCS
;
29 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
30 static HANDLE ProcessHeap
;
31 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
32 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
33 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
35 /* PROTOTYPES ***************************************************************/
37 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
38 static VOID
CloseDefaultKeys(VOID
);
39 #define ClosePredefKey(Handle) \
40 if ((ULONG_PTR)Handle & 0x1) { \
43 #define IsPredefKey(HKey) \
44 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
45 #define GetPredefKeyIndex(HKey) \
46 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
48 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
49 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
54 /* FUNCTIONS ****************************************************************/
55 /* check if value type needs string conversion (Ansi<->Unicode) */
56 __inline
static int is_string( DWORD type
)
58 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
61 /************************************************************************
62 * RegInitDefaultHandles
67 TRACE("RegInitialize()\n");
72 ProcessHeap
= RtlGetProcessHeap();
73 RtlZeroMemory(DefaultHandleTable
,
74 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
75 RtlInitializeCriticalSection(&HandleTableCS
);
77 DllInitialized
= TRUE
;
84 /************************************************************************
90 TRACE("RegCleanup()\n");
93 RtlDeleteCriticalSection(&HandleTableCS
);
100 OpenPredefinedKey(IN ULONG Index
,
107 case 0: /* HKEY_CLASSES_ROOT */
108 Status
= OpenClassesRootKey (Handle
);
111 case 1: /* HKEY_CURRENT_USER */
112 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
116 case 2: /* HKEY_LOCAL_MACHINE */
117 Status
= OpenLocalMachineKey (Handle
);
120 case 3: /* HKEY_USERS */
121 Status
= OpenUsersKey (Handle
);
124 case 4: /* HKEY_PERFORMANCE_DATA */
125 Status
= OpenPerformanceDataKey (Handle
);
129 case 5: /* HKEY_CURRENT_CONFIG */
130 Status
= OpenCurrentConfigKey (Handle
);
133 case 6: /* HKEY_DYN_DATA */
134 Status
= STATUS_NOT_IMPLEMENTED
;
138 WARN("MapDefaultHandle() no handle creator\n");
139 Status
= STATUS_INVALID_PARAMETER
;
148 MapDefaultKey(OUT PHANDLE RealKey
,
153 BOOLEAN DoOpen
, DefDisabled
;
154 NTSTATUS Status
= STATUS_SUCCESS
;
156 TRACE("MapDefaultKey (Key %x)\n", Key
);
158 if (!IsPredefKey(Key
))
160 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
161 return STATUS_SUCCESS
;
164 /* Handle special cases here */
165 Index
= GetPredefKeyIndex(Key
);
166 if (Index
>= MAX_DEFAULT_HANDLES
)
168 return STATUS_INVALID_PARAMETER
;
170 RegInitialize(); /* HACK until delay-loading is implemented */
171 RtlEnterCriticalSection (&HandleTableCS
);
173 if (Key
== HKEY_CURRENT_USER
)
174 DefDisabled
= DefaultHandleHKUDisabled
;
176 DefDisabled
= DefaultHandlesDisabled
;
180 Handle
= &DefaultHandleTable
[Index
];
181 DoOpen
= (*Handle
== NULL
);
191 /* create/open the default handle */
192 Status
= OpenPredefinedKey(Index
,
196 if (NT_SUCCESS(Status
))
201 *(PULONG_PTR
)Handle
|= 0x1;
204 RtlLeaveCriticalSection (&HandleTableCS
);
211 CloseDefaultKeys(VOID
)
214 RegInitialize(); /* HACK until delay-loading is implemented */
215 RtlEnterCriticalSection(&HandleTableCS
);
217 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
219 if (DefaultHandleTable
[i
] != NULL
)
221 NtClose(DefaultHandleTable
[i
]);
222 DefaultHandleTable
[i
] = NULL
;
226 RtlLeaveCriticalSection(&HandleTableCS
);
231 OpenClassesRootKey(PHANDLE KeyHandle
)
233 OBJECT_ATTRIBUTES Attributes
;
234 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
236 TRACE("OpenClassesRootKey()\n");
238 InitializeObjectAttributes(&Attributes
,
240 OBJ_CASE_INSENSITIVE
,
243 return NtOpenKey(KeyHandle
,
250 OpenLocalMachineKey(PHANDLE KeyHandle
)
252 OBJECT_ATTRIBUTES Attributes
;
253 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
256 TRACE("OpenLocalMachineKey()\n");
258 InitializeObjectAttributes(&Attributes
,
260 OBJ_CASE_INSENSITIVE
,
263 Status
= NtOpenKey(KeyHandle
,
267 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
274 OpenUsersKey(PHANDLE KeyHandle
)
276 OBJECT_ATTRIBUTES Attributes
;
277 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
279 TRACE("OpenUsersKey()\n");
281 InitializeObjectAttributes(&Attributes
,
283 OBJ_CASE_INSENSITIVE
,
286 return NtOpenKey(KeyHandle
,
293 OpenCurrentConfigKey (PHANDLE KeyHandle
)
295 OBJECT_ATTRIBUTES Attributes
;
296 UNICODE_STRING KeyName
=
297 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
299 TRACE("OpenCurrentConfigKey()\n");
301 InitializeObjectAttributes(&Attributes
,
303 OBJ_CASE_INSENSITIVE
,
306 return NtOpenKey(KeyHandle
,
312 /************************************************************************
313 * RegDisablePredefinedCache
318 RegDisablePredefinedCache(VOID
)
320 RegInitialize(); /* HACK until delay-loading is implemented */
321 RtlEnterCriticalSection(&HandleTableCS
);
322 DefaultHandleHKUDisabled
= TRUE
;
323 RtlLeaveCriticalSection(&HandleTableCS
);
324 return ERROR_SUCCESS
;
328 /************************************************************************
329 * RegDisablePredefinedCacheEx
334 RegDisablePredefinedCacheEx(VOID
)
336 RegInitialize(); /* HACK until delay-loading is implemented */
337 RtlEnterCriticalSection(&HandleTableCS
);
338 DefaultHandlesDisabled
= TRUE
;
339 DefaultHandleHKUDisabled
= TRUE
;
340 RtlLeaveCriticalSection(&HandleTableCS
);
341 return ERROR_SUCCESS
;
345 /************************************************************************
346 * RegOverridePredefKey
351 RegOverridePredefKey(IN HKEY hKey
,
352 IN HKEY hNewHKey OPTIONAL
)
354 LONG ErrorCode
= ERROR_SUCCESS
;
356 if ((hKey
== HKEY_CLASSES_ROOT
||
357 hKey
== HKEY_CURRENT_CONFIG
||
358 hKey
== HKEY_CURRENT_USER
||
359 hKey
== HKEY_LOCAL_MACHINE
||
360 hKey
== HKEY_PERFORMANCE_DATA
||
361 hKey
== HKEY_USERS
) &&
362 !IsPredefKey(hNewHKey
))
367 Index
= GetPredefKeyIndex(hKey
);
368 Handle
= &DefaultHandleTable
[Index
];
370 if (hNewHKey
== NULL
)
372 /* restore the default mapping */
373 NTSTATUS Status
= OpenPredefinedKey(Index
,
375 if (!NT_SUCCESS(Status
))
377 return RtlNtStatusToDosError(Status
);
380 ASSERT(hNewHKey
!= NULL
);
382 RegInitialize(); /* HACK until delay-loading is implemented */
383 RtlEnterCriticalSection(&HandleTableCS
);
385 /* close the currently mapped handle if existing */
391 /* update the mapping */
394 RtlLeaveCriticalSection(&HandleTableCS
);
397 ErrorCode
= ERROR_INVALID_HANDLE
;
403 /************************************************************************
409 RegCloseKey(HKEY hKey
)
413 /* don't close null handle or a pseudo handle */
414 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
416 return ERROR_INVALID_HANDLE
;
419 Status
= NtClose(hKey
);
420 if (!NT_SUCCESS(Status
))
422 return RtlNtStatusToDosError(Status
);
425 return ERROR_SUCCESS
;
430 RegpCopyTree(IN HKEY hKeySrc
,
435 LIST_ENTRY ListEntry
;
438 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
440 LIST_ENTRY copyQueueHead
;
441 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
444 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
445 KEY_NODE_INFORMATION
*KeyNode
;
448 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
449 NTSTATUS Status
= STATUS_SUCCESS
;
450 NTSTATUS Status2
= STATUS_SUCCESS
;
452 InitializeListHead(©QueueHead
);
454 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
457 if (Info
.Buffer
== NULL
)
459 return STATUS_INSUFFICIENT_RESOURCES
;
462 copyKeys
= RtlAllocateHeap(ProcessHeap
,
464 sizeof(REGP_COPY_KEYS
));
465 if (copyKeys
!= NULL
)
467 copyKeys
->hKeySrc
= hKeySrc
;
468 copyKeys
->hKeyDest
= hKeyDest
;
469 InsertHeadList(©QueueHead
,
470 ©Keys
->ListEntry
);
472 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
476 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
480 /* enumerate all values and copy them */
484 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
486 KeyValueFullInformation
,
489 &BufferSizeRequired
);
490 if (NT_SUCCESS(Status2
))
492 UNICODE_STRING ValueName
;
495 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
496 ValueName
.Length
= Info
.KeyValue
->NameLength
;
497 ValueName
.MaximumLength
= ValueName
.Length
;
498 ValueName
.Buffer
= Info
.KeyValue
->Name
;
500 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
502 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
504 Info
.KeyValue
->TitleIndex
,
507 Info
.KeyValue
->DataLength
);
509 /* don't break, let's try to copy as many values as possible */
510 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
517 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
521 ASSERT(BufferSize
< BufferSizeRequired
);
523 Buffer
= RtlReAllocateHeap(ProcessHeap
,
529 Info
.Buffer
= Buffer
;
534 /* don't break, let's try to copy as many values as possible */
535 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
538 if (NT_SUCCESS(Status
))
546 /* break to avoid an infinite loop in case of denied access or
548 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
557 /* enumerate all subkeys and open and enqueue them */
561 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
566 &BufferSizeRequired
);
567 if (NT_SUCCESS(Status2
))
569 HANDLE KeyHandle
, NewKeyHandle
;
570 OBJECT_ATTRIBUTES ObjectAttributes
;
571 UNICODE_STRING SubKeyName
, ClassName
;
573 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
574 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
575 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
576 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
577 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
578 ClassName
.MaximumLength
= ClassName
.Length
;
579 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
581 /* open the subkey with sufficient rights */
583 InitializeObjectAttributes(&ObjectAttributes
,
585 OBJ_CASE_INSENSITIVE
,
589 Status2
= NtOpenKey(&KeyHandle
,
590 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
592 if (NT_SUCCESS(Status2
))
594 /* FIXME - attempt to query the security information */
596 InitializeObjectAttributes(&ObjectAttributes
,
598 OBJ_CASE_INSENSITIVE
,
602 Status2
= NtCreateKey(&NewKeyHandle
,
605 Info
.KeyNode
->TitleIndex
,
609 if (NT_SUCCESS(Status2
))
611 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
613 sizeof(REGP_COPY_KEYS
));
614 if (newCopyKeys
!= NULL
)
616 /* save the handles and enqueue the subkey */
617 newCopyKeys
->hKeySrc
= KeyHandle
;
618 newCopyKeys
->hKeyDest
= NewKeyHandle
;
619 InsertTailList(©QueueHead
,
620 &newCopyKeys
->ListEntry
);
625 NtClose(NewKeyHandle
);
627 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
636 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
643 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
647 ASSERT(BufferSize
< BufferSizeRequired
);
649 Buffer
= RtlReAllocateHeap(ProcessHeap
,
655 Info
.Buffer
= Buffer
;
660 /* don't break, let's try to copy as many keys as possible */
661 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
664 if (NT_SUCCESS(Status
))
672 /* break to avoid an infinite loop in case of denied access or
674 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
683 /* close the handles and remove the entry from the list */
684 if (copyKeys
->hKeySrc
!= hKeySrc
)
686 NtClose(copyKeys
->hKeySrc
);
688 if (copyKeys
->hKeyDest
!= hKeyDest
)
690 NtClose(copyKeys
->hKeyDest
);
693 RemoveEntryList(©Keys
->ListEntry
);
695 RtlFreeHeap(ProcessHeap
,
698 } while (!IsListEmpty(©QueueHead
));
701 Status
= STATUS_INSUFFICIENT_RESOURCES
;
703 RtlFreeHeap(ProcessHeap
,
711 /************************************************************************
717 RegCopyTreeW(IN HKEY hKeySrc
,
718 IN LPCWSTR lpSubKey OPTIONAL
,
721 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
724 Status
= MapDefaultKey(&KeyHandle
,
726 if (!NT_SUCCESS(Status
))
728 return RtlNtStatusToDosError(Status
);
731 Status
= MapDefaultKey(&DestKeyHandle
,
733 if (!NT_SUCCESS(Status
))
738 if (lpSubKey
!= NULL
)
740 OBJECT_ATTRIBUTES ObjectAttributes
;
741 UNICODE_STRING SubKeyName
;
743 RtlInitUnicodeString(&SubKeyName
,
746 InitializeObjectAttributes(&ObjectAttributes
,
748 OBJ_CASE_INSENSITIVE
,
752 Status
= NtOpenKey(&SubKeyHandle
,
753 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
755 if (!NT_SUCCESS(Status
))
760 CurKey
= SubKeyHandle
;
765 Status
= RegpCopyTree(CurKey
,
768 if (SubKeyHandle
!= NULL
)
770 NtClose(SubKeyHandle
);
774 ClosePredefKey(DestKeyHandle
);
776 ClosePredefKey(KeyHandle
);
778 if (!NT_SUCCESS(Status
))
780 return RtlNtStatusToDosError(Status
);
783 return ERROR_SUCCESS
;
787 /************************************************************************
793 RegCopyTreeA(IN HKEY hKeySrc
,
794 IN LPCSTR lpSubKey OPTIONAL
,
797 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
800 if (lpSubKey
!= NULL
&&
801 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
804 return ERROR_NOT_ENOUGH_MEMORY
;
807 Ret
= RegCopyTreeW(hKeySrc
,
811 RtlFreeUnicodeString(&SubKeyName
);
817 /************************************************************************
818 * RegConnectRegistryA
823 RegConnectRegistryA(IN LPCSTR lpMachineName
,
827 UNICODE_STRING MachineName
= { 0, 0, NULL
};
830 if (lpMachineName
!= NULL
&&
831 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
832 (LPSTR
)lpMachineName
))
834 return ERROR_NOT_ENOUGH_MEMORY
;
837 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
841 RtlFreeUnicodeString(&MachineName
);
847 /************************************************************************
848 * RegConnectRegistryW
853 RegConnectRegistryW(LPCWSTR lpMachineName
,
859 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
861 if (!lpMachineName
|| !*lpMachineName
)
863 /* Use the local machine name */
864 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
868 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
869 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
871 /* MSDN says lpMachineName must start with \\ : not so */
872 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
875 if (GetComputerNameW(compName
, &len
))
877 if (!_wcsicmp(lpMachineName
, compName
))
878 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
881 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
882 ret
= ERROR_BAD_NETPATH
;
886 ret
= GetLastError();
893 /************************************************************************
896 * Create key and all necessary intermediate keys
899 CreateNestedKey(PHKEY KeyHandle
,
900 POBJECT_ATTRIBUTES ObjectAttributes
,
901 PUNICODE_STRING ClassString
,
904 DWORD
*lpdwDisposition
)
906 OBJECT_ATTRIBUTES LocalObjectAttributes
;
907 UNICODE_STRING LocalKeyName
;
910 ULONG FullNameLength
;
913 HANDLE LocalKeyHandle
;
915 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
921 (PULONG
)lpdwDisposition
);
922 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
923 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
926 /* Copy object attributes */
927 RtlCopyMemory(&LocalObjectAttributes
,
929 sizeof(OBJECT_ATTRIBUTES
));
930 RtlCreateUnicodeString(&LocalKeyName
,
931 ObjectAttributes
->ObjectName
->Buffer
);
932 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
933 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
935 LocalKeyHandle
= NULL
;
937 /* Remove the last part of the key name and try to create the key again. */
938 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
940 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
941 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
943 Status
= STATUS_UNSUCCESSFUL
;
948 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
950 Status
= NtCreateKey(&LocalKeyHandle
,
952 &LocalObjectAttributes
,
957 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
960 if (!NT_SUCCESS(Status
))
962 RtlFreeUnicodeString(&LocalKeyName
);
966 /* Add removed parts of the key name and create them too. */
967 Length
= wcslen(LocalKeyName
.Buffer
);
971 NtClose (LocalKeyHandle
);
973 LocalKeyName
.Buffer
[Length
] = L
'\\';
974 Length
= wcslen (LocalKeyName
.Buffer
);
975 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
977 if (Length
== FullNameLength
)
979 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
985 (PULONG
)lpdwDisposition
);
989 Status
= NtCreateKey(&LocalKeyHandle
,
991 &LocalObjectAttributes
,
996 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
997 if (!NT_SUCCESS(Status
))
1001 RtlFreeUnicodeString(&LocalKeyName
);
1007 /************************************************************************
1013 RegCreateKeyExA(HKEY hKey
,
1019 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1021 LPDWORD lpdwDisposition
)
1023 UNICODE_STRING SubKeyString
;
1024 UNICODE_STRING ClassString
;
1025 OBJECT_ATTRIBUTES ObjectAttributes
;
1027 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1030 TRACE("RegCreateKeyExA() called\n");
1032 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1033 return ERROR_INVALID_USER_BUFFER
;
1035 /* get the real parent key */
1036 Status
= MapDefaultKey(&ParentKey
,
1038 if (!NT_SUCCESS(Status
))
1040 return RtlNtStatusToDosError(Status
);
1043 TRACE("ParentKey %p\n", ParentKey
);
1045 if (lpClass
!= NULL
)
1047 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1051 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1052 Attributes
|= OBJ_OPENLINK
;
1054 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1056 InitializeObjectAttributes(&ObjectAttributes
,
1060 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1061 Status
= CreateNestedKey(phkResult
,
1063 (lpClass
== NULL
)? NULL
: &ClassString
,
1067 RtlFreeUnicodeString(&SubKeyString
);
1068 if (lpClass
!= NULL
)
1070 RtlFreeUnicodeString(&ClassString
);
1073 ClosePredefKey(ParentKey
);
1075 TRACE("Status %x\n", Status
);
1076 if (!NT_SUCCESS(Status
))
1078 return RtlNtStatusToDosError(Status
);
1081 return ERROR_SUCCESS
;
1085 /************************************************************************
1091 RegCreateKeyExW(HKEY hKey
,
1097 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1099 LPDWORD lpdwDisposition
)
1101 UNICODE_STRING SubKeyString
;
1102 UNICODE_STRING ClassString
;
1103 OBJECT_ATTRIBUTES ObjectAttributes
;
1105 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1108 TRACE("RegCreateKeyExW() called\n");
1110 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1111 return ERROR_INVALID_USER_BUFFER
;
1113 /* get the real parent key */
1114 Status
= MapDefaultKey(&ParentKey
,
1116 if (!NT_SUCCESS(Status
))
1118 return RtlNtStatusToDosError(Status
);
1121 TRACE("ParentKey %p\n", ParentKey
);
1123 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1124 Attributes
|= OBJ_OPENLINK
;
1126 RtlInitUnicodeString(&ClassString
,
1128 RtlInitUnicodeString(&SubKeyString
,
1130 InitializeObjectAttributes(&ObjectAttributes
,
1134 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1135 Status
= CreateNestedKey(phkResult
,
1137 (lpClass
== NULL
)? NULL
: &ClassString
,
1142 ClosePredefKey(ParentKey
);
1144 TRACE("Status %x\n", Status
);
1145 if (!NT_SUCCESS(Status
))
1147 return RtlNtStatusToDosError(Status
);
1150 return ERROR_SUCCESS
;
1154 /************************************************************************
1160 RegCreateKeyA(HKEY hKey
,
1164 return RegCreateKeyExA(hKey
,
1176 /************************************************************************
1182 RegCreateKeyW(HKEY hKey
,
1186 return RegCreateKeyExW(hKey
,
1198 /************************************************************************
1204 RegDeleteKeyA(HKEY hKey
,
1207 OBJECT_ATTRIBUTES ObjectAttributes
;
1208 UNICODE_STRING SubKeyName
;
1213 /* Make sure we got a subkey */
1217 return ERROR_INVALID_PARAMETER
;
1220 Status
= MapDefaultKey(&ParentKey
,
1222 if (!NT_SUCCESS(Status
))
1224 return RtlNtStatusToDosError(Status
);
1227 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1229 InitializeObjectAttributes(&ObjectAttributes
,
1231 OBJ_CASE_INSENSITIVE
,
1235 Status
= NtOpenKey(&TargetKey
,
1238 RtlFreeUnicodeString(&SubKeyName
);
1239 if (!NT_SUCCESS(Status
))
1244 Status
= NtDeleteKey(TargetKey
);
1245 NtClose (TargetKey
);
1248 ClosePredefKey(ParentKey
);
1250 if (!NT_SUCCESS(Status
))
1252 return RtlNtStatusToDosError(Status
);
1255 return ERROR_SUCCESS
;
1259 /************************************************************************
1265 RegDeleteKeyW(HKEY hKey
,
1268 OBJECT_ATTRIBUTES ObjectAttributes
;
1269 UNICODE_STRING SubKeyName
;
1274 /* Make sure we got a subkey */
1278 return ERROR_INVALID_PARAMETER
;
1281 Status
= MapDefaultKey(&ParentKey
,
1283 if (!NT_SUCCESS(Status
))
1285 return RtlNtStatusToDosError(Status
);
1288 RtlInitUnicodeString(&SubKeyName
,
1290 InitializeObjectAttributes(&ObjectAttributes
,
1292 OBJ_CASE_INSENSITIVE
,
1295 Status
= NtOpenKey(&TargetKey
,
1298 if (!NT_SUCCESS(Status
))
1303 Status
= NtDeleteKey(TargetKey
);
1307 ClosePredefKey(ParentKey
);
1309 if (!NT_SUCCESS(Status
))
1311 return RtlNtStatusToDosError(Status
);
1314 return ERROR_SUCCESS
;
1318 /************************************************************************
1325 RegDeleteKeyExA(HKEY hKey
,
1330 OBJECT_ATTRIBUTES ObjectAttributes
;
1331 UNICODE_STRING SubKeyName
;
1336 /* Make sure we got a subkey */
1340 return ERROR_INVALID_PARAMETER
;
1343 Status
= MapDefaultKey(&ParentKey
,
1345 if (!NT_SUCCESS(Status
))
1347 return RtlNtStatusToDosError(Status
);
1350 if (samDesired
& KEY_WOW64_32KEY
)
1351 ERR("Wow64 not yet supported!\n");
1353 if (samDesired
& KEY_WOW64_64KEY
)
1354 ERR("Wow64 not yet supported!\n");
1356 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1358 InitializeObjectAttributes(&ObjectAttributes
,
1360 OBJ_CASE_INSENSITIVE
,
1364 Status
= NtOpenKey(&TargetKey
,
1367 RtlFreeUnicodeString(&SubKeyName
);
1368 if (!NT_SUCCESS(Status
))
1373 Status
= NtDeleteKey(TargetKey
);
1374 NtClose (TargetKey
);
1377 ClosePredefKey(ParentKey
);
1379 if (!NT_SUCCESS(Status
))
1381 return RtlNtStatusToDosError(Status
);
1384 return ERROR_SUCCESS
;
1388 /************************************************************************
1395 RegDeleteKeyExW(HKEY hKey
,
1400 OBJECT_ATTRIBUTES ObjectAttributes
;
1401 UNICODE_STRING SubKeyName
;
1406 /* Make sure we got a subkey */
1410 return ERROR_INVALID_PARAMETER
;
1413 Status
= MapDefaultKey(&ParentKey
,
1415 if (!NT_SUCCESS(Status
))
1417 return RtlNtStatusToDosError(Status
);
1420 if (samDesired
& KEY_WOW64_32KEY
)
1421 ERR("Wow64 not yet supported!\n");
1423 if (samDesired
& KEY_WOW64_64KEY
)
1424 ERR("Wow64 not yet supported!\n");
1427 RtlInitUnicodeString(&SubKeyName
,
1429 InitializeObjectAttributes(&ObjectAttributes
,
1431 OBJ_CASE_INSENSITIVE
,
1434 Status
= NtOpenKey(&TargetKey
,
1437 if (!NT_SUCCESS(Status
))
1442 Status
= NtDeleteKey(TargetKey
);
1446 ClosePredefKey(ParentKey
);
1448 if (!NT_SUCCESS(Status
))
1450 return RtlNtStatusToDosError(Status
);
1453 return ERROR_SUCCESS
;
1457 /************************************************************************
1458 * RegDeleteKeyValueW
1463 RegDeleteKeyValueW(IN HKEY hKey
,
1464 IN LPCWSTR lpSubKey OPTIONAL
,
1465 IN LPCWSTR lpValueName OPTIONAL
)
1467 UNICODE_STRING ValueName
;
1468 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1471 Status
= MapDefaultKey(&KeyHandle
,
1473 if (!NT_SUCCESS(Status
))
1475 return RtlNtStatusToDosError(Status
);
1478 if (lpSubKey
!= NULL
)
1480 OBJECT_ATTRIBUTES ObjectAttributes
;
1481 UNICODE_STRING SubKeyName
;
1483 RtlInitUnicodeString(&SubKeyName
,
1486 InitializeObjectAttributes(&ObjectAttributes
,
1488 OBJ_CASE_INSENSITIVE
,
1492 Status
= NtOpenKey(&SubKeyHandle
,
1495 if (!NT_SUCCESS(Status
))
1500 CurKey
= SubKeyHandle
;
1505 RtlInitUnicodeString(&ValueName
,
1506 (LPWSTR
)lpValueName
);
1508 Status
= NtDeleteValueKey(CurKey
,
1511 if (SubKeyHandle
!= NULL
)
1513 NtClose(SubKeyHandle
);
1517 ClosePredefKey(KeyHandle
);
1519 if (!NT_SUCCESS(Status
))
1521 return RtlNtStatusToDosError(Status
);
1524 return ERROR_SUCCESS
;
1528 /************************************************************************
1529 * RegDeleteKeyValueA
1534 RegDeleteKeyValueA(IN HKEY hKey
,
1535 IN LPCSTR lpSubKey OPTIONAL
,
1536 IN LPCSTR lpValueName OPTIONAL
)
1538 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1541 if (lpSubKey
!= NULL
&&
1542 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1545 return ERROR_NOT_ENOUGH_MEMORY
;
1548 if (lpValueName
!= NULL
&&
1549 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1550 (LPSTR
)lpValueName
))
1552 RtlFreeUnicodeString(&SubKey
);
1553 return ERROR_NOT_ENOUGH_MEMORY
;
1556 Ret
= RegDeleteKeyValueW(hKey
,
1560 RtlFreeUnicodeString(&SubKey
);
1561 RtlFreeUnicodeString(&ValueName
);
1567 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1569 RegpDeleteTree(IN HKEY hKey
)
1573 LIST_ENTRY ListEntry
;
1575 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1577 LIST_ENTRY delQueueHead
;
1578 PREG_DEL_KEYS delKeys
, newDelKeys
;
1581 PKEY_BASIC_INFORMATION BasicInfo
;
1582 PREG_DEL_KEYS KeyDelRoot
;
1583 NTSTATUS Status
= STATUS_SUCCESS
;
1584 NTSTATUS Status2
= STATUS_SUCCESS
;
1586 InitializeListHead(&delQueueHead
);
1588 ProcessHeap
= RtlGetProcessHeap();
1590 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1591 structure for the root key, we only do that for subkeys as we need to
1592 allocate REGP_DEL_KEYS structures anyway! */
1593 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1595 sizeof(REGP_DEL_KEYS
));
1596 if (KeyDelRoot
!= NULL
)
1598 KeyDelRoot
->KeyHandle
= hKey
;
1599 InsertTailList(&delQueueHead
,
1600 &KeyDelRoot
->ListEntry
);
1604 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1613 /* check if this key contains subkeys and delete them first by queuing
1614 them at the head of the list */
1615 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1617 KeyBasicInformation
,
1622 if (NT_SUCCESS(Status2
))
1624 OBJECT_ATTRIBUTES ObjectAttributes
;
1625 UNICODE_STRING SubKeyName
;
1627 ASSERT(newDelKeys
!= NULL
);
1628 ASSERT(BasicInfo
!= NULL
);
1630 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1631 SubKeyName
.Length
= BasicInfo
->NameLength
;
1632 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1633 SubKeyName
.Buffer
= BasicInfo
->Name
;
1635 InitializeObjectAttributes(&ObjectAttributes
,
1637 OBJ_CASE_INSENSITIVE
,
1641 /* open the subkey */
1642 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1643 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1645 if (!NT_SUCCESS(Status2
))
1650 /* enqueue this key to the head of the deletion queue */
1651 InsertHeadList(&delQueueHead
,
1652 &newDelKeys
->ListEntry
);
1654 /* try again from the head of the list */
1659 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1661 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1663 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1664 if (newDelKeys
!= NULL
)
1666 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1669 goto ReadFirstSubKey
;
1673 /* don't break, let's try to delete as many keys as possible */
1674 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1675 goto SubKeyFailureNoFree
;
1678 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1680 PREG_DEL_KEYS newDelKeys2
;
1682 ASSERT(newDelKeys
!= NULL
);
1684 /* we need more memory to query the key name */
1685 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1688 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1689 if (newDelKeys2
!= NULL
)
1691 newDelKeys
= newDelKeys2
;
1692 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1695 goto ReadFirstSubKey
;
1699 /* don't break, let's try to delete as many keys as possible */
1700 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1703 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1705 /* in some race conditions where another thread would delete
1706 the same tree at the same time, newDelKeys could actually
1708 if (newDelKeys
!= NULL
)
1710 RtlFreeHeap(ProcessHeap
,
1718 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1719 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1720 if (newDelKeys
!= NULL
)
1722 RtlFreeHeap(ProcessHeap
,
1727 SubKeyFailureNoFree
:
1728 /* don't break, let's try to delete as many keys as possible */
1729 if (NT_SUCCESS(Status
))
1735 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1737 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1739 if (!NT_SUCCESS(Status2
))
1741 /* close the key handle so we don't leak handles for keys we were
1742 unable to delete. But only do this for handles not supplied
1745 if (delKeys
->KeyHandle
!= hKey
)
1747 NtClose(delKeys
->KeyHandle
);
1750 if (NT_SUCCESS(Status
))
1752 /* don't break, let's try to delete as many keys as possible */
1757 /* remove the entry from the list */
1758 RemoveEntryList(&delKeys
->ListEntry
);
1760 RtlFreeHeap(ProcessHeap
,
1763 } while (!IsListEmpty(&delQueueHead
));
1766 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1772 /************************************************************************
1778 RegDeleteTreeW(IN HKEY hKey
,
1779 IN LPCWSTR lpSubKey OPTIONAL
)
1781 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1784 Status
= MapDefaultKey(&KeyHandle
,
1786 if (!NT_SUCCESS(Status
))
1788 return RtlNtStatusToDosError(Status
);
1791 if (lpSubKey
!= NULL
)
1793 OBJECT_ATTRIBUTES ObjectAttributes
;
1794 UNICODE_STRING SubKeyName
;
1796 RtlInitUnicodeString(&SubKeyName
,
1799 InitializeObjectAttributes(&ObjectAttributes
,
1801 OBJ_CASE_INSENSITIVE
,
1805 Status
= NtOpenKey(&SubKeyHandle
,
1806 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1808 if (!NT_SUCCESS(Status
))
1813 CurKey
= SubKeyHandle
;
1818 Status
= RegpDeleteTree(CurKey
);
1820 if (NT_SUCCESS(Status
))
1822 /* make sure we only close hKey (KeyHandle) when the caller specified a
1823 subkey, because the handle would be invalid already! */
1824 if (CurKey
!= KeyHandle
)
1826 ClosePredefKey(KeyHandle
);
1829 return ERROR_SUCCESS
;
1833 /* make sure we close all handles we created! */
1834 if (SubKeyHandle
!= NULL
)
1836 NtClose(SubKeyHandle
);
1840 ClosePredefKey(KeyHandle
);
1842 return RtlNtStatusToDosError(Status
);
1848 /************************************************************************
1855 RegDeleteTreeW(HKEY hKey
,
1859 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1860 DWORD dwMaxLen
, dwSize
;
1864 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1866 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1868 Status
= MapDefaultKey(&KeyHandle
,
1870 if (!NT_SUCCESS(Status
))
1872 return RtlNtStatusToDosError(Status
);
1875 hSubKey
= KeyHandle
;
1879 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1882 ClosePredefKey(KeyHandle
);
1887 /* Get highest length for keys, values */
1888 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1889 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1890 if (ret
) goto cleanup
;
1894 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1895 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1897 /* Name too big: alloc a buffer for it */
1898 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1900 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1906 /* Recursively delete all the subkeys */
1910 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1911 NULL
, NULL
, NULL
)) break;
1913 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1914 if (ret
) goto cleanup
;
1918 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1923 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1924 NULL
, NULL
, NULL
, NULL
)) break;
1926 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1927 if (ret
) goto cleanup
;
1931 /* Free buffer if allocated */
1932 if (lpszName
!= szNameBuf
)
1933 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1935 RegCloseKey(hSubKey
);
1937 ClosePredefKey(KeyHandle
);
1943 /************************************************************************
1949 RegDeleteTreeA(IN HKEY hKey
,
1950 IN LPCSTR lpSubKey OPTIONAL
)
1952 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1955 if (lpSubKey
!= NULL
&&
1956 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1959 return ERROR_NOT_ENOUGH_MEMORY
;
1962 Ret
= RegDeleteTreeW(hKey
,
1965 RtlFreeUnicodeString(&SubKeyName
);
1971 /************************************************************************
1972 * RegDisableReflectionKey
1977 RegDisableReflectionKey(IN HKEY hBase
)
1979 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1980 return ERROR_CALL_NOT_IMPLEMENTED
;
1984 /************************************************************************
1985 * RegEnableReflectionKey
1990 RegEnableReflectionKey(IN HKEY hBase
)
1992 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1993 return ERROR_CALL_NOT_IMPLEMENTED
;
1997 /******************************************************************************
1998 * RegpApplyRestrictions [internal]
2000 * Helper function for RegGetValueA/W.
2003 RegpApplyRestrictions(DWORD dwFlags
,
2008 /* Check if the type is restricted by the passed flags */
2009 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
2015 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
2016 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
2017 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
2018 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
2019 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
2020 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
2021 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
2024 if (dwFlags
& dwMask
)
2026 /* Type is not restricted, check for size mismatch */
2027 if (dwType
== REG_BINARY
)
2031 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2033 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2036 if (cbExpect
&& cbData
!= cbExpect
)
2037 *ret
= ERROR_DATATYPE_MISMATCH
;
2040 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2045 /******************************************************************************
2046 * RegGetValueW [ADVAPI32.@]
2048 * Retrieves the type and data for a value name associated with a key,
2049 * optionally expanding its content and restricting its type.
2052 * hKey [I] Handle to an open key.
2053 * pszSubKey [I] Name of the subkey of hKey.
2054 * pszValue [I] Name of value under hKey/szSubKey to query.
2055 * dwFlags [I] Flags restricting the value type to retrieve.
2056 * pdwType [O] Destination for the values type, may be NULL.
2057 * pvData [O] Destination for the values content, may be NULL.
2058 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2059 * retrieve the whole content, including the trailing '\0'
2063 * Success: ERROR_SUCCESS
2064 * Failure: nonzero error code from Winerror.h
2067 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2068 * expanded and pdwType is set to REG_SZ instead.
2069 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2070 * without RRF_NOEXPAND is thus not allowed.
2071 * An exception is the case where RRF_RT_ANY is specified, because then
2072 * RRF_NOEXPAND is allowed.
2075 RegGetValueW(HKEY hKey
,
2083 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2087 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2088 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2089 pvData
, pcbData
, cbData
);
2091 if (pvData
&& !pcbData
)
2092 return ERROR_INVALID_PARAMETER
;
2093 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2094 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2095 return ERROR_INVALID_PARAMETER
;
2097 if (pszSubKey
&& pszSubKey
[0])
2099 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2100 if (ret
!= ERROR_SUCCESS
) return ret
;
2103 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2105 /* If we are going to expand we need to read in the whole the value even
2106 * if the passed buffer was too small as the expanded string might be
2107 * smaller than the unexpanded one and could fit into cbData bytes. */
2108 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2109 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2113 HeapFree(GetProcessHeap(), 0, pvBuf
);
2115 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2118 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2122 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2123 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2124 &dwType
, pvBuf
, &cbData
);
2127 /* Even if cbData was large enough we have to copy the
2128 * string since ExpandEnvironmentStrings can't handle
2129 * overlapping buffers. */
2130 CopyMemory(pvBuf
, pvData
, cbData
);
2133 /* Both the type or the value itself could have been modified in
2134 * between so we have to keep retrying until the buffer is large
2135 * enough or we no longer have to expand the value. */
2137 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2139 if (ret
== ERROR_SUCCESS
)
2141 /* Recheck dwType in case it changed since the first call */
2142 if (dwType
== REG_EXPAND_SZ
)
2144 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2145 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2147 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2148 ret
= ERROR_MORE_DATA
;
2151 CopyMemory(pvData
, pvBuf
, *pcbData
);
2154 HeapFree(GetProcessHeap(), 0, pvBuf
);
2157 if (pszSubKey
&& pszSubKey
[0])
2160 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2162 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2163 ZeroMemory(pvData
, *pcbData
);
2175 /******************************************************************************
2176 * RegGetValueA [ADVAPI32.@]
2181 RegGetValueA(HKEY hKey
,
2189 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2193 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2194 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2197 if (pvData
&& !pcbData
)
2198 return ERROR_INVALID_PARAMETER
;
2199 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2200 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2201 return ERROR_INVALID_PARAMETER
;
2203 if (pszSubKey
&& pszSubKey
[0])
2205 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2206 if (ret
!= ERROR_SUCCESS
) return ret
;
2209 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2211 /* If we are going to expand we need to read in the whole the value even
2212 * if the passed buffer was too small as the expanded string might be
2213 * smaller than the unexpanded one and could fit into cbData bytes. */
2214 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2215 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2218 HeapFree(GetProcessHeap(), 0, pvBuf
);
2220 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2223 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2227 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2228 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2229 &dwType
, pvBuf
, &cbData
);
2232 /* Even if cbData was large enough we have to copy the
2233 * string since ExpandEnvironmentStrings can't handle
2234 * overlapping buffers. */
2235 CopyMemory(pvBuf
, pvData
, cbData
);
2238 /* Both the type or the value itself could have been modified in
2239 * between so we have to keep retrying until the buffer is large
2240 * enough or we no longer have to expand the value. */
2241 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2243 if (ret
== ERROR_SUCCESS
)
2245 /* Recheck dwType in case it changed since the first call */
2246 if (dwType
== REG_EXPAND_SZ
)
2248 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2249 pcbData
? *pcbData
: 0);
2251 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2252 ret
= ERROR_MORE_DATA
;
2255 CopyMemory(pvData
, pvBuf
, *pcbData
);
2258 HeapFree(GetProcessHeap(), 0, pvBuf
);
2261 if (pszSubKey
&& pszSubKey
[0])
2264 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2266 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2267 ZeroMemory(pvData
, *pcbData
);
2269 if (pdwType
) *pdwType
= dwType
;
2270 if (pcbData
) *pcbData
= cbData
;
2276 /************************************************************************
2282 RegSetKeyValueW(IN HKEY hKey
,
2283 IN LPCWSTR lpSubKey OPTIONAL
,
2284 IN LPCWSTR lpValueName OPTIONAL
,
2286 IN LPCVOID lpData OPTIONAL
,
2289 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2293 Status
= MapDefaultKey(&KeyHandle
,
2295 if (!NT_SUCCESS(Status
))
2297 return RtlNtStatusToDosError(Status
);
2300 if (lpSubKey
!= NULL
)
2302 OBJECT_ATTRIBUTES ObjectAttributes
;
2303 UNICODE_STRING SubKeyName
;
2305 RtlInitUnicodeString(&SubKeyName
,
2308 InitializeObjectAttributes(&ObjectAttributes
,
2310 OBJ_CASE_INSENSITIVE
,
2314 Status
= NtOpenKey(&SubKeyHandle
,
2317 if (!NT_SUCCESS(Status
))
2319 Ret
= RtlNtStatusToDosError(Status
);
2323 CurKey
= SubKeyHandle
;
2328 Ret
= RegSetValueExW(CurKey
,
2335 if (SubKeyHandle
!= NULL
)
2337 NtClose(SubKeyHandle
);
2341 ClosePredefKey(KeyHandle
);
2347 /************************************************************************
2353 RegSetKeyValueA(IN HKEY hKey
,
2354 IN LPCSTR lpSubKey OPTIONAL
,
2355 IN LPCSTR lpValueName OPTIONAL
,
2357 IN LPCVOID lpData OPTIONAL
,
2360 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2364 Status
= MapDefaultKey(&KeyHandle
,
2366 if (!NT_SUCCESS(Status
))
2368 return RtlNtStatusToDosError(Status
);
2371 if (lpSubKey
!= NULL
)
2373 OBJECT_ATTRIBUTES ObjectAttributes
;
2374 UNICODE_STRING SubKeyName
;
2376 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2379 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2383 InitializeObjectAttributes(&ObjectAttributes
,
2385 OBJ_CASE_INSENSITIVE
,
2389 Status
= NtOpenKey(&SubKeyHandle
,
2393 RtlFreeUnicodeString(&SubKeyName
);
2395 if (!NT_SUCCESS(Status
))
2397 Ret
= RtlNtStatusToDosError(Status
);
2401 CurKey
= SubKeyHandle
;
2406 Ret
= RegSetValueExA(CurKey
,
2413 if (SubKeyHandle
!= NULL
)
2415 NtClose(SubKeyHandle
);
2419 ClosePredefKey(KeyHandle
);
2425 /************************************************************************
2431 RegDeleteValueA(HKEY hKey
,
2434 UNICODE_STRING ValueName
;
2438 Status
= MapDefaultKey(&KeyHandle
,
2440 if (!NT_SUCCESS(Status
))
2442 return RtlNtStatusToDosError(Status
);
2445 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2446 (LPSTR
)lpValueName
);
2447 Status
= NtDeleteValueKey(KeyHandle
,
2449 RtlFreeUnicodeString (&ValueName
);
2451 ClosePredefKey(KeyHandle
);
2453 if (!NT_SUCCESS(Status
))
2455 return RtlNtStatusToDosError(Status
);
2458 return ERROR_SUCCESS
;
2462 /************************************************************************
2468 RegDeleteValueW(HKEY hKey
,
2469 LPCWSTR lpValueName
)
2471 UNICODE_STRING ValueName
;
2475 Status
= MapDefaultKey(&KeyHandle
,
2477 if (!NT_SUCCESS(Status
))
2479 return RtlNtStatusToDosError(Status
);
2482 RtlInitUnicodeString(&ValueName
,
2483 (LPWSTR
)lpValueName
);
2485 Status
= NtDeleteValueKey(KeyHandle
,
2488 ClosePredefKey(KeyHandle
);
2490 if (!NT_SUCCESS(Status
))
2492 return RtlNtStatusToDosError(Status
);
2495 return ERROR_SUCCESS
;
2499 /************************************************************************
2505 RegEnumKeyA(HKEY hKey
,
2513 return RegEnumKeyExA(hKey
,
2524 /************************************************************************
2530 RegEnumKeyW(HKEY hKey
,
2538 return RegEnumKeyExW(hKey
,
2549 /************************************************************************
2555 RegEnumKeyExA(HKEY hKey
,
2562 PFILETIME lpftLastWriteTime
)
2566 KEY_NODE_INFORMATION Node
;
2567 KEY_BASIC_INFORMATION Basic
;
2570 UNICODE_STRING StringU
;
2571 ANSI_STRING StringA
;
2572 LONG ErrorCode
= ERROR_SUCCESS
;
2574 DWORD ClassLength
= 0;
2580 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2581 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2583 if ((lpClass
) && (!lpcbClass
))
2585 return ERROR_INVALID_PARAMETER
;
2588 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2589 if (!NT_SUCCESS(Status
))
2591 return RtlNtStatusToDosError(Status
);
2596 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2607 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2614 /* The class name should start at a dword boundary */
2615 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2619 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2622 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2623 if (KeyInfo
== NULL
)
2625 ErrorCode
= ERROR_OUTOFMEMORY
;
2629 Status
= NtEnumerateKey(KeyHandle
,
2631 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2635 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2636 if (!NT_SUCCESS(Status
))
2638 ErrorCode
= RtlNtStatusToDosError (Status
);
2642 if (lpClass
== NULL
)
2644 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2646 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2650 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2651 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2652 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2657 if (KeyInfo
->Node
.NameLength
> NameLength
||
2658 KeyInfo
->Node
.ClassLength
> ClassLength
)
2660 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2664 StringA
.Buffer
= lpClass
;
2666 StringA
.MaximumLength
= *lpcbClass
;
2667 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2668 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2669 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2670 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2671 lpClass
[StringA
.Length
] = 0;
2672 *lpcbClass
= StringA
.Length
;
2673 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2674 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2675 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2679 if (ErrorCode
== ERROR_SUCCESS
)
2681 StringA
.Buffer
= lpName
;
2683 StringA
.MaximumLength
= *lpcbName
;
2684 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2685 lpName
[StringA
.Length
] = 0;
2686 *lpcbName
= StringA
.Length
;
2687 if (lpftLastWriteTime
!= NULL
)
2689 if (lpClass
== NULL
)
2691 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2692 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2696 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2697 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2703 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2704 TRACE("Key Name1 Length %d\n", NameLength
);
2705 TRACE("Key Name Length %d\n", *lpcbName
);
2706 TRACE("Key Name %s\n", lpName
);
2708 RtlFreeHeap(ProcessHeap
,
2713 ClosePredefKey(KeyHandle
);
2719 /************************************************************************
2725 RegEnumKeyExW(HKEY hKey
,
2732 PFILETIME lpftLastWriteTime
)
2736 KEY_NODE_INFORMATION Node
;
2737 KEY_BASIC_INFORMATION Basic
;
2743 ULONG ClassLength
= 0;
2745 LONG ErrorCode
= ERROR_SUCCESS
;
2748 Status
= MapDefaultKey(&KeyHandle
,
2750 if (!NT_SUCCESS(Status
))
2752 return RtlNtStatusToDosError(Status
);
2757 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2768 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2775 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2779 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2782 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2785 if (KeyInfo
== NULL
)
2787 ErrorCode
= ERROR_OUTOFMEMORY
;
2791 Status
= NtEnumerateKey(KeyHandle
,
2793 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2797 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2798 if (!NT_SUCCESS(Status
))
2800 ErrorCode
= RtlNtStatusToDosError (Status
);
2804 if (lpClass
== NULL
)
2806 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2808 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2812 RtlCopyMemory(lpName
,
2813 KeyInfo
->Basic
.Name
,
2814 KeyInfo
->Basic
.NameLength
);
2815 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2816 lpName
[*lpcbName
] = 0;
2821 if (KeyInfo
->Node
.NameLength
> NameLength
||
2822 KeyInfo
->Node
.ClassLength
> ClassLength
)
2824 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2828 RtlCopyMemory(lpName
,
2830 KeyInfo
->Node
.NameLength
);
2831 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2832 lpName
[*lpcbName
] = 0;
2833 RtlCopyMemory(lpClass
,
2834 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2835 KeyInfo
->Node
.ClassLength
);
2836 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2837 lpClass
[*lpcbClass
] = 0;
2841 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2843 if (lpClass
== NULL
)
2845 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2846 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2850 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2851 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2856 RtlFreeHeap(ProcessHeap
,
2861 ClosePredefKey(KeyHandle
);
2867 /************************************************************************
2873 RegEnumValueA(HKEY hKey
,
2885 char buffer
[256], *buf_ptr
= buffer
;
2886 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2887 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2889 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2890 // hkey, index, value, val_count, reserved, type, data, count );
2892 /* NT only checks count, not val_count */
2893 if ((data
&& !count
) || reserved
)
2894 return ERROR_INVALID_PARAMETER
;
2896 status
= MapDefaultKey(&KeyHandle
, hKey
);
2897 if (!NT_SUCCESS(status
))
2899 return RtlNtStatusToDosError(status
);
2902 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2903 if (data
) total_size
+= *count
;
2904 total_size
= min( sizeof(buffer
), total_size
);
2906 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2907 buffer
, total_size
, &total_size
);
2908 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2910 /* we need to fetch the contents for a string type even if not requested,
2911 * because we need to compute the length of the ASCII string. */
2912 if (value
|| data
|| is_string(info
->Type
))
2914 /* retry with a dynamically allocated buffer */
2915 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2917 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2918 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2920 status
= STATUS_INSUFFICIENT_RESOURCES
;
2923 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2924 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2925 buf_ptr
, total_size
, &total_size
);
2928 if (status
) goto done
;
2930 if (is_string(info
->Type
))
2933 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2937 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2940 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2942 /* if the type is REG_SZ and data is not 0-terminated
2943 * and there is enough space in the buffer NT appends a \0 */
2944 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2947 info
->DataLength
= len
;
2951 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2952 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2955 if (value
&& !status
)
2959 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2960 if (len
>= *val_count
)
2962 status
= STATUS_BUFFER_OVERFLOW
;
2965 len
= *val_count
- 1;
2966 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2972 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2978 else status
= STATUS_SUCCESS
;
2980 if (type
) *type
= info
->Type
;
2981 if (count
) *count
= info
->DataLength
;
2984 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2985 ClosePredefKey(KeyHandle
);
2986 return RtlNtStatusToDosError(status
);
2990 /******************************************************************************
2991 * RegEnumValueW [ADVAPI32.@]
2995 * hkey [I] Handle to key to query
2996 * index [I] Index of value to query
2997 * value [O] Value string
2998 * val_count [I/O] Size of value buffer (in wchars)
2999 * reserved [I] Reserved
3000 * type [O] Type code
3001 * data [O] Value data
3002 * count [I/O] Size of data buffer (in bytes)
3005 * Success: ERROR_SUCCESS
3006 * Failure: nonzero error code from Winerror.h
3009 RegEnumValueW(HKEY hKey
,
3021 char buffer
[256], *buf_ptr
= buffer
;
3022 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
3023 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
3025 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
3026 // hkey, index, value, val_count, reserved, type, data, count );
3028 /* NT only checks count, not val_count */
3029 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3031 status
= MapDefaultKey(&KeyHandle
, hKey
);
3032 if (!NT_SUCCESS(status
))
3034 return RtlNtStatusToDosError(status
);
3037 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
3038 if (data
) total_size
+= *count
;
3039 total_size
= min( sizeof(buffer
), total_size
);
3041 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3042 buffer
, total_size
, &total_size
);
3043 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
3047 /* retry with a dynamically allocated buffer */
3048 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
3050 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3051 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3053 status
= ERROR_NOT_ENOUGH_MEMORY
;
3056 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
3057 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3058 buf_ptr
, total_size
, &total_size
);
3061 if (status
) goto done
;
3065 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3067 status
= STATUS_BUFFER_OVERFLOW
;
3070 memcpy( value
, info
->Name
, info
->NameLength
);
3071 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3072 value
[*val_count
] = 0;
3077 if (info
->DataLength
> *count
)
3079 status
= STATUS_BUFFER_OVERFLOW
;
3082 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3083 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3085 /* if the type is REG_SZ and data is not 0-terminated
3086 * and there is enough space in the buffer NT appends a \0 */
3087 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3088 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3092 else status
= STATUS_SUCCESS
;
3095 if (type
) *type
= info
->Type
;
3096 if (count
) *count
= info
->DataLength
;
3099 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3100 ClosePredefKey(KeyHandle
);
3101 return RtlNtStatusToDosError(status
);
3105 /************************************************************************
3111 RegFlushKey(HKEY hKey
)
3116 if (hKey
== HKEY_PERFORMANCE_DATA
)
3118 return ERROR_SUCCESS
;
3121 Status
= MapDefaultKey(&KeyHandle
,
3123 if (!NT_SUCCESS(Status
))
3125 return RtlNtStatusToDosError(Status
);
3128 Status
= NtFlushKey(KeyHandle
);
3130 ClosePredefKey(KeyHandle
);
3132 if (!NT_SUCCESS(Status
))
3134 return RtlNtStatusToDosError(Status
);
3137 return ERROR_SUCCESS
;
3141 /************************************************************************
3147 RegGetKeySecurity(HKEY hKey
,
3148 SECURITY_INFORMATION SecurityInformation
,
3149 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3150 LPDWORD lpcbSecurityDescriptor
)
3155 if (hKey
== HKEY_PERFORMANCE_DATA
)
3157 return ERROR_INVALID_HANDLE
;
3160 Status
= MapDefaultKey(&KeyHandle
,
3162 if (!NT_SUCCESS(Status
))
3164 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3165 return RtlNtStatusToDosError(Status
);
3169 Status
= NtQuerySecurityObject(KeyHandle
,
3170 SecurityInformation
,
3171 pSecurityDescriptor
,
3172 *lpcbSecurityDescriptor
,
3173 lpcbSecurityDescriptor
);
3176 ClosePredefKey(KeyHandle
);
3178 if (!NT_SUCCESS(Status
))
3180 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3181 return RtlNtStatusToDosError(Status
);
3184 return ERROR_SUCCESS
;
3188 /************************************************************************
3194 RegLoadKeyA(HKEY hKey
,
3198 UNICODE_STRING FileName
;
3199 UNICODE_STRING KeyName
;
3202 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3204 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3207 ErrorCode
= RegLoadKeyW(hKey
,
3211 RtlFreeUnicodeString(&FileName
);
3212 RtlFreeUnicodeString(&KeyName
);
3218 /************************************************************************
3224 RegLoadKeyW(HKEY hKey
,
3228 OBJECT_ATTRIBUTES FileObjectAttributes
;
3229 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3230 UNICODE_STRING FileName
;
3231 UNICODE_STRING KeyName
;
3234 LONG ErrorCode
= ERROR_SUCCESS
;
3236 if (hKey
== HKEY_PERFORMANCE_DATA
)
3238 return ERROR_INVALID_HANDLE
;
3241 Status
= MapDefaultKey(&KeyHandle
,
3243 if (!NT_SUCCESS(Status
))
3245 return RtlNtStatusToDosError(Status
);
3248 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3253 ErrorCode
= ERROR_BAD_PATHNAME
;
3257 InitializeObjectAttributes(&FileObjectAttributes
,
3259 OBJ_CASE_INSENSITIVE
,
3263 RtlInitUnicodeString(&KeyName
,
3266 InitializeObjectAttributes(&KeyObjectAttributes
,
3268 OBJ_CASE_INSENSITIVE
,
3272 Status
= NtLoadKey(&KeyObjectAttributes
,
3273 &FileObjectAttributes
);
3275 RtlFreeHeap(RtlGetProcessHeap(),
3279 if (!NT_SUCCESS(Status
))
3281 ErrorCode
= RtlNtStatusToDosError(Status
);
3286 ClosePredefKey(KeyHandle
);
3292 /************************************************************************
3293 * RegNotifyChangeKeyValue
3298 RegNotifyChangeKeyValue(HKEY hKey
,
3300 DWORD dwNotifyFilter
,
3304 IO_STATUS_BLOCK IoStatusBlock
;
3307 LONG ErrorCode
= ERROR_SUCCESS
;
3309 if (hKey
== HKEY_PERFORMANCE_DATA
)
3311 return ERROR_INVALID_HANDLE
;
3314 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3316 return ERROR_INVALID_PARAMETER
;
3319 Status
= MapDefaultKey(&KeyHandle
,
3321 if (!NT_SUCCESS(Status
))
3323 return RtlNtStatusToDosError(Status
);
3326 /* FIXME: Remote key handles must fail */
3328 Status
= NtNotifyChangeKey(KeyHandle
,
3338 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3340 ErrorCode
= RtlNtStatusToDosError(Status
);
3343 ClosePredefKey(KeyHandle
);
3349 /************************************************************************
3350 * RegOpenCurrentUser
3355 RegOpenCurrentUser(IN REGSAM samDesired
,
3356 OUT PHKEY phkResult
)
3360 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3361 (PHANDLE
)phkResult
);
3362 if (!NT_SUCCESS(Status
))
3364 /* NOTE - don't set the last error code! just return the error! */
3365 return RtlNtStatusToDosError(Status
);
3368 return ERROR_SUCCESS
;
3372 /************************************************************************
3375 * 20050503 Fireball - imported from WINE
3380 RegOpenKeyA(HKEY hKey
,
3384 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3385 hKey
, lpSubKey
, phkResult
);
3388 return ERROR_INVALID_PARAMETER
;
3390 if (!hKey
&& lpSubKey
&& phkResult
)
3392 return ERROR_INVALID_HANDLE
;
3395 if (!lpSubKey
|| !*lpSubKey
)
3398 return ERROR_SUCCESS
;
3401 return RegOpenKeyExA(hKey
,
3409 /************************************************************************
3414 * 20050503 Fireball - imported from WINE
3419 RegOpenKeyW(HKEY hKey
,
3423 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3424 hKey
, lpSubKey
, phkResult
);
3427 return ERROR_INVALID_PARAMETER
;
3429 if (!hKey
&& lpSubKey
&& phkResult
)
3431 return ERROR_INVALID_HANDLE
;
3434 if (!lpSubKey
|| !*lpSubKey
)
3437 return ERROR_SUCCESS
;
3440 return RegOpenKeyExW(hKey
,
3448 /************************************************************************
3454 RegOpenKeyExA(HKEY hKey
,
3460 OBJECT_ATTRIBUTES ObjectAttributes
;
3461 UNICODE_STRING SubKeyString
;
3464 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3465 LONG ErrorCode
= ERROR_SUCCESS
;
3467 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3468 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3471 return ERROR_INVALID_PARAMETER
;
3474 Status
= MapDefaultKey(&KeyHandle
,
3476 if (!NT_SUCCESS(Status
))
3478 return RtlNtStatusToDosError(Status
);
3481 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3482 Attributes
|= OBJ_OPENLINK
;
3484 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3486 InitializeObjectAttributes(&ObjectAttributes
,
3492 Status
= NtOpenKey((PHANDLE
)phkResult
,
3495 RtlFreeUnicodeString(&SubKeyString
);
3496 if (!NT_SUCCESS(Status
))
3498 ErrorCode
= RtlNtStatusToDosError(Status
);
3501 ClosePredefKey(KeyHandle
);
3507 /************************************************************************
3513 RegOpenKeyExW(HKEY hKey
,
3519 OBJECT_ATTRIBUTES ObjectAttributes
;
3520 UNICODE_STRING SubKeyString
;
3523 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3524 LONG ErrorCode
= ERROR_SUCCESS
;
3526 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3527 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3530 return ERROR_INVALID_PARAMETER
;
3533 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3534 if (!NT_SUCCESS(Status
))
3536 return RtlNtStatusToDosError(Status
);
3539 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3540 Attributes
|= OBJ_OPENLINK
;
3542 if (lpSubKey
!= NULL
)
3543 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3545 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3547 InitializeObjectAttributes(&ObjectAttributes
,
3553 Status
= NtOpenKey((PHANDLE
)phkResult
,
3556 if (!NT_SUCCESS(Status
))
3558 ErrorCode
= RtlNtStatusToDosError(Status
);
3561 ClosePredefKey(KeyHandle
);
3567 /************************************************************************
3568 * RegOpenUserClassesRoot
3573 RegOpenUserClassesRoot(IN HANDLE hToken
,
3575 IN REGSAM samDesired
,
3576 OUT PHKEY phkResult
)
3578 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3579 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3580 PTOKEN_USER TokenUserData
;
3581 ULONG RequiredLength
;
3582 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3583 OBJECT_ATTRIBUTES ObjectAttributes
;
3586 /* check parameters */
3587 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3589 return ERROR_INVALID_PARAMETER
;
3593 * Get the user sid from the token
3597 /* determine how much memory we need */
3598 Status
= NtQueryInformationToken(hToken
,
3603 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3605 /* NOTE - as opposed to all other registry functions windows does indeed
3606 change the last error code in case the caller supplied a invalid
3607 handle for example! */
3608 return RtlNtStatusToDosError(Status
);
3610 RegInitialize(); /* HACK until delay-loading is implemented */
3611 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3614 if (TokenUserData
== NULL
)
3616 return ERROR_NOT_ENOUGH_MEMORY
;
3619 /* attempt to read the information */
3620 Status
= NtQueryInformationToken(hToken
,
3625 if (!NT_SUCCESS(Status
))
3627 RtlFreeHeap(ProcessHeap
,
3630 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3632 /* the information appears to have changed?! try again */
3636 /* NOTE - as opposed to all other registry functions windows does indeed
3637 change the last error code in case the caller supplied a invalid
3638 handle for example! */
3639 return RtlNtStatusToDosError(Status
);
3643 * Build the absolute path for the user's registry in the form
3644 * "\Registry\User\<SID>_Classes"
3646 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3647 TokenUserData
->User
.Sid
,
3650 /* we don't need the user data anymore, free it */
3651 RtlFreeHeap(ProcessHeap
,
3655 if (!NT_SUCCESS(Status
))
3657 return RtlNtStatusToDosError(Status
);
3660 /* allocate enough memory for the entire key string */
3661 UserClassesKeyRoot
.Length
= 0;
3662 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3663 sizeof(UserClassesKeyPrefix
) +
3664 sizeof(UserClassesKeySuffix
);
3665 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3667 UserClassesKeyRoot
.MaximumLength
);
3668 if (UserClassesKeyRoot
.Buffer
== NULL
)
3670 RtlFreeUnicodeString(&UserSidString
);
3671 return RtlNtStatusToDosError(Status
);
3674 /* build the string */
3675 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3676 UserClassesKeyPrefix
);
3677 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3679 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3680 UserClassesKeySuffix
);
3682 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3687 InitializeObjectAttributes(&ObjectAttributes
,
3688 &UserClassesKeyRoot
,
3689 OBJ_CASE_INSENSITIVE
,
3693 Status
= NtOpenKey((PHANDLE
)phkResult
,
3697 RtlFreeUnicodeString(&UserSidString
);
3698 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3700 if (!NT_SUCCESS(Status
))
3702 return RtlNtStatusToDosError(Status
);
3705 return ERROR_SUCCESS
;
3709 /************************************************************************
3715 RegQueryInfoKeyA(HKEY hKey
,
3720 LPDWORD lpcbMaxSubKeyLen
,
3721 LPDWORD lpcbMaxClassLen
,
3723 LPDWORD lpcbMaxValueNameLen
,
3724 LPDWORD lpcbMaxValueLen
,
3725 LPDWORD lpcbSecurityDescriptor
,
3726 PFILETIME lpftLastWriteTime
)
3728 WCHAR ClassName
[MAX_PATH
];
3729 UNICODE_STRING UnicodeString
;
3730 ANSI_STRING AnsiString
;
3733 RtlInitUnicodeString(&UnicodeString
,
3735 if (lpClass
!= NULL
)
3737 UnicodeString
.Buffer
= &ClassName
[0];
3738 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3739 AnsiString
.MaximumLength
= *lpcbClass
;
3742 ErrorCode
= RegQueryInfoKeyW(hKey
,
3743 UnicodeString
.Buffer
,
3750 lpcbMaxValueNameLen
,
3752 lpcbSecurityDescriptor
,
3754 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3756 AnsiString
.Buffer
= lpClass
;
3757 AnsiString
.Length
= 0;
3758 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3759 RtlUnicodeStringToAnsiString(&AnsiString
,
3762 *lpcbClass
= AnsiString
.Length
;
3763 lpClass
[AnsiString
.Length
] = 0;
3770 /************************************************************************
3776 RegQueryInfoKeyW(HKEY hKey
,
3781 LPDWORD lpcbMaxSubKeyLen
,
3782 LPDWORD lpcbMaxClassLen
,
3784 LPDWORD lpcbMaxValueNameLen
,
3785 LPDWORD lpcbMaxValueLen
,
3786 LPDWORD lpcbSecurityDescriptor
,
3787 PFILETIME lpftLastWriteTime
)
3789 KEY_FULL_INFORMATION FullInfoBuffer
;
3790 PKEY_FULL_INFORMATION FullInfo
;
3792 ULONG ClassLength
= 0;
3796 LONG ErrorCode
= ERROR_SUCCESS
;
3798 if ((lpClass
) && (!lpcbClass
))
3800 return ERROR_INVALID_PARAMETER
;
3803 Status
= MapDefaultKey(&KeyHandle
,
3805 if (!NT_SUCCESS(Status
))
3807 return RtlNtStatusToDosError(Status
);
3810 if (lpClass
!= NULL
)
3814 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3821 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3822 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3825 if (FullInfo
== NULL
)
3827 ErrorCode
= ERROR_OUTOFMEMORY
;
3831 FullInfo
->ClassLength
= ClassLength
;
3835 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3836 FullInfo
= &FullInfoBuffer
;
3837 FullInfo
->ClassLength
= 0;
3839 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3841 Status
= NtQueryKey(KeyHandle
,
3846 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3847 if (!NT_SUCCESS(Status
))
3849 if (lpClass
!= NULL
)
3851 RtlFreeHeap(ProcessHeap
,
3856 ErrorCode
= RtlNtStatusToDosError(Status
);
3860 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3861 if (lpcSubKeys
!= NULL
)
3863 *lpcSubKeys
= FullInfo
->SubKeys
;
3866 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3867 if (lpcbMaxSubKeyLen
!= NULL
)
3869 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3872 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3873 if (lpcbMaxClassLen
!= NULL
)
3875 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3878 TRACE("Values %lu\n", FullInfo
->Values
);
3879 if (lpcValues
!= NULL
)
3881 *lpcValues
= FullInfo
->Values
;
3884 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3885 if (lpcbMaxValueNameLen
!= NULL
)
3887 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3890 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3891 if (lpcbMaxValueLen
!= NULL
)
3893 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3897 if (lpcbSecurityDescriptor
!= NULL
)
3899 Status
= NtQuerySecurityObject(KeyHandle
,
3900 OWNER_SECURITY_INFORMATION
|
3901 GROUP_SECURITY_INFORMATION
|
3902 DACL_SECURITY_INFORMATION
,
3905 lpcbSecurityDescriptor
);
3906 if (!NT_SUCCESS(Status
))
3908 if (lpClass
!= NULL
)
3910 RtlFreeHeap(ProcessHeap
,
3915 ErrorCode
= RtlNtStatusToDosError(Status
);
3921 if (lpftLastWriteTime
!= NULL
)
3923 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3924 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3927 if (lpClass
!= NULL
)
3929 if (FullInfo
->ClassLength
> ClassLength
)
3931 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3935 RtlCopyMemory(lpClass
,
3937 FullInfo
->ClassLength
);
3938 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3939 lpClass
[*lpcbClass
] = 0;
3942 RtlFreeHeap(ProcessHeap
,
3948 ClosePredefKey(KeyHandle
);
3954 /************************************************************************
3955 * RegQueryMultipleValuesA
3960 RegQueryMultipleValuesA(HKEY hKey
,
3967 DWORD maxBytes
= *ldwTotsize
;
3968 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3971 if (maxBytes
>= (1024*1024))
3972 return ERROR_TRANSFER_TOO_LONG
;
3976 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3977 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3979 for (i
= 0; i
< num_vals
; i
++)
3981 val_list
[i
].ve_valuelen
= 0;
3982 ErrorCode
= RegQueryValueExA(hKey
,
3983 val_list
[i
].ve_valuename
,
3987 &val_list
[i
].ve_valuelen
);
3988 if (ErrorCode
!= ERROR_SUCCESS
)
3993 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3995 ErrorCode
= RegQueryValueExA(hKey
,
3996 val_list
[i
].ve_valuename
,
3998 &val_list
[i
].ve_type
,
4000 &val_list
[i
].ve_valuelen
);
4001 if (ErrorCode
!= ERROR_SUCCESS
)
4006 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
4008 bufptr
+= val_list
[i
].ve_valuelen
;
4011 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
4014 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
4018 /************************************************************************
4019 * RegQueryMultipleValuesW
4024 RegQueryMultipleValuesW(HKEY hKey
,
4031 DWORD maxBytes
= *ldwTotsize
;
4032 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
4035 if (maxBytes
>= (1024*1024))
4036 return ERROR_TRANSFER_TOO_LONG
;
4040 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
4041 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
4043 for (i
= 0; i
< num_vals
; i
++)
4045 val_list
[i
].ve_valuelen
= 0;
4046 ErrorCode
= RegQueryValueExW(hKey
,
4047 val_list
[i
].ve_valuename
,
4051 &val_list
[i
].ve_valuelen
);
4052 if (ErrorCode
!= ERROR_SUCCESS
)
4057 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
4059 ErrorCode
= RegQueryValueExW(hKey
,
4060 val_list
[i
].ve_valuename
,
4062 &val_list
[i
].ve_type
,
4064 &val_list
[i
].ve_valuelen
);
4065 if (ErrorCode
!= ERROR_SUCCESS
)
4070 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
4072 bufptr
+= val_list
[i
].ve_valuelen
;
4075 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
4078 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
4082 /************************************************************************
4083 * RegQueryReflectionKey
4088 RegQueryReflectionKey(IN HKEY hBase
,
4089 OUT BOOL
* bIsReflectionDisabled
)
4091 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4092 hBase
, bIsReflectionDisabled
);
4093 return ERROR_CALL_NOT_IMPLEMENTED
;
4097 /******************************************************************************
4098 * RegQueryValueExA [ADVAPI32.@]
4100 * Get the type and contents of a specified value under with a key.
4103 * hkey [I] Handle of the key to query
4104 * name [I] Name of value under hkey to query
4105 * reserved [I] Reserved - must be NULL
4106 * type [O] Destination for the value type, or NULL if not required
4107 * data [O] Destination for the values contents, or NULL if not required
4108 * count [I/O] Size of data, updated with the number of bytes returned
4111 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4112 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4113 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4114 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4117 * MSDN states that if data is too small it is partially filled. In reality
4118 * it remains untouched.
4122 RegQueryValueExA(HKEY hkeyorg
,
4132 UNICODE_STRING nameW
;
4133 DWORD total_size
, datalen
= 0;
4134 char buffer
[256], *buf_ptr
= buffer
;
4135 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4136 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4138 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4139 hkeyorg
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
4141 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4142 status
= MapDefaultKey(&hkey
, hkeyorg
);
4143 if (!NT_SUCCESS(status
))
4145 return RtlNtStatusToDosError(status
);
4148 if (count
) datalen
= *count
;
4149 if (!data
&& count
) *count
= 0;
4151 RtlInitAnsiString( &nameA
, name
);
4152 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
4154 ClosePredefKey(hkey
);
4155 return RtlNtStatusToDosError(status
);
4158 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4159 buffer
, sizeof(buffer
), &total_size
);
4160 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4162 /* we need to fetch the contents for a string type even if not requested,
4163 * because we need to compute the length of the ASCII string. */
4164 if (data
|| is_string(info
->Type
))
4166 /* retry with a dynamically allocated buffer */
4167 while (status
== STATUS_BUFFER_OVERFLOW
)
4169 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4170 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4172 status
= STATUS_NO_MEMORY
;
4175 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4176 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4177 buf_ptr
, total_size
, &total_size
);
4180 if (status
) goto done
;
4182 if (is_string(info
->Type
))
4186 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
4187 total_size
- info_size
);
4190 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4193 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
4194 total_size
- info_size
);
4195 /* if the type is REG_SZ and data is not 0-terminated
4196 * and there is enough space in the buffer NT appends a \0 */
4197 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
4200 total_size
= len
+ info_size
;
4204 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4205 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4208 else status
= STATUS_SUCCESS
;
4210 if (type
) *type
= info
->Type
;
4211 if (count
) *count
= total_size
- info_size
;
4214 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4215 RtlFreeUnicodeString( &nameW
);
4216 ClosePredefKey(hkey
);
4217 return RtlNtStatusToDosError(status
);
4221 /************************************************************************
4228 RegQueryValueExW(HKEY hkeyorg
,
4237 UNICODE_STRING name_str
;
4239 char buffer
[256], *buf_ptr
= buffer
;
4240 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4241 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4243 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4244 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4245 (count
&& data
) ? *count
: 0 );
4247 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4249 status
= MapDefaultKey(&hkey
, hkeyorg
);
4250 if (!NT_SUCCESS(status
))
4252 return RtlNtStatusToDosError(status
);
4255 RtlInitUnicodeString( &name_str
, name
);
4257 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4260 total_size
= info_size
;
4261 if (count
) *count
= 0;
4264 /* this matches Win9x behaviour - NT sets *type to a random value */
4265 if (type
) *type
= REG_NONE
;
4267 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4268 buffer
, total_size
, &total_size
);
4269 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4273 /* retry with a dynamically allocated buffer */
4274 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4276 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4277 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4279 ClosePredefKey(hkey
);
4280 return ERROR_NOT_ENOUGH_MEMORY
;
4282 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4283 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4284 buf_ptr
, total_size
, &total_size
);
4287 if (NT_SUCCESS(status
))
4289 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4290 /* if the type is REG_SZ and data is not 0-terminated
4291 * and there is enough space in the buffer NT appends a \0 */
4292 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4294 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4295 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4298 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4300 else status
= STATUS_SUCCESS
;
4302 if (type
) *type
= info
->Type
;
4303 if (count
) *count
= total_size
- info_size
;
4306 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4307 ClosePredefKey(hkey
);
4308 return RtlNtStatusToDosError(status
);
4312 /************************************************************************
4317 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4322 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4324 if (name
&& name
[0])
4326 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4328 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4329 if (subkey
!= hkey
) RegCloseKey( subkey
);
4330 if (ret
== ERROR_FILE_NOT_FOUND
)
4332 /* return empty string if default value not found */
4333 if (data
) *data
= 0;
4334 if (count
) *count
= 1;
4335 ret
= ERROR_SUCCESS
;
4341 /************************************************************************
4346 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4351 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4354 return ERROR_INVALID_HANDLE
;
4356 if (name
&& name
[0])
4358 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4359 if (ret
!= ERROR_SUCCESS
)
4365 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4369 RegCloseKey( subkey
);
4372 if (ret
== ERROR_FILE_NOT_FOUND
)
4374 /* return empty string if default value not found */
4378 *count
= sizeof(WCHAR
);
4379 ret
= ERROR_SUCCESS
;
4385 /************************************************************************
4391 RegReplaceKeyA(HKEY hKey
,
4396 UNICODE_STRING SubKey
;
4397 UNICODE_STRING NewFile
;
4398 UNICODE_STRING OldFile
;
4401 RtlCreateUnicodeStringFromAsciiz(&SubKey
,
4403 RtlCreateUnicodeStringFromAsciiz(&OldFile
,
4405 RtlCreateUnicodeStringFromAsciiz(&NewFile
,
4408 ErrorCode
= RegReplaceKeyW(hKey
,
4413 RtlFreeUnicodeString(&OldFile
);
4414 RtlFreeUnicodeString(&NewFile
);
4415 RtlFreeUnicodeString(&SubKey
);
4421 /************************************************************************
4427 RegReplaceKeyW(HKEY hKey
,
4432 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4433 OBJECT_ATTRIBUTES NewObjectAttributes
;
4434 OBJECT_ATTRIBUTES OldObjectAttributes
;
4435 UNICODE_STRING SubKeyName
;
4436 UNICODE_STRING NewFileName
;
4437 UNICODE_STRING OldFileName
;
4438 BOOLEAN CloseRealKey
;
4439 HANDLE RealKeyHandle
;
4442 LONG ErrorCode
= ERROR_SUCCESS
;
4444 if (hKey
== HKEY_PERFORMANCE_DATA
)
4446 return ERROR_INVALID_HANDLE
;
4449 Status
= MapDefaultKey(&KeyHandle
,
4451 if (!NT_SUCCESS(Status
))
4453 return RtlNtStatusToDosError(Status
);
4456 /* Open the real key */
4457 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4459 RtlInitUnicodeString(&SubKeyName
,
4461 InitializeObjectAttributes(&KeyObjectAttributes
,
4463 OBJ_CASE_INSENSITIVE
,
4466 Status
= NtOpenKey(&RealKeyHandle
,
4468 &KeyObjectAttributes
);
4469 if (!NT_SUCCESS(Status
))
4471 ErrorCode
= RtlNtStatusToDosError(Status
);
4475 CloseRealKey
= TRUE
;
4479 RealKeyHandle
= KeyHandle
;
4480 CloseRealKey
= FALSE
;
4483 /* Convert new file name */
4484 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4491 NtClose(RealKeyHandle
);
4494 ErrorCode
= ERROR_INVALID_PARAMETER
;
4498 InitializeObjectAttributes(&NewObjectAttributes
,
4500 OBJ_CASE_INSENSITIVE
,
4504 /* Convert old file name */
4505 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4510 RtlFreeHeap(RtlGetProcessHeap (),
4512 NewFileName
.Buffer
);
4515 NtClose(RealKeyHandle
);
4518 ErrorCode
= ERROR_INVALID_PARAMETER
;
4522 InitializeObjectAttributes(&OldObjectAttributes
,
4524 OBJ_CASE_INSENSITIVE
,
4528 Status
= NtReplaceKey(&NewObjectAttributes
,
4530 &OldObjectAttributes
);
4532 RtlFreeHeap(RtlGetProcessHeap(),
4534 OldFileName
.Buffer
);
4535 RtlFreeHeap(RtlGetProcessHeap(),
4537 NewFileName
.Buffer
);
4541 NtClose(RealKeyHandle
);
4544 if (!NT_SUCCESS(Status
))
4546 return RtlNtStatusToDosError(Status
);
4550 ClosePredefKey(KeyHandle
);
4556 /************************************************************************
4562 RegRestoreKeyA(HKEY hKey
,
4566 UNICODE_STRING FileName
;
4569 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4572 ErrorCode
= RegRestoreKeyW(hKey
,
4576 RtlFreeUnicodeString(&FileName
);
4582 /************************************************************************
4588 RegRestoreKeyW(HKEY hKey
,
4592 OBJECT_ATTRIBUTES ObjectAttributes
;
4593 IO_STATUS_BLOCK IoStatusBlock
;
4594 UNICODE_STRING FileName
;
4599 if (hKey
== HKEY_PERFORMANCE_DATA
)
4601 return ERROR_INVALID_HANDLE
;
4604 Status
= MapDefaultKey(&KeyHandle
,
4606 if (!NT_SUCCESS(Status
))
4608 return RtlNtStatusToDosError(Status
);
4611 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4616 Status
= STATUS_INVALID_PARAMETER
;
4620 InitializeObjectAttributes(&ObjectAttributes
,
4622 OBJ_CASE_INSENSITIVE
,
4626 Status
= NtOpenFile(&FileHandle
,
4631 FILE_SYNCHRONOUS_IO_NONALERT
);
4632 RtlFreeHeap(RtlGetProcessHeap(),
4635 if (!NT_SUCCESS(Status
))
4640 Status
= NtRestoreKey(KeyHandle
,
4643 NtClose (FileHandle
);
4646 ClosePredefKey(KeyHandle
);
4648 if (!NT_SUCCESS(Status
))
4650 return RtlNtStatusToDosError(Status
);
4653 return ERROR_SUCCESS
;
4657 /************************************************************************
4663 RegSaveKeyA(HKEY hKey
,
4665 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4667 UNICODE_STRING FileName
;
4670 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4672 ErrorCode
= RegSaveKeyW(hKey
,
4674 lpSecurityAttributes
);
4675 RtlFreeUnicodeString(&FileName
);
4681 /************************************************************************
4687 RegSaveKeyW(HKEY hKey
,
4689 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4691 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4692 OBJECT_ATTRIBUTES ObjectAttributes
;
4693 UNICODE_STRING FileName
;
4694 IO_STATUS_BLOCK IoStatusBlock
;
4699 Status
= MapDefaultKey(&KeyHandle
,
4701 if (!NT_SUCCESS(Status
))
4703 return RtlNtStatusToDosError(Status
);
4706 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4711 Status
= STATUS_INVALID_PARAMETER
;
4715 if (lpSecurityAttributes
!= NULL
)
4717 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4720 InitializeObjectAttributes(&ObjectAttributes
,
4722 OBJ_CASE_INSENSITIVE
,
4724 SecurityDescriptor
);
4725 Status
= NtCreateFile(&FileHandle
,
4726 GENERIC_WRITE
| SYNCHRONIZE
,
4730 FILE_ATTRIBUTE_NORMAL
,
4733 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4736 RtlFreeHeap(RtlGetProcessHeap(),
4739 if (!NT_SUCCESS(Status
))
4744 Status
= NtSaveKey(KeyHandle
,
4746 NtClose (FileHandle
);
4749 ClosePredefKey(KeyHandle
);
4751 if (!NT_SUCCESS(Status
))
4753 return RtlNtStatusToDosError(Status
);
4756 return ERROR_SUCCESS
;
4760 /************************************************************************
4767 RegSaveKeyExA(HKEY hKey
,
4769 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4772 UNICODE_STRING FileName
;
4775 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4777 ErrorCode
= RegSaveKeyExW(hKey
,
4779 lpSecurityAttributes
,
4781 RtlFreeUnicodeString(&FileName
);
4787 /************************************************************************
4794 RegSaveKeyExW(HKEY hKey
,
4796 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4801 case REG_STANDARD_FORMAT
:
4802 case REG_LATEST_FORMAT
:
4803 case REG_NO_COMPRESSION
:
4806 return ERROR_INVALID_PARAMETER
;
4809 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4811 return RegSaveKeyW(hKey
,
4813 lpSecurityAttributes
);
4817 /************************************************************************
4823 RegSetKeySecurity(HKEY hKey
,
4824 SECURITY_INFORMATION SecurityInformation
,
4825 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4830 if (hKey
== HKEY_PERFORMANCE_DATA
)
4832 return ERROR_INVALID_HANDLE
;
4835 Status
= MapDefaultKey(&KeyHandle
,
4837 if (!NT_SUCCESS(Status
))
4839 return RtlNtStatusToDosError(Status
);
4842 Status
= NtSetSecurityObject(KeyHandle
,
4843 SecurityInformation
,
4844 pSecurityDescriptor
);
4846 ClosePredefKey(KeyHandle
);
4848 if (!NT_SUCCESS(Status
))
4850 return RtlNtStatusToDosError(Status
);
4853 return ERROR_SUCCESS
;
4857 /************************************************************************
4863 RegSetValueExA(HKEY hKey
,
4870 UNICODE_STRING ValueName
;
4872 ANSI_STRING AnsiString
;
4873 UNICODE_STRING Data
;
4879 /* Convert SubKey name to Unicode */
4880 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4883 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4886 return ERROR_NOT_ENOUGH_MEMORY
;
4890 ValueName
.Buffer
= NULL
;
4893 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4896 if (is_string(dwType
) && (cbData
!= 0))
4898 /* Convert ANSI string Data to Unicode */
4899 /* If last character NOT zero then increment length */
4900 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4901 AnsiString
.Buffer
= (PSTR
)lpData
;
4902 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4903 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4904 Status
= RtlAnsiStringToUnicodeString(&Data
,
4908 if (!NT_SUCCESS(Status
))
4910 if (pValueName
!= NULL
)
4911 RtlFreeUnicodeString(&ValueName
);
4913 return RtlNtStatusToDosError(Status
);
4915 pData
= (LPBYTE
)Data
.Buffer
;
4916 DataSize
= cbData
* sizeof(WCHAR
);
4921 pData
= (LPBYTE
)lpData
;
4925 ErrorCode
= RegSetValueExW(hKey
,
4932 if (pValueName
!= NULL
)
4933 RtlFreeUnicodeString(&ValueName
);
4935 if (Data
.Buffer
!= NULL
)
4936 RtlFreeUnicodeString(&Data
);
4942 /************************************************************************
4948 RegSetValueExW(HKEY hKey
,
4949 LPCWSTR lpValueName
,
4955 UNICODE_STRING ValueName
;
4959 if (is_string(dwType
) && (cbData
!= 0))
4961 PWSTR pwsData
= (PWSTR
)lpData
;
4965 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4966 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4968 /* Increment length if last character is not zero and next is zero */
4969 cbData
+= sizeof(WCHAR
);
4972 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4974 _SEH2_YIELD(return ERROR_NOACCESS
);
4979 Status
= MapDefaultKey(&KeyHandle
,
4981 if (!NT_SUCCESS(Status
))
4983 return RtlNtStatusToDosError(Status
);
4986 RtlInitUnicodeString(&ValueName
, lpValueName
);
4988 Status
= NtSetValueKey(KeyHandle
,
4995 ClosePredefKey(KeyHandle
);
4997 if (!NT_SUCCESS(Status
))
4999 return RtlNtStatusToDosError(Status
);
5002 return ERROR_SUCCESS
;
5006 /************************************************************************
5012 RegSetValueA(HKEY hKeyOriginal
,
5023 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
5025 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
5027 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
5028 if (!NT_SUCCESS(Status
))
5030 return RtlNtStatusToDosError (Status
);
5034 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5036 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
5037 if (ret
!= ERROR_SUCCESS
)
5041 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
5043 RegCloseKey(subkey
);
5046 ClosePredefKey(hKey
);
5052 /************************************************************************
5058 RegSetValueW(HKEY hKeyOriginal
,
5069 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
5071 if (dwType
!= REG_SZ
|| !lpData
)
5072 return ERROR_INVALID_PARAMETER
;
5074 Status
= MapDefaultKey(&hKey
,
5076 if (!NT_SUCCESS(Status
))
5078 return RtlNtStatusToDosError(Status
);
5082 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5084 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
5085 if (ret
!= ERROR_SUCCESS
)
5089 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
5090 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
5092 RegCloseKey(subkey
);
5095 ClosePredefKey(hKey
);
5101 /************************************************************************
5107 RegUnLoadKeyA(HKEY hKey
,
5110 UNICODE_STRING KeyName
;
5113 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
5116 ErrorCode
= RegUnLoadKeyW(hKey
,
5119 RtlFreeUnicodeString (&KeyName
);
5125 /************************************************************************
5131 RegUnLoadKeyW(HKEY hKey
,
5134 OBJECT_ATTRIBUTES ObjectAttributes
;
5135 UNICODE_STRING KeyName
;
5139 if (hKey
== HKEY_PERFORMANCE_DATA
)
5141 return ERROR_INVALID_HANDLE
;
5144 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5145 if (!NT_SUCCESS(Status
))
5147 return RtlNtStatusToDosError(Status
);
5150 RtlInitUnicodeString(&KeyName
,
5153 InitializeObjectAttributes(&ObjectAttributes
,
5155 OBJ_CASE_INSENSITIVE
,
5159 Status
= NtUnloadKey(&ObjectAttributes
);
5161 ClosePredefKey(KeyHandle
);
5163 if (!NT_SUCCESS(Status
))
5165 return RtlNtStatusToDosError(Status
);
5168 return ERROR_SUCCESS
;
5172 /******************************************************************************
5173 * load_string [Internal]
5175 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5176 * avoid importing user32, which is higher level than advapi32. Helper for
5179 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5186 /* Negative values have to be inverted. */
5187 if (HIWORD(resId
) == 0xffff)
5188 resId
= (UINT
)(-((INT
)resId
));
5190 /* Load the resource into memory and get a pointer to it. */
5191 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5192 if (!hResource
) return 0;
5193 hMemory
= LoadResource(hModule
, hResource
);
5194 if (!hMemory
) return 0;
5195 pString
= LockResource(hMemory
);
5197 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5198 idxString
= resId
& 0xf;
5199 while (idxString
--) pString
+= *pString
+ 1;
5201 /* If no buffer is given, return length of the string. */
5202 if (!pwszBuffer
) return *pString
;
5204 /* Else copy over the string, respecting the buffer size. */
5205 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5208 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5209 pwszBuffer
[cMaxChars
] = L
'\0';
5216 /************************************************************************
5222 RegLoadMUIStringW(IN HKEY hKey
,
5223 IN LPCWSTR pszValue OPTIONAL
,
5224 OUT LPWSTR pszOutBuf
,
5226 OUT LPDWORD pcbData OPTIONAL
,
5228 IN LPCWSTR pszDirectory OPTIONAL
)
5230 DWORD dwValueType
, cbData
;
5231 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5234 /* Parameter sanity checks. */
5235 if (!hKey
|| !pszOutBuf
)
5236 return ERROR_INVALID_PARAMETER
;
5238 if (pszDirectory
&& *pszDirectory
)
5240 FIXME("BaseDir parameter not yet supported!\n");
5241 return ERROR_INVALID_PARAMETER
;
5244 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5245 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5246 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5247 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5249 result
= ERROR_FILE_NOT_FOUND
;
5252 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5253 if (!pwszTempBuffer
)
5255 result
= ERROR_NOT_ENOUGH_MEMORY
;
5258 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5259 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5261 /* Expand environment variables, if appropriate, or copy the original string over. */
5262 if (dwValueType
== REG_EXPAND_SZ
)
5264 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5265 if (!cbData
) goto cleanup
;
5266 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5267 if (!pwszExpandedBuffer
)
5269 result
= ERROR_NOT_ENOUGH_MEMORY
;
5272 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5276 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5277 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5280 /* If the value references a resource based string, parse the value and load the string.
5281 * Else just copy over the original value. */
5282 result
= ERROR_SUCCESS
;
5283 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5285 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5289 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5293 /* Format of the expanded value is 'path_to_dll,-resId' */
5294 if (!pComma
|| pComma
[1] != L
'-')
5296 result
= ERROR_BADKEY
;
5300 uiStringId
= _wtoi(pComma
+2);
5303 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5304 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5305 result
= ERROR_BADKEY
;
5306 FreeLibrary(hModule
);
5310 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5311 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5316 /************************************************************************
5322 RegLoadMUIStringA(IN HKEY hKey
,
5323 IN LPCSTR pszValue OPTIONAL
,
5324 OUT LPSTR pszOutBuf
,
5326 OUT LPDWORD pcbData OPTIONAL
,
5328 IN LPCSTR pszDirectory OPTIONAL
)
5330 UNICODE_STRING valueW
, baseDirW
;
5332 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5335 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5336 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5337 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5338 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5340 result
= ERROR_NOT_ENOUGH_MEMORY
;
5344 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5347 if (result
== ERROR_SUCCESS
)
5349 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5355 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5356 RtlFreeUnicodeString(&baseDirW
);
5357 RtlFreeUnicodeString(&valueW
);