2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
23 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
25 /* DEFINES ******************************************************************/
27 #define MAX_DEFAULT_HANDLES 6
28 #define REG_MAX_NAME_SIZE 256
29 #define REG_MAX_DATA_SIZE 2048
31 /* GLOBALS ******************************************************************/
33 static RTL_CRITICAL_SECTION HandleTableCS
;
34 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
35 static HANDLE ProcessHeap
;
36 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
37 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
38 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
40 /* PROTOTYPES ***************************************************************/
42 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
43 static VOID
CloseDefaultKeys(VOID
);
44 #define ClosePredefKey(Handle) \
45 if ((ULONG_PTR)Handle & 0x1) { \
48 #define IsPredefKey(HKey) \
49 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey) \
51 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
53 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
54 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
55 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
56 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
59 /* FUNCTIONS ****************************************************************/
60 /* check if value type needs string conversion (Ansi<->Unicode) */
61 __inline
static int is_string( DWORD type
)
63 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
66 /************************************************************************
67 * RegInitDefaultHandles
72 TRACE("RegInitialize()\n");
77 ProcessHeap
= RtlGetProcessHeap();
78 RtlZeroMemory(DefaultHandleTable
,
79 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
80 RtlInitializeCriticalSection(&HandleTableCS
);
82 DllInitialized
= TRUE
;
89 /************************************************************************
95 TRACE("RegCleanup()\n");
98 RtlDeleteCriticalSection(&HandleTableCS
);
105 OpenPredefinedKey(IN ULONG Index
,
112 case 0: /* HKEY_CLASSES_ROOT */
113 Status
= OpenClassesRootKey (Handle
);
116 case 1: /* HKEY_CURRENT_USER */
117 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
121 case 2: /* HKEY_LOCAL_MACHINE */
122 Status
= OpenLocalMachineKey (Handle
);
125 case 3: /* HKEY_USERS */
126 Status
= OpenUsersKey (Handle
);
129 case 4: /* HKEY_PERFORMANCE_DATA */
130 Status
= OpenPerformanceDataKey (Handle
);
134 case 5: /* HKEY_CURRENT_CONFIG */
135 Status
= OpenCurrentConfigKey (Handle
);
138 case 6: /* HKEY_DYN_DATA */
139 Status
= STATUS_NOT_IMPLEMENTED
;
143 WARN("MapDefaultHandle() no handle creator\n");
144 Status
= STATUS_INVALID_PARAMETER
;
153 MapDefaultKey(OUT PHANDLE RealKey
,
158 BOOLEAN DoOpen
, DefDisabled
;
159 NTSTATUS Status
= STATUS_SUCCESS
;
161 TRACE("MapDefaultKey (Key %x)\n", Key
);
163 if (!IsPredefKey(Key
))
165 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
166 return STATUS_SUCCESS
;
169 /* Handle special cases here */
170 Index
= GetPredefKeyIndex(Key
);
171 if (Index
>= MAX_DEFAULT_HANDLES
)
173 return STATUS_INVALID_PARAMETER
;
175 RegInitialize(); /* HACK until delay-loading is implemented */
176 RtlEnterCriticalSection (&HandleTableCS
);
178 if (Key
== HKEY_CURRENT_USER
)
179 DefDisabled
= DefaultHandleHKUDisabled
;
181 DefDisabled
= DefaultHandlesDisabled
;
185 Handle
= &DefaultHandleTable
[Index
];
186 DoOpen
= (*Handle
== NULL
);
196 /* create/open the default handle */
197 Status
= OpenPredefinedKey(Index
,
201 if (NT_SUCCESS(Status
))
206 *(PULONG_PTR
)Handle
|= 0x1;
209 RtlLeaveCriticalSection (&HandleTableCS
);
216 CloseDefaultKeys(VOID
)
219 RegInitialize(); /* HACK until delay-loading is implemented */
220 RtlEnterCriticalSection(&HandleTableCS
);
222 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
224 if (DefaultHandleTable
[i
] != NULL
)
226 NtClose(DefaultHandleTable
[i
]);
227 DefaultHandleTable
[i
] = NULL
;
231 RtlLeaveCriticalSection(&HandleTableCS
);
236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle
)
238 OBJECT_ATTRIBUTES Attributes
;
239 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
242 TRACE("OpenClassesRootKey()\n");
244 InitializeObjectAttributes(&Attributes
,
246 OBJ_CASE_INSENSITIVE
,
249 Status
= NtOpenKey(KeyHandle
,
253 if (!NT_SUCCESS(Status
))
256 /* Mark it as HKCR */
257 MakeHKCRKey((HKEY
*)KeyHandle
);
264 OpenLocalMachineKey(PHANDLE KeyHandle
)
266 OBJECT_ATTRIBUTES Attributes
;
267 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
270 TRACE("OpenLocalMachineKey()\n");
272 InitializeObjectAttributes(&Attributes
,
274 OBJ_CASE_INSENSITIVE
,
277 Status
= NtOpenKey(KeyHandle
,
281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
288 OpenUsersKey(PHANDLE KeyHandle
)
290 OBJECT_ATTRIBUTES Attributes
;
291 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
293 TRACE("OpenUsersKey()\n");
295 InitializeObjectAttributes(&Attributes
,
297 OBJ_CASE_INSENSITIVE
,
300 return NtOpenKey(KeyHandle
,
307 OpenCurrentConfigKey (PHANDLE KeyHandle
)
309 OBJECT_ATTRIBUTES Attributes
;
310 UNICODE_STRING KeyName
=
311 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
313 TRACE("OpenCurrentConfigKey()\n");
315 InitializeObjectAttributes(&Attributes
,
317 OBJ_CASE_INSENSITIVE
,
320 return NtOpenKey(KeyHandle
,
326 /************************************************************************
327 * RegDisablePredefinedCache
332 RegDisablePredefinedCache(VOID
)
334 RegInitialize(); /* HACK until delay-loading is implemented */
335 RtlEnterCriticalSection(&HandleTableCS
);
336 DefaultHandleHKUDisabled
= TRUE
;
337 RtlLeaveCriticalSection(&HandleTableCS
);
338 return ERROR_SUCCESS
;
342 /************************************************************************
343 * RegDisablePredefinedCacheEx
348 RegDisablePredefinedCacheEx(VOID
)
350 RegInitialize(); /* HACK until delay-loading is implemented */
351 RtlEnterCriticalSection(&HandleTableCS
);
352 DefaultHandlesDisabled
= TRUE
;
353 DefaultHandleHKUDisabled
= TRUE
;
354 RtlLeaveCriticalSection(&HandleTableCS
);
355 return ERROR_SUCCESS
;
359 /************************************************************************
360 * RegOverridePredefKey
365 RegOverridePredefKey(IN HKEY hKey
,
366 IN HKEY hNewHKey OPTIONAL
)
368 LONG ErrorCode
= ERROR_SUCCESS
;
370 if ((hKey
== HKEY_CLASSES_ROOT
||
371 hKey
== HKEY_CURRENT_CONFIG
||
372 hKey
== HKEY_CURRENT_USER
||
373 hKey
== HKEY_LOCAL_MACHINE
||
374 hKey
== HKEY_PERFORMANCE_DATA
||
375 hKey
== HKEY_USERS
) &&
376 !IsPredefKey(hNewHKey
))
381 Index
= GetPredefKeyIndex(hKey
);
382 Handle
= &DefaultHandleTable
[Index
];
384 if (hNewHKey
== NULL
)
386 /* restore the default mapping */
387 NTSTATUS Status
= OpenPredefinedKey(Index
,
389 if (!NT_SUCCESS(Status
))
391 return RtlNtStatusToDosError(Status
);
394 ASSERT(hNewHKey
!= NULL
);
396 RegInitialize(); /* HACK until delay-loading is implemented */
397 RtlEnterCriticalSection(&HandleTableCS
);
399 /* close the currently mapped handle if existing */
405 /* update the mapping */
408 RtlLeaveCriticalSection(&HandleTableCS
);
411 ErrorCode
= ERROR_INVALID_HANDLE
;
417 /************************************************************************
423 RegCloseKey(HKEY hKey
)
427 /* don't close null handle or a pseudo handle */
428 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
430 return ERROR_INVALID_HANDLE
;
433 Status
= NtClose(hKey
);
434 if (!NT_SUCCESS(Status
))
436 return RtlNtStatusToDosError(Status
);
439 return ERROR_SUCCESS
;
444 RegpCopyTree(IN HKEY hKeySrc
,
449 LIST_ENTRY ListEntry
;
452 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
454 LIST_ENTRY copyQueueHead
;
455 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
458 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
459 KEY_NODE_INFORMATION
*KeyNode
;
462 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
463 NTSTATUS Status
= STATUS_SUCCESS
;
464 NTSTATUS Status2
= STATUS_SUCCESS
;
466 InitializeListHead(©QueueHead
);
468 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
471 if (Info
.Buffer
== NULL
)
473 return STATUS_INSUFFICIENT_RESOURCES
;
476 copyKeys
= RtlAllocateHeap(ProcessHeap
,
478 sizeof(REGP_COPY_KEYS
));
479 if (copyKeys
!= NULL
)
481 copyKeys
->hKeySrc
= hKeySrc
;
482 copyKeys
->hKeyDest
= hKeyDest
;
483 InsertHeadList(©QueueHead
,
484 ©Keys
->ListEntry
);
486 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
490 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
494 /* enumerate all values and copy them */
498 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
500 KeyValueFullInformation
,
503 &BufferSizeRequired
);
504 if (NT_SUCCESS(Status2
))
506 UNICODE_STRING ValueName
;
509 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
510 ValueName
.Length
= Info
.KeyValue
->NameLength
;
511 ValueName
.MaximumLength
= ValueName
.Length
;
512 ValueName
.Buffer
= Info
.KeyValue
->Name
;
514 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
516 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
518 Info
.KeyValue
->TitleIndex
,
521 Info
.KeyValue
->DataLength
);
523 /* don't break, let's try to copy as many values as possible */
524 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
531 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
535 ASSERT(BufferSize
< BufferSizeRequired
);
537 Buffer
= RtlReAllocateHeap(ProcessHeap
,
543 Info
.Buffer
= Buffer
;
548 /* don't break, let's try to copy as many values as possible */
549 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
552 if (NT_SUCCESS(Status
))
560 /* break to avoid an infinite loop in case of denied access or
562 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
571 /* enumerate all subkeys and open and enqueue them */
575 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
580 &BufferSizeRequired
);
581 if (NT_SUCCESS(Status2
))
583 HANDLE KeyHandle
, NewKeyHandle
;
584 OBJECT_ATTRIBUTES ObjectAttributes
;
585 UNICODE_STRING SubKeyName
, ClassName
;
587 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
588 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
589 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
590 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
591 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
592 ClassName
.MaximumLength
= ClassName
.Length
;
593 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
595 /* open the subkey with sufficient rights */
597 InitializeObjectAttributes(&ObjectAttributes
,
599 OBJ_CASE_INSENSITIVE
,
603 Status2
= NtOpenKey(&KeyHandle
,
604 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
606 if (NT_SUCCESS(Status2
))
608 /* FIXME - attempt to query the security information */
610 InitializeObjectAttributes(&ObjectAttributes
,
612 OBJ_CASE_INSENSITIVE
,
616 Status2
= NtCreateKey(&NewKeyHandle
,
619 Info
.KeyNode
->TitleIndex
,
623 if (NT_SUCCESS(Status2
))
625 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
627 sizeof(REGP_COPY_KEYS
));
628 if (newCopyKeys
!= NULL
)
630 /* save the handles and enqueue the subkey */
631 newCopyKeys
->hKeySrc
= KeyHandle
;
632 newCopyKeys
->hKeyDest
= NewKeyHandle
;
633 InsertTailList(©QueueHead
,
634 &newCopyKeys
->ListEntry
);
639 NtClose(NewKeyHandle
);
641 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
650 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
657 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
661 ASSERT(BufferSize
< BufferSizeRequired
);
663 Buffer
= RtlReAllocateHeap(ProcessHeap
,
669 Info
.Buffer
= Buffer
;
674 /* don't break, let's try to copy as many keys as possible */
675 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
678 if (NT_SUCCESS(Status
))
686 /* break to avoid an infinite loop in case of denied access or
688 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
697 /* close the handles and remove the entry from the list */
698 if (copyKeys
->hKeySrc
!= hKeySrc
)
700 NtClose(copyKeys
->hKeySrc
);
702 if (copyKeys
->hKeyDest
!= hKeyDest
)
704 NtClose(copyKeys
->hKeyDest
);
707 RemoveEntryList(©Keys
->ListEntry
);
709 RtlFreeHeap(ProcessHeap
,
712 } while (!IsListEmpty(©QueueHead
));
715 Status
= STATUS_INSUFFICIENT_RESOURCES
;
717 RtlFreeHeap(ProcessHeap
,
725 /************************************************************************
731 RegCopyTreeW(IN HKEY hKeySrc
,
732 IN LPCWSTR lpSubKey OPTIONAL
,
735 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
738 Status
= MapDefaultKey(&KeyHandle
,
740 if (!NT_SUCCESS(Status
))
742 return RtlNtStatusToDosError(Status
);
745 Status
= MapDefaultKey(&DestKeyHandle
,
747 if (!NT_SUCCESS(Status
))
752 if (lpSubKey
!= NULL
)
754 OBJECT_ATTRIBUTES ObjectAttributes
;
755 UNICODE_STRING SubKeyName
;
757 RtlInitUnicodeString(&SubKeyName
,
760 InitializeObjectAttributes(&ObjectAttributes
,
762 OBJ_CASE_INSENSITIVE
,
766 Status
= NtOpenKey(&SubKeyHandle
,
767 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
769 if (!NT_SUCCESS(Status
))
774 CurKey
= SubKeyHandle
;
779 Status
= RegpCopyTree(CurKey
,
782 if (SubKeyHandle
!= NULL
)
784 NtClose(SubKeyHandle
);
788 ClosePredefKey(DestKeyHandle
);
790 ClosePredefKey(KeyHandle
);
792 if (!NT_SUCCESS(Status
))
794 return RtlNtStatusToDosError(Status
);
797 return ERROR_SUCCESS
;
801 /************************************************************************
807 RegCopyTreeA(IN HKEY hKeySrc
,
808 IN LPCSTR lpSubKey OPTIONAL
,
811 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
814 if (lpSubKey
!= NULL
&&
815 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
818 return ERROR_NOT_ENOUGH_MEMORY
;
821 Ret
= RegCopyTreeW(hKeySrc
,
825 RtlFreeUnicodeString(&SubKeyName
);
831 /************************************************************************
832 * RegConnectRegistryA
837 RegConnectRegistryA(IN LPCSTR lpMachineName
,
841 UNICODE_STRING MachineName
= { 0, 0, NULL
};
844 if (lpMachineName
!= NULL
&&
845 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
846 (LPSTR
)lpMachineName
))
848 return ERROR_NOT_ENOUGH_MEMORY
;
851 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
855 RtlFreeUnicodeString(&MachineName
);
861 /************************************************************************
862 * RegConnectRegistryW
867 RegConnectRegistryW(LPCWSTR lpMachineName
,
873 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
875 if (!lpMachineName
|| !*lpMachineName
)
877 /* Use the local machine name */
878 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
882 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
883 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
885 /* MSDN says lpMachineName must start with \\ : not so */
886 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
889 if (GetComputerNameW(compName
, &len
))
891 if (!_wcsicmp(lpMachineName
, compName
))
892 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
895 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
896 ret
= ERROR_BAD_NETPATH
;
900 ret
= GetLastError();
907 /************************************************************************
910 * Create key and all necessary intermediate keys
913 CreateNestedKey(PHKEY KeyHandle
,
914 POBJECT_ATTRIBUTES ObjectAttributes
,
915 PUNICODE_STRING ClassString
,
918 DWORD
*lpdwDisposition
)
920 OBJECT_ATTRIBUTES LocalObjectAttributes
;
921 UNICODE_STRING LocalKeyName
;
924 ULONG FullNameLength
;
927 HANDLE LocalKeyHandle
;
929 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
935 (PULONG
)lpdwDisposition
);
936 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
937 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
940 /* Copy object attributes */
941 RtlCopyMemory(&LocalObjectAttributes
,
943 sizeof(OBJECT_ATTRIBUTES
));
944 RtlCreateUnicodeString(&LocalKeyName
,
945 ObjectAttributes
->ObjectName
->Buffer
);
946 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
947 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
949 LocalKeyHandle
= NULL
;
951 /* Remove the last part of the key name and try to create the key again. */
952 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
954 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
955 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
957 Status
= STATUS_UNSUCCESSFUL
;
962 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
964 Status
= NtCreateKey(&LocalKeyHandle
,
966 &LocalObjectAttributes
,
971 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
974 if (!NT_SUCCESS(Status
))
976 RtlFreeUnicodeString(&LocalKeyName
);
980 /* Add removed parts of the key name and create them too. */
981 Length
= wcslen(LocalKeyName
.Buffer
);
985 NtClose (LocalKeyHandle
);
987 LocalKeyName
.Buffer
[Length
] = L
'\\';
988 Length
= wcslen (LocalKeyName
.Buffer
);
989 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
991 if (Length
== FullNameLength
)
993 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
999 (PULONG
)lpdwDisposition
);
1003 Status
= NtCreateKey(&LocalKeyHandle
,
1005 &LocalObjectAttributes
,
1010 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
1011 if (!NT_SUCCESS(Status
))
1015 RtlFreeUnicodeString(&LocalKeyName
);
1021 /************************************************************************
1029 _In_ LPCSTR lpSubKey
,
1030 _In_ DWORD Reserved
,
1032 _In_ DWORD dwOptions
,
1033 _In_ REGSAM samDesired
,
1034 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1035 _Out_ PHKEY phkResult
,
1036 _Out_ LPDWORD lpdwDisposition
)
1038 UNICODE_STRING SubKeyString
;
1039 UNICODE_STRING ClassString
;
1042 RtlCreateUnicodeStringFromAsciiz(&ClassString
, lpClass
);
1043 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, (LPSTR
)lpSubKey
);
1045 ErrorCode
= RegCreateKeyExW(
1047 SubKeyString
.Buffer
,
1052 lpSecurityAttributes
,
1056 RtlFreeUnicodeString(&SubKeyString
);
1057 RtlFreeUnicodeString(&ClassString
);
1063 /************************************************************************
1069 RegCreateKeyExW(HKEY hKey
,
1075 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1077 LPDWORD lpdwDisposition
)
1079 UNICODE_STRING SubKeyString
;
1080 UNICODE_STRING ClassString
;
1081 OBJECT_ATTRIBUTES ObjectAttributes
;
1083 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1086 TRACE("RegCreateKeyExW() called\n");
1088 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1089 return ERROR_INVALID_USER_BUFFER
;
1091 /* get the real parent key */
1092 Status
= MapDefaultKey(&ParentKey
,
1094 if (!NT_SUCCESS(Status
))
1096 return RtlNtStatusToDosError(Status
);
1099 TRACE("ParentKey %p\n", ParentKey
);
1101 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1102 Attributes
|= OBJ_OPENLINK
;
1104 RtlInitUnicodeString(&ClassString
,
1106 RtlInitUnicodeString(&SubKeyString
,
1108 InitializeObjectAttributes(&ObjectAttributes
,
1112 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1113 Status
= CreateNestedKey(phkResult
,
1115 (lpClass
== NULL
)? NULL
: &ClassString
,
1120 ClosePredefKey(ParentKey
);
1122 TRACE("Status %x\n", Status
);
1123 if (!NT_SUCCESS(Status
))
1125 return RtlNtStatusToDosError(Status
);
1128 return ERROR_SUCCESS
;
1132 /************************************************************************
1138 RegCreateKeyA(HKEY hKey
,
1142 return RegCreateKeyExA(hKey
,
1154 /************************************************************************
1160 RegCreateKeyW(HKEY hKey
,
1164 return RegCreateKeyExW(hKey
,
1176 /************************************************************************
1182 RegDeleteKeyA(HKEY hKey
,
1186 UNICODE_STRING SubKeyName
;
1188 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
, (LPSTR
)lpSubKey
);
1190 ErrorCode
= RegDeleteKeyW(hKey
, SubKeyName
.Buffer
);
1192 RtlFreeUnicodeString(&SubKeyName
);
1198 /************************************************************************
1204 RegDeleteKeyW(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 RtlInitUnicodeString(&SubKeyName
,
1229 InitializeObjectAttributes(&ObjectAttributes
,
1231 OBJ_CASE_INSENSITIVE
,
1234 Status
= NtOpenKey(&TargetKey
,
1237 if (!NT_SUCCESS(Status
))
1242 Status
= NtDeleteKey(TargetKey
);
1246 ClosePredefKey(ParentKey
);
1248 if (!NT_SUCCESS(Status
))
1250 return RtlNtStatusToDosError(Status
);
1253 return ERROR_SUCCESS
;
1257 /************************************************************************
1264 RegDeleteKeyExA(HKEY hKey
,
1269 OBJECT_ATTRIBUTES ObjectAttributes
;
1270 UNICODE_STRING SubKeyName
;
1275 /* Make sure we got a subkey */
1279 return ERROR_INVALID_PARAMETER
;
1282 Status
= MapDefaultKey(&ParentKey
,
1284 if (!NT_SUCCESS(Status
))
1286 return RtlNtStatusToDosError(Status
);
1289 if (samDesired
& KEY_WOW64_32KEY
)
1290 ERR("Wow64 not yet supported!\n");
1292 if (samDesired
& KEY_WOW64_64KEY
)
1293 ERR("Wow64 not yet supported!\n");
1295 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1297 InitializeObjectAttributes(&ObjectAttributes
,
1299 OBJ_CASE_INSENSITIVE
,
1303 Status
= NtOpenKey(&TargetKey
,
1306 RtlFreeUnicodeString(&SubKeyName
);
1307 if (!NT_SUCCESS(Status
))
1312 Status
= NtDeleteKey(TargetKey
);
1313 NtClose (TargetKey
);
1316 ClosePredefKey(ParentKey
);
1318 if (!NT_SUCCESS(Status
))
1320 return RtlNtStatusToDosError(Status
);
1323 return ERROR_SUCCESS
;
1327 /************************************************************************
1334 RegDeleteKeyExW(HKEY hKey
,
1339 OBJECT_ATTRIBUTES ObjectAttributes
;
1340 UNICODE_STRING SubKeyName
;
1345 /* Make sure we got a subkey */
1349 return ERROR_INVALID_PARAMETER
;
1352 Status
= MapDefaultKey(&ParentKey
,
1354 if (!NT_SUCCESS(Status
))
1356 return RtlNtStatusToDosError(Status
);
1359 if (samDesired
& KEY_WOW64_32KEY
)
1360 ERR("Wow64 not yet supported!\n");
1362 if (samDesired
& KEY_WOW64_64KEY
)
1363 ERR("Wow64 not yet supported!\n");
1366 RtlInitUnicodeString(&SubKeyName
,
1368 InitializeObjectAttributes(&ObjectAttributes
,
1370 OBJ_CASE_INSENSITIVE
,
1373 Status
= NtOpenKey(&TargetKey
,
1376 if (!NT_SUCCESS(Status
))
1381 Status
= NtDeleteKey(TargetKey
);
1385 ClosePredefKey(ParentKey
);
1387 if (!NT_SUCCESS(Status
))
1389 return RtlNtStatusToDosError(Status
);
1392 return ERROR_SUCCESS
;
1396 /************************************************************************
1397 * RegDeleteKeyValueW
1402 RegDeleteKeyValueW(IN HKEY hKey
,
1403 IN LPCWSTR lpSubKey OPTIONAL
,
1404 IN LPCWSTR lpValueName OPTIONAL
)
1406 UNICODE_STRING ValueName
;
1407 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1410 Status
= MapDefaultKey(&KeyHandle
,
1412 if (!NT_SUCCESS(Status
))
1414 return RtlNtStatusToDosError(Status
);
1417 if (lpSubKey
!= NULL
)
1419 OBJECT_ATTRIBUTES ObjectAttributes
;
1420 UNICODE_STRING SubKeyName
;
1422 RtlInitUnicodeString(&SubKeyName
,
1425 InitializeObjectAttributes(&ObjectAttributes
,
1427 OBJ_CASE_INSENSITIVE
,
1431 Status
= NtOpenKey(&SubKeyHandle
,
1434 if (!NT_SUCCESS(Status
))
1439 CurKey
= SubKeyHandle
;
1444 RtlInitUnicodeString(&ValueName
,
1445 (LPWSTR
)lpValueName
);
1447 Status
= NtDeleteValueKey(CurKey
,
1450 if (SubKeyHandle
!= NULL
)
1452 NtClose(SubKeyHandle
);
1456 ClosePredefKey(KeyHandle
);
1458 if (!NT_SUCCESS(Status
))
1460 return RtlNtStatusToDosError(Status
);
1463 return ERROR_SUCCESS
;
1467 /************************************************************************
1468 * RegDeleteKeyValueA
1473 RegDeleteKeyValueA(IN HKEY hKey
,
1474 IN LPCSTR lpSubKey OPTIONAL
,
1475 IN LPCSTR lpValueName OPTIONAL
)
1477 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1480 if (lpSubKey
!= NULL
&&
1481 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1484 return ERROR_NOT_ENOUGH_MEMORY
;
1487 if (lpValueName
!= NULL
&&
1488 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1489 (LPSTR
)lpValueName
))
1491 RtlFreeUnicodeString(&SubKey
);
1492 return ERROR_NOT_ENOUGH_MEMORY
;
1495 Ret
= RegDeleteKeyValueW(hKey
,
1499 RtlFreeUnicodeString(&SubKey
);
1500 RtlFreeUnicodeString(&ValueName
);
1506 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1508 RegpDeleteTree(IN HKEY hKey
)
1512 LIST_ENTRY ListEntry
;
1514 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1516 LIST_ENTRY delQueueHead
;
1517 PREG_DEL_KEYS delKeys
, newDelKeys
;
1520 PKEY_BASIC_INFORMATION BasicInfo
;
1521 PREG_DEL_KEYS KeyDelRoot
;
1522 NTSTATUS Status
= STATUS_SUCCESS
;
1523 NTSTATUS Status2
= STATUS_SUCCESS
;
1525 InitializeListHead(&delQueueHead
);
1527 ProcessHeap
= RtlGetProcessHeap();
1529 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1530 structure for the root key, we only do that for subkeys as we need to
1531 allocate REGP_DEL_KEYS structures anyway! */
1532 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1534 sizeof(REGP_DEL_KEYS
));
1535 if (KeyDelRoot
!= NULL
)
1537 KeyDelRoot
->KeyHandle
= hKey
;
1538 InsertTailList(&delQueueHead
,
1539 &KeyDelRoot
->ListEntry
);
1543 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1552 /* check if this key contains subkeys and delete them first by queuing
1553 them at the head of the list */
1554 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1556 KeyBasicInformation
,
1561 if (NT_SUCCESS(Status2
))
1563 OBJECT_ATTRIBUTES ObjectAttributes
;
1564 UNICODE_STRING SubKeyName
;
1566 ASSERT(newDelKeys
!= NULL
);
1567 ASSERT(BasicInfo
!= NULL
);
1569 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1570 SubKeyName
.Length
= BasicInfo
->NameLength
;
1571 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1572 SubKeyName
.Buffer
= BasicInfo
->Name
;
1574 InitializeObjectAttributes(&ObjectAttributes
,
1576 OBJ_CASE_INSENSITIVE
,
1580 /* open the subkey */
1581 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1582 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1584 if (!NT_SUCCESS(Status2
))
1589 /* enqueue this key to the head of the deletion queue */
1590 InsertHeadList(&delQueueHead
,
1591 &newDelKeys
->ListEntry
);
1593 /* try again from the head of the list */
1598 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1600 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1602 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1603 if (newDelKeys
!= NULL
)
1605 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1608 goto ReadFirstSubKey
;
1612 /* don't break, let's try to delete as many keys as possible */
1613 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1614 goto SubKeyFailureNoFree
;
1617 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1619 PREG_DEL_KEYS newDelKeys2
;
1621 ASSERT(newDelKeys
!= NULL
);
1623 /* we need more memory to query the key name */
1624 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1627 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1628 if (newDelKeys2
!= NULL
)
1630 newDelKeys
= newDelKeys2
;
1631 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1634 goto ReadFirstSubKey
;
1638 /* don't break, let's try to delete as many keys as possible */
1639 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1642 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1644 /* in some race conditions where another thread would delete
1645 the same tree at the same time, newDelKeys could actually
1647 if (newDelKeys
!= NULL
)
1649 RtlFreeHeap(ProcessHeap
,
1657 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1658 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1659 if (newDelKeys
!= NULL
)
1661 RtlFreeHeap(ProcessHeap
,
1666 SubKeyFailureNoFree
:
1667 /* don't break, let's try to delete as many keys as possible */
1668 if (NT_SUCCESS(Status
))
1674 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1676 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1678 if (!NT_SUCCESS(Status2
))
1680 /* close the key handle so we don't leak handles for keys we were
1681 unable to delete. But only do this for handles not supplied
1684 if (delKeys
->KeyHandle
!= hKey
)
1686 NtClose(delKeys
->KeyHandle
);
1689 if (NT_SUCCESS(Status
))
1691 /* don't break, let's try to delete as many keys as possible */
1696 /* remove the entry from the list */
1697 RemoveEntryList(&delKeys
->ListEntry
);
1699 RtlFreeHeap(ProcessHeap
,
1702 } while (!IsListEmpty(&delQueueHead
));
1705 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1711 /************************************************************************
1717 RegDeleteTreeW(IN HKEY hKey
,
1718 IN LPCWSTR lpSubKey OPTIONAL
)
1720 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1723 Status
= MapDefaultKey(&KeyHandle
,
1725 if (!NT_SUCCESS(Status
))
1727 return RtlNtStatusToDosError(Status
);
1730 if (lpSubKey
!= NULL
)
1732 OBJECT_ATTRIBUTES ObjectAttributes
;
1733 UNICODE_STRING SubKeyName
;
1735 RtlInitUnicodeString(&SubKeyName
,
1738 InitializeObjectAttributes(&ObjectAttributes
,
1740 OBJ_CASE_INSENSITIVE
,
1744 Status
= NtOpenKey(&SubKeyHandle
,
1745 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1747 if (!NT_SUCCESS(Status
))
1752 CurKey
= SubKeyHandle
;
1757 Status
= RegpDeleteTree(CurKey
);
1759 if (NT_SUCCESS(Status
))
1761 /* make sure we only close hKey (KeyHandle) when the caller specified a
1762 subkey, because the handle would be invalid already! */
1763 if (CurKey
!= KeyHandle
)
1765 ClosePredefKey(KeyHandle
);
1768 return ERROR_SUCCESS
;
1772 /* make sure we close all handles we created! */
1773 if (SubKeyHandle
!= NULL
)
1775 NtClose(SubKeyHandle
);
1779 ClosePredefKey(KeyHandle
);
1781 return RtlNtStatusToDosError(Status
);
1787 /************************************************************************
1794 RegDeleteTreeW(HKEY hKey
,
1798 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1799 DWORD dwMaxLen
, dwSize
;
1803 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1805 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1807 Status
= MapDefaultKey(&KeyHandle
,
1809 if (!NT_SUCCESS(Status
))
1811 return RtlNtStatusToDosError(Status
);
1814 hSubKey
= KeyHandle
;
1818 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1821 ClosePredefKey(KeyHandle
);
1826 /* Get highest length for keys, values */
1827 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1828 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1829 if (ret
) goto cleanup
;
1833 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1834 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1836 /* Name too big: alloc a buffer for it */
1837 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1839 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1845 /* Recursively delete all the subkeys */
1849 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1850 NULL
, NULL
, NULL
)) break;
1852 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1853 if (ret
) goto cleanup
;
1857 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1862 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1863 NULL
, NULL
, NULL
, NULL
)) break;
1865 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1866 if (ret
) goto cleanup
;
1870 /* Free buffer if allocated */
1871 if (lpszName
!= szNameBuf
)
1872 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1874 RegCloseKey(hSubKey
);
1876 ClosePredefKey(KeyHandle
);
1882 /************************************************************************
1888 RegDeleteTreeA(IN HKEY hKey
,
1889 IN LPCSTR lpSubKey OPTIONAL
)
1891 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1894 if (lpSubKey
!= NULL
&&
1895 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1898 return ERROR_NOT_ENOUGH_MEMORY
;
1901 Ret
= RegDeleteTreeW(hKey
,
1904 RtlFreeUnicodeString(&SubKeyName
);
1910 /************************************************************************
1911 * RegDisableReflectionKey
1916 RegDisableReflectionKey(IN HKEY hBase
)
1918 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1919 return ERROR_CALL_NOT_IMPLEMENTED
;
1923 /************************************************************************
1924 * RegEnableReflectionKey
1929 RegEnableReflectionKey(IN HKEY hBase
)
1931 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1932 return ERROR_CALL_NOT_IMPLEMENTED
;
1936 /******************************************************************************
1937 * RegpApplyRestrictions [internal]
1939 * Helper function for RegGetValueA/W.
1942 RegpApplyRestrictions(DWORD dwFlags
,
1947 /* Check if the type is restricted by the passed flags */
1948 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1954 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1955 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1956 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1957 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1958 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1959 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1960 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1963 if (dwFlags
& dwMask
)
1965 /* Type is not restricted, check for size mismatch */
1966 if (dwType
== REG_BINARY
)
1970 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1972 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1975 if (cbExpect
&& cbData
!= cbExpect
)
1976 *ret
= ERROR_DATATYPE_MISMATCH
;
1979 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1984 /******************************************************************************
1985 * RegGetValueW [ADVAPI32.@]
1987 * Retrieves the type and data for a value name associated with a key,
1988 * optionally expanding its content and restricting its type.
1991 * hKey [I] Handle to an open key.
1992 * pszSubKey [I] Name of the subkey of hKey.
1993 * pszValue [I] Name of value under hKey/szSubKey to query.
1994 * dwFlags [I] Flags restricting the value type to retrieve.
1995 * pdwType [O] Destination for the values type, may be NULL.
1996 * pvData [O] Destination for the values content, may be NULL.
1997 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1998 * retrieve the whole content, including the trailing '\0'
2002 * Success: ERROR_SUCCESS
2003 * Failure: nonzero error code from Winerror.h
2006 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2007 * expanded and pdwType is set to REG_SZ instead.
2008 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2009 * without RRF_NOEXPAND is thus not allowed.
2010 * An exception is the case where RRF_RT_ANY is specified, because then
2011 * RRF_NOEXPAND is allowed.
2014 RegGetValueW(HKEY hKey
,
2022 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2026 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2027 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2028 pvData
, pcbData
, cbData
);
2030 if (pvData
&& !pcbData
)
2031 return ERROR_INVALID_PARAMETER
;
2032 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2033 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2034 return ERROR_INVALID_PARAMETER
;
2036 if (pszSubKey
&& pszSubKey
[0])
2038 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2039 if (ret
!= ERROR_SUCCESS
) return ret
;
2042 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2044 /* If we are going to expand we need to read in the whole the value even
2045 * if the passed buffer was too small as the expanded string might be
2046 * smaller than the unexpanded one and could fit into cbData bytes. */
2047 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2048 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2052 HeapFree(GetProcessHeap(), 0, pvBuf
);
2054 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2057 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2061 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2062 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2063 &dwType
, pvBuf
, &cbData
);
2066 /* Even if cbData was large enough we have to copy the
2067 * string since ExpandEnvironmentStrings can't handle
2068 * overlapping buffers. */
2069 CopyMemory(pvBuf
, pvData
, cbData
);
2072 /* Both the type or the value itself could have been modified in
2073 * between so we have to keep retrying until the buffer is large
2074 * enough or we no longer have to expand the value. */
2076 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2078 if (ret
== ERROR_SUCCESS
)
2080 /* Recheck dwType in case it changed since the first call */
2081 if (dwType
== REG_EXPAND_SZ
)
2083 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2084 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2086 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2087 ret
= ERROR_MORE_DATA
;
2090 CopyMemory(pvData
, pvBuf
, *pcbData
);
2093 HeapFree(GetProcessHeap(), 0, pvBuf
);
2096 if (pszSubKey
&& pszSubKey
[0])
2099 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2101 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2102 ZeroMemory(pvData
, *pcbData
);
2114 /******************************************************************************
2115 * RegGetValueA [ADVAPI32.@]
2120 RegGetValueA(HKEY hKey
,
2128 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2132 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2133 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2136 if (pvData
&& !pcbData
)
2137 return ERROR_INVALID_PARAMETER
;
2138 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2139 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2140 return ERROR_INVALID_PARAMETER
;
2142 if (pszSubKey
&& pszSubKey
[0])
2144 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2145 if (ret
!= ERROR_SUCCESS
) return ret
;
2148 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2150 /* If we are going to expand we need to read in the whole the value even
2151 * if the passed buffer was too small as the expanded string might be
2152 * smaller than the unexpanded one and could fit into cbData bytes. */
2153 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2154 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2157 HeapFree(GetProcessHeap(), 0, pvBuf
);
2159 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2162 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2166 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2167 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2168 &dwType
, pvBuf
, &cbData
);
2171 /* Even if cbData was large enough we have to copy the
2172 * string since ExpandEnvironmentStrings can't handle
2173 * overlapping buffers. */
2174 CopyMemory(pvBuf
, pvData
, cbData
);
2177 /* Both the type or the value itself could have been modified in
2178 * between so we have to keep retrying until the buffer is large
2179 * enough or we no longer have to expand the value. */
2180 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2182 if (ret
== ERROR_SUCCESS
)
2184 /* Recheck dwType in case it changed since the first call */
2185 if (dwType
== REG_EXPAND_SZ
)
2187 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2188 pcbData
? *pcbData
: 0);
2190 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2191 ret
= ERROR_MORE_DATA
;
2194 CopyMemory(pvData
, pvBuf
, *pcbData
);
2197 HeapFree(GetProcessHeap(), 0, pvBuf
);
2200 if (pszSubKey
&& pszSubKey
[0])
2203 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2205 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2206 ZeroMemory(pvData
, *pcbData
);
2208 if (pdwType
) *pdwType
= dwType
;
2209 if (pcbData
) *pcbData
= cbData
;
2215 /************************************************************************
2221 RegSetKeyValueW(IN HKEY hKey
,
2222 IN LPCWSTR lpSubKey OPTIONAL
,
2223 IN LPCWSTR lpValueName OPTIONAL
,
2225 IN LPCVOID lpData OPTIONAL
,
2228 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2232 Status
= MapDefaultKey(&KeyHandle
,
2234 if (!NT_SUCCESS(Status
))
2236 return RtlNtStatusToDosError(Status
);
2239 if (lpSubKey
!= NULL
)
2241 OBJECT_ATTRIBUTES ObjectAttributes
;
2242 UNICODE_STRING SubKeyName
;
2244 RtlInitUnicodeString(&SubKeyName
,
2247 InitializeObjectAttributes(&ObjectAttributes
,
2249 OBJ_CASE_INSENSITIVE
,
2253 Status
= NtOpenKey(&SubKeyHandle
,
2256 if (!NT_SUCCESS(Status
))
2258 Ret
= RtlNtStatusToDosError(Status
);
2262 CurKey
= SubKeyHandle
;
2267 Ret
= RegSetValueExW(CurKey
,
2274 if (SubKeyHandle
!= NULL
)
2276 NtClose(SubKeyHandle
);
2280 ClosePredefKey(KeyHandle
);
2286 /************************************************************************
2292 RegSetKeyValueA(IN HKEY hKey
,
2293 IN LPCSTR lpSubKey OPTIONAL
,
2294 IN LPCSTR lpValueName OPTIONAL
,
2296 IN LPCVOID lpData OPTIONAL
,
2299 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2303 Status
= MapDefaultKey(&KeyHandle
,
2305 if (!NT_SUCCESS(Status
))
2307 return RtlNtStatusToDosError(Status
);
2310 if (lpSubKey
!= NULL
)
2312 OBJECT_ATTRIBUTES ObjectAttributes
;
2313 UNICODE_STRING SubKeyName
;
2315 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2318 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2322 InitializeObjectAttributes(&ObjectAttributes
,
2324 OBJ_CASE_INSENSITIVE
,
2328 Status
= NtOpenKey(&SubKeyHandle
,
2332 RtlFreeUnicodeString(&SubKeyName
);
2334 if (!NT_SUCCESS(Status
))
2336 Ret
= RtlNtStatusToDosError(Status
);
2340 CurKey
= SubKeyHandle
;
2345 Ret
= RegSetValueExA(CurKey
,
2352 if (SubKeyHandle
!= NULL
)
2354 NtClose(SubKeyHandle
);
2358 ClosePredefKey(KeyHandle
);
2364 /************************************************************************
2370 RegDeleteValueA(HKEY hKey
,
2373 UNICODE_STRING ValueName
;
2377 Status
= MapDefaultKey(&KeyHandle
,
2379 if (!NT_SUCCESS(Status
))
2381 return RtlNtStatusToDosError(Status
);
2384 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2385 (LPSTR
)lpValueName
);
2386 Status
= NtDeleteValueKey(KeyHandle
,
2388 RtlFreeUnicodeString (&ValueName
);
2390 ClosePredefKey(KeyHandle
);
2392 if (!NT_SUCCESS(Status
))
2394 return RtlNtStatusToDosError(Status
);
2397 return ERROR_SUCCESS
;
2401 /************************************************************************
2407 RegDeleteValueW(HKEY hKey
,
2408 LPCWSTR lpValueName
)
2410 UNICODE_STRING ValueName
;
2414 Status
= MapDefaultKey(&KeyHandle
,
2416 if (!NT_SUCCESS(Status
))
2418 return RtlNtStatusToDosError(Status
);
2421 RtlInitUnicodeString(&ValueName
,
2422 (LPWSTR
)lpValueName
);
2424 Status
= NtDeleteValueKey(KeyHandle
,
2427 ClosePredefKey(KeyHandle
);
2429 if (!NT_SUCCESS(Status
))
2431 return RtlNtStatusToDosError(Status
);
2434 return ERROR_SUCCESS
;
2438 /************************************************************************
2444 RegEnumKeyA(HKEY hKey
,
2452 return RegEnumKeyExA(hKey
,
2463 /************************************************************************
2469 RegEnumKeyW(HKEY hKey
,
2477 return RegEnumKeyExW(hKey
,
2488 /************************************************************************
2494 RegEnumKeyExA(HKEY hKey
,
2501 PFILETIME lpftLastWriteTime
)
2505 KEY_NODE_INFORMATION Node
;
2506 KEY_BASIC_INFORMATION Basic
;
2509 UNICODE_STRING StringU
;
2510 ANSI_STRING StringA
;
2511 LONG ErrorCode
= ERROR_SUCCESS
;
2513 DWORD ClassLength
= 0;
2519 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2520 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2522 if ((lpClass
) && (!lpcbClass
))
2524 return ERROR_INVALID_PARAMETER
;
2527 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2528 if (!NT_SUCCESS(Status
))
2530 return RtlNtStatusToDosError(Status
);
2535 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2546 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2553 /* The class name should start at a dword boundary */
2554 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2558 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2561 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2562 if (KeyInfo
== NULL
)
2564 ErrorCode
= ERROR_OUTOFMEMORY
;
2568 Status
= NtEnumerateKey(KeyHandle
,
2570 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2574 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2575 if (!NT_SUCCESS(Status
))
2577 ErrorCode
= RtlNtStatusToDosError (Status
);
2581 if (lpClass
== NULL
)
2583 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2585 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2589 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2590 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2591 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2596 if (KeyInfo
->Node
.NameLength
> NameLength
||
2597 KeyInfo
->Node
.ClassLength
> ClassLength
)
2599 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2603 StringA
.Buffer
= lpClass
;
2605 StringA
.MaximumLength
= *lpcbClass
;
2606 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2607 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2608 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2609 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2610 lpClass
[StringA
.Length
] = 0;
2611 *lpcbClass
= StringA
.Length
;
2612 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2613 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2614 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2618 if (ErrorCode
== ERROR_SUCCESS
)
2620 StringA
.Buffer
= lpName
;
2622 StringA
.MaximumLength
= *lpcbName
;
2623 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2624 lpName
[StringA
.Length
] = 0;
2625 *lpcbName
= StringA
.Length
;
2626 if (lpftLastWriteTime
!= NULL
)
2628 if (lpClass
== NULL
)
2630 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2631 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2635 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2636 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2642 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2643 TRACE("Key Name1 Length %d\n", NameLength
);
2644 TRACE("Key Name Length %d\n", *lpcbName
);
2645 TRACE("Key Name %s\n", lpName
);
2647 RtlFreeHeap(ProcessHeap
,
2652 ClosePredefKey(KeyHandle
);
2658 /************************************************************************
2664 RegEnumKeyExW(HKEY hKey
,
2671 PFILETIME lpftLastWriteTime
)
2675 KEY_NODE_INFORMATION Node
;
2676 KEY_BASIC_INFORMATION Basic
;
2682 ULONG ClassLength
= 0;
2684 LONG ErrorCode
= ERROR_SUCCESS
;
2687 Status
= MapDefaultKey(&KeyHandle
,
2689 if (!NT_SUCCESS(Status
))
2691 return RtlNtStatusToDosError(Status
);
2696 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2707 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2714 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2718 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2721 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2724 if (KeyInfo
== NULL
)
2726 ErrorCode
= ERROR_OUTOFMEMORY
;
2730 Status
= NtEnumerateKey(KeyHandle
,
2732 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2736 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2737 if (!NT_SUCCESS(Status
))
2739 ErrorCode
= RtlNtStatusToDosError (Status
);
2743 if (lpClass
== NULL
)
2745 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2747 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2751 RtlCopyMemory(lpName
,
2752 KeyInfo
->Basic
.Name
,
2753 KeyInfo
->Basic
.NameLength
);
2754 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2755 lpName
[*lpcbName
] = 0;
2760 if (KeyInfo
->Node
.NameLength
> NameLength
||
2761 KeyInfo
->Node
.ClassLength
> ClassLength
)
2763 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2767 RtlCopyMemory(lpName
,
2769 KeyInfo
->Node
.NameLength
);
2770 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2771 lpName
[*lpcbName
] = 0;
2772 RtlCopyMemory(lpClass
,
2773 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2774 KeyInfo
->Node
.ClassLength
);
2775 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2776 lpClass
[*lpcbClass
] = 0;
2780 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2782 if (lpClass
== NULL
)
2784 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2785 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2789 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2790 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2795 RtlFreeHeap(ProcessHeap
,
2800 ClosePredefKey(KeyHandle
);
2806 /************************************************************************
2812 RegEnumValueA(HKEY hKey
,
2824 char buffer
[256], *buf_ptr
= buffer
;
2825 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2826 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2828 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2829 // hkey, index, value, val_count, reserved, type, data, count );
2831 /* NT only checks count, not val_count */
2832 if ((data
&& !count
) || reserved
)
2833 return ERROR_INVALID_PARAMETER
;
2835 status
= MapDefaultKey(&KeyHandle
, hKey
);
2836 if (!NT_SUCCESS(status
))
2838 return RtlNtStatusToDosError(status
);
2841 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2842 if (data
) total_size
+= *count
;
2843 total_size
= min( sizeof(buffer
), total_size
);
2845 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2846 buffer
, total_size
, &total_size
);
2847 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2849 /* we need to fetch the contents for a string type even if not requested,
2850 * because we need to compute the length of the ASCII string. */
2851 if (value
|| data
|| is_string(info
->Type
))
2853 /* retry with a dynamically allocated buffer */
2854 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2856 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2857 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2859 status
= STATUS_INSUFFICIENT_RESOURCES
;
2862 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2863 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2864 buf_ptr
, total_size
, &total_size
);
2867 if (status
) goto done
;
2869 if (is_string(info
->Type
))
2872 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2876 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2879 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2881 /* if the type is REG_SZ and data is not 0-terminated
2882 * and there is enough space in the buffer NT appends a \0 */
2883 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2886 info
->DataLength
= len
;
2890 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2891 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2894 if (value
&& !status
)
2898 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2899 if (len
>= *val_count
)
2901 status
= STATUS_BUFFER_OVERFLOW
;
2904 len
= *val_count
- 1;
2905 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2911 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2917 else status
= STATUS_SUCCESS
;
2919 if (type
) *type
= info
->Type
;
2920 if (count
) *count
= info
->DataLength
;
2923 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2924 ClosePredefKey(KeyHandle
);
2925 return RtlNtStatusToDosError(status
);
2929 /******************************************************************************
2930 * RegEnumValueW [ADVAPI32.@]
2934 * hkey [I] Handle to key to query
2935 * index [I] Index of value to query
2936 * value [O] Value string
2937 * val_count [I/O] Size of value buffer (in wchars)
2938 * reserved [I] Reserved
2939 * type [O] Type code
2940 * data [O] Value data
2941 * count [I/O] Size of data buffer (in bytes)
2944 * Success: ERROR_SUCCESS
2945 * Failure: nonzero error code from Winerror.h
2948 RegEnumValueW(HKEY hKey
,
2960 char buffer
[256], *buf_ptr
= buffer
;
2961 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2962 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2964 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2965 // hkey, index, value, val_count, reserved, type, data, count );
2967 /* NT only checks count, not val_count */
2968 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2970 status
= MapDefaultKey(&KeyHandle
, hKey
);
2971 if (!NT_SUCCESS(status
))
2973 return RtlNtStatusToDosError(status
);
2976 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2977 if (data
) total_size
+= *count
;
2978 total_size
= min( sizeof(buffer
), total_size
);
2980 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2981 buffer
, total_size
, &total_size
);
2982 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2986 /* retry with a dynamically allocated buffer */
2987 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2989 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2990 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2992 status
= ERROR_NOT_ENOUGH_MEMORY
;
2995 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2996 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2997 buf_ptr
, total_size
, &total_size
);
3000 if (status
) goto done
;
3004 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3006 status
= STATUS_BUFFER_OVERFLOW
;
3009 memcpy( value
, info
->Name
, info
->NameLength
);
3010 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3011 value
[*val_count
] = 0;
3016 if (info
->DataLength
> *count
)
3018 status
= STATUS_BUFFER_OVERFLOW
;
3021 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3022 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3024 /* if the type is REG_SZ and data is not 0-terminated
3025 * and there is enough space in the buffer NT appends a \0 */
3026 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3027 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3031 else status
= STATUS_SUCCESS
;
3034 if (type
) *type
= info
->Type
;
3035 if (count
) *count
= info
->DataLength
;
3038 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3039 ClosePredefKey(KeyHandle
);
3040 return RtlNtStatusToDosError(status
);
3044 /************************************************************************
3050 RegFlushKey(HKEY hKey
)
3055 if (hKey
== HKEY_PERFORMANCE_DATA
)
3057 return ERROR_SUCCESS
;
3060 Status
= MapDefaultKey(&KeyHandle
,
3062 if (!NT_SUCCESS(Status
))
3064 return RtlNtStatusToDosError(Status
);
3067 Status
= NtFlushKey(KeyHandle
);
3069 ClosePredefKey(KeyHandle
);
3071 if (!NT_SUCCESS(Status
))
3073 return RtlNtStatusToDosError(Status
);
3076 return ERROR_SUCCESS
;
3080 /************************************************************************
3086 RegGetKeySecurity(HKEY hKey
,
3087 SECURITY_INFORMATION SecurityInformation
,
3088 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3089 LPDWORD lpcbSecurityDescriptor
)
3094 if (hKey
== HKEY_PERFORMANCE_DATA
)
3096 return ERROR_INVALID_HANDLE
;
3099 Status
= MapDefaultKey(&KeyHandle
,
3101 if (!NT_SUCCESS(Status
))
3103 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3104 return RtlNtStatusToDosError(Status
);
3107 Status
= NtQuerySecurityObject(KeyHandle
,
3108 SecurityInformation
,
3109 pSecurityDescriptor
,
3110 *lpcbSecurityDescriptor
,
3111 lpcbSecurityDescriptor
);
3113 ClosePredefKey(KeyHandle
);
3115 if (!NT_SUCCESS(Status
))
3117 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3118 return RtlNtStatusToDosError(Status
);
3121 return ERROR_SUCCESS
;
3125 /************************************************************************
3131 RegLoadKeyA(HKEY hKey
,
3135 UNICODE_STRING FileName
;
3136 UNICODE_STRING KeyName
;
3139 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3141 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3144 ErrorCode
= RegLoadKeyW(hKey
,
3148 RtlFreeUnicodeString(&FileName
);
3149 RtlFreeUnicodeString(&KeyName
);
3155 /************************************************************************
3161 RegLoadKeyW(HKEY hKey
,
3165 OBJECT_ATTRIBUTES FileObjectAttributes
;
3166 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3167 UNICODE_STRING FileName
;
3168 UNICODE_STRING KeyName
;
3171 LONG ErrorCode
= ERROR_SUCCESS
;
3173 if (hKey
== HKEY_PERFORMANCE_DATA
)
3175 return ERROR_INVALID_HANDLE
;
3178 Status
= MapDefaultKey(&KeyHandle
,
3180 if (!NT_SUCCESS(Status
))
3182 return RtlNtStatusToDosError(Status
);
3185 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3190 ErrorCode
= ERROR_BAD_PATHNAME
;
3194 InitializeObjectAttributes(&FileObjectAttributes
,
3196 OBJ_CASE_INSENSITIVE
,
3200 RtlInitUnicodeString(&KeyName
,
3203 InitializeObjectAttributes(&KeyObjectAttributes
,
3205 OBJ_CASE_INSENSITIVE
,
3209 Status
= NtLoadKey(&KeyObjectAttributes
,
3210 &FileObjectAttributes
);
3212 RtlFreeHeap(RtlGetProcessHeap(),
3216 if (!NT_SUCCESS(Status
))
3218 ErrorCode
= RtlNtStatusToDosError(Status
);
3223 ClosePredefKey(KeyHandle
);
3229 /************************************************************************
3230 * RegNotifyChangeKeyValue
3235 RegNotifyChangeKeyValue(HKEY hKey
,
3237 DWORD dwNotifyFilter
,
3241 IO_STATUS_BLOCK IoStatusBlock
;
3244 LONG ErrorCode
= ERROR_SUCCESS
;
3246 if (hKey
== HKEY_PERFORMANCE_DATA
)
3248 return ERROR_INVALID_HANDLE
;
3251 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3253 return ERROR_INVALID_PARAMETER
;
3256 Status
= MapDefaultKey(&KeyHandle
,
3258 if (!NT_SUCCESS(Status
))
3260 return RtlNtStatusToDosError(Status
);
3263 /* FIXME: Remote key handles must fail */
3265 Status
= NtNotifyChangeKey(KeyHandle
,
3275 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3277 ErrorCode
= RtlNtStatusToDosError(Status
);
3280 ClosePredefKey(KeyHandle
);
3286 /************************************************************************
3287 * RegOpenCurrentUser
3292 RegOpenCurrentUser(IN REGSAM samDesired
,
3293 OUT PHKEY phkResult
)
3297 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3298 (PHANDLE
)phkResult
);
3299 if (!NT_SUCCESS(Status
))
3301 /* NOTE - don't set the last error code! just return the error! */
3302 return RtlNtStatusToDosError(Status
);
3305 return ERROR_SUCCESS
;
3309 /************************************************************************
3312 * 20050503 Fireball - imported from WINE
3317 RegOpenKeyA(HKEY hKey
,
3321 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3322 hKey
, lpSubKey
, phkResult
);
3325 return ERROR_INVALID_PARAMETER
;
3327 if (!hKey
&& lpSubKey
&& phkResult
)
3329 return ERROR_INVALID_HANDLE
;
3332 if (!lpSubKey
|| !*lpSubKey
)
3335 return ERROR_SUCCESS
;
3338 return RegOpenKeyExA(hKey
,
3346 /************************************************************************
3351 * 20050503 Fireball - imported from WINE
3356 RegOpenKeyW(HKEY hKey
,
3360 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3361 hKey
, lpSubKey
, phkResult
);
3364 return ERROR_INVALID_PARAMETER
;
3366 if (!hKey
&& lpSubKey
&& phkResult
)
3368 return ERROR_INVALID_HANDLE
;
3371 if (!lpSubKey
|| !*lpSubKey
)
3374 return ERROR_SUCCESS
;
3377 return RegOpenKeyExW(hKey
,
3385 /************************************************************************
3393 _In_ LPCSTR lpSubKey
,
3394 _In_ DWORD ulOptions
,
3395 _In_ REGSAM samDesired
,
3396 _Out_ PHKEY phkResult
)
3398 UNICODE_STRING SubKeyString
;
3401 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3402 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3404 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3407 ErrorCode
= RegOpenKeyExW(hKey
, SubKeyString
.Buffer
, ulOptions
, samDesired
, phkResult
);
3409 RtlFreeUnicodeString(&SubKeyString
);
3415 /************************************************************************
3421 RegOpenKeyExW(HKEY hKey
,
3427 OBJECT_ATTRIBUTES ObjectAttributes
;
3428 UNICODE_STRING SubKeyString
;
3431 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3432 LONG ErrorCode
= ERROR_SUCCESS
;
3434 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3435 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3438 return ERROR_INVALID_PARAMETER
;
3441 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3442 if (!NT_SUCCESS(Status
))
3444 return RtlNtStatusToDosError(Status
);
3447 if (IsHKCRKey(KeyHandle
))
3448 return OpenHKCRKey(KeyHandle
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3450 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3451 Attributes
|= OBJ_OPENLINK
;
3453 if (lpSubKey
!= NULL
)
3454 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3456 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3458 InitializeObjectAttributes(&ObjectAttributes
,
3464 Status
= NtOpenKey((PHANDLE
)phkResult
,
3468 if (!NT_SUCCESS(Status
))
3470 ErrorCode
= RtlNtStatusToDosError(Status
);
3474 ClosePredefKey(KeyHandle
);
3480 /************************************************************************
3481 * RegOpenUserClassesRoot
3486 RegOpenUserClassesRoot(IN HANDLE hToken
,
3488 IN REGSAM samDesired
,
3489 OUT PHKEY phkResult
)
3491 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3492 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3493 PTOKEN_USER TokenUserData
;
3494 ULONG RequiredLength
;
3495 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3496 OBJECT_ATTRIBUTES ObjectAttributes
;
3499 /* check parameters */
3500 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3502 return ERROR_INVALID_PARAMETER
;
3506 * Get the user sid from the token
3510 /* determine how much memory we need */
3511 Status
= NtQueryInformationToken(hToken
,
3516 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3518 /* NOTE - as opposed to all other registry functions windows does indeed
3519 change the last error code in case the caller supplied a invalid
3520 handle for example! */
3521 return RtlNtStatusToDosError(Status
);
3523 RegInitialize(); /* HACK until delay-loading is implemented */
3524 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3527 if (TokenUserData
== NULL
)
3529 return ERROR_NOT_ENOUGH_MEMORY
;
3532 /* attempt to read the information */
3533 Status
= NtQueryInformationToken(hToken
,
3538 if (!NT_SUCCESS(Status
))
3540 RtlFreeHeap(ProcessHeap
,
3543 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3545 /* the information appears to have changed?! try again */
3549 /* NOTE - as opposed to all other registry functions windows does indeed
3550 change the last error code in case the caller supplied a invalid
3551 handle for example! */
3552 return RtlNtStatusToDosError(Status
);
3556 * Build the absolute path for the user's registry in the form
3557 * "\Registry\User\<SID>_Classes"
3559 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3560 TokenUserData
->User
.Sid
,
3563 /* we don't need the user data anymore, free it */
3564 RtlFreeHeap(ProcessHeap
,
3568 if (!NT_SUCCESS(Status
))
3570 return RtlNtStatusToDosError(Status
);
3573 /* allocate enough memory for the entire key string */
3574 UserClassesKeyRoot
.Length
= 0;
3575 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3576 sizeof(UserClassesKeyPrefix
) +
3577 sizeof(UserClassesKeySuffix
);
3578 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3580 UserClassesKeyRoot
.MaximumLength
);
3581 if (UserClassesKeyRoot
.Buffer
== NULL
)
3583 RtlFreeUnicodeString(&UserSidString
);
3584 return RtlNtStatusToDosError(Status
);
3587 /* build the string */
3588 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3589 UserClassesKeyPrefix
);
3590 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3592 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3593 UserClassesKeySuffix
);
3595 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3600 InitializeObjectAttributes(&ObjectAttributes
,
3601 &UserClassesKeyRoot
,
3602 OBJ_CASE_INSENSITIVE
,
3606 Status
= NtOpenKey((PHANDLE
)phkResult
,
3610 RtlFreeUnicodeString(&UserSidString
);
3611 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3613 if (!NT_SUCCESS(Status
))
3615 return RtlNtStatusToDosError(Status
);
3618 return ERROR_SUCCESS
;
3622 /************************************************************************
3628 RegQueryInfoKeyA(HKEY hKey
,
3633 LPDWORD lpcbMaxSubKeyLen
,
3634 LPDWORD lpcbMaxClassLen
,
3636 LPDWORD lpcbMaxValueNameLen
,
3637 LPDWORD lpcbMaxValueLen
,
3638 LPDWORD lpcbSecurityDescriptor
,
3639 PFILETIME lpftLastWriteTime
)
3641 WCHAR ClassName
[MAX_PATH
];
3642 UNICODE_STRING UnicodeString
;
3643 ANSI_STRING AnsiString
;
3646 RtlInitUnicodeString(&UnicodeString
,
3648 if (lpClass
!= NULL
)
3650 UnicodeString
.Buffer
= &ClassName
[0];
3651 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3652 AnsiString
.MaximumLength
= *lpcbClass
;
3655 ErrorCode
= RegQueryInfoKeyW(hKey
,
3656 UnicodeString
.Buffer
,
3663 lpcbMaxValueNameLen
,
3665 lpcbSecurityDescriptor
,
3667 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3669 AnsiString
.Buffer
= lpClass
;
3670 AnsiString
.Length
= 0;
3671 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3672 RtlUnicodeStringToAnsiString(&AnsiString
,
3675 *lpcbClass
= AnsiString
.Length
;
3676 lpClass
[AnsiString
.Length
] = 0;
3683 /************************************************************************
3689 RegQueryInfoKeyW(HKEY hKey
,
3694 LPDWORD lpcbMaxSubKeyLen
,
3695 LPDWORD lpcbMaxClassLen
,
3697 LPDWORD lpcbMaxValueNameLen
,
3698 LPDWORD lpcbMaxValueLen
,
3699 LPDWORD lpcbSecurityDescriptor
,
3700 PFILETIME lpftLastWriteTime
)
3702 KEY_FULL_INFORMATION FullInfoBuffer
;
3703 PKEY_FULL_INFORMATION FullInfo
;
3705 ULONG ClassLength
= 0;
3709 LONG ErrorCode
= ERROR_SUCCESS
;
3711 if ((lpClass
) && (!lpcbClass
))
3713 return ERROR_INVALID_PARAMETER
;
3716 Status
= MapDefaultKey(&KeyHandle
,
3718 if (!NT_SUCCESS(Status
))
3720 return RtlNtStatusToDosError(Status
);
3723 if (lpClass
!= NULL
)
3727 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3734 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3735 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3738 if (FullInfo
== NULL
)
3740 ErrorCode
= ERROR_OUTOFMEMORY
;
3744 FullInfo
->ClassLength
= ClassLength
;
3748 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3749 FullInfo
= &FullInfoBuffer
;
3750 FullInfo
->ClassLength
= 0;
3752 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3754 Status
= NtQueryKey(KeyHandle
,
3759 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3760 if (!NT_SUCCESS(Status
))
3762 if (lpClass
!= NULL
)
3764 RtlFreeHeap(ProcessHeap
,
3769 ErrorCode
= RtlNtStatusToDosError(Status
);
3773 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3774 if (lpcSubKeys
!= NULL
)
3776 *lpcSubKeys
= FullInfo
->SubKeys
;
3779 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3780 if (lpcbMaxSubKeyLen
!= NULL
)
3782 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3785 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3786 if (lpcbMaxClassLen
!= NULL
)
3788 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3791 TRACE("Values %lu\n", FullInfo
->Values
);
3792 if (lpcValues
!= NULL
)
3794 *lpcValues
= FullInfo
->Values
;
3797 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3798 if (lpcbMaxValueNameLen
!= NULL
)
3800 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3803 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3804 if (lpcbMaxValueLen
!= NULL
)
3806 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3809 if (lpcbSecurityDescriptor
!= NULL
)
3811 Status
= NtQuerySecurityObject(KeyHandle
,
3812 OWNER_SECURITY_INFORMATION
|
3813 GROUP_SECURITY_INFORMATION
|
3814 DACL_SECURITY_INFORMATION
,
3817 lpcbSecurityDescriptor
);
3818 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
3820 if (lpClass
!= NULL
)
3822 RtlFreeHeap(ProcessHeap
,
3827 ErrorCode
= RtlNtStatusToDosError(Status
);
3832 if (lpftLastWriteTime
!= NULL
)
3834 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3835 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3838 if (lpClass
!= NULL
)
3840 if (FullInfo
->ClassLength
> ClassLength
)
3842 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3846 RtlCopyMemory(lpClass
,
3848 FullInfo
->ClassLength
);
3849 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3850 lpClass
[*lpcbClass
] = 0;
3853 RtlFreeHeap(ProcessHeap
,
3859 ClosePredefKey(KeyHandle
);
3865 /************************************************************************
3866 * RegQueryMultipleValuesA
3871 RegQueryMultipleValuesA(HKEY hKey
,
3878 DWORD maxBytes
= *ldwTotsize
;
3879 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3882 if (maxBytes
>= (1024*1024))
3883 return ERROR_TRANSFER_TOO_LONG
;
3887 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3888 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3890 for (i
= 0; i
< num_vals
; i
++)
3892 val_list
[i
].ve_valuelen
= 0;
3893 ErrorCode
= RegQueryValueExA(hKey
,
3894 val_list
[i
].ve_valuename
,
3898 &val_list
[i
].ve_valuelen
);
3899 if (ErrorCode
!= ERROR_SUCCESS
)
3904 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3906 ErrorCode
= RegQueryValueExA(hKey
,
3907 val_list
[i
].ve_valuename
,
3909 &val_list
[i
].ve_type
,
3911 &val_list
[i
].ve_valuelen
);
3912 if (ErrorCode
!= ERROR_SUCCESS
)
3917 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3919 bufptr
+= val_list
[i
].ve_valuelen
;
3922 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3925 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3929 /************************************************************************
3930 * RegQueryMultipleValuesW
3935 RegQueryMultipleValuesW(HKEY hKey
,
3942 DWORD maxBytes
= *ldwTotsize
;
3943 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3946 if (maxBytes
>= (1024*1024))
3947 return ERROR_TRANSFER_TOO_LONG
;
3951 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3952 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3954 for (i
= 0; i
< num_vals
; i
++)
3956 val_list
[i
].ve_valuelen
= 0;
3957 ErrorCode
= RegQueryValueExW(hKey
,
3958 val_list
[i
].ve_valuename
,
3962 &val_list
[i
].ve_valuelen
);
3963 if (ErrorCode
!= ERROR_SUCCESS
)
3968 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3970 ErrorCode
= RegQueryValueExW(hKey
,
3971 val_list
[i
].ve_valuename
,
3973 &val_list
[i
].ve_type
,
3975 &val_list
[i
].ve_valuelen
);
3976 if (ErrorCode
!= ERROR_SUCCESS
)
3981 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3983 bufptr
+= val_list
[i
].ve_valuelen
;
3986 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3989 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3993 /************************************************************************
3994 * RegQueryReflectionKey
3999 RegQueryReflectionKey(IN HKEY hBase
,
4000 OUT BOOL
* bIsReflectionDisabled
)
4002 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4003 hBase
, bIsReflectionDisabled
);
4004 return ERROR_CALL_NOT_IMPLEMENTED
;
4008 /******************************************************************************
4009 * RegQueryValueExA [ADVAPI32.@]
4011 * Get the type and contents of a specified value under with a key.
4014 * hkey [I] Handle of the key to query
4015 * name [I] Name of value under hkey to query
4016 * reserved [I] Reserved - must be NULL
4017 * type [O] Destination for the value type, or NULL if not required
4018 * data [O] Destination for the values contents, or NULL if not required
4019 * count [I/O] Size of data, updated with the number of bytes returned
4022 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4023 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4024 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4025 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4028 * MSDN states that if data is too small it is partially filled. In reality
4029 * it remains untouched.
4033 RegQueryValueExA(HKEY hkeyorg
,
4043 UNICODE_STRING nameW
;
4044 DWORD total_size
, datalen
= 0;
4045 char buffer
[256], *buf_ptr
= buffer
;
4046 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4047 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4049 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4050 hkeyorg
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
4052 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4053 status
= MapDefaultKey(&hkey
, hkeyorg
);
4054 if (!NT_SUCCESS(status
))
4056 return RtlNtStatusToDosError(status
);
4059 if (count
) datalen
= *count
;
4060 if (!data
&& count
) *count
= 0;
4062 RtlInitAnsiString( &nameA
, name
);
4063 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
4065 ClosePredefKey(hkey
);
4066 return RtlNtStatusToDosError(status
);
4069 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4070 buffer
, sizeof(buffer
), &total_size
);
4071 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4073 /* we need to fetch the contents for a string type even if not requested,
4074 * because we need to compute the length of the ASCII string. */
4075 if (data
|| is_string(info
->Type
))
4077 /* retry with a dynamically allocated buffer */
4078 while (status
== STATUS_BUFFER_OVERFLOW
)
4080 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4081 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4083 status
= STATUS_NO_MEMORY
;
4086 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4087 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4088 buf_ptr
, total_size
, &total_size
);
4091 if (status
) goto done
;
4093 if (is_string(info
->Type
))
4097 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
4098 total_size
- info_size
);
4101 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4104 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
4105 total_size
- info_size
);
4106 /* if the type is REG_SZ and data is not 0-terminated
4107 * and there is enough space in the buffer NT appends a \0 */
4108 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
4111 total_size
= len
+ info_size
;
4115 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4116 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4119 else status
= STATUS_SUCCESS
;
4121 if (type
) *type
= info
->Type
;
4122 if (count
) *count
= total_size
- info_size
;
4125 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4126 RtlFreeUnicodeString( &nameW
);
4127 ClosePredefKey(hkey
);
4128 return RtlNtStatusToDosError(status
);
4132 /************************************************************************
4139 RegQueryValueExW(HKEY hkeyorg
,
4148 UNICODE_STRING name_str
;
4150 char buffer
[256], *buf_ptr
= buffer
;
4151 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4152 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4154 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4155 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4156 (count
&& data
) ? *count
: 0 );
4158 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4160 status
= MapDefaultKey(&hkey
, hkeyorg
);
4161 if (!NT_SUCCESS(status
))
4163 return RtlNtStatusToDosError(status
);
4166 RtlInitUnicodeString( &name_str
, name
);
4168 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4171 total_size
= info_size
;
4172 if (count
) *count
= 0;
4175 /* this matches Win9x behaviour - NT sets *type to a random value */
4176 if (type
) *type
= REG_NONE
;
4178 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4179 buffer
, total_size
, &total_size
);
4180 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4184 /* retry with a dynamically allocated buffer */
4185 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4187 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4188 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4190 ClosePredefKey(hkey
);
4191 return ERROR_NOT_ENOUGH_MEMORY
;
4193 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4194 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4195 buf_ptr
, total_size
, &total_size
);
4198 if (NT_SUCCESS(status
))
4200 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4201 /* if the type is REG_SZ and data is not 0-terminated
4202 * and there is enough space in the buffer NT appends a \0 */
4203 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4205 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4206 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4209 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4211 else status
= STATUS_SUCCESS
;
4213 if (type
) *type
= info
->Type
;
4214 if (count
) *count
= total_size
- info_size
;
4217 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4218 ClosePredefKey(hkey
);
4219 return RtlNtStatusToDosError(status
);
4223 /************************************************************************
4228 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4233 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4235 if (name
&& name
[0])
4237 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4239 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4240 if (subkey
!= hkey
) RegCloseKey( subkey
);
4241 if (ret
== ERROR_FILE_NOT_FOUND
)
4243 /* return empty string if default value not found */
4244 if (data
) *data
= 0;
4245 if (count
) *count
= 1;
4246 ret
= ERROR_SUCCESS
;
4252 /************************************************************************
4257 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4262 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4265 return ERROR_INVALID_HANDLE
;
4267 if (name
&& name
[0])
4269 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4270 if (ret
!= ERROR_SUCCESS
)
4276 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4280 RegCloseKey( subkey
);
4283 if (ret
== ERROR_FILE_NOT_FOUND
)
4285 /* return empty string if default value not found */
4289 *count
= sizeof(WCHAR
);
4290 ret
= ERROR_SUCCESS
;
4296 /************************************************************************
4302 RegReplaceKeyA(HKEY hKey
,
4307 UNICODE_STRING SubKey
;
4308 UNICODE_STRING NewFile
;
4309 UNICODE_STRING OldFile
;
4312 RtlCreateUnicodeStringFromAsciiz(&SubKey
,
4314 RtlCreateUnicodeStringFromAsciiz(&OldFile
,
4316 RtlCreateUnicodeStringFromAsciiz(&NewFile
,
4319 ErrorCode
= RegReplaceKeyW(hKey
,
4324 RtlFreeUnicodeString(&OldFile
);
4325 RtlFreeUnicodeString(&NewFile
);
4326 RtlFreeUnicodeString(&SubKey
);
4332 /************************************************************************
4338 RegReplaceKeyW(HKEY hKey
,
4343 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4344 OBJECT_ATTRIBUTES NewObjectAttributes
;
4345 OBJECT_ATTRIBUTES OldObjectAttributes
;
4346 UNICODE_STRING SubKeyName
;
4347 UNICODE_STRING NewFileName
;
4348 UNICODE_STRING OldFileName
;
4349 BOOLEAN CloseRealKey
;
4350 HANDLE RealKeyHandle
;
4353 LONG ErrorCode
= ERROR_SUCCESS
;
4355 if (hKey
== HKEY_PERFORMANCE_DATA
)
4357 return ERROR_INVALID_HANDLE
;
4360 Status
= MapDefaultKey(&KeyHandle
,
4362 if (!NT_SUCCESS(Status
))
4364 return RtlNtStatusToDosError(Status
);
4367 /* Open the real key */
4368 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4370 RtlInitUnicodeString(&SubKeyName
,
4372 InitializeObjectAttributes(&KeyObjectAttributes
,
4374 OBJ_CASE_INSENSITIVE
,
4377 Status
= NtOpenKey(&RealKeyHandle
,
4379 &KeyObjectAttributes
);
4380 if (!NT_SUCCESS(Status
))
4382 ErrorCode
= RtlNtStatusToDosError(Status
);
4386 CloseRealKey
= TRUE
;
4390 RealKeyHandle
= KeyHandle
;
4391 CloseRealKey
= FALSE
;
4394 /* Convert new file name */
4395 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4402 NtClose(RealKeyHandle
);
4405 ErrorCode
= ERROR_INVALID_PARAMETER
;
4409 InitializeObjectAttributes(&NewObjectAttributes
,
4411 OBJ_CASE_INSENSITIVE
,
4415 /* Convert old file name */
4416 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4421 RtlFreeHeap(RtlGetProcessHeap (),
4423 NewFileName
.Buffer
);
4426 NtClose(RealKeyHandle
);
4429 ErrorCode
= ERROR_INVALID_PARAMETER
;
4433 InitializeObjectAttributes(&OldObjectAttributes
,
4435 OBJ_CASE_INSENSITIVE
,
4439 Status
= NtReplaceKey(&NewObjectAttributes
,
4441 &OldObjectAttributes
);
4443 RtlFreeHeap(RtlGetProcessHeap(),
4445 OldFileName
.Buffer
);
4446 RtlFreeHeap(RtlGetProcessHeap(),
4448 NewFileName
.Buffer
);
4452 NtClose(RealKeyHandle
);
4455 if (!NT_SUCCESS(Status
))
4457 return RtlNtStatusToDosError(Status
);
4461 ClosePredefKey(KeyHandle
);
4467 /************************************************************************
4473 RegRestoreKeyA(HKEY hKey
,
4477 UNICODE_STRING FileName
;
4480 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4483 ErrorCode
= RegRestoreKeyW(hKey
,
4487 RtlFreeUnicodeString(&FileName
);
4493 /************************************************************************
4499 RegRestoreKeyW(HKEY hKey
,
4503 OBJECT_ATTRIBUTES ObjectAttributes
;
4504 IO_STATUS_BLOCK IoStatusBlock
;
4505 UNICODE_STRING FileName
;
4510 if (hKey
== HKEY_PERFORMANCE_DATA
)
4512 return ERROR_INVALID_HANDLE
;
4515 Status
= MapDefaultKey(&KeyHandle
,
4517 if (!NT_SUCCESS(Status
))
4519 return RtlNtStatusToDosError(Status
);
4522 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4527 Status
= STATUS_INVALID_PARAMETER
;
4531 InitializeObjectAttributes(&ObjectAttributes
,
4533 OBJ_CASE_INSENSITIVE
,
4537 Status
= NtOpenFile(&FileHandle
,
4542 FILE_SYNCHRONOUS_IO_NONALERT
);
4543 RtlFreeHeap(RtlGetProcessHeap(),
4546 if (!NT_SUCCESS(Status
))
4551 Status
= NtRestoreKey(KeyHandle
,
4554 NtClose (FileHandle
);
4557 ClosePredefKey(KeyHandle
);
4559 if (!NT_SUCCESS(Status
))
4561 return RtlNtStatusToDosError(Status
);
4564 return ERROR_SUCCESS
;
4568 /************************************************************************
4574 RegSaveKeyA(HKEY hKey
,
4576 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4578 UNICODE_STRING FileName
;
4581 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4583 ErrorCode
= RegSaveKeyW(hKey
,
4585 lpSecurityAttributes
);
4586 RtlFreeUnicodeString(&FileName
);
4592 /************************************************************************
4598 RegSaveKeyW(HKEY hKey
,
4600 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4602 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4603 OBJECT_ATTRIBUTES ObjectAttributes
;
4604 UNICODE_STRING FileName
;
4605 IO_STATUS_BLOCK IoStatusBlock
;
4610 Status
= MapDefaultKey(&KeyHandle
,
4612 if (!NT_SUCCESS(Status
))
4614 return RtlNtStatusToDosError(Status
);
4617 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4622 Status
= STATUS_INVALID_PARAMETER
;
4626 if (lpSecurityAttributes
!= NULL
)
4628 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4631 InitializeObjectAttributes(&ObjectAttributes
,
4633 OBJ_CASE_INSENSITIVE
,
4635 SecurityDescriptor
);
4636 Status
= NtCreateFile(&FileHandle
,
4637 GENERIC_WRITE
| SYNCHRONIZE
,
4641 FILE_ATTRIBUTE_NORMAL
,
4644 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4647 RtlFreeHeap(RtlGetProcessHeap(),
4650 if (!NT_SUCCESS(Status
))
4655 Status
= NtSaveKey(KeyHandle
,
4657 NtClose (FileHandle
);
4660 ClosePredefKey(KeyHandle
);
4662 if (!NT_SUCCESS(Status
))
4664 return RtlNtStatusToDosError(Status
);
4667 return ERROR_SUCCESS
;
4671 /************************************************************************
4678 RegSaveKeyExA(HKEY hKey
,
4680 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4683 UNICODE_STRING FileName
;
4686 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4688 ErrorCode
= RegSaveKeyExW(hKey
,
4690 lpSecurityAttributes
,
4692 RtlFreeUnicodeString(&FileName
);
4698 /************************************************************************
4705 RegSaveKeyExW(HKEY hKey
,
4707 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4712 case REG_STANDARD_FORMAT
:
4713 case REG_LATEST_FORMAT
:
4714 case REG_NO_COMPRESSION
:
4717 return ERROR_INVALID_PARAMETER
;
4720 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4722 return RegSaveKeyW(hKey
,
4724 lpSecurityAttributes
);
4728 /************************************************************************
4734 RegSetKeySecurity(HKEY hKey
,
4735 SECURITY_INFORMATION SecurityInformation
,
4736 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4741 if (hKey
== HKEY_PERFORMANCE_DATA
)
4743 return ERROR_INVALID_HANDLE
;
4746 Status
= MapDefaultKey(&KeyHandle
,
4748 if (!NT_SUCCESS(Status
))
4750 return RtlNtStatusToDosError(Status
);
4753 Status
= NtSetSecurityObject(KeyHandle
,
4754 SecurityInformation
,
4755 pSecurityDescriptor
);
4757 ClosePredefKey(KeyHandle
);
4759 if (!NT_SUCCESS(Status
))
4761 return RtlNtStatusToDosError(Status
);
4764 return ERROR_SUCCESS
;
4768 /************************************************************************
4774 RegSetValueExA(HKEY hKey
,
4781 UNICODE_STRING ValueName
;
4783 ANSI_STRING AnsiString
;
4784 UNICODE_STRING Data
;
4790 /* Convert SubKey name to Unicode */
4791 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4794 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4797 return ERROR_NOT_ENOUGH_MEMORY
;
4801 ValueName
.Buffer
= NULL
;
4804 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4807 if (is_string(dwType
) && (cbData
!= 0))
4809 /* Convert ANSI string Data to Unicode */
4810 /* If last character NOT zero then increment length */
4811 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4812 AnsiString
.Buffer
= (PSTR
)lpData
;
4813 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4814 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4815 Status
= RtlAnsiStringToUnicodeString(&Data
,
4819 if (!NT_SUCCESS(Status
))
4821 if (pValueName
!= NULL
)
4822 RtlFreeUnicodeString(&ValueName
);
4824 return RtlNtStatusToDosError(Status
);
4826 pData
= (LPBYTE
)Data
.Buffer
;
4827 DataSize
= cbData
* sizeof(WCHAR
);
4832 pData
= (LPBYTE
)lpData
;
4836 ErrorCode
= RegSetValueExW(hKey
,
4843 if (pValueName
!= NULL
)
4844 RtlFreeUnicodeString(&ValueName
);
4846 if (Data
.Buffer
!= NULL
)
4847 RtlFreeUnicodeString(&Data
);
4853 /************************************************************************
4859 RegSetValueExW(HKEY hKey
,
4860 LPCWSTR lpValueName
,
4866 UNICODE_STRING ValueName
;
4870 if (is_string(dwType
) && (cbData
!= 0))
4872 PWSTR pwsData
= (PWSTR
)lpData
;
4876 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4877 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4879 /* Increment length if last character is not zero and next is zero */
4880 cbData
+= sizeof(WCHAR
);
4883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4885 _SEH2_YIELD(return ERROR_NOACCESS
);
4890 Status
= MapDefaultKey(&KeyHandle
,
4892 if (!NT_SUCCESS(Status
))
4894 return RtlNtStatusToDosError(Status
);
4897 RtlInitUnicodeString(&ValueName
, lpValueName
);
4899 Status
= NtSetValueKey(KeyHandle
,
4906 ClosePredefKey(KeyHandle
);
4908 if (!NT_SUCCESS(Status
))
4910 return RtlNtStatusToDosError(Status
);
4913 return ERROR_SUCCESS
;
4917 /************************************************************************
4923 RegSetValueA(HKEY hKeyOriginal
,
4934 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4936 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4938 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4939 if (!NT_SUCCESS(Status
))
4941 return RtlNtStatusToDosError (Status
);
4945 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4947 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
4948 if (ret
!= ERROR_SUCCESS
)
4952 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4954 RegCloseKey(subkey
);
4957 ClosePredefKey(hKey
);
4963 /************************************************************************
4969 RegSetValueW(HKEY hKeyOriginal
,
4980 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4982 if (dwType
!= REG_SZ
|| !lpData
)
4983 return ERROR_INVALID_PARAMETER
;
4985 Status
= MapDefaultKey(&hKey
,
4987 if (!NT_SUCCESS(Status
))
4989 return RtlNtStatusToDosError(Status
);
4993 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4995 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
4996 if (ret
!= ERROR_SUCCESS
)
5000 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
5001 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
5003 RegCloseKey(subkey
);
5006 ClosePredefKey(hKey
);
5012 /************************************************************************
5018 RegUnLoadKeyA(HKEY hKey
,
5021 UNICODE_STRING KeyName
;
5024 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
5027 ErrorCode
= RegUnLoadKeyW(hKey
,
5030 RtlFreeUnicodeString (&KeyName
);
5036 /************************************************************************
5042 RegUnLoadKeyW(HKEY hKey
,
5045 OBJECT_ATTRIBUTES ObjectAttributes
;
5046 UNICODE_STRING KeyName
;
5050 if (hKey
== HKEY_PERFORMANCE_DATA
)
5052 return ERROR_INVALID_HANDLE
;
5055 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5056 if (!NT_SUCCESS(Status
))
5058 return RtlNtStatusToDosError(Status
);
5061 RtlInitUnicodeString(&KeyName
,
5064 InitializeObjectAttributes(&ObjectAttributes
,
5066 OBJ_CASE_INSENSITIVE
,
5070 Status
= NtUnloadKey(&ObjectAttributes
);
5072 ClosePredefKey(KeyHandle
);
5074 if (!NT_SUCCESS(Status
))
5076 return RtlNtStatusToDosError(Status
);
5079 return ERROR_SUCCESS
;
5083 /******************************************************************************
5084 * load_string [Internal]
5086 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5087 * avoid importing user32, which is higher level than advapi32. Helper for
5090 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5097 /* Negative values have to be inverted. */
5098 if (HIWORD(resId
) == 0xffff)
5099 resId
= (UINT
)(-((INT
)resId
));
5101 /* Load the resource into memory and get a pointer to it. */
5102 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5103 if (!hResource
) return 0;
5104 hMemory
= LoadResource(hModule
, hResource
);
5105 if (!hMemory
) return 0;
5106 pString
= LockResource(hMemory
);
5108 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5109 idxString
= resId
& 0xf;
5110 while (idxString
--) pString
+= *pString
+ 1;
5112 /* If no buffer is given, return length of the string. */
5113 if (!pwszBuffer
) return *pString
;
5115 /* Else copy over the string, respecting the buffer size. */
5116 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5119 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5120 pwszBuffer
[cMaxChars
] = L
'\0';
5127 /************************************************************************
5133 RegLoadMUIStringW(IN HKEY hKey
,
5134 IN LPCWSTR pszValue OPTIONAL
,
5135 OUT LPWSTR pszOutBuf
,
5137 OUT LPDWORD pcbData OPTIONAL
,
5139 IN LPCWSTR pszDirectory OPTIONAL
)
5141 DWORD dwValueType
, cbData
;
5142 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5145 /* Parameter sanity checks. */
5146 if (!hKey
|| !pszOutBuf
)
5147 return ERROR_INVALID_PARAMETER
;
5149 if (pszDirectory
&& *pszDirectory
)
5151 FIXME("BaseDir parameter not yet supported!\n");
5152 return ERROR_INVALID_PARAMETER
;
5155 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5156 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5157 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5158 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5160 result
= ERROR_FILE_NOT_FOUND
;
5163 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5164 if (!pwszTempBuffer
)
5166 result
= ERROR_NOT_ENOUGH_MEMORY
;
5169 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5170 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5172 /* Expand environment variables, if appropriate, or copy the original string over. */
5173 if (dwValueType
== REG_EXPAND_SZ
)
5175 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5176 if (!cbData
) goto cleanup
;
5177 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5178 if (!pwszExpandedBuffer
)
5180 result
= ERROR_NOT_ENOUGH_MEMORY
;
5183 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5187 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5188 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5191 /* If the value references a resource based string, parse the value and load the string.
5192 * Else just copy over the original value. */
5193 result
= ERROR_SUCCESS
;
5194 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5196 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5200 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5204 /* Format of the expanded value is 'path_to_dll,-resId' */
5205 if (!pComma
|| pComma
[1] != L
'-')
5207 result
= ERROR_BADKEY
;
5211 uiStringId
= _wtoi(pComma
+2);
5214 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5215 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5216 result
= ERROR_BADKEY
;
5217 FreeLibrary(hModule
);
5221 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5222 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5227 /************************************************************************
5233 RegLoadMUIStringA(IN HKEY hKey
,
5234 IN LPCSTR pszValue OPTIONAL
,
5235 OUT LPSTR pszOutBuf
,
5237 OUT LPDWORD pcbData OPTIONAL
,
5239 IN LPCSTR pszDirectory OPTIONAL
)
5241 UNICODE_STRING valueW
, baseDirW
;
5243 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5246 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5247 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5248 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5249 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5251 result
= ERROR_NOT_ENOUGH_MEMORY
;
5255 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5258 if (result
== ERROR_SUCCESS
)
5260 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5266 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5267 RtlFreeUnicodeString(&baseDirW
);
5268 RtlFreeUnicodeString(&valueW
);