2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
17 #include <wine/debug.h>
19 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
21 /* DEFINES ******************************************************************/
23 #define MAX_DEFAULT_HANDLES 6
24 #define REG_MAX_NAME_SIZE 256
25 #define REG_MAX_DATA_SIZE 2048
27 /* GLOBALS ******************************************************************/
29 static RTL_CRITICAL_SECTION HandleTableCS
;
30 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
31 static HANDLE ProcessHeap
;
32 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
33 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
35 /* PROTOTYPES ***************************************************************/
37 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
38 static VOID
CloseDefaultKeys(VOID
);
39 #define ClosePredefKey(Handle) \
40 if ((ULONG_PTR)Handle & 0x1) { \
43 #define IsPredefKey(HKey) \
44 (((ULONG)(HKey) & 0xF0000000) == 0x80000000)
45 #define GetPredefKeyIndex(HKey) \
46 ((ULONG)(HKey) & 0x0FFFFFFF)
48 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
49 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
54 /* FUNCTIONS ****************************************************************/
55 /* check if value type needs string conversion (Ansi<->Unicode) */
56 __inline
static int is_string( DWORD type
)
58 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
61 /************************************************************************
62 * RegInitDefaultHandles
67 TRACE("RegInitialize()\n");
69 ProcessHeap
= RtlGetProcessHeap();
70 RtlZeroMemory (DefaultHandleTable
,
71 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
72 RtlInitializeCriticalSection (&HandleTableCS
);
78 /************************************************************************
84 TRACE("RegCleanup()\n");
87 RtlDeleteCriticalSection (&HandleTableCS
);
94 OpenPredefinedKey(IN ULONG Index
,
101 case 0: /* HKEY_CLASSES_ROOT */
102 Status
= OpenClassesRootKey (Handle
);
105 case 1: /* HKEY_CURRENT_USER */
106 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
110 case 2: /* HKEY_LOCAL_MACHINE */
111 Status
= OpenLocalMachineKey (Handle
);
114 case 3: /* HKEY_USERS */
115 Status
= OpenUsersKey (Handle
);
118 case 4: /* HKEY_PERFORMANCE_DATA */
119 Status
= OpenPerformanceDataKey (Handle
);
123 case 5: /* HKEY_CURRENT_CONFIG */
124 Status
= OpenCurrentConfigKey (Handle
);
127 case 6: /* HKEY_DYN_DATA */
128 Status
= STATUS_NOT_IMPLEMENTED
;
132 WARN("MapDefaultHandle() no handle creator\n");
133 Status
= STATUS_INVALID_PARAMETER
;
142 MapDefaultKey (OUT PHANDLE RealKey
,
147 BOOLEAN DoOpen
, DefDisabled
;
148 NTSTATUS Status
= STATUS_SUCCESS
;
150 TRACE("MapDefaultKey (Key %x)\n", Key
);
152 if (!IsPredefKey(Key
))
154 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
155 return STATUS_SUCCESS
;
158 /* Handle special cases here */
159 Index
= GetPredefKeyIndex(Key
);
160 if (Index
>= MAX_DEFAULT_HANDLES
)
162 return STATUS_INVALID_PARAMETER
;
165 RtlEnterCriticalSection (&HandleTableCS
);
167 if (Key
== HKEY_CURRENT_USER
)
168 DefDisabled
= DefaultHandleHKUDisabled
;
170 DefDisabled
= DefaultHandlesDisabled
;
174 Handle
= &DefaultHandleTable
[Index
];
175 DoOpen
= (*Handle
== NULL
);
185 /* create/open the default handle */
186 Status
= OpenPredefinedKey(Index
,
190 if (NT_SUCCESS(Status
))
195 *(PULONG_PTR
)Handle
|= 0x1;
198 RtlLeaveCriticalSection (&HandleTableCS
);
205 CloseDefaultKeys (VOID
)
209 RtlEnterCriticalSection (&HandleTableCS
);
210 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
212 if (DefaultHandleTable
[i
] != NULL
)
214 NtClose (DefaultHandleTable
[i
]);
215 DefaultHandleTable
[i
] = NULL
;
218 RtlLeaveCriticalSection (&HandleTableCS
);
223 OpenClassesRootKey (PHANDLE KeyHandle
)
225 OBJECT_ATTRIBUTES Attributes
;
226 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
228 TRACE("OpenClassesRootKey()\n");
230 InitializeObjectAttributes (&Attributes
,
232 OBJ_CASE_INSENSITIVE
,
235 return NtOpenKey (KeyHandle
,
242 OpenLocalMachineKey (PHANDLE KeyHandle
)
244 OBJECT_ATTRIBUTES Attributes
;
245 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
248 TRACE("OpenLocalMachineKey()\n");
250 InitializeObjectAttributes (&Attributes
,
252 OBJ_CASE_INSENSITIVE
,
255 Status
= NtOpenKey (KeyHandle
,
259 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
265 OpenUsersKey (PHANDLE KeyHandle
)
267 OBJECT_ATTRIBUTES Attributes
;
268 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
270 TRACE("OpenUsersKey()\n");
272 InitializeObjectAttributes (&Attributes
,
274 OBJ_CASE_INSENSITIVE
,
277 return NtOpenKey (KeyHandle
,
284 OpenCurrentConfigKey (PHANDLE KeyHandle
)
286 OBJECT_ATTRIBUTES Attributes
;
287 UNICODE_STRING KeyName
=
288 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
290 TRACE("OpenCurrentConfigKey()\n");
292 InitializeObjectAttributes (&Attributes
,
294 OBJ_CASE_INSENSITIVE
,
297 return NtOpenKey (KeyHandle
,
303 /************************************************************************
304 * RegDisablePredefinedCache
309 RegDisablePredefinedCache(VOID
)
311 RtlEnterCriticalSection (&HandleTableCS
);
312 DefaultHandleHKUDisabled
= TRUE
;
313 RtlLeaveCriticalSection (&HandleTableCS
);
314 return ERROR_SUCCESS
;
318 /************************************************************************
319 * RegDisablePredefinedCacheEx
324 RegDisablePredefinedCacheEx(VOID
)
326 RtlEnterCriticalSection (&HandleTableCS
);
327 DefaultHandlesDisabled
= TRUE
;
328 DefaultHandleHKUDisabled
= TRUE
;
329 RtlLeaveCriticalSection (&HandleTableCS
);
330 return ERROR_SUCCESS
;
334 /************************************************************************
335 * RegOverridePredefKey
340 RegOverridePredefKey(IN HKEY hKey
,
341 IN HKEY hNewHKey OPTIONAL
)
343 LONG ErrorCode
= ERROR_SUCCESS
;
345 if ((hKey
== HKEY_CLASSES_ROOT
||
346 hKey
== HKEY_CURRENT_CONFIG
||
347 hKey
== HKEY_CURRENT_USER
||
348 hKey
== HKEY_LOCAL_MACHINE
||
349 hKey
== HKEY_PERFORMANCE_DATA
||
350 hKey
== HKEY_USERS
) &&
351 !IsPredefKey(hNewHKey
))
356 Index
= GetPredefKeyIndex(hKey
);
357 Handle
= &DefaultHandleTable
[Index
];
359 if (hNewHKey
== NULL
)
361 /* restore the default mapping */
362 NTSTATUS Status
= OpenPredefinedKey(Index
,
364 if (!NT_SUCCESS(Status
))
366 return RtlNtStatusToDosError(Status
);
369 ASSERT(hNewHKey
!= NULL
);
372 RtlEnterCriticalSection (&HandleTableCS
);
374 /* close the currently mapped handle if existing */
380 /* update the mapping */
383 RtlLeaveCriticalSection (&HandleTableCS
);
386 ErrorCode
= ERROR_INVALID_HANDLE
;
392 /************************************************************************
398 RegCloseKey (HKEY hKey
)
402 /* don't close null handle or a pseudo handle */
403 if ((!hKey
) || (((ULONG
)hKey
& 0xF0000000) == 0x80000000))
405 return ERROR_INVALID_HANDLE
;
408 Status
= NtClose (hKey
);
409 if (!NT_SUCCESS(Status
))
411 return RtlNtStatusToDosError (Status
);
414 return ERROR_SUCCESS
;
419 RegpCopyTree(IN HKEY hKeySrc
,
424 LIST_ENTRY ListEntry
;
427 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
429 LIST_ENTRY copyQueueHead
;
430 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
433 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
434 KEY_NODE_INFORMATION
*KeyNode
;
437 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
438 NTSTATUS Status
= STATUS_SUCCESS
;
439 NTSTATUS Status2
= STATUS_SUCCESS
;
441 InitializeListHead(©QueueHead
);
443 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
446 if (Info
.Buffer
== NULL
)
448 return STATUS_INSUFFICIENT_RESOURCES
;
451 copyKeys
= RtlAllocateHeap(ProcessHeap
,
453 sizeof(REGP_COPY_KEYS
));
454 if (copyKeys
!= NULL
)
456 copyKeys
->hKeySrc
= hKeySrc
;
457 copyKeys
->hKeyDest
= hKeyDest
;
458 InsertHeadList(©QueueHead
,
459 ©Keys
->ListEntry
);
461 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
465 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
469 /* enumerate all values and copy them */
473 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
475 KeyValueFullInformation
,
478 &BufferSizeRequired
);
479 if (NT_SUCCESS(Status2
))
481 UNICODE_STRING ValueName
;
484 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
485 ValueName
.Length
= Info
.KeyValue
->NameLength
;
486 ValueName
.MaximumLength
= ValueName
.Length
;
487 ValueName
.Buffer
= Info
.KeyValue
->Name
;
489 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
491 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
493 Info
.KeyValue
->TitleIndex
,
496 Info
.KeyValue
->DataLength
);
498 /* don't break, let's try to copy as many values as possible */
499 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
506 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
510 ASSERT(BufferSize
< BufferSizeRequired
);
512 Buffer
= RtlReAllocateHeap(ProcessHeap
,
518 Info
.Buffer
= Buffer
;
523 /* don't break, let's try to copy as many values as possible */
524 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
527 if (NT_SUCCESS(Status
))
535 /* break to avoid an infinite loop in case of denied access or
537 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
546 /* enumerate all subkeys and open and enqueue them */
550 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
555 &BufferSizeRequired
);
556 if (NT_SUCCESS(Status2
))
558 HANDLE KeyHandle
, NewKeyHandle
;
559 OBJECT_ATTRIBUTES ObjectAttributes
;
560 UNICODE_STRING SubKeyName
, ClassName
;
562 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
563 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
564 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
565 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
566 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
567 ClassName
.MaximumLength
= ClassName
.Length
;
568 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
570 /* open the subkey with sufficient rights */
572 InitializeObjectAttributes(&ObjectAttributes
,
574 OBJ_CASE_INSENSITIVE
,
578 Status2
= NtOpenKey(&KeyHandle
,
579 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
581 if (NT_SUCCESS(Status2
))
583 /* FIXME - attempt to query the security information */
585 InitializeObjectAttributes(&ObjectAttributes
,
587 OBJ_CASE_INSENSITIVE
,
591 Status2
= NtCreateKey(&NewKeyHandle
,
594 Info
.KeyNode
->TitleIndex
,
598 if (NT_SUCCESS(Status2
))
600 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
602 sizeof(REGP_COPY_KEYS
));
603 if (newCopyKeys
!= NULL
)
605 /* save the handles and enqueue the subkey */
606 newCopyKeys
->hKeySrc
= KeyHandle
;
607 newCopyKeys
->hKeyDest
= NewKeyHandle
;
608 InsertTailList(©QueueHead
,
609 &newCopyKeys
->ListEntry
);
614 NtClose(NewKeyHandle
);
616 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
625 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
632 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
636 ASSERT(BufferSize
< BufferSizeRequired
);
638 Buffer
= RtlReAllocateHeap(ProcessHeap
,
644 Info
.Buffer
= Buffer
;
649 /* don't break, let's try to copy as many keys as possible */
650 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
653 if (NT_SUCCESS(Status
))
661 /* break to avoid an infinite loop in case of denied access or
663 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
672 /* close the handles and remove the entry from the list */
673 if (copyKeys
->hKeySrc
!= hKeySrc
)
675 NtClose(copyKeys
->hKeySrc
);
677 if (copyKeys
->hKeyDest
!= hKeyDest
)
679 NtClose(copyKeys
->hKeyDest
);
682 RemoveEntryList(©Keys
->ListEntry
);
684 RtlFreeHeap(ProcessHeap
,
687 } while (!IsListEmpty(©QueueHead
));
690 Status
= STATUS_INSUFFICIENT_RESOURCES
;
692 RtlFreeHeap(ProcessHeap
,
700 /************************************************************************
706 RegCopyTreeW(IN HKEY hKeySrc
,
707 IN LPCWSTR lpSubKey OPTIONAL
,
710 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
713 Status
= MapDefaultKey(&KeyHandle
,
715 if (!NT_SUCCESS(Status
))
717 return RtlNtStatusToDosError(Status
);
720 Status
= MapDefaultKey(&DestKeyHandle
,
722 if (!NT_SUCCESS(Status
))
727 if (lpSubKey
!= NULL
)
729 OBJECT_ATTRIBUTES ObjectAttributes
;
730 UNICODE_STRING SubKeyName
;
732 RtlInitUnicodeString(&SubKeyName
,
735 InitializeObjectAttributes(&ObjectAttributes
,
737 OBJ_CASE_INSENSITIVE
,
741 Status
= NtOpenKey(&SubKeyHandle
,
742 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
744 if (!NT_SUCCESS(Status
))
749 CurKey
= SubKeyHandle
;
754 Status
= RegpCopyTree(CurKey
,
757 if (SubKeyHandle
!= NULL
)
759 NtClose(SubKeyHandle
);
763 ClosePredefKey(DestKeyHandle
);
765 ClosePredefKey(KeyHandle
);
767 if (!NT_SUCCESS(Status
))
769 return RtlNtStatusToDosError(Status
);
772 return ERROR_SUCCESS
;
776 /************************************************************************
782 RegCopyTreeA(IN HKEY hKeySrc
,
783 IN LPCSTR lpSubKey OPTIONAL
,
786 UNICODE_STRING SubKeyName
= {0};
789 if (lpSubKey
!= NULL
&&
790 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
793 return ERROR_NOT_ENOUGH_MEMORY
;
796 Ret
= RegCopyTreeW(hKeySrc
,
800 RtlFreeUnicodeString(&SubKeyName
);
806 /************************************************************************
807 * RegConnectRegistryA
812 RegConnectRegistryA (IN LPCSTR lpMachineName
,
816 UNICODE_STRING MachineName
= {0};
819 if (lpMachineName
!= NULL
&&
820 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
821 (LPSTR
)lpMachineName
))
823 return ERROR_NOT_ENOUGH_MEMORY
;
826 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
830 RtlFreeUnicodeString(&MachineName
);
836 /************************************************************************
837 * RegConnectRegistryW
842 RegConnectRegistryW (LPCWSTR lpMachineName
,
848 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
850 if (!lpMachineName
|| !*lpMachineName
) {
851 /* Use the local machine name */
852 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
855 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
856 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
858 /* MSDN says lpMachineName must start with \\ : not so */
859 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
861 if (GetComputerNameW(compName
, &len
))
863 if (!_wcsicmp(lpMachineName
, compName
))
864 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
867 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
868 ret
= ERROR_BAD_NETPATH
;
872 ret
= GetLastError();
878 /************************************************************************
881 * Create key and all necessary intermediate keys
884 CreateNestedKey(PHKEY KeyHandle
,
885 POBJECT_ATTRIBUTES ObjectAttributes
,
886 PUNICODE_STRING ClassString
,
889 DWORD
*lpdwDisposition
)
891 OBJECT_ATTRIBUTES LocalObjectAttributes
;
892 UNICODE_STRING LocalKeyName
;
895 ULONG FullNameLength
;
898 HANDLE LocalKeyHandle
;
900 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
906 (PULONG
)lpdwDisposition
);
907 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
908 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
911 /* Copy object attributes */
912 RtlCopyMemory (&LocalObjectAttributes
,
914 sizeof(OBJECT_ATTRIBUTES
));
915 RtlCreateUnicodeString (&LocalKeyName
,
916 ObjectAttributes
->ObjectName
->Buffer
);
917 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
918 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
920 /* Remove the last part of the key name and try to create the key again. */
921 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
923 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
924 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
926 Status
= STATUS_UNSUCCESSFUL
;
930 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
932 Status
= NtCreateKey (&LocalKeyHandle
,
934 &LocalObjectAttributes
,
939 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
942 if (!NT_SUCCESS(Status
))
944 RtlFreeUnicodeString (&LocalKeyName
);
948 /* Add removed parts of the key name and create them too. */
949 Length
= wcslen (LocalKeyName
.Buffer
);
952 NtClose (LocalKeyHandle
);
954 LocalKeyName
.Buffer
[Length
] = L
'\\';
955 Length
= wcslen (LocalKeyName
.Buffer
);
956 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
958 if (Length
== FullNameLength
)
960 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
966 (PULONG
)lpdwDisposition
);
969 Status
= NtCreateKey (&LocalKeyHandle
,
971 &LocalObjectAttributes
,
976 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
977 if (!NT_SUCCESS(Status
))
981 RtlFreeUnicodeString (&LocalKeyName
);
987 /************************************************************************
993 RegCreateKeyExA (HKEY hKey
,
999 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1001 LPDWORD lpdwDisposition
)
1003 UNICODE_STRING SubKeyString
;
1004 UNICODE_STRING ClassString
;
1005 OBJECT_ATTRIBUTES Attributes
;
1009 TRACE("RegCreateKeyExA() called\n");
1011 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1012 return ERROR_INVALID_USER_BUFFER
;
1014 /* get the real parent key */
1015 Status
= MapDefaultKey (&ParentKey
,
1017 if (!NT_SUCCESS(Status
))
1019 return RtlNtStatusToDosError (Status
);
1021 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
1023 if (lpClass
!= NULL
)
1025 RtlCreateUnicodeStringFromAsciiz (&ClassString
,
1029 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1031 InitializeObjectAttributes (&Attributes
,
1033 OBJ_CASE_INSENSITIVE
,
1035 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1036 Status
= CreateNestedKey(phkResult
,
1038 (lpClass
== NULL
)? NULL
: &ClassString
,
1042 RtlFreeUnicodeString (&SubKeyString
);
1043 if (lpClass
!= NULL
)
1045 RtlFreeUnicodeString (&ClassString
);
1048 ClosePredefKey(ParentKey
);
1050 TRACE("Status %x\n", Status
);
1051 if (!NT_SUCCESS(Status
))
1053 return RtlNtStatusToDosError (Status
);
1056 return ERROR_SUCCESS
;
1060 /************************************************************************
1066 RegCreateKeyExW (HKEY hKey
,
1072 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1074 LPDWORD lpdwDisposition
)
1076 UNICODE_STRING SubKeyString
;
1077 UNICODE_STRING ClassString
;
1078 OBJECT_ATTRIBUTES Attributes
;
1082 TRACE("RegCreateKeyExW() called\n");
1084 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1085 return ERROR_INVALID_USER_BUFFER
;
1087 /* get the real parent key */
1088 Status
= MapDefaultKey (&ParentKey
,
1090 if (!NT_SUCCESS(Status
))
1092 return RtlNtStatusToDosError(Status
);
1094 TRACE("ParentKey %x\n", (ULONG
)ParentKey
);
1096 RtlInitUnicodeString (&ClassString
,
1098 RtlInitUnicodeString (&SubKeyString
,
1100 InitializeObjectAttributes (&Attributes
,
1102 OBJ_CASE_INSENSITIVE
,
1104 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1105 Status
= CreateNestedKey(phkResult
,
1107 (lpClass
== NULL
)? NULL
: &ClassString
,
1112 ClosePredefKey(ParentKey
);
1114 TRACE("Status %x\n", Status
);
1115 if (!NT_SUCCESS(Status
))
1117 return RtlNtStatusToDosError (Status
);
1120 return ERROR_SUCCESS
;
1124 /************************************************************************
1130 RegCreateKeyA (HKEY hKey
,
1134 return RegCreateKeyExA (hKey
,
1146 /************************************************************************
1152 RegCreateKeyW (HKEY hKey
,
1156 return RegCreateKeyExW (hKey
,
1168 /************************************************************************
1174 RegDeleteKeyA (HKEY hKey
,
1177 OBJECT_ATTRIBUTES ObjectAttributes
;
1178 UNICODE_STRING SubKeyName
;
1183 /* Make sure we got a subkey */
1187 return ERROR_INVALID_PARAMETER
;
1190 Status
= MapDefaultKey (&ParentKey
,
1192 if (!NT_SUCCESS(Status
))
1194 return RtlNtStatusToDosError (Status
);
1197 RtlCreateUnicodeStringFromAsciiz (&SubKeyName
,
1199 InitializeObjectAttributes(&ObjectAttributes
,
1201 OBJ_CASE_INSENSITIVE
,
1205 Status
= NtOpenKey (&TargetKey
,
1208 RtlFreeUnicodeString (&SubKeyName
);
1209 if (!NT_SUCCESS(Status
))
1214 Status
= NtDeleteKey (TargetKey
);
1215 NtClose (TargetKey
);
1218 ClosePredefKey(ParentKey
);
1220 if (!NT_SUCCESS(Status
))
1222 return RtlNtStatusToDosError(Status
);
1225 return ERROR_SUCCESS
;
1229 /************************************************************************
1235 RegDeleteKeyW (HKEY hKey
,
1238 OBJECT_ATTRIBUTES ObjectAttributes
;
1239 UNICODE_STRING SubKeyName
;
1244 /* Make sure we got a subkey */
1248 return ERROR_INVALID_PARAMETER
;
1251 Status
= MapDefaultKey (&ParentKey
,
1253 if (!NT_SUCCESS(Status
))
1255 return RtlNtStatusToDosError (Status
);
1258 RtlInitUnicodeString (&SubKeyName
,
1260 InitializeObjectAttributes (&ObjectAttributes
,
1262 OBJ_CASE_INSENSITIVE
,
1265 Status
= NtOpenKey (&TargetKey
,
1268 if (!NT_SUCCESS(Status
))
1273 Status
= NtDeleteKey (TargetKey
);
1274 NtClose (TargetKey
);
1277 ClosePredefKey(ParentKey
);
1279 if (!NT_SUCCESS(Status
))
1281 return RtlNtStatusToDosError (Status
);
1284 return ERROR_SUCCESS
;
1287 /************************************************************************
1294 RegDeleteKeyExA ( HKEY hKey
,
1300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1301 return ERROR_CALL_NOT_IMPLEMENTED
;
1304 /************************************************************************
1311 RegDeleteKeyExW (HKEY hKey
,
1317 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1318 return ERROR_CALL_NOT_IMPLEMENTED
;
1321 /************************************************************************
1322 * RegDeleteKeyValueW
1327 RegDeleteKeyValueW(IN HKEY hKey
,
1328 IN LPCWSTR lpSubKey OPTIONAL
,
1329 IN LPCWSTR lpValueName OPTIONAL
)
1331 UNICODE_STRING ValueName
;
1332 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1335 Status
= MapDefaultKey(&KeyHandle
,
1337 if (!NT_SUCCESS(Status
))
1339 return RtlNtStatusToDosError(Status
);
1342 if (lpSubKey
!= NULL
)
1344 OBJECT_ATTRIBUTES ObjectAttributes
;
1345 UNICODE_STRING SubKeyName
;
1347 RtlInitUnicodeString(&SubKeyName
,
1350 InitializeObjectAttributes(&ObjectAttributes
,
1352 OBJ_CASE_INSENSITIVE
,
1356 Status
= NtOpenKey(&SubKeyHandle
,
1359 if (!NT_SUCCESS(Status
))
1364 CurKey
= SubKeyHandle
;
1369 RtlInitUnicodeString(&ValueName
,
1370 (LPWSTR
)lpValueName
);
1372 Status
= NtDeleteValueKey(CurKey
,
1375 if (SubKeyHandle
!= NULL
)
1377 NtClose(SubKeyHandle
);
1381 ClosePredefKey(KeyHandle
);
1383 if (!NT_SUCCESS(Status
))
1385 return RtlNtStatusToDosError(Status
);
1388 return ERROR_SUCCESS
;
1392 /************************************************************************
1393 * RegDeleteKeyValueA
1398 RegDeleteKeyValueA(IN HKEY hKey
,
1399 IN LPCSTR lpSubKey OPTIONAL
,
1400 IN LPCSTR lpValueName OPTIONAL
)
1402 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1405 if (lpSubKey
!= NULL
&&
1406 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1409 return ERROR_NOT_ENOUGH_MEMORY
;
1412 if (lpValueName
!= NULL
&&
1413 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1414 (LPSTR
)lpValueName
))
1416 RtlFreeUnicodeString(&SubKey
);
1417 return ERROR_NOT_ENOUGH_MEMORY
;
1420 Ret
= RegDeleteKeyValueW(hKey
,
1424 RtlFreeUnicodeString(&SubKey
);
1425 RtlFreeUnicodeString(&ValueName
);
1431 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1433 RegpDeleteTree(IN HKEY hKey
)
1437 LIST_ENTRY ListEntry
;
1439 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1441 LIST_ENTRY delQueueHead
;
1442 PREG_DEL_KEYS delKeys
, newDelKeys
;
1445 PKEY_BASIC_INFORMATION BasicInfo
;
1446 PREG_DEL_KEYS KeyDelRoot
;
1447 NTSTATUS Status
= STATUS_SUCCESS
;
1448 NTSTATUS Status2
= STATUS_SUCCESS
;
1450 InitializeListHead(&delQueueHead
);
1452 ProcessHeap
= RtlGetProcessHeap();
1454 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1455 structure for the root key, we only do that for subkeys as we need to
1456 allocate REGP_DEL_KEYS structures anyway! */
1457 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1459 sizeof(REGP_DEL_KEYS
));
1460 if (KeyDelRoot
!= NULL
)
1462 KeyDelRoot
->KeyHandle
= hKey
;
1463 InsertTailList(&delQueueHead
,
1464 &KeyDelRoot
->ListEntry
);
1468 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1477 /* check if this key contains subkeys and delete them first by queuing
1478 them at the head of the list */
1479 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1481 KeyBasicInformation
,
1486 if (NT_SUCCESS(Status2
))
1488 OBJECT_ATTRIBUTES ObjectAttributes
;
1489 UNICODE_STRING SubKeyName
;
1491 ASSERT(newDelKeys
!= NULL
);
1492 ASSERT(BasicInfo
!= NULL
);
1494 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1495 SubKeyName
.Length
= BasicInfo
->NameLength
;
1496 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1497 SubKeyName
.Buffer
= BasicInfo
->Name
;
1499 InitializeObjectAttributes(&ObjectAttributes
,
1501 OBJ_CASE_INSENSITIVE
,
1505 /* open the subkey */
1506 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1507 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1509 if (!NT_SUCCESS(Status2
))
1514 /* enqueue this key to the head of the deletion queue */
1515 InsertHeadList(&delQueueHead
,
1516 &newDelKeys
->ListEntry
);
1518 /* try again from the head of the list */
1523 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1525 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1527 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1528 if (newDelKeys
!= NULL
)
1530 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1533 goto ReadFirstSubKey
;
1537 /* don't break, let's try to delete as many keys as possible */
1538 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1539 goto SubKeyFailureNoFree
;
1542 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1544 PREG_DEL_KEYS newDelKeys2
;
1546 ASSERT(newDelKeys
!= NULL
);
1548 /* we need more memory to query the key name */
1549 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1552 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1553 if (newDelKeys2
!= NULL
)
1555 newDelKeys
= newDelKeys2
;
1556 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1559 goto ReadFirstSubKey
;
1563 /* don't break, let's try to delete as many keys as possible */
1564 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1567 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1569 /* in some race conditions where another thread would delete
1570 the same tree at the same time, newDelKeys could actually
1572 if (newDelKeys
!= NULL
)
1574 RtlFreeHeap(ProcessHeap
,
1582 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1583 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1584 if (newDelKeys
!= NULL
)
1586 RtlFreeHeap(ProcessHeap
,
1591 SubKeyFailureNoFree
:
1592 /* don't break, let's try to delete as many keys as possible */
1593 if (NT_SUCCESS(Status
))
1599 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1601 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1603 if (!NT_SUCCESS(Status2
))
1605 /* close the key handle so we don't leak handles for keys we were
1606 unable to delete. But only do this for handles not supplied
1609 if (delKeys
->KeyHandle
!= hKey
)
1611 NtClose(delKeys
->KeyHandle
);
1614 if (NT_SUCCESS(Status
))
1616 /* don't break, let's try to delete as many keys as possible */
1621 /* remove the entry from the list */
1622 RemoveEntryList(&delKeys
->ListEntry
);
1624 RtlFreeHeap(ProcessHeap
,
1627 } while (!IsListEmpty(&delQueueHead
));
1630 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1636 /************************************************************************
1642 RegDeleteTreeW(IN HKEY hKey
,
1643 IN LPCWSTR lpSubKey OPTIONAL
)
1645 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1648 Status
= MapDefaultKey(&KeyHandle
,
1650 if (!NT_SUCCESS(Status
))
1652 return RtlNtStatusToDosError(Status
);
1655 if (lpSubKey
!= NULL
)
1657 OBJECT_ATTRIBUTES ObjectAttributes
;
1658 UNICODE_STRING SubKeyName
;
1660 RtlInitUnicodeString(&SubKeyName
,
1663 InitializeObjectAttributes(&ObjectAttributes
,
1665 OBJ_CASE_INSENSITIVE
,
1669 Status
= NtOpenKey(&SubKeyHandle
,
1670 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1672 if (!NT_SUCCESS(Status
))
1677 CurKey
= SubKeyHandle
;
1682 Status
= RegpDeleteTree(CurKey
);
1684 if (NT_SUCCESS(Status
))
1686 /* make sure we only close hKey (KeyHandle) when the caller specified a
1687 subkey, because the handle would be invalid already! */
1688 if (CurKey
!= KeyHandle
)
1690 ClosePredefKey(KeyHandle
);
1693 return ERROR_SUCCESS
;
1697 /* make sure we close all handles we created! */
1698 if (SubKeyHandle
!= NULL
)
1700 NtClose(SubKeyHandle
);
1704 ClosePredefKey(KeyHandle
);
1706 return RtlNtStatusToDosError(Status
);
1711 /************************************************************************
1718 RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
1721 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1722 DWORD dwMaxLen
, dwSize
;
1726 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1728 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1730 Status
= MapDefaultKey(&KeyHandle
,
1732 if (!NT_SUCCESS(Status
))
1734 return RtlNtStatusToDosError(Status
);
1737 hSubKey
= KeyHandle
;
1741 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1744 ClosePredefKey(KeyHandle
);
1749 /* Get highest length for keys, values */
1750 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1751 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1752 if (ret
) goto cleanup
;
1756 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1757 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1759 /* Name too big: alloc a buffer for it */
1760 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1762 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1768 /* Recursively delete all the subkeys */
1772 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1773 NULL
, NULL
, NULL
)) break;
1775 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1776 if (ret
) goto cleanup
;
1780 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1785 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1786 NULL
, NULL
, NULL
, NULL
)) break;
1788 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1789 if (ret
) goto cleanup
;
1793 /* Free buffer if allocated */
1794 if (lpszName
!= szNameBuf
)
1795 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1797 RegCloseKey(hSubKey
);
1799 ClosePredefKey(KeyHandle
);
1805 /************************************************************************
1811 RegDeleteTreeA(IN HKEY hKey
,
1812 IN LPCSTR lpSubKey OPTIONAL
)
1814 UNICODE_STRING SubKeyName
= {0};
1817 if (lpSubKey
!= NULL
&&
1818 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1821 return ERROR_NOT_ENOUGH_MEMORY
;
1824 Ret
= RegDeleteTreeW(hKey
,
1827 RtlFreeUnicodeString(&SubKeyName
);
1833 /************************************************************************
1834 * RegDisableReflectionKey
1839 RegDisableReflectionKey(IN HKEY hBase
)
1841 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1842 return ERROR_CALL_NOT_IMPLEMENTED
;
1846 /************************************************************************
1847 * RegEnableReflectionKey
1852 RegEnableReflectionKey(IN HKEY hBase
)
1854 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1855 return ERROR_CALL_NOT_IMPLEMENTED
;
1858 /******************************************************************************
1859 * RegpApplyRestrictions [internal]
1861 * Helper function for RegGetValueA/W.
1864 RegpApplyRestrictions( DWORD dwFlags
, DWORD dwType
, DWORD cbData
,
1867 /* Check if the type is restricted by the passed flags */
1868 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1874 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1875 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1876 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1877 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1878 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1879 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1880 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1883 if (dwFlags
& dwMask
)
1885 /* Type is not restricted, check for size mismatch */
1886 if (dwType
== REG_BINARY
)
1890 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1892 else if ((dwFlags
& RRF_RT_QWORD
) == RRF_RT_QWORD
)
1895 if (cbExpect
&& cbData
!= cbExpect
)
1896 *ret
= ERROR_DATATYPE_MISMATCH
;
1899 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1904 /******************************************************************************
1905 * RegGetValueW [ADVAPI32.@]
1907 * Retrieves the type and data for a value name associated with a key,
1908 * optionally expanding its content and restricting its type.
1911 * hKey [I] Handle to an open key.
1912 * pszSubKey [I] Name of the subkey of hKey.
1913 * pszValue [I] Name of value under hKey/szSubKey to query.
1914 * dwFlags [I] Flags restricting the value type to retrieve.
1915 * pdwType [O] Destination for the values type, may be NULL.
1916 * pvData [O] Destination for the values content, may be NULL.
1917 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1918 * retrieve the whole content, including the trailing '\0'
1922 * Success: ERROR_SUCCESS
1923 * Failure: nonzero error code from Winerror.h
1926 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1927 * expanded and pdwType is set to REG_SZ instead.
1928 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1929 * without RRF_NOEXPAND is thus not allowed.
1930 * An exception is the case where RRF_RT_ANY is specified, because then
1931 * RRF_NOEXPAND is allowed.
1933 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1934 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1937 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1941 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1942 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1943 pvData
, pcbData
, cbData
);
1945 if (pvData
&& !pcbData
)
1946 return ERROR_INVALID_PARAMETER
;
1947 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1948 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1949 return ERROR_INVALID_PARAMETER
;
1951 if (pszSubKey
&& pszSubKey
[0])
1953 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1954 if (ret
!= ERROR_SUCCESS
) return ret
;
1957 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1959 /* If we are going to expand we need to read in the whole the value even
1960 * if the passed buffer was too small as the expanded string might be
1961 * smaller than the unexpanded one and could fit into cbData bytes. */
1962 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1963 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1966 HeapFree(GetProcessHeap(), 0, pvBuf
);
1968 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1971 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1975 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1976 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1977 &dwType
, pvBuf
, &cbData
);
1980 /* Even if cbData was large enough we have to copy the
1981 * string since ExpandEnvironmentStrings can't handle
1982 * overlapping buffers. */
1983 CopyMemory(pvBuf
, pvData
, cbData
);
1986 /* Both the type or the value itself could have been modified in
1987 * between so we have to keep retrying until the buffer is large
1988 * enough or we no longer have to expand the value. */
1989 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1991 if (ret
== ERROR_SUCCESS
)
1993 /* Recheck dwType in case it changed since the first call */
1994 if (dwType
== REG_EXPAND_SZ
)
1996 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1997 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1999 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2000 ret
= ERROR_MORE_DATA
;
2003 CopyMemory(pvData
, pvBuf
, *pcbData
);
2006 HeapFree(GetProcessHeap(), 0, pvBuf
);
2009 if (pszSubKey
&& pszSubKey
[0])
2012 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2014 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2015 ZeroMemory(pvData
, *pcbData
);
2017 if (pdwType
) *pdwType
= dwType
;
2018 if (pcbData
) *pcbData
= cbData
;
2024 /******************************************************************************
2025 * RegGetValueA [ADVAPI32.@]
2029 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
2030 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
2033 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2037 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2038 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2041 if (pvData
&& !pcbData
)
2042 return ERROR_INVALID_PARAMETER
;
2043 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2044 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2045 return ERROR_INVALID_PARAMETER
;
2047 if (pszSubKey
&& pszSubKey
[0])
2049 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2050 if (ret
!= ERROR_SUCCESS
) return ret
;
2053 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2055 /* If we are going to expand we need to read in the whole the value even
2056 * if the passed buffer was too small as the expanded string might be
2057 * smaller than the unexpanded one and could fit into cbData bytes. */
2058 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2059 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2062 HeapFree(GetProcessHeap(), 0, pvBuf
);
2064 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2067 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2071 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2072 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2073 &dwType
, pvBuf
, &cbData
);
2076 /* Even if cbData was large enough we have to copy the
2077 * string since ExpandEnvironmentStrings can't handle
2078 * overlapping buffers. */
2079 CopyMemory(pvBuf
, pvData
, cbData
);
2082 /* Both the type or the value itself could have been modified in
2083 * between so we have to keep retrying until the buffer is large
2084 * enough or we no longer have to expand the value. */
2085 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2087 if (ret
== ERROR_SUCCESS
)
2089 /* Recheck dwType in case it changed since the first call */
2090 if (dwType
== REG_EXPAND_SZ
)
2092 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2093 pcbData
? *pcbData
: 0);
2095 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2096 ret
= ERROR_MORE_DATA
;
2099 CopyMemory(pvData
, pvBuf
, *pcbData
);
2102 HeapFree(GetProcessHeap(), 0, pvBuf
);
2105 if (pszSubKey
&& pszSubKey
[0])
2108 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2110 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2111 ZeroMemory(pvData
, *pcbData
);
2113 if (pdwType
) *pdwType
= dwType
;
2114 if (pcbData
) *pcbData
= cbData
;
2120 /************************************************************************
2126 RegSetKeyValueW(IN HKEY hKey
,
2127 IN LPCWSTR lpSubKey OPTIONAL
,
2128 IN LPCWSTR lpValueName OPTIONAL
,
2130 IN LPCVOID lpData OPTIONAL
,
2133 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2137 Status
= MapDefaultKey(&KeyHandle
,
2139 if (!NT_SUCCESS(Status
))
2141 return RtlNtStatusToDosError(Status
);
2144 if (lpSubKey
!= NULL
)
2146 OBJECT_ATTRIBUTES ObjectAttributes
;
2147 UNICODE_STRING SubKeyName
;
2149 RtlInitUnicodeString(&SubKeyName
,
2152 InitializeObjectAttributes(&ObjectAttributes
,
2154 OBJ_CASE_INSENSITIVE
,
2158 Status
= NtOpenKey(&SubKeyHandle
,
2161 if (!NT_SUCCESS(Status
))
2163 Ret
= RtlNtStatusToDosError(Status
);
2167 CurKey
= SubKeyHandle
;
2172 Ret
= RegSetValueExW(CurKey
,
2179 if (SubKeyHandle
!= NULL
)
2181 NtClose(SubKeyHandle
);
2185 ClosePredefKey(KeyHandle
);
2191 /************************************************************************
2197 RegSetKeyValueA(IN HKEY hKey
,
2198 IN LPCSTR lpSubKey OPTIONAL
,
2199 IN LPCSTR lpValueName OPTIONAL
,
2201 IN LPCVOID lpData OPTIONAL
,
2204 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2208 Status
= MapDefaultKey(&KeyHandle
,
2210 if (!NT_SUCCESS(Status
))
2212 return RtlNtStatusToDosError(Status
);
2215 if (lpSubKey
!= NULL
)
2217 OBJECT_ATTRIBUTES ObjectAttributes
;
2218 UNICODE_STRING SubKeyName
;
2220 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2223 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2227 InitializeObjectAttributes(&ObjectAttributes
,
2229 OBJ_CASE_INSENSITIVE
,
2233 Status
= NtOpenKey(&SubKeyHandle
,
2237 RtlFreeUnicodeString(&SubKeyName
);
2239 if (!NT_SUCCESS(Status
))
2241 Ret
= RtlNtStatusToDosError(Status
);
2245 CurKey
= SubKeyHandle
;
2250 Ret
= RegSetValueExA(CurKey
,
2257 if (SubKeyHandle
!= NULL
)
2259 NtClose(SubKeyHandle
);
2263 ClosePredefKey(KeyHandle
);
2269 /************************************************************************
2275 RegDeleteValueA (HKEY hKey
,
2278 UNICODE_STRING ValueName
;
2282 Status
= MapDefaultKey (&KeyHandle
,
2284 if (!NT_SUCCESS(Status
))
2286 return RtlNtStatusToDosError (Status
);
2289 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
2290 (LPSTR
)lpValueName
);
2291 Status
= NtDeleteValueKey (KeyHandle
,
2293 RtlFreeUnicodeString (&ValueName
);
2295 ClosePredefKey(KeyHandle
);
2297 if (!NT_SUCCESS(Status
))
2299 return RtlNtStatusToDosError (Status
);
2302 return ERROR_SUCCESS
;
2306 /************************************************************************
2312 RegDeleteValueW (HKEY hKey
,
2313 LPCWSTR lpValueName
)
2315 UNICODE_STRING ValueName
;
2319 Status
= MapDefaultKey (&KeyHandle
,
2321 if (!NT_SUCCESS(Status
))
2323 return RtlNtStatusToDosError (Status
);
2326 RtlInitUnicodeString (&ValueName
,
2327 (LPWSTR
)lpValueName
);
2329 Status
= NtDeleteValueKey (KeyHandle
,
2332 ClosePredefKey(KeyHandle
);
2334 if (!NT_SUCCESS(Status
))
2336 return RtlNtStatusToDosError (Status
);
2339 return ERROR_SUCCESS
;
2343 /************************************************************************
2349 RegEnumKeyA (HKEY hKey
,
2357 return RegEnumKeyExA (hKey
,
2368 /************************************************************************
2374 RegEnumKeyW (HKEY hKey
,
2382 return RegEnumKeyExW (hKey
,
2393 /************************************************************************
2399 RegEnumKeyExA (HKEY hKey
,
2406 PFILETIME lpftLastWriteTime
)
2410 KEY_NODE_INFORMATION Node
;
2411 KEY_BASIC_INFORMATION Basic
;
2414 UNICODE_STRING StringU
;
2415 ANSI_STRING StringA
;
2416 LONG ErrorCode
= ERROR_SUCCESS
;
2418 DWORD ClassLength
= 0;
2424 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2425 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2427 if ((lpClass
) && (!lpcbClass
))
2429 return ERROR_INVALID_PARAMETER
;
2432 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2433 if (!NT_SUCCESS(Status
))
2435 return RtlNtStatusToDosError (Status
);
2440 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2451 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2458 /* The class name should start at a dword boundary */
2459 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2463 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2466 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2467 if (KeyInfo
== NULL
)
2469 ErrorCode
= ERROR_OUTOFMEMORY
;
2473 Status
= NtEnumerateKey (KeyHandle
,
2475 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2479 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2480 if (!NT_SUCCESS(Status
))
2482 ErrorCode
= RtlNtStatusToDosError (Status
);
2486 if (lpClass
== NULL
)
2488 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2490 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2494 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2495 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2496 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2501 if (KeyInfo
->Node
.NameLength
> NameLength
||
2502 KeyInfo
->Node
.ClassLength
> ClassLength
)
2504 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2508 StringA
.Buffer
= lpClass
;
2510 StringA
.MaximumLength
= *lpcbClass
;
2511 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2512 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2513 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2514 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2515 lpClass
[StringA
.Length
] = 0;
2516 *lpcbClass
= StringA
.Length
;
2517 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2518 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2519 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2523 if (ErrorCode
== ERROR_SUCCESS
)
2525 StringA
.Buffer
= lpName
;
2527 StringA
.MaximumLength
= *lpcbName
;
2528 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2529 lpName
[StringA
.Length
] = 0;
2530 *lpcbName
= StringA
.Length
;
2531 if (lpftLastWriteTime
!= NULL
)
2533 if (lpClass
== NULL
)
2535 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2536 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2540 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2541 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2547 TRACE("Key Namea0 Length %d\n", StringU
.Length
);
2548 TRACE("Key Namea1 Length %d\n", NameLength
);
2549 TRACE("Key Namea Length %d\n", *lpcbName
);
2550 TRACE("Key Namea %s\n", lpName
);
2552 RtlFreeHeap (ProcessHeap
,
2557 ClosePredefKey(KeyHandle
);
2563 /************************************************************************
2569 RegEnumKeyExW (HKEY hKey
,
2576 PFILETIME lpftLastWriteTime
)
2580 KEY_NODE_INFORMATION Node
;
2581 KEY_BASIC_INFORMATION Basic
;
2587 ULONG ClassLength
= 0;
2589 LONG ErrorCode
= ERROR_SUCCESS
;
2592 Status
= MapDefaultKey(&KeyHandle
,
2594 if (!NT_SUCCESS(Status
))
2596 return RtlNtStatusToDosError (Status
);
2601 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2612 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2619 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2623 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2626 KeyInfo
= RtlAllocateHeap (ProcessHeap
,
2629 if (KeyInfo
== NULL
)
2631 ErrorCode
= ERROR_OUTOFMEMORY
;
2635 Status
= NtEnumerateKey (KeyHandle
,
2637 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2641 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2642 if (!NT_SUCCESS(Status
))
2644 ErrorCode
= RtlNtStatusToDosError (Status
);
2648 if (lpClass
== NULL
)
2650 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2652 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2656 RtlCopyMemory (lpName
,
2657 KeyInfo
->Basic
.Name
,
2658 KeyInfo
->Basic
.NameLength
);
2659 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2660 lpName
[*lpcbName
] = 0;
2665 if (KeyInfo
->Node
.NameLength
> NameLength
||
2666 KeyInfo
->Node
.ClassLength
> ClassLength
)
2668 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2672 RtlCopyMemory (lpName
,
2674 KeyInfo
->Node
.NameLength
);
2675 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2676 lpName
[*lpcbName
] = 0;
2677 RtlCopyMemory (lpClass
,
2678 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2679 KeyInfo
->Node
.ClassLength
);
2680 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2681 lpClass
[*lpcbClass
] = 0;
2685 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2687 if (lpClass
== NULL
)
2689 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2690 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2694 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2695 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2700 RtlFreeHeap (ProcessHeap
,
2705 ClosePredefKey(KeyHandle
);
2710 /************************************************************************
2716 RegEnumValueA( HKEY hKey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2717 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2722 char buffer
[256], *buf_ptr
= buffer
;
2723 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2724 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2726 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2727 // hkey, index, value, val_count, reserved, type, data, count );
2729 /* NT only checks count, not val_count */
2730 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2731 status
= MapDefaultKey (&KeyHandle
, hKey
);
2732 if (!NT_SUCCESS(status
))
2734 return RtlNtStatusToDosError (status
);
2737 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2738 if (data
) total_size
+= *count
;
2739 total_size
= min( sizeof(buffer
), total_size
);
2741 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2742 buffer
, total_size
, &total_size
);
2743 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2745 /* we need to fetch the contents for a string type even if not requested,
2746 * because we need to compute the length of the ASCII string. */
2747 if (value
|| data
|| is_string(info
->Type
))
2749 /* retry with a dynamically allocated buffer */
2750 while (status
== STATUS_BUFFER_OVERFLOW
)
2752 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2753 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2755 status
= STATUS_INSUFFICIENT_RESOURCES
;
2758 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2759 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2760 buf_ptr
, total_size
, &total_size
);
2763 if (status
) goto done
;
2765 if (is_string(info
->Type
))
2768 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2769 total_size
- info
->DataOffset
);
2772 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2775 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2776 total_size
- info
->DataOffset
);
2777 /* if the type is REG_SZ and data is not 0-terminated
2778 * and there is enough space in the buffer NT appends a \0 */
2779 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2782 info
->DataLength
= len
;
2786 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2787 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2790 if (value
&& !status
)
2794 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2795 if (len
>= *val_count
)
2797 status
= STATUS_BUFFER_OVERFLOW
;
2800 len
= *val_count
- 1;
2801 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2807 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2813 else status
= STATUS_SUCCESS
;
2815 if (type
) *type
= info
->Type
;
2816 if (count
) *count
= info
->DataLength
;
2819 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2820 ClosePredefKey(KeyHandle
);
2821 return RtlNtStatusToDosError(status
);
2824 /******************************************************************************
2825 * RegEnumValueW [ADVAPI32.@]
2829 * hkey [I] Handle to key to query
2830 * index [I] Index of value to query
2831 * value [O] Value string
2832 * val_count [I/O] Size of value buffer (in wchars)
2833 * reserved [I] Reserved
2834 * type [O] Type code
2835 * data [O] Value data
2836 * count [I/O] Size of data buffer (in bytes)
2839 * Success: ERROR_SUCCESS
2840 * Failure: nonzero error code from Winerror.h
2843 RegEnumValueW( HKEY hKey
, DWORD index
, LPWSTR value
, PDWORD val_count
,
2844 PDWORD reserved
, PDWORD type
, LPBYTE data
, PDWORD count
)
2849 char buffer
[256], *buf_ptr
= buffer
;
2850 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2851 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2853 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2854 // hkey, index, value, val_count, reserved, type, data, count );
2856 /* NT only checks count, not val_count */
2857 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2859 status
= MapDefaultKey (&KeyHandle
, hKey
);
2860 if (!NT_SUCCESS(status
))
2862 return RtlNtStatusToDosError (status
);
2865 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2866 if (data
) total_size
+= *count
;
2867 total_size
= min( sizeof(buffer
), total_size
);
2869 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2870 buffer
, total_size
, &total_size
);
2871 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2875 /* retry with a dynamically allocated buffer */
2876 while (status
== STATUS_BUFFER_OVERFLOW
)
2878 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2879 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2881 status
= ERROR_NOT_ENOUGH_MEMORY
;
2884 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2885 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2886 buf_ptr
, total_size
, &total_size
);
2889 if (status
) goto done
;
2893 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2895 status
= STATUS_BUFFER_OVERFLOW
;
2898 memcpy( value
, info
->Name
, info
->NameLength
);
2899 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2900 value
[*val_count
] = 0;
2905 if (total_size
- info
->DataOffset
> *count
)
2907 status
= STATUS_BUFFER_OVERFLOW
;
2910 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2911 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2913 /* if the type is REG_SZ and data is not 0-terminated
2914 * and there is enough space in the buffer NT appends a \0 */
2915 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2916 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2920 else status
= STATUS_SUCCESS
;
2923 if (type
) *type
= info
->Type
;
2924 if (count
) *count
= info
->DataLength
;
2927 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2928 ClosePredefKey(KeyHandle
);
2929 return RtlNtStatusToDosError(status
);
2932 /************************************************************************
2938 RegFlushKey(HKEY hKey
)
2943 if (hKey
== HKEY_PERFORMANCE_DATA
)
2945 return ERROR_SUCCESS
;
2948 Status
= MapDefaultKey (&KeyHandle
,
2950 if (!NT_SUCCESS(Status
))
2952 return RtlNtStatusToDosError (Status
);
2955 Status
= NtFlushKey (KeyHandle
);
2957 ClosePredefKey(KeyHandle
);
2959 if (!NT_SUCCESS(Status
))
2961 return RtlNtStatusToDosError (Status
);
2964 return ERROR_SUCCESS
;
2968 /************************************************************************
2974 RegGetKeySecurity(HKEY hKey
,
2975 SECURITY_INFORMATION SecurityInformation
,
2976 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2977 LPDWORD lpcbSecurityDescriptor
)
2982 if (hKey
== HKEY_PERFORMANCE_DATA
)
2984 return ERROR_INVALID_HANDLE
;
2987 Status
= MapDefaultKey(&KeyHandle
,
2989 if (!NT_SUCCESS(Status
))
2991 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
2992 return RtlNtStatusToDosError (Status
);
2995 Status
= NtQuerySecurityObject(KeyHandle
,
2996 SecurityInformation
,
2997 pSecurityDescriptor
,
2998 *lpcbSecurityDescriptor
,
2999 lpcbSecurityDescriptor
);
3002 ClosePredefKey(KeyHandle
);
3004 if (!NT_SUCCESS(Status
))
3006 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3007 return RtlNtStatusToDosError (Status
);
3010 return ERROR_SUCCESS
;
3014 /************************************************************************
3020 RegLoadKeyA (HKEY hKey
,
3024 UNICODE_STRING FileName
;
3025 UNICODE_STRING KeyName
;
3028 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
3030 RtlCreateUnicodeStringFromAsciiz (&FileName
,
3033 ErrorCode
= RegLoadKeyW (hKey
,
3037 RtlFreeUnicodeString (&FileName
);
3038 RtlFreeUnicodeString (&KeyName
);
3044 /************************************************************************
3050 RegLoadKeyW (HKEY hKey
,
3054 OBJECT_ATTRIBUTES FileObjectAttributes
;
3055 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3056 UNICODE_STRING FileName
;
3057 UNICODE_STRING KeyName
;
3060 LONG ErrorCode
= ERROR_SUCCESS
;
3062 if (hKey
== HKEY_PERFORMANCE_DATA
)
3064 return ERROR_INVALID_HANDLE
;
3067 Status
= MapDefaultKey (&KeyHandle
,
3069 if (!NT_SUCCESS(Status
))
3071 return RtlNtStatusToDosError (Status
);
3074 if (!RtlDosPathNameToNtPathName_U (lpFile
,
3079 ErrorCode
= ERROR_BAD_PATHNAME
;
3083 InitializeObjectAttributes (&FileObjectAttributes
,
3085 OBJ_CASE_INSENSITIVE
,
3089 RtlInitUnicodeString (&KeyName
,
3092 InitializeObjectAttributes (&KeyObjectAttributes
,
3094 OBJ_CASE_INSENSITIVE
,
3098 Status
= NtLoadKey (&KeyObjectAttributes
,
3099 &FileObjectAttributes
);
3101 RtlFreeHeap (RtlGetProcessHeap (),
3105 if (!NT_SUCCESS(Status
))
3107 ErrorCode
= RtlNtStatusToDosError (Status
);
3112 ClosePredefKey(KeyHandle
);
3118 /************************************************************************
3119 * RegNotifyChangeKeyValue
3124 RegNotifyChangeKeyValue (HKEY hKey
,
3126 DWORD dwNotifyFilter
,
3130 IO_STATUS_BLOCK IoStatusBlock
;
3133 LONG ErrorCode
= ERROR_SUCCESS
;
3135 if (hKey
== HKEY_PERFORMANCE_DATA
)
3137 return ERROR_INVALID_HANDLE
;
3140 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3142 return ERROR_INVALID_PARAMETER
;
3145 Status
= MapDefaultKey (&KeyHandle
,
3147 if (!NT_SUCCESS(Status
))
3149 return RtlNtStatusToDosError (Status
);
3152 /* FIXME: Remote key handles must fail */
3154 Status
= NtNotifyChangeKey (KeyHandle
,
3164 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3166 ErrorCode
= RtlNtStatusToDosError (Status
);
3169 ClosePredefKey(KeyHandle
);
3175 /************************************************************************
3176 * RegOpenCurrentUser
3181 RegOpenCurrentUser (IN REGSAM samDesired
,
3182 OUT PHKEY phkResult
)
3186 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3187 (PHANDLE
)phkResult
);
3188 if (!NT_SUCCESS(Status
))
3190 /* NOTE - don't set the last error code! just return the error! */
3191 return RtlNtStatusToDosError(Status
);
3194 return ERROR_SUCCESS
;
3198 /************************************************************************
3201 * 20050503 Fireball - imported from WINE
3206 RegOpenKeyA (HKEY hKey
,
3210 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3212 if (!hKey
&& lpSubKey
&& phkResult
)
3214 return ERROR_INVALID_HANDLE
;
3217 if (!lpSubKey
|| !*lpSubKey
)
3220 return ERROR_SUCCESS
;
3223 return RegOpenKeyExA( hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3227 /************************************************************************
3232 * 20050503 Fireball - imported from WINE
3237 RegOpenKeyW (HKEY hKey
,
3241 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n", hKey
, lpSubKey
, phkResult
);
3243 if (!hKey
&& lpSubKey
&& phkResult
)
3245 return ERROR_INVALID_HANDLE
;
3248 if (!lpSubKey
|| !*lpSubKey
)
3251 return ERROR_SUCCESS
;
3253 return RegOpenKeyExW(hKey
, lpSubKey
, 0, MAXIMUM_ALLOWED
, phkResult
);
3257 /************************************************************************
3263 RegOpenKeyExA (HKEY hKey
,
3269 OBJECT_ATTRIBUTES ObjectAttributes
;
3270 UNICODE_STRING SubKeyString
;
3273 LONG ErrorCode
= ERROR_SUCCESS
;
3275 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3276 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3278 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3279 if (!NT_SUCCESS(Status
))
3281 return RtlNtStatusToDosError (Status
);
3284 RtlCreateUnicodeStringFromAsciiz (&SubKeyString
, (LPSTR
)lpSubKey
);
3285 InitializeObjectAttributes (&ObjectAttributes
,
3287 OBJ_CASE_INSENSITIVE
,
3291 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3292 RtlFreeUnicodeString (&SubKeyString
);
3293 if (!NT_SUCCESS(Status
))
3295 ErrorCode
= RtlNtStatusToDosError (Status
);
3298 ClosePredefKey(KeyHandle
);
3304 /************************************************************************
3310 RegOpenKeyExW (HKEY hKey
,
3316 OBJECT_ATTRIBUTES ObjectAttributes
;
3317 UNICODE_STRING SubKeyString
;
3320 LONG ErrorCode
= ERROR_SUCCESS
;
3322 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3323 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3325 Status
= MapDefaultKey (&KeyHandle
, hKey
);
3326 if (!NT_SUCCESS(Status
))
3328 return RtlNtStatusToDosError (Status
);
3331 if (lpSubKey
!= NULL
)
3332 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)lpSubKey
);
3334 RtlInitUnicodeString (&SubKeyString
, (LPWSTR
)L
"");
3336 InitializeObjectAttributes (&ObjectAttributes
,
3338 OBJ_CASE_INSENSITIVE
,
3342 Status
= NtOpenKey ((PHANDLE
)phkResult
, samDesired
, &ObjectAttributes
);
3344 if (!NT_SUCCESS(Status
))
3346 ErrorCode
= RtlNtStatusToDosError (Status
);
3349 ClosePredefKey(KeyHandle
);
3355 /************************************************************************
3356 * RegOpenUserClassesRoot
3361 RegOpenUserClassesRoot (IN HANDLE hToken
,
3363 IN REGSAM samDesired
,
3364 OUT PHKEY phkResult
)
3366 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3367 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3368 PTOKEN_USER TokenUserData
;
3369 ULONG RequiredLength
;
3370 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3371 OBJECT_ATTRIBUTES ObjectAttributes
;
3374 /* check parameters */
3375 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3377 return ERROR_INVALID_PARAMETER
;
3381 * Get the user sid from the token
3385 /* determine how much memory we need */
3386 Status
= NtQueryInformationToken(hToken
,
3391 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3393 /* NOTE - as opposed to all other registry functions windows does indeed
3394 change the last error code in case the caller supplied a invalid
3395 handle for example! */
3396 return RtlNtStatusToDosError (Status
);
3399 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3402 if (TokenUserData
== NULL
)
3404 return ERROR_NOT_ENOUGH_MEMORY
;
3407 /* attempt to read the information */
3408 Status
= NtQueryInformationToken(hToken
,
3413 if (!NT_SUCCESS(Status
))
3415 RtlFreeHeap(ProcessHeap
,
3418 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3420 /* the information appears to have changed?! try again */
3424 /* NOTE - as opposed to all other registry functions windows does indeed
3425 change the last error code in case the caller supplied a invalid
3426 handle for example! */
3427 return RtlNtStatusToDosError (Status
);
3431 * Build the absolute path for the user's registry in the form
3432 * "\Registry\User\<SID>_Classes"
3434 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3435 TokenUserData
->User
.Sid
,
3438 /* we don't need the user data anymore, free it */
3439 RtlFreeHeap(ProcessHeap
,
3443 if (!NT_SUCCESS(Status
))
3445 return RtlNtStatusToDosError (Status
);
3448 /* allocate enough memory for the entire key string */
3449 UserClassesKeyRoot
.Length
= 0;
3450 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3451 sizeof(UserClassesKeyPrefix
) +
3452 sizeof(UserClassesKeySuffix
);
3453 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3455 UserClassesKeyRoot
.MaximumLength
);
3456 if (UserClassesKeyRoot
.Buffer
== NULL
)
3458 RtlFreeUnicodeString(&UserSidString
);
3459 return RtlNtStatusToDosError (Status
);
3462 /* build the string */
3463 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3464 UserClassesKeyPrefix
);
3465 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3467 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3468 UserClassesKeySuffix
);
3470 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3476 InitializeObjectAttributes (&ObjectAttributes
,
3477 &UserClassesKeyRoot
,
3478 OBJ_CASE_INSENSITIVE
,
3482 Status
= NtOpenKey((PHANDLE
)phkResult
,
3486 RtlFreeUnicodeString(&UserSidString
);
3487 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3489 if (!NT_SUCCESS(Status
))
3491 return RtlNtStatusToDosError (Status
);
3494 return ERROR_SUCCESS
;
3498 /************************************************************************
3504 RegQueryInfoKeyA (HKEY hKey
,
3509 LPDWORD lpcbMaxSubKeyLen
,
3510 LPDWORD lpcbMaxClassLen
,
3512 LPDWORD lpcbMaxValueNameLen
,
3513 LPDWORD lpcbMaxValueLen
,
3514 LPDWORD lpcbSecurityDescriptor
,
3515 PFILETIME lpftLastWriteTime
)
3517 WCHAR ClassName
[MAX_PATH
];
3518 UNICODE_STRING UnicodeString
;
3519 ANSI_STRING AnsiString
;
3522 RtlInitUnicodeString (&UnicodeString
,
3524 if (lpClass
!= NULL
)
3526 UnicodeString
.Buffer
= &ClassName
[0];
3527 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3528 AnsiString
.MaximumLength
= *lpcbClass
;
3531 ErrorCode
= RegQueryInfoKeyW (hKey
,
3532 UnicodeString
.Buffer
,
3539 lpcbMaxValueNameLen
,
3541 lpcbSecurityDescriptor
,
3543 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3545 AnsiString
.Buffer
= lpClass
;
3546 AnsiString
.Length
= 0;
3547 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3548 RtlUnicodeStringToAnsiString (&AnsiString
,
3551 *lpcbClass
= AnsiString
.Length
;
3552 lpClass
[AnsiString
.Length
] = 0;
3559 /************************************************************************
3565 RegQueryInfoKeyW (HKEY hKey
,
3570 LPDWORD lpcbMaxSubKeyLen
,
3571 LPDWORD lpcbMaxClassLen
,
3573 LPDWORD lpcbMaxValueNameLen
,
3574 LPDWORD lpcbMaxValueLen
,
3575 LPDWORD lpcbSecurityDescriptor
,
3576 PFILETIME lpftLastWriteTime
)
3578 KEY_FULL_INFORMATION FullInfoBuffer
;
3579 PKEY_FULL_INFORMATION FullInfo
;
3581 ULONG ClassLength
= 0;
3585 LONG ErrorCode
= ERROR_SUCCESS
;
3587 if ((lpClass
) && (!lpcbClass
))
3589 return ERROR_INVALID_PARAMETER
;
3592 Status
= MapDefaultKey (&KeyHandle
,
3594 if (!NT_SUCCESS(Status
))
3596 return RtlNtStatusToDosError (Status
);
3599 if (lpClass
!= NULL
)
3603 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3610 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3611 FullInfo
= RtlAllocateHeap (ProcessHeap
,
3614 if (FullInfo
== NULL
)
3616 ErrorCode
= ERROR_OUTOFMEMORY
;
3620 FullInfo
->ClassLength
= ClassLength
;
3624 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3625 FullInfo
= &FullInfoBuffer
;
3626 FullInfo
->ClassLength
= 0;
3628 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3630 Status
= NtQueryKey (KeyHandle
,
3635 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3636 if (!NT_SUCCESS(Status
))
3638 if (lpClass
!= NULL
)
3640 RtlFreeHeap (ProcessHeap
,
3645 ErrorCode
= RtlNtStatusToDosError (Status
);
3649 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3650 if (lpcSubKeys
!= NULL
)
3652 *lpcSubKeys
= FullInfo
->SubKeys
;
3655 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3656 if (lpcbMaxSubKeyLen
!= NULL
)
3658 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3661 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3662 if (lpcbMaxClassLen
!= NULL
)
3664 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3667 TRACE("Values %lu\n", FullInfo
->Values
);
3668 if (lpcValues
!= NULL
)
3670 *lpcValues
= FullInfo
->Values
;
3673 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3674 if (lpcbMaxValueNameLen
!= NULL
)
3676 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3679 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3680 if (lpcbMaxValueLen
!= NULL
)
3682 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3685 if (lpcbSecurityDescriptor
!= NULL
)
3687 Status
= NtQuerySecurityObject(KeyHandle
,
3688 OWNER_SECURITY_INFORMATION
|
3689 GROUP_SECURITY_INFORMATION
|
3690 DACL_SECURITY_INFORMATION
,
3693 lpcbSecurityDescriptor
);
3694 if (!NT_SUCCESS(Status
))
3696 if (lpClass
!= NULL
)
3698 RtlFreeHeap(ProcessHeap
,
3703 ErrorCode
= RtlNtStatusToDosError (Status
);
3709 if (lpftLastWriteTime
!= NULL
)
3711 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3712 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3715 if (lpClass
!= NULL
)
3717 if (FullInfo
->ClassLength
> ClassLength
)
3719 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3723 RtlCopyMemory (lpClass
,
3725 FullInfo
->ClassLength
);
3726 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3727 lpClass
[*lpcbClass
] = 0;
3730 RtlFreeHeap (ProcessHeap
,
3736 ClosePredefKey(KeyHandle
);
3742 /************************************************************************
3743 * RegQueryMultipleValuesA
3748 RegQueryMultipleValuesA (HKEY hKey
,
3755 DWORD maxBytes
= *ldwTotsize
;
3756 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3759 if (maxBytes
>= (1024*1024))
3760 return ERROR_TRANSFER_TOO_LONG
;
3764 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3765 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3767 for (i
= 0; i
< num_vals
; i
++)
3769 val_list
[i
].ve_valuelen
= 0;
3770 ErrorCode
= RegQueryValueExA (hKey
,
3771 val_list
[i
].ve_valuename
,
3775 &val_list
[i
].ve_valuelen
);
3776 if (ErrorCode
!= ERROR_SUCCESS
)
3781 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3783 ErrorCode
= RegQueryValueExA (hKey
,
3784 val_list
[i
].ve_valuename
,
3786 &val_list
[i
].ve_type
,
3788 &val_list
[i
].ve_valuelen
);
3789 if (ErrorCode
!= ERROR_SUCCESS
)
3794 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3796 bufptr
+= val_list
[i
].ve_valuelen
;
3799 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3802 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3806 /************************************************************************
3807 * RegQueryMultipleValuesW
3812 RegQueryMultipleValuesW (HKEY hKey
,
3819 DWORD maxBytes
= *ldwTotsize
;
3820 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3823 if (maxBytes
>= (1024*1024))
3824 return ERROR_TRANSFER_TOO_LONG
;
3828 TRACE ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3829 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3831 for (i
= 0; i
< num_vals
; i
++)
3833 val_list
[i
].ve_valuelen
= 0;
3834 ErrorCode
= RegQueryValueExW (hKey
,
3835 val_list
[i
].ve_valuename
,
3839 &val_list
[i
].ve_valuelen
);
3840 if (ErrorCode
!= ERROR_SUCCESS
)
3845 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3847 ErrorCode
= RegQueryValueExW (hKey
,
3848 val_list
[i
].ve_valuename
,
3850 &val_list
[i
].ve_type
,
3852 &val_list
[i
].ve_valuelen
);
3853 if (ErrorCode
!= ERROR_SUCCESS
)
3858 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3860 bufptr
+= val_list
[i
].ve_valuelen
;
3863 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3866 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3870 /************************************************************************
3871 * RegQueryReflectionKey
3876 RegQueryReflectionKey(IN HKEY hBase
,
3877 OUT BOOL
* bIsReflectionDisabled
)
3879 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3880 hBase
, bIsReflectionDisabled
);
3881 return ERROR_CALL_NOT_IMPLEMENTED
;
3885 /************************************************************************
3892 RegQueryValueExW(HKEY hkeyorg
,
3901 UNICODE_STRING name_str
;
3903 char buffer
[256], *buf_ptr
= buffer
;
3904 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
3905 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
3907 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
3908 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
3909 (count
&& data
) ? *count
: 0 );
3911 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3912 //if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
3914 status
= MapDefaultKey(&hkey
, hkeyorg
);
3915 if (!NT_SUCCESS(status
))
3917 return RtlNtStatusToDosError(status
);
3920 RtlInitUnicodeString( &name_str
, name
);
3922 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
3925 total_size
= info_size
;
3926 if (count
) *count
= 0;
3929 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
3930 buffer
, total_size
, &total_size
);
3931 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
3935 /* retry with a dynamically allocated buffer */
3936 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
3938 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3939 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3940 return ERROR_NOT_ENOUGH_MEMORY
;
3941 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
3942 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
3943 buf_ptr
, total_size
, &total_size
);
3948 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
3949 /* if the type is REG_SZ and data is not 0-terminated
3950 * and there is enough space in the buffer NT appends a \0 */
3951 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
3953 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
3954 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3957 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
3959 else status
= STATUS_SUCCESS
;
3961 if (type
) *type
= info
->Type
;
3962 if (count
) *count
= total_size
- info_size
;
3965 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3966 ClosePredefKey(hkey
);
3967 return RtlNtStatusToDosError(status
);
3971 /************************************************************************
3977 RegQueryValueExA (HKEY hKey
,
3984 UNICODE_STRING ValueName
;
3985 UNICODE_STRING ValueData
;
3986 ANSI_STRING AnsiString
;
3991 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3992 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3994 if (lpData
!= NULL
&& lpcbData
== NULL
)
3996 return ERROR_INVALID_PARAMETER
;
4001 ValueData
.Length
= 0;
4002 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
4003 ValueData
.Buffer
= RtlAllocateHeap (ProcessHeap
,
4005 ValueData
.MaximumLength
);
4006 if (!ValueData
.Buffer
)
4008 return ERROR_OUTOFMEMORY
;
4013 ValueData
.Buffer
= NULL
;
4014 ValueData
.Length
= 0;
4015 ValueData
.MaximumLength
= 0;
4021 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4022 (LPSTR
)lpValueName
);
4024 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
4025 ErrorCode
= RegQueryValueExW (hKey
,
4029 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
4031 TRACE("ErrorCode %lu\n", ErrorCode
);
4032 RtlFreeUnicodeString(&ValueName
);
4034 if (ErrorCode
== ERROR_SUCCESS
||
4035 ErrorCode
== ERROR_MORE_DATA
)
4042 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
4044 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4046 RtlInitAnsiString(&AnsiString
, NULL
);
4047 AnsiString
.Buffer
= (LPSTR
)lpData
;
4048 AnsiString
.MaximumLength
= *lpcbData
;
4049 ValueData
.Length
= Length
;
4050 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
4051 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
4053 Length
= Length
/ sizeof(WCHAR
);
4055 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4057 if (*lpcbData
< Length
)
4059 ErrorCode
= ERROR_MORE_DATA
;
4063 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
4067 if (lpcbData
!= NULL
)
4073 if (ValueData
.Buffer
!= NULL
)
4075 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
4082 /************************************************************************
4088 RegQueryValueA (HKEY hKey
,
4093 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
4094 UNICODE_STRING SubKeyName
;
4095 UNICODE_STRING Value
;
4096 ANSI_STRING AnsiString
;
4100 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
4101 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4103 if (lpValue
!= NULL
&&
4106 return ERROR_INVALID_PARAMETER
;
4109 RtlInitUnicodeString (&SubKeyName
,
4111 RtlInitUnicodeString (&Value
,
4113 if (lpSubKey
!= NULL
&&
4114 strlen(lpSubKey
) != 0)
4116 RtlInitAnsiString (&AnsiString
,
4118 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
4119 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
4120 RtlAnsiStringToUnicodeString (&SubKeyName
,
4125 if (lpValue
!= NULL
)
4127 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
4128 Value
.MaximumLength
= ValueSize
;
4129 Value
.Buffer
= RtlAllocateHeap (ProcessHeap
,
4132 if (Value
.Buffer
== NULL
)
4134 return ERROR_OUTOFMEMORY
;
4142 ErrorCode
= RegQueryValueW (hKey
,
4143 (LPCWSTR
)SubKeyName
.Buffer
,
4146 if (ErrorCode
== ERROR_SUCCESS
)
4148 if (lpValue
!= NULL
)
4150 Value
.Length
= ValueSize
;
4151 RtlInitAnsiString (&AnsiString
,
4153 AnsiString
.Buffer
= lpValue
;
4154 AnsiString
.MaximumLength
= *lpcbValue
;
4155 RtlUnicodeStringToAnsiString (&AnsiString
,
4158 *lpcbValue
= ValueSize
;
4160 else if (lpcbValue
!= NULL
)
4162 *lpcbValue
= ValueSize
;
4166 if (Value
.Buffer
!= NULL
)
4168 RtlFreeHeap (ProcessHeap
,
4177 /************************************************************************
4183 RegQueryValueW (HKEY hKey
,
4188 OBJECT_ATTRIBUTES ObjectAttributes
;
4189 UNICODE_STRING SubKeyString
;
4196 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
4197 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4199 Status
= MapDefaultKey (&KeyHandle
,
4201 if (!NT_SUCCESS(Status
))
4203 return RtlNtStatusToDosError (Status
);
4206 if (lpSubKey
!= NULL
&&
4207 wcslen(lpSubKey
) != 0)
4209 RtlInitUnicodeString (&SubKeyString
,
4211 InitializeObjectAttributes (&ObjectAttributes
,
4213 OBJ_CASE_INSENSITIVE
,
4216 Status
= NtOpenKey (&RealKey
,
4219 if (!NT_SUCCESS(Status
))
4221 ErrorCode
= RtlNtStatusToDosError (Status
);
4224 CloseRealKey
= TRUE
;
4229 CloseRealKey
= FALSE
;
4232 ErrorCode
= RegQueryValueExW (RealKey
,
4237 (LPDWORD
)lpcbValue
);
4244 ClosePredefKey(KeyHandle
);
4250 /************************************************************************
4256 RegReplaceKeyA (HKEY hKey
,
4261 UNICODE_STRING SubKey
;
4262 UNICODE_STRING NewFile
;
4263 UNICODE_STRING OldFile
;
4266 RtlCreateUnicodeStringFromAsciiz (&SubKey
,
4268 RtlCreateUnicodeStringFromAsciiz (&OldFile
,
4270 RtlCreateUnicodeStringFromAsciiz (&NewFile
,
4273 ErrorCode
= RegReplaceKeyW (hKey
,
4278 RtlFreeUnicodeString (&OldFile
);
4279 RtlFreeUnicodeString (&NewFile
);
4280 RtlFreeUnicodeString (&SubKey
);
4286 /************************************************************************
4292 RegReplaceKeyW (HKEY hKey
,
4297 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4298 OBJECT_ATTRIBUTES NewObjectAttributes
;
4299 OBJECT_ATTRIBUTES OldObjectAttributes
;
4300 UNICODE_STRING SubKeyName
;
4301 UNICODE_STRING NewFileName
;
4302 UNICODE_STRING OldFileName
;
4303 BOOLEAN CloseRealKey
;
4304 HANDLE RealKeyHandle
;
4307 LONG ErrorCode
= ERROR_SUCCESS
;
4309 if (hKey
== HKEY_PERFORMANCE_DATA
)
4311 return ERROR_INVALID_HANDLE
;
4314 Status
= MapDefaultKey (&KeyHandle
,
4316 if (!NT_SUCCESS(Status
))
4318 return RtlNtStatusToDosError (Status
);
4321 /* Open the real key */
4322 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4324 RtlInitUnicodeString (&SubKeyName
,
4326 InitializeObjectAttributes (&KeyObjectAttributes
,
4328 OBJ_CASE_INSENSITIVE
,
4331 Status
= NtOpenKey (&RealKeyHandle
,
4333 &KeyObjectAttributes
);
4334 if (!NT_SUCCESS(Status
))
4336 ErrorCode
= RtlNtStatusToDosError (Status
);
4339 CloseRealKey
= TRUE
;
4343 RealKeyHandle
= KeyHandle
;
4344 CloseRealKey
= FALSE
;
4347 /* Convert new file name */
4348 if (!RtlDosPathNameToNtPathName_U (lpNewFile
,
4355 NtClose (RealKeyHandle
);
4357 ErrorCode
= ERROR_INVALID_PARAMETER
;
4361 InitializeObjectAttributes (&NewObjectAttributes
,
4363 OBJ_CASE_INSENSITIVE
,
4367 /* Convert old file name */
4368 if (!RtlDosPathNameToNtPathName_U (lpOldFile
,
4373 RtlFreeHeap (RtlGetProcessHeap (),
4375 NewFileName
.Buffer
);
4378 NtClose (RealKeyHandle
);
4380 ErrorCode
= ERROR_INVALID_PARAMETER
;
4384 InitializeObjectAttributes (&OldObjectAttributes
,
4386 OBJ_CASE_INSENSITIVE
,
4390 Status
= NtReplaceKey (&NewObjectAttributes
,
4392 &OldObjectAttributes
);
4394 RtlFreeHeap (RtlGetProcessHeap (),
4396 OldFileName
.Buffer
);
4397 RtlFreeHeap (RtlGetProcessHeap (),
4399 NewFileName
.Buffer
);
4403 NtClose (RealKeyHandle
);
4406 if (!NT_SUCCESS(Status
))
4408 return RtlNtStatusToDosError (Status
);
4412 ClosePredefKey(KeyHandle
);
4418 /************************************************************************
4424 RegRestoreKeyA (HKEY hKey
,
4428 UNICODE_STRING FileName
;
4431 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4434 ErrorCode
= RegRestoreKeyW (hKey
,
4438 RtlFreeUnicodeString (&FileName
);
4444 /************************************************************************
4450 RegRestoreKeyW (HKEY hKey
,
4454 OBJECT_ATTRIBUTES ObjectAttributes
;
4455 IO_STATUS_BLOCK IoStatusBlock
;
4456 UNICODE_STRING FileName
;
4461 if (hKey
== HKEY_PERFORMANCE_DATA
)
4463 return ERROR_INVALID_HANDLE
;
4466 Status
= MapDefaultKey (&KeyHandle
,
4468 if (!NT_SUCCESS(Status
))
4470 return RtlNtStatusToDosError (Status
);
4473 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4478 Status
= STATUS_INVALID_PARAMETER
;
4482 InitializeObjectAttributes (&ObjectAttributes
,
4484 OBJ_CASE_INSENSITIVE
,
4488 Status
= NtOpenFile (&FileHandle
,
4493 FILE_SYNCHRONOUS_IO_NONALERT
);
4494 RtlFreeHeap (RtlGetProcessHeap(),
4497 if (!NT_SUCCESS(Status
))
4502 Status
= NtRestoreKey (KeyHandle
,
4505 NtClose (FileHandle
);
4508 ClosePredefKey(KeyHandle
);
4510 if (!NT_SUCCESS(Status
))
4512 return RtlNtStatusToDosError (Status
);
4515 return ERROR_SUCCESS
;
4519 /************************************************************************
4525 RegSaveKeyA (HKEY hKey
,
4527 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4529 UNICODE_STRING FileName
;
4532 RtlCreateUnicodeStringFromAsciiz (&FileName
,
4534 ErrorCode
= RegSaveKeyW (hKey
,
4536 lpSecurityAttributes
);
4537 RtlFreeUnicodeString (&FileName
);
4543 /************************************************************************
4549 RegSaveKeyW (HKEY hKey
,
4551 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4553 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4554 OBJECT_ATTRIBUTES ObjectAttributes
;
4555 UNICODE_STRING FileName
;
4556 IO_STATUS_BLOCK IoStatusBlock
;
4561 Status
= MapDefaultKey (&KeyHandle
,
4563 if (!NT_SUCCESS(Status
))
4565 return RtlNtStatusToDosError (Status
);
4568 if (!RtlDosPathNameToNtPathName_U (lpFile
,
4573 Status
= STATUS_INVALID_PARAMETER
;
4577 if (lpSecurityAttributes
!= NULL
)
4579 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4582 InitializeObjectAttributes (&ObjectAttributes
,
4584 OBJ_CASE_INSENSITIVE
,
4586 SecurityDescriptor
);
4587 Status
= NtCreateFile (&FileHandle
,
4588 GENERIC_WRITE
| SYNCHRONIZE
,
4592 FILE_ATTRIBUTE_NORMAL
,
4595 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4598 RtlFreeHeap (RtlGetProcessHeap (),
4601 if (!NT_SUCCESS(Status
))
4606 Status
= NtSaveKey (KeyHandle
,
4608 NtClose (FileHandle
);
4611 ClosePredefKey(KeyHandle
);
4613 if (!NT_SUCCESS(Status
))
4615 return RtlNtStatusToDosError (Status
);
4618 return ERROR_SUCCESS
;
4622 /************************************************************************
4628 RegSetKeySecurity (HKEY hKey
,
4629 SECURITY_INFORMATION SecurityInformation
,
4630 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4635 if (hKey
== HKEY_PERFORMANCE_DATA
)
4637 return ERROR_INVALID_HANDLE
;
4640 Status
= MapDefaultKey (&KeyHandle
,
4642 if (!NT_SUCCESS(Status
))
4644 return RtlNtStatusToDosError (Status
);
4647 Status
= NtSetSecurityObject (KeyHandle
,
4648 SecurityInformation
,
4649 pSecurityDescriptor
);
4651 ClosePredefKey(KeyHandle
);
4653 if (!NT_SUCCESS(Status
))
4655 return RtlNtStatusToDosError (Status
);
4658 return ERROR_SUCCESS
;
4662 /************************************************************************
4668 RegSetValueExA (HKEY hKey
,
4675 UNICODE_STRING ValueName
;
4677 ANSI_STRING AnsiString
;
4678 UNICODE_STRING Data
;
4683 if (lpValueName
!= NULL
&&
4684 strlen(lpValueName
) != 0)
4686 RtlCreateUnicodeStringFromAsciiz (&ValueName
,
4688 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4695 if (((dwType
== REG_SZ
) ||
4696 (dwType
== REG_MULTI_SZ
) ||
4697 (dwType
== REG_EXPAND_SZ
)) &&
4700 /* NT adds one if the caller forgot the NULL-termination character */
4701 if (lpData
[cbData
- 1] != '\0')
4706 RtlInitAnsiString (&AnsiString
,
4708 AnsiString
.Buffer
= (PSTR
)lpData
;
4709 AnsiString
.Length
= cbData
- 1;
4710 AnsiString
.MaximumLength
= cbData
;
4711 RtlAnsiStringToUnicodeString (&Data
,
4714 pData
= (LPBYTE
)Data
.Buffer
;
4715 DataSize
= cbData
* sizeof(WCHAR
);
4719 RtlInitUnicodeString (&Data
,
4721 pData
= (LPBYTE
)lpData
;
4725 ErrorCode
= RegSetValueExW (hKey
,
4731 if (pValueName
!= NULL
)
4733 RtlFreeHeap (ProcessHeap
,
4738 if (Data
.Buffer
!= NULL
)
4740 RtlFreeHeap (ProcessHeap
,
4749 /************************************************************************
4755 RegSetValueExW (HKEY hKey
,
4756 LPCWSTR lpValueName
,
4762 UNICODE_STRING ValueName
;
4763 PUNICODE_STRING pValueName
;
4767 Status
= MapDefaultKey (&KeyHandle
,
4769 if (!NT_SUCCESS(Status
))
4771 return RtlNtStatusToDosError (Status
);
4774 if (lpValueName
!= NULL
)
4776 RtlInitUnicodeString (&ValueName
,
4781 RtlInitUnicodeString (&ValueName
, L
"");
4783 pValueName
= &ValueName
;
4785 if (((dwType
== REG_SZ
) ||
4786 (dwType
== REG_MULTI_SZ
) ||
4787 (dwType
== REG_EXPAND_SZ
)) &&
4788 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4790 /* NT adds one if the caller forgot the NULL-termination character */
4791 cbData
+= sizeof(WCHAR
);
4794 Status
= NtSetValueKey (KeyHandle
,
4801 ClosePredefKey(KeyHandle
);
4803 if (!NT_SUCCESS(Status
))
4805 return RtlNtStatusToDosError (Status
);
4808 return ERROR_SUCCESS
;
4812 /************************************************************************
4818 RegSetValueA (HKEY hKeyOriginal
,
4829 TRACE("(%p,%s,%d,%s,%d)\n", hKey
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4831 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4833 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4834 if (!NT_SUCCESS(Status
))
4836 return RtlNtStatusToDosError (Status
);
4840 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4842 if ((ret
= RegCreateKeyA( hKey
, lpSubKey
, &subkey
)) != ERROR_SUCCESS
) goto Cleanup
;
4844 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4845 if (subkey
!= hKey
) RegCloseKey( subkey
);
4848 ClosePredefKey(hKey
);
4854 /************************************************************************
4860 RegSetValueW (HKEY hKeyOriginal
,
4871 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4873 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4875 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4876 if (!NT_SUCCESS(Status
))
4878 return RtlNtStatusToDosError (Status
);
4882 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4884 if ((ret
= RegCreateKeyW( hKey
, lpSubKey
, &subkey
)) != ERROR_SUCCESS
) goto Cleanup
;
4887 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
4888 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
4889 if (subkey
!= hKey
) RegCloseKey( subkey
);
4892 ClosePredefKey(hKey
);
4898 /************************************************************************
4904 RegUnLoadKeyA (HKEY hKey
,
4907 UNICODE_STRING KeyName
;
4910 RtlCreateUnicodeStringFromAsciiz (&KeyName
,
4913 ErrorCode
= RegUnLoadKeyW (hKey
,
4916 RtlFreeUnicodeString (&KeyName
);
4922 /************************************************************************
4928 RegUnLoadKeyW (HKEY hKey
,
4931 OBJECT_ATTRIBUTES ObjectAttributes
;
4932 UNICODE_STRING KeyName
;
4936 if (hKey
== HKEY_PERFORMANCE_DATA
)
4938 return ERROR_INVALID_HANDLE
;
4941 Status
= MapDefaultKey (&KeyHandle
, hKey
);
4942 if (!NT_SUCCESS(Status
))
4944 return RtlNtStatusToDosError (Status
);
4947 RtlInitUnicodeString (&KeyName
,
4950 InitializeObjectAttributes (&ObjectAttributes
,
4952 OBJ_CASE_INSENSITIVE
,
4956 Status
= NtUnloadKey (&ObjectAttributes
);
4958 ClosePredefKey(KeyHandle
);
4960 if (!NT_SUCCESS(Status
))
4962 return RtlNtStatusToDosError (Status
);
4965 return ERROR_SUCCESS
;
4968 /******************************************************************************
4969 * load_string [Internal]
4971 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
4972 * avoid importing user32, which is higher level than advapi32. Helper for
4975 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
4982 /* Negative values have to be inverted. */
4983 if (HIWORD(resId
) == 0xffff)
4984 resId
= (UINT
)(-((INT
)resId
));
4986 /* Load the resource into memory and get a pointer to it. */
4987 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
4988 if (!hResource
) return 0;
4989 hMemory
= LoadResource(hModule
, hResource
);
4990 if (!hMemory
) return 0;
4991 pString
= LockResource(hMemory
);
4993 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
4994 idxString
= resId
& 0xf;
4995 while (idxString
--) pString
+= *pString
+ 1;
4997 /* If no buffer is given, return length of the string. */
4998 if (!pwszBuffer
) return *pString
;
5000 /* Else copy over the string, respecting the buffer size. */
5001 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5002 if (cMaxChars
>= 0) {
5003 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5004 pwszBuffer
[cMaxChars
] = L
'\0';
5011 /************************************************************************
5017 RegLoadMUIStringW(IN HKEY hKey
,
5018 IN LPCWSTR pszValue OPTIONAL
,
5019 OUT LPWSTR pszOutBuf
,
5021 OUT LPDWORD pcbData OPTIONAL
,
5023 IN LPCWSTR pszDirectory OPTIONAL
)
5025 DWORD dwValueType
, cbData
;
5026 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5029 /* Parameter sanity checks. */
5030 if (!hKey
|| !pszOutBuf
)
5031 return ERROR_INVALID_PARAMETER
;
5033 if (pszDirectory
&& *pszDirectory
) {
5034 FIXME("BaseDir parameter not yet supported!\n");
5035 return ERROR_INVALID_PARAMETER
;
5038 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5039 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5040 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5041 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
5042 result
= ERROR_FILE_NOT_FOUND
;
5045 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5046 if (!pwszTempBuffer
) {
5047 result
= ERROR_NOT_ENOUGH_MEMORY
;
5050 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5051 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5053 /* Expand environment variables, if appropriate, or copy the original string over. */
5054 if (dwValueType
== REG_EXPAND_SZ
) {
5055 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5056 if (!cbData
) goto cleanup
;
5057 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5058 if (!pwszExpandedBuffer
) {
5059 result
= ERROR_NOT_ENOUGH_MEMORY
;
5062 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5064 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5065 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5068 /* If the value references a resource based string, parse the value and load the string.
5069 * Else just copy over the original value. */
5070 result
= ERROR_SUCCESS
;
5071 if (*pwszExpandedBuffer
!= L
'@') { /* '@' is the prefix for resource based string entries. */
5072 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5074 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5078 /* Format of the expanded value is 'path_to_dll,-resId' */
5079 if (!pComma
|| pComma
[1] != L
'-') {
5080 result
= ERROR_BADKEY
;
5084 uiStringId
= _wtoi(pComma
+2);
5087 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5088 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5089 result
= ERROR_BADKEY
;
5090 FreeLibrary(hModule
);
5094 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5095 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5100 /************************************************************************
5106 RegLoadMUIStringA(IN HKEY hKey
,
5107 IN LPCSTR pszValue OPTIONAL
,
5108 OUT LPSTR pszOutBuf
,
5110 OUT LPDWORD pcbData OPTIONAL
,
5112 IN LPCSTR pszDirectory OPTIONAL
)
5114 UNICODE_STRING valueW
, baseDirW
;
5116 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5119 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5120 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5121 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5122 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5124 result
= ERROR_NOT_ENOUGH_MEMORY
;
5128 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5131 if (result
== ERROR_SUCCESS
) {
5132 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5138 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5139 RtlFreeUnicodeString(&baseDirW
);
5140 RtlFreeUnicodeString(&valueW
);