2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
18 #include <ndk/cmfuncs.h>
19 #include <pseh/pseh2.h>
23 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
25 /* DEFINES ******************************************************************/
27 #define MAX_DEFAULT_HANDLES 6
28 #define REG_MAX_NAME_SIZE 256
29 #define REG_MAX_DATA_SIZE 2048
31 /* GLOBALS ******************************************************************/
33 static RTL_CRITICAL_SECTION HandleTableCS
;
34 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
35 static HANDLE ProcessHeap
;
36 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
37 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
38 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
40 /* PROTOTYPES ***************************************************************/
42 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
43 static VOID
CloseDefaultKeys(VOID
);
44 #define ClosePredefKey(Handle) \
45 if ((ULONG_PTR)Handle & 0x1) { \
48 #define IsPredefKey(HKey) \
49 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
50 #define GetPredefKeyIndex(HKey) \
51 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
53 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
54 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
55 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
56 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
59 /* FUNCTIONS ****************************************************************/
60 /* check if value type needs string conversion (Ansi<->Unicode) */
61 __inline
static int is_string( DWORD type
)
63 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
66 /************************************************************************
67 * RegInitDefaultHandles
72 TRACE("RegInitialize()\n");
77 ProcessHeap
= RtlGetProcessHeap();
78 RtlZeroMemory(DefaultHandleTable
,
79 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
80 RtlInitializeCriticalSection(&HandleTableCS
);
82 DllInitialized
= TRUE
;
89 /************************************************************************
95 TRACE("RegCleanup()\n");
98 RtlDeleteCriticalSection(&HandleTableCS
);
105 OpenPredefinedKey(IN ULONG Index
,
112 case 0: /* HKEY_CLASSES_ROOT */
113 Status
= OpenClassesRootKey (Handle
);
116 case 1: /* HKEY_CURRENT_USER */
117 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
121 case 2: /* HKEY_LOCAL_MACHINE */
122 Status
= OpenLocalMachineKey (Handle
);
125 case 3: /* HKEY_USERS */
126 Status
= OpenUsersKey (Handle
);
129 case 4: /* HKEY_PERFORMANCE_DATA */
130 Status
= OpenPerformanceDataKey (Handle
);
134 case 5: /* HKEY_CURRENT_CONFIG */
135 Status
= OpenCurrentConfigKey (Handle
);
138 case 6: /* HKEY_DYN_DATA */
139 Status
= STATUS_NOT_IMPLEMENTED
;
143 WARN("MapDefaultHandle() no handle creator\n");
144 Status
= STATUS_INVALID_PARAMETER
;
153 MapDefaultKey(OUT PHANDLE RealKey
,
158 BOOLEAN DoOpen
, DefDisabled
;
159 NTSTATUS Status
= STATUS_SUCCESS
;
161 TRACE("MapDefaultKey (Key %x)\n", Key
);
163 if (!IsPredefKey(Key
))
165 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
166 return STATUS_SUCCESS
;
169 /* Handle special cases here */
170 Index
= GetPredefKeyIndex(Key
);
171 if (Index
>= MAX_DEFAULT_HANDLES
)
173 return STATUS_INVALID_PARAMETER
;
175 RegInitialize(); /* HACK until delay-loading is implemented */
176 RtlEnterCriticalSection (&HandleTableCS
);
178 if (Key
== HKEY_CURRENT_USER
)
179 DefDisabled
= DefaultHandleHKUDisabled
;
181 DefDisabled
= DefaultHandlesDisabled
;
185 Handle
= &DefaultHandleTable
[Index
];
186 DoOpen
= (*Handle
== NULL
);
196 /* create/open the default handle */
197 Status
= OpenPredefinedKey(Index
,
201 if (NT_SUCCESS(Status
))
206 *(PULONG_PTR
)Handle
|= 0x1;
209 RtlLeaveCriticalSection (&HandleTableCS
);
216 CloseDefaultKeys(VOID
)
219 RegInitialize(); /* HACK until delay-loading is implemented */
220 RtlEnterCriticalSection(&HandleTableCS
);
222 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
224 if (DefaultHandleTable
[i
] != NULL
)
226 NtClose(DefaultHandleTable
[i
]);
227 DefaultHandleTable
[i
] = NULL
;
231 RtlLeaveCriticalSection(&HandleTableCS
);
236 OpenClassesRootKey(_Out_ PHANDLE KeyHandle
)
238 OBJECT_ATTRIBUTES Attributes
;
239 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
242 TRACE("OpenClassesRootKey()\n");
244 InitializeObjectAttributes(&Attributes
,
246 OBJ_CASE_INSENSITIVE
,
249 Status
= NtOpenKey(KeyHandle
,
253 if (!NT_SUCCESS(Status
))
256 /* Mark it as HKCR */
257 MakeHKCRKey((HKEY
*)KeyHandle
);
264 OpenLocalMachineKey(PHANDLE KeyHandle
)
266 OBJECT_ATTRIBUTES Attributes
;
267 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
270 TRACE("OpenLocalMachineKey()\n");
272 InitializeObjectAttributes(&Attributes
,
274 OBJ_CASE_INSENSITIVE
,
277 Status
= NtOpenKey(KeyHandle
,
281 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
288 OpenUsersKey(PHANDLE KeyHandle
)
290 OBJECT_ATTRIBUTES Attributes
;
291 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
293 TRACE("OpenUsersKey()\n");
295 InitializeObjectAttributes(&Attributes
,
297 OBJ_CASE_INSENSITIVE
,
300 return NtOpenKey(KeyHandle
,
307 OpenCurrentConfigKey (PHANDLE KeyHandle
)
309 OBJECT_ATTRIBUTES Attributes
;
310 UNICODE_STRING KeyName
=
311 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
313 TRACE("OpenCurrentConfigKey()\n");
315 InitializeObjectAttributes(&Attributes
,
317 OBJ_CASE_INSENSITIVE
,
320 return NtOpenKey(KeyHandle
,
326 /************************************************************************
327 * RegDisablePredefinedCache
332 RegDisablePredefinedCache(VOID
)
334 RegInitialize(); /* HACK until delay-loading is implemented */
335 RtlEnterCriticalSection(&HandleTableCS
);
336 DefaultHandleHKUDisabled
= TRUE
;
337 RtlLeaveCriticalSection(&HandleTableCS
);
338 return ERROR_SUCCESS
;
342 /************************************************************************
343 * RegDisablePredefinedCacheEx
348 RegDisablePredefinedCacheEx(VOID
)
350 RegInitialize(); /* HACK until delay-loading is implemented */
351 RtlEnterCriticalSection(&HandleTableCS
);
352 DefaultHandlesDisabled
= TRUE
;
353 DefaultHandleHKUDisabled
= TRUE
;
354 RtlLeaveCriticalSection(&HandleTableCS
);
355 return ERROR_SUCCESS
;
359 /************************************************************************
360 * RegOverridePredefKey
365 RegOverridePredefKey(IN HKEY hKey
,
366 IN HKEY hNewHKey OPTIONAL
)
368 LONG ErrorCode
= ERROR_SUCCESS
;
370 if ((hKey
== HKEY_CLASSES_ROOT
||
371 hKey
== HKEY_CURRENT_CONFIG
||
372 hKey
== HKEY_CURRENT_USER
||
373 hKey
== HKEY_LOCAL_MACHINE
||
374 hKey
== HKEY_PERFORMANCE_DATA
||
375 hKey
== HKEY_USERS
) &&
376 !IsPredefKey(hNewHKey
))
381 Index
= GetPredefKeyIndex(hKey
);
382 Handle
= &DefaultHandleTable
[Index
];
384 if (hNewHKey
== NULL
)
386 /* restore the default mapping */
387 NTSTATUS Status
= OpenPredefinedKey(Index
,
389 if (!NT_SUCCESS(Status
))
391 return RtlNtStatusToDosError(Status
);
394 ASSERT(hNewHKey
!= NULL
);
396 RegInitialize(); /* HACK until delay-loading is implemented */
397 RtlEnterCriticalSection(&HandleTableCS
);
399 /* close the currently mapped handle if existing */
405 /* update the mapping */
408 RtlLeaveCriticalSection(&HandleTableCS
);
411 ErrorCode
= ERROR_INVALID_HANDLE
;
417 /************************************************************************
423 RegCloseKey(HKEY hKey
)
427 /* don't close null handle or a pseudo handle */
428 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
430 return ERROR_INVALID_HANDLE
;
433 Status
= NtClose(hKey
);
434 if (!NT_SUCCESS(Status
))
436 return RtlNtStatusToDosError(Status
);
439 return ERROR_SUCCESS
;
444 RegpCopyTree(IN HKEY hKeySrc
,
449 LIST_ENTRY ListEntry
;
452 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
454 LIST_ENTRY copyQueueHead
;
455 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
458 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
459 KEY_NODE_INFORMATION
*KeyNode
;
462 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
463 NTSTATUS Status
= STATUS_SUCCESS
;
464 NTSTATUS Status2
= STATUS_SUCCESS
;
466 InitializeListHead(©QueueHead
);
468 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
471 if (Info
.Buffer
== NULL
)
473 return STATUS_INSUFFICIENT_RESOURCES
;
476 copyKeys
= RtlAllocateHeap(ProcessHeap
,
478 sizeof(REGP_COPY_KEYS
));
479 if (copyKeys
!= NULL
)
481 copyKeys
->hKeySrc
= hKeySrc
;
482 copyKeys
->hKeyDest
= hKeyDest
;
483 InsertHeadList(©QueueHead
,
484 ©Keys
->ListEntry
);
486 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
490 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
494 /* enumerate all values and copy them */
498 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
500 KeyValueFullInformation
,
503 &BufferSizeRequired
);
504 if (NT_SUCCESS(Status2
))
506 UNICODE_STRING ValueName
;
509 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
510 ValueName
.Length
= Info
.KeyValue
->NameLength
;
511 ValueName
.MaximumLength
= ValueName
.Length
;
512 ValueName
.Buffer
= Info
.KeyValue
->Name
;
514 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
516 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
518 Info
.KeyValue
->TitleIndex
,
521 Info
.KeyValue
->DataLength
);
523 /* don't break, let's try to copy as many values as possible */
524 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
531 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
535 ASSERT(BufferSize
< BufferSizeRequired
);
537 Buffer
= RtlReAllocateHeap(ProcessHeap
,
543 Info
.Buffer
= Buffer
;
548 /* don't break, let's try to copy as many values as possible */
549 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
552 if (NT_SUCCESS(Status
))
560 /* break to avoid an infinite loop in case of denied access or
562 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
571 /* enumerate all subkeys and open and enqueue them */
575 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
580 &BufferSizeRequired
);
581 if (NT_SUCCESS(Status2
))
583 HANDLE KeyHandle
, NewKeyHandle
;
584 OBJECT_ATTRIBUTES ObjectAttributes
;
585 UNICODE_STRING SubKeyName
, ClassName
;
587 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
588 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
589 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
590 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
591 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
592 ClassName
.MaximumLength
= ClassName
.Length
;
593 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
595 /* open the subkey with sufficient rights */
597 InitializeObjectAttributes(&ObjectAttributes
,
599 OBJ_CASE_INSENSITIVE
,
603 Status2
= NtOpenKey(&KeyHandle
,
604 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
606 if (NT_SUCCESS(Status2
))
608 /* FIXME - attempt to query the security information */
610 InitializeObjectAttributes(&ObjectAttributes
,
612 OBJ_CASE_INSENSITIVE
,
616 Status2
= NtCreateKey(&NewKeyHandle
,
619 Info
.KeyNode
->TitleIndex
,
623 if (NT_SUCCESS(Status2
))
625 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
627 sizeof(REGP_COPY_KEYS
));
628 if (newCopyKeys
!= NULL
)
630 /* save the handles and enqueue the subkey */
631 newCopyKeys
->hKeySrc
= KeyHandle
;
632 newCopyKeys
->hKeyDest
= NewKeyHandle
;
633 InsertTailList(©QueueHead
,
634 &newCopyKeys
->ListEntry
);
639 NtClose(NewKeyHandle
);
641 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
650 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
657 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
661 ASSERT(BufferSize
< BufferSizeRequired
);
663 Buffer
= RtlReAllocateHeap(ProcessHeap
,
669 Info
.Buffer
= Buffer
;
674 /* don't break, let's try to copy as many keys as possible */
675 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
678 if (NT_SUCCESS(Status
))
686 /* break to avoid an infinite loop in case of denied access or
688 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
697 /* close the handles and remove the entry from the list */
698 if (copyKeys
->hKeySrc
!= hKeySrc
)
700 NtClose(copyKeys
->hKeySrc
);
702 if (copyKeys
->hKeyDest
!= hKeyDest
)
704 NtClose(copyKeys
->hKeyDest
);
707 RemoveEntryList(©Keys
->ListEntry
);
709 RtlFreeHeap(ProcessHeap
,
712 } while (!IsListEmpty(©QueueHead
));
715 Status
= STATUS_INSUFFICIENT_RESOURCES
;
717 RtlFreeHeap(ProcessHeap
,
725 /************************************************************************
731 RegCopyTreeW(IN HKEY hKeySrc
,
732 IN LPCWSTR lpSubKey OPTIONAL
,
735 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
738 Status
= MapDefaultKey(&KeyHandle
,
740 if (!NT_SUCCESS(Status
))
742 return RtlNtStatusToDosError(Status
);
745 Status
= MapDefaultKey(&DestKeyHandle
,
747 if (!NT_SUCCESS(Status
))
752 if (lpSubKey
!= NULL
)
754 OBJECT_ATTRIBUTES ObjectAttributes
;
755 UNICODE_STRING SubKeyName
;
757 RtlInitUnicodeString(&SubKeyName
,
760 InitializeObjectAttributes(&ObjectAttributes
,
762 OBJ_CASE_INSENSITIVE
,
766 Status
= NtOpenKey(&SubKeyHandle
,
767 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
769 if (!NT_SUCCESS(Status
))
774 CurKey
= SubKeyHandle
;
779 Status
= RegpCopyTree(CurKey
,
782 if (SubKeyHandle
!= NULL
)
784 NtClose(SubKeyHandle
);
788 ClosePredefKey(DestKeyHandle
);
790 ClosePredefKey(KeyHandle
);
792 if (!NT_SUCCESS(Status
))
794 return RtlNtStatusToDosError(Status
);
797 return ERROR_SUCCESS
;
801 /************************************************************************
807 RegCopyTreeA(IN HKEY hKeySrc
,
808 IN LPCSTR lpSubKey OPTIONAL
,
811 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
814 if (lpSubKey
!= NULL
&&
815 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
818 return ERROR_NOT_ENOUGH_MEMORY
;
821 Ret
= RegCopyTreeW(hKeySrc
,
825 RtlFreeUnicodeString(&SubKeyName
);
831 /************************************************************************
832 * RegConnectRegistryA
837 RegConnectRegistryA(IN LPCSTR lpMachineName
,
841 UNICODE_STRING MachineName
= { 0, 0, NULL
};
844 if (lpMachineName
!= NULL
&&
845 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
846 (LPSTR
)lpMachineName
))
848 return ERROR_NOT_ENOUGH_MEMORY
;
851 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
855 RtlFreeUnicodeString(&MachineName
);
861 /************************************************************************
862 * RegConnectRegistryW
867 RegConnectRegistryW(LPCWSTR lpMachineName
,
873 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
875 if (!lpMachineName
|| !*lpMachineName
)
877 /* Use the local machine name */
878 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
882 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
883 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
885 /* MSDN says lpMachineName must start with \\ : not so */
886 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
889 if (GetComputerNameW(compName
, &len
))
891 if (!_wcsicmp(lpMachineName
, compName
))
892 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
895 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
896 ret
= ERROR_BAD_NETPATH
;
900 ret
= GetLastError();
907 /************************************************************************
910 * Create key and all necessary intermediate keys
913 CreateNestedKey(PHKEY KeyHandle
,
914 POBJECT_ATTRIBUTES ObjectAttributes
,
915 PUNICODE_STRING ClassString
,
918 DWORD
*lpdwDisposition
)
920 OBJECT_ATTRIBUTES LocalObjectAttributes
;
921 UNICODE_STRING LocalKeyName
;
924 ULONG FullNameLength
;
927 HANDLE LocalKeyHandle
;
929 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
935 (PULONG
)lpdwDisposition
);
936 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
937 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
940 /* Copy object attributes */
941 RtlCopyMemory(&LocalObjectAttributes
,
943 sizeof(OBJECT_ATTRIBUTES
));
944 RtlCreateUnicodeString(&LocalKeyName
,
945 ObjectAttributes
->ObjectName
->Buffer
);
946 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
947 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
949 LocalKeyHandle
= NULL
;
951 /* Remove the last part of the key name and try to create the key again. */
952 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
954 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
955 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
957 Status
= STATUS_UNSUCCESSFUL
;
962 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
964 Status
= NtCreateKey(&LocalKeyHandle
,
966 &LocalObjectAttributes
,
971 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
974 if (!NT_SUCCESS(Status
))
976 RtlFreeUnicodeString(&LocalKeyName
);
980 /* Add removed parts of the key name and create them too. */
981 Length
= wcslen(LocalKeyName
.Buffer
);
985 NtClose (LocalKeyHandle
);
987 LocalKeyName
.Buffer
[Length
] = L
'\\';
988 Length
= wcslen (LocalKeyName
.Buffer
);
989 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
991 if (Length
== FullNameLength
)
993 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
999 (PULONG
)lpdwDisposition
);
1003 Status
= NtCreateKey(&LocalKeyHandle
,
1005 &LocalObjectAttributes
,
1010 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
1011 if (!NT_SUCCESS(Status
))
1015 RtlFreeUnicodeString(&LocalKeyName
);
1021 /************************************************************************
1029 _In_ LPCSTR lpSubKey
,
1030 _In_ DWORD Reserved
,
1032 _In_ DWORD dwOptions
,
1033 _In_ REGSAM samDesired
,
1034 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1035 _Out_ PHKEY phkResult
,
1036 _Out_ LPDWORD lpdwDisposition
)
1038 UNICODE_STRING SubKeyString
;
1039 UNICODE_STRING ClassString
;
1042 RtlInitEmptyUnicodeString(&ClassString
, NULL
, 0);
1043 RtlInitEmptyUnicodeString(&SubKeyString
, NULL
, 0);
1047 if (!RtlCreateUnicodeStringFromAsciiz(&ClassString
, lpClass
))
1049 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1056 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, lpSubKey
))
1058 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1063 ErrorCode
= RegCreateKeyExW(
1065 SubKeyString
.Buffer
,
1070 lpSecurityAttributes
,
1075 RtlFreeUnicodeString(&SubKeyString
);
1076 RtlFreeUnicodeString(&ClassString
);
1082 /************************************************************************
1091 _In_ LPCWSTR lpSubKey
,
1092 _In_ DWORD Reserved
,
1093 _In_opt_ LPWSTR lpClass
,
1094 _In_ DWORD dwOptions
,
1095 _In_ REGSAM samDesired
,
1096 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1097 _Out_ PHKEY phkResult
,
1098 _Out_opt_ LPDWORD lpdwDisposition
)
1100 UNICODE_STRING SubKeyString
;
1101 UNICODE_STRING ClassString
;
1102 OBJECT_ATTRIBUTES ObjectAttributes
;
1104 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1107 TRACE("RegCreateKeyExW() called\n");
1109 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1110 return ERROR_INVALID_USER_BUFFER
;
1112 /* get the real parent key */
1113 Status
= MapDefaultKey(&ParentKey
,
1115 if (!NT_SUCCESS(Status
))
1117 return RtlNtStatusToDosError(Status
);
1120 TRACE("ParentKey %p\n", ParentKey
);
1122 if (IsHKCRKey(ParentKey
))
1124 LONG ErrorCode
= CreateHKCRKey(
1131 lpSecurityAttributes
,
1134 ClosePredefKey(ParentKey
);
1138 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1139 Attributes
|= OBJ_OPENLINK
;
1141 RtlInitUnicodeString(&ClassString
,
1143 RtlInitUnicodeString(&SubKeyString
,
1145 InitializeObjectAttributes(&ObjectAttributes
,
1149 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1150 Status
= CreateNestedKey(phkResult
,
1152 (lpClass
== NULL
)? NULL
: &ClassString
,
1157 ClosePredefKey(ParentKey
);
1159 TRACE("Status %x\n", Status
);
1160 if (!NT_SUCCESS(Status
))
1162 return RtlNtStatusToDosError(Status
);
1165 return ERROR_SUCCESS
;
1169 /************************************************************************
1175 RegCreateKeyA(HKEY hKey
,
1179 return RegCreateKeyExA(hKey
,
1191 /************************************************************************
1197 RegCreateKeyW(HKEY hKey
,
1201 return RegCreateKeyExW(hKey
,
1213 /************************************************************************
1222 _In_ LPCSTR lpSubKey
)
1224 return RegDeleteKeyExA(hKey
, lpSubKey
, 0, 0);
1228 /************************************************************************
1237 _In_ LPCWSTR lpSubKey
)
1239 return RegDeleteKeyExW(hKey
, lpSubKey
, 0, 0);
1243 /************************************************************************
1252 _In_ LPCSTR lpSubKey
,
1253 _In_ REGSAM samDesired
,
1254 _In_ DWORD Reserved
)
1257 UNICODE_STRING SubKeyName
;
1261 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
, lpSubKey
))
1262 return ERROR_NOT_ENOUGH_MEMORY
;
1265 RtlInitEmptyUnicodeString(&SubKeyName
, NULL
, 0);
1267 ErrorCode
= RegDeleteKeyExW(hKey
, SubKeyName
.Buffer
, samDesired
, Reserved
);
1269 RtlFreeUnicodeString(&SubKeyName
);
1275 /************************************************************************
1284 _In_ LPCWSTR lpSubKey
,
1285 _In_ REGSAM samDesired
,
1286 _In_ DWORD Reserved
)
1288 OBJECT_ATTRIBUTES ObjectAttributes
;
1289 UNICODE_STRING SubKeyName
;
1294 /* Make sure we got a subkey */
1298 return ERROR_INVALID_PARAMETER
;
1301 Status
= MapDefaultKey(&ParentKey
,
1303 if (!NT_SUCCESS(Status
))
1305 return RtlNtStatusToDosError(Status
);
1308 if (IsHKCRKey(ParentKey
))
1310 LONG ErrorCode
= DeleteHKCRKey(ParentKey
, lpSubKey
, samDesired
, Reserved
);
1311 ClosePredefKey(ParentKey
);
1315 if (samDesired
& KEY_WOW64_32KEY
)
1316 ERR("Wow64 not yet supported!\n");
1318 if (samDesired
& KEY_WOW64_64KEY
)
1319 ERR("Wow64 not yet supported!\n");
1322 RtlInitUnicodeString(&SubKeyName
,
1324 InitializeObjectAttributes(&ObjectAttributes
,
1326 OBJ_CASE_INSENSITIVE
,
1329 Status
= NtOpenKey(&TargetKey
,
1332 if (!NT_SUCCESS(Status
))
1337 Status
= NtDeleteKey(TargetKey
);
1341 ClosePredefKey(ParentKey
);
1343 if (!NT_SUCCESS(Status
))
1345 return RtlNtStatusToDosError(Status
);
1348 return ERROR_SUCCESS
;
1352 /************************************************************************
1353 * RegDeleteKeyValueW
1358 RegDeleteKeyValueW(IN HKEY hKey
,
1359 IN LPCWSTR lpSubKey OPTIONAL
,
1360 IN LPCWSTR lpValueName OPTIONAL
)
1362 UNICODE_STRING ValueName
;
1363 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1366 Status
= MapDefaultKey(&KeyHandle
,
1368 if (!NT_SUCCESS(Status
))
1370 return RtlNtStatusToDosError(Status
);
1373 if (lpSubKey
!= NULL
)
1375 OBJECT_ATTRIBUTES ObjectAttributes
;
1376 UNICODE_STRING SubKeyName
;
1378 RtlInitUnicodeString(&SubKeyName
,
1381 InitializeObjectAttributes(&ObjectAttributes
,
1383 OBJ_CASE_INSENSITIVE
,
1387 Status
= NtOpenKey(&SubKeyHandle
,
1390 if (!NT_SUCCESS(Status
))
1395 CurKey
= SubKeyHandle
;
1400 RtlInitUnicodeString(&ValueName
,
1401 (LPWSTR
)lpValueName
);
1403 Status
= NtDeleteValueKey(CurKey
,
1406 if (SubKeyHandle
!= NULL
)
1408 NtClose(SubKeyHandle
);
1412 ClosePredefKey(KeyHandle
);
1414 if (!NT_SUCCESS(Status
))
1416 return RtlNtStatusToDosError(Status
);
1419 return ERROR_SUCCESS
;
1423 /************************************************************************
1424 * RegDeleteKeyValueA
1429 RegDeleteKeyValueA(IN HKEY hKey
,
1430 IN LPCSTR lpSubKey OPTIONAL
,
1431 IN LPCSTR lpValueName OPTIONAL
)
1433 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1436 if (lpSubKey
!= NULL
&&
1437 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1440 return ERROR_NOT_ENOUGH_MEMORY
;
1443 if (lpValueName
!= NULL
&&
1444 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1445 (LPSTR
)lpValueName
))
1447 RtlFreeUnicodeString(&SubKey
);
1448 return ERROR_NOT_ENOUGH_MEMORY
;
1451 Ret
= RegDeleteKeyValueW(hKey
,
1455 RtlFreeUnicodeString(&SubKey
);
1456 RtlFreeUnicodeString(&ValueName
);
1462 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1464 RegpDeleteTree(IN HKEY hKey
)
1468 LIST_ENTRY ListEntry
;
1470 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1472 LIST_ENTRY delQueueHead
;
1473 PREG_DEL_KEYS delKeys
, newDelKeys
;
1476 PKEY_BASIC_INFORMATION BasicInfo
;
1477 PREG_DEL_KEYS KeyDelRoot
;
1478 NTSTATUS Status
= STATUS_SUCCESS
;
1479 NTSTATUS Status2
= STATUS_SUCCESS
;
1481 InitializeListHead(&delQueueHead
);
1483 ProcessHeap
= RtlGetProcessHeap();
1485 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1486 structure for the root key, we only do that for subkeys as we need to
1487 allocate REGP_DEL_KEYS structures anyway! */
1488 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1490 sizeof(REGP_DEL_KEYS
));
1491 if (KeyDelRoot
!= NULL
)
1493 KeyDelRoot
->KeyHandle
= hKey
;
1494 InsertTailList(&delQueueHead
,
1495 &KeyDelRoot
->ListEntry
);
1499 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1508 /* check if this key contains subkeys and delete them first by queuing
1509 them at the head of the list */
1510 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1512 KeyBasicInformation
,
1517 if (NT_SUCCESS(Status2
))
1519 OBJECT_ATTRIBUTES ObjectAttributes
;
1520 UNICODE_STRING SubKeyName
;
1522 ASSERT(newDelKeys
!= NULL
);
1523 ASSERT(BasicInfo
!= NULL
);
1525 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1526 SubKeyName
.Length
= BasicInfo
->NameLength
;
1527 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1528 SubKeyName
.Buffer
= BasicInfo
->Name
;
1530 InitializeObjectAttributes(&ObjectAttributes
,
1532 OBJ_CASE_INSENSITIVE
,
1536 /* open the subkey */
1537 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1538 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1540 if (!NT_SUCCESS(Status2
))
1545 /* enqueue this key to the head of the deletion queue */
1546 InsertHeadList(&delQueueHead
,
1547 &newDelKeys
->ListEntry
);
1549 /* try again from the head of the list */
1554 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1556 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1558 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1559 if (newDelKeys
!= NULL
)
1561 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1564 goto ReadFirstSubKey
;
1568 /* don't break, let's try to delete as many keys as possible */
1569 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1570 goto SubKeyFailureNoFree
;
1573 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1575 PREG_DEL_KEYS newDelKeys2
;
1577 ASSERT(newDelKeys
!= NULL
);
1579 /* we need more memory to query the key name */
1580 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1583 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1584 if (newDelKeys2
!= NULL
)
1586 newDelKeys
= newDelKeys2
;
1587 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1590 goto ReadFirstSubKey
;
1594 /* don't break, let's try to delete as many keys as possible */
1595 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1598 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1600 /* in some race conditions where another thread would delete
1601 the same tree at the same time, newDelKeys could actually
1603 if (newDelKeys
!= NULL
)
1605 RtlFreeHeap(ProcessHeap
,
1613 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1614 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1615 if (newDelKeys
!= NULL
)
1617 RtlFreeHeap(ProcessHeap
,
1622 SubKeyFailureNoFree
:
1623 /* don't break, let's try to delete as many keys as possible */
1624 if (NT_SUCCESS(Status
))
1630 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1632 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1634 if (!NT_SUCCESS(Status2
))
1636 /* close the key handle so we don't leak handles for keys we were
1637 unable to delete. But only do this for handles not supplied
1640 if (delKeys
->KeyHandle
!= hKey
)
1642 NtClose(delKeys
->KeyHandle
);
1645 if (NT_SUCCESS(Status
))
1647 /* don't break, let's try to delete as many keys as possible */
1652 /* remove the entry from the list */
1653 RemoveEntryList(&delKeys
->ListEntry
);
1655 RtlFreeHeap(ProcessHeap
,
1658 } while (!IsListEmpty(&delQueueHead
));
1661 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1667 /************************************************************************
1673 RegDeleteTreeW(IN HKEY hKey
,
1674 IN LPCWSTR lpSubKey OPTIONAL
)
1676 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1679 Status
= MapDefaultKey(&KeyHandle
,
1681 if (!NT_SUCCESS(Status
))
1683 return RtlNtStatusToDosError(Status
);
1686 if (lpSubKey
!= NULL
)
1688 OBJECT_ATTRIBUTES ObjectAttributes
;
1689 UNICODE_STRING SubKeyName
;
1691 RtlInitUnicodeString(&SubKeyName
,
1694 InitializeObjectAttributes(&ObjectAttributes
,
1696 OBJ_CASE_INSENSITIVE
,
1700 Status
= NtOpenKey(&SubKeyHandle
,
1701 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1703 if (!NT_SUCCESS(Status
))
1708 CurKey
= SubKeyHandle
;
1713 Status
= RegpDeleteTree(CurKey
);
1715 if (NT_SUCCESS(Status
))
1717 /* make sure we only close hKey (KeyHandle) when the caller specified a
1718 subkey, because the handle would be invalid already! */
1719 if (CurKey
!= KeyHandle
)
1721 ClosePredefKey(KeyHandle
);
1724 return ERROR_SUCCESS
;
1728 /* make sure we close all handles we created! */
1729 if (SubKeyHandle
!= NULL
)
1731 NtClose(SubKeyHandle
);
1735 ClosePredefKey(KeyHandle
);
1737 return RtlNtStatusToDosError(Status
);
1743 /************************************************************************
1750 RegDeleteTreeW(HKEY hKey
,
1754 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1755 DWORD dwMaxLen
, dwSize
;
1759 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1761 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1763 Status
= MapDefaultKey(&KeyHandle
,
1765 if (!NT_SUCCESS(Status
))
1767 return RtlNtStatusToDosError(Status
);
1770 hSubKey
= KeyHandle
;
1774 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1777 ClosePredefKey(KeyHandle
);
1782 /* Get highest length for keys, values */
1783 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1784 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1785 if (ret
) goto cleanup
;
1789 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1790 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1792 /* Name too big: alloc a buffer for it */
1793 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1795 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1801 /* Recursively delete all the subkeys */
1805 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1806 NULL
, NULL
, NULL
)) break;
1808 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1809 if (ret
) goto cleanup
;
1813 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1818 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1819 NULL
, NULL
, NULL
, NULL
)) break;
1821 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1822 if (ret
) goto cleanup
;
1826 /* Free buffer if allocated */
1827 if (lpszName
!= szNameBuf
)
1828 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1830 RegCloseKey(hSubKey
);
1832 ClosePredefKey(KeyHandle
);
1838 /************************************************************************
1844 RegDeleteTreeA(IN HKEY hKey
,
1845 IN LPCSTR lpSubKey OPTIONAL
)
1847 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1850 if (lpSubKey
!= NULL
&&
1851 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1854 return ERROR_NOT_ENOUGH_MEMORY
;
1857 Ret
= RegDeleteTreeW(hKey
,
1860 RtlFreeUnicodeString(&SubKeyName
);
1866 /************************************************************************
1867 * RegDisableReflectionKey
1872 RegDisableReflectionKey(IN HKEY hBase
)
1874 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1875 return ERROR_CALL_NOT_IMPLEMENTED
;
1879 /************************************************************************
1880 * RegEnableReflectionKey
1885 RegEnableReflectionKey(IN HKEY hBase
)
1887 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1888 return ERROR_CALL_NOT_IMPLEMENTED
;
1892 /******************************************************************************
1893 * RegpApplyRestrictions [internal]
1895 * Helper function for RegGetValueA/W.
1898 RegpApplyRestrictions(DWORD dwFlags
,
1903 /* Check if the type is restricted by the passed flags */
1904 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1910 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1911 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1912 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1913 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1914 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1915 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1916 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1919 if (dwFlags
& dwMask
)
1921 /* Type is not restricted, check for size mismatch */
1922 if (dwType
== REG_BINARY
)
1926 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1928 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1931 if (cbExpect
&& cbData
!= cbExpect
)
1932 *ret
= ERROR_DATATYPE_MISMATCH
;
1935 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1940 /******************************************************************************
1941 * RegGetValueW [ADVAPI32.@]
1943 * Retrieves the type and data for a value name associated with a key,
1944 * optionally expanding its content and restricting its type.
1947 * hKey [I] Handle to an open key.
1948 * pszSubKey [I] Name of the subkey of hKey.
1949 * pszValue [I] Name of value under hKey/szSubKey to query.
1950 * dwFlags [I] Flags restricting the value type to retrieve.
1951 * pdwType [O] Destination for the values type, may be NULL.
1952 * pvData [O] Destination for the values content, may be NULL.
1953 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1954 * retrieve the whole content, including the trailing '\0'
1958 * Success: ERROR_SUCCESS
1959 * Failure: nonzero error code from Winerror.h
1962 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1963 * expanded and pdwType is set to REG_SZ instead.
1964 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1965 * without RRF_NOEXPAND is thus not allowed.
1966 * An exception is the case where RRF_RT_ANY is specified, because then
1967 * RRF_NOEXPAND is allowed.
1970 RegGetValueW(HKEY hKey
,
1978 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1982 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1983 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1984 pvData
, pcbData
, cbData
);
1986 if (pvData
&& !pcbData
)
1987 return ERROR_INVALID_PARAMETER
;
1988 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1989 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1990 return ERROR_INVALID_PARAMETER
;
1992 if (pszSubKey
&& pszSubKey
[0])
1994 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1995 if (ret
!= ERROR_SUCCESS
) return ret
;
1998 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2000 /* If we are going to expand we need to read in the whole the value even
2001 * if the passed buffer was too small as the expanded string might be
2002 * smaller than the unexpanded one and could fit into cbData bytes. */
2003 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2004 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2008 HeapFree(GetProcessHeap(), 0, pvBuf
);
2010 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2013 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2017 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2018 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2019 &dwType
, pvBuf
, &cbData
);
2022 /* Even if cbData was large enough we have to copy the
2023 * string since ExpandEnvironmentStrings can't handle
2024 * overlapping buffers. */
2025 CopyMemory(pvBuf
, pvData
, cbData
);
2028 /* Both the type or the value itself could have been modified in
2029 * between so we have to keep retrying until the buffer is large
2030 * enough or we no longer have to expand the value. */
2032 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2034 if (ret
== ERROR_SUCCESS
)
2036 /* Recheck dwType in case it changed since the first call */
2037 if (dwType
== REG_EXPAND_SZ
)
2039 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2040 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2042 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2043 ret
= ERROR_MORE_DATA
;
2046 CopyMemory(pvData
, pvBuf
, *pcbData
);
2049 HeapFree(GetProcessHeap(), 0, pvBuf
);
2052 if (pszSubKey
&& pszSubKey
[0])
2055 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2057 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2058 ZeroMemory(pvData
, *pcbData
);
2070 /******************************************************************************
2071 * RegGetValueA [ADVAPI32.@]
2076 RegGetValueA(HKEY hKey
,
2084 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2088 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2089 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2092 if (pvData
&& !pcbData
)
2093 return ERROR_INVALID_PARAMETER
;
2094 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2095 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2096 return ERROR_INVALID_PARAMETER
;
2098 if (pszSubKey
&& pszSubKey
[0])
2100 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2101 if (ret
!= ERROR_SUCCESS
) return ret
;
2104 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2106 /* If we are going to expand we need to read in the whole the value even
2107 * if the passed buffer was too small as the expanded string might be
2108 * smaller than the unexpanded one and could fit into cbData bytes. */
2109 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2110 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2113 HeapFree(GetProcessHeap(), 0, pvBuf
);
2115 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2118 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2122 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2123 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2124 &dwType
, pvBuf
, &cbData
);
2127 /* Even if cbData was large enough we have to copy the
2128 * string since ExpandEnvironmentStrings can't handle
2129 * overlapping buffers. */
2130 CopyMemory(pvBuf
, pvData
, cbData
);
2133 /* Both the type or the value itself could have been modified in
2134 * between so we have to keep retrying until the buffer is large
2135 * enough or we no longer have to expand the value. */
2136 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2138 if (ret
== ERROR_SUCCESS
)
2140 /* Recheck dwType in case it changed since the first call */
2141 if (dwType
== REG_EXPAND_SZ
)
2143 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2144 pcbData
? *pcbData
: 0);
2146 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2147 ret
= ERROR_MORE_DATA
;
2150 CopyMemory(pvData
, pvBuf
, *pcbData
);
2153 HeapFree(GetProcessHeap(), 0, pvBuf
);
2156 if (pszSubKey
&& pszSubKey
[0])
2159 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2161 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2162 ZeroMemory(pvData
, *pcbData
);
2164 if (pdwType
) *pdwType
= dwType
;
2165 if (pcbData
) *pcbData
= cbData
;
2171 /************************************************************************
2177 RegSetKeyValueW(IN HKEY hKey
,
2178 IN LPCWSTR lpSubKey OPTIONAL
,
2179 IN LPCWSTR lpValueName OPTIONAL
,
2181 IN LPCVOID lpData OPTIONAL
,
2184 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2188 Status
= MapDefaultKey(&KeyHandle
,
2190 if (!NT_SUCCESS(Status
))
2192 return RtlNtStatusToDosError(Status
);
2195 if (lpSubKey
!= NULL
)
2197 OBJECT_ATTRIBUTES ObjectAttributes
;
2198 UNICODE_STRING SubKeyName
;
2200 RtlInitUnicodeString(&SubKeyName
,
2203 InitializeObjectAttributes(&ObjectAttributes
,
2205 OBJ_CASE_INSENSITIVE
,
2209 Status
= NtOpenKey(&SubKeyHandle
,
2212 if (!NT_SUCCESS(Status
))
2214 Ret
= RtlNtStatusToDosError(Status
);
2218 CurKey
= SubKeyHandle
;
2223 Ret
= RegSetValueExW(CurKey
,
2230 if (SubKeyHandle
!= NULL
)
2232 NtClose(SubKeyHandle
);
2236 ClosePredefKey(KeyHandle
);
2242 /************************************************************************
2248 RegSetKeyValueA(IN HKEY hKey
,
2249 IN LPCSTR lpSubKey OPTIONAL
,
2250 IN LPCSTR lpValueName OPTIONAL
,
2252 IN LPCVOID lpData OPTIONAL
,
2255 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2259 Status
= MapDefaultKey(&KeyHandle
,
2261 if (!NT_SUCCESS(Status
))
2263 return RtlNtStatusToDosError(Status
);
2266 if (lpSubKey
!= NULL
)
2268 OBJECT_ATTRIBUTES ObjectAttributes
;
2269 UNICODE_STRING SubKeyName
;
2271 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2274 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2278 InitializeObjectAttributes(&ObjectAttributes
,
2280 OBJ_CASE_INSENSITIVE
,
2284 Status
= NtOpenKey(&SubKeyHandle
,
2288 RtlFreeUnicodeString(&SubKeyName
);
2290 if (!NT_SUCCESS(Status
))
2292 Ret
= RtlNtStatusToDosError(Status
);
2296 CurKey
= SubKeyHandle
;
2301 Ret
= RegSetValueExA(CurKey
,
2308 if (SubKeyHandle
!= NULL
)
2310 NtClose(SubKeyHandle
);
2314 ClosePredefKey(KeyHandle
);
2320 /************************************************************************
2326 RegDeleteValueA(HKEY hKey
,
2329 UNICODE_STRING ValueName
;
2333 Status
= MapDefaultKey(&KeyHandle
,
2335 if (!NT_SUCCESS(Status
))
2337 return RtlNtStatusToDosError(Status
);
2340 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2341 (LPSTR
)lpValueName
);
2342 Status
= NtDeleteValueKey(KeyHandle
,
2344 RtlFreeUnicodeString (&ValueName
);
2346 ClosePredefKey(KeyHandle
);
2348 if (!NT_SUCCESS(Status
))
2350 return RtlNtStatusToDosError(Status
);
2353 return ERROR_SUCCESS
;
2357 /************************************************************************
2363 RegDeleteValueW(HKEY hKey
,
2364 LPCWSTR lpValueName
)
2366 UNICODE_STRING ValueName
;
2370 Status
= MapDefaultKey(&KeyHandle
,
2372 if (!NT_SUCCESS(Status
))
2374 return RtlNtStatusToDosError(Status
);
2377 RtlInitUnicodeString(&ValueName
,
2378 (LPWSTR
)lpValueName
);
2380 Status
= NtDeleteValueKey(KeyHandle
,
2383 ClosePredefKey(KeyHandle
);
2385 if (!NT_SUCCESS(Status
))
2387 return RtlNtStatusToDosError(Status
);
2390 return ERROR_SUCCESS
;
2394 /************************************************************************
2400 RegEnumKeyA(HKEY hKey
,
2408 return RegEnumKeyExA(hKey
,
2419 /************************************************************************
2425 RegEnumKeyW(HKEY hKey
,
2433 return RegEnumKeyExW(hKey
,
2444 /************************************************************************
2455 _Inout_ LPDWORD lpcbName
,
2456 _Reserved_ LPDWORD lpReserved
,
2457 _Out_opt_ LPSTR lpClass
,
2458 _Inout_opt_ LPDWORD lpcbClass
,
2459 _Out_opt_ PFILETIME lpftLastWriteTime
)
2461 WCHAR
* NameBuffer
= NULL
;
2462 WCHAR
* ClassBuffer
= NULL
;
2463 DWORD NameLength
, ClassLength
;
2466 /* Allocate our buffers */
2469 NameLength
= *lpcbName
;
2470 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName
* sizeof(WCHAR
));
2471 if (NameBuffer
== NULL
)
2473 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2482 ClassLength
= *lpcbClass
;
2483 ClassBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass
* sizeof(WCHAR
));
2484 if (ClassBuffer
== NULL
)
2486 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2492 /* Do the actual call */
2493 ErrorCode
= RegEnumKeyExW(
2503 if (ErrorCode
!= ERROR_SUCCESS
)
2506 /* Convert the strings */
2507 RtlUnicodeToMultiByteN(lpName
, *lpcbName
, 0, NameBuffer
, *lpcbName
* sizeof(WCHAR
));
2508 /* NULL terminate if we can */
2509 if (NameLength
> *lpcbName
)
2510 lpName
[*lpcbName
] = '\0';
2514 RtlUnicodeToMultiByteN(lpClass
, *lpcbClass
, 0, NameBuffer
, *lpcbClass
* sizeof(WCHAR
));
2515 if (ClassLength
> *lpcbClass
)
2516 lpClass
[*lpcbClass
] = '\0';
2521 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2523 RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer
);
2529 /************************************************************************
2539 _Out_ LPWSTR lpName
,
2540 _Inout_ LPDWORD lpcbName
,
2541 _Reserved_ LPDWORD lpReserved
,
2542 _Out_opt_ LPWSTR lpClass
,
2543 _Inout_opt_ LPDWORD lpcbClass
,
2544 _Out_opt_ PFILETIME lpftLastWriteTime
)
2548 KEY_NODE_INFORMATION Node
;
2549 KEY_BASIC_INFORMATION Basic
;
2555 ULONG ClassLength
= 0;
2557 LONG ErrorCode
= ERROR_SUCCESS
;
2560 Status
= MapDefaultKey(&KeyHandle
,
2562 if (!NT_SUCCESS(Status
))
2564 return RtlNtStatusToDosError(Status
);
2567 if (IsHKCRKey(KeyHandle
))
2569 ErrorCode
= EnumHKCRKey(
2578 ClosePredefKey(KeyHandle
);
2584 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2595 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2602 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2606 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2609 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2612 if (KeyInfo
== NULL
)
2614 ErrorCode
= ERROR_OUTOFMEMORY
;
2618 Status
= NtEnumerateKey(KeyHandle
,
2620 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2624 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2625 if (!NT_SUCCESS(Status
))
2627 ErrorCode
= RtlNtStatusToDosError (Status
);
2631 if (lpClass
== NULL
)
2633 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2635 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2639 RtlCopyMemory(lpName
,
2640 KeyInfo
->Basic
.Name
,
2641 KeyInfo
->Basic
.NameLength
);
2642 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2643 lpName
[*lpcbName
] = 0;
2648 if (KeyInfo
->Node
.NameLength
> NameLength
||
2649 KeyInfo
->Node
.ClassLength
> ClassLength
)
2651 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2655 RtlCopyMemory(lpName
,
2657 KeyInfo
->Node
.NameLength
);
2658 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2659 lpName
[*lpcbName
] = 0;
2660 RtlCopyMemory(lpClass
,
2661 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2662 KeyInfo
->Node
.ClassLength
);
2663 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2664 lpClass
[*lpcbClass
] = 0;
2668 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2670 if (lpClass
== NULL
)
2672 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2673 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2677 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2678 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2683 RtlFreeHeap(ProcessHeap
,
2688 ClosePredefKey(KeyHandle
);
2694 /************************************************************************
2704 _Inout_ LPDWORD lpcbName
,
2705 _Reserved_ LPDWORD lpdwReserved
,
2706 _Out_opt_ LPDWORD lpdwType
,
2707 _Out_opt_ LPBYTE lpData
,
2708 _Inout_opt_ LPDWORD lpcbData
)
2711 DWORD NameBufferSize
, NameLength
;
2713 DWORD LocalType
= REG_NONE
;
2714 BOOL NameOverflow
= FALSE
;
2716 /* Do parameter checks now, once and for all. */
2717 if (!lpName
|| !lpcbName
)
2718 return ERROR_INVALID_PARAMETER
;
2720 if ((lpData
&& !lpcbData
) || lpdwReserved
)
2721 return ERROR_INVALID_PARAMETER
;
2723 /* Get the size of the buffer we must use for the first call ro RegEnumValueW */
2724 ErrorCode
= RegQueryInfoKeyW(
2725 hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &NameBufferSize
, NULL
, NULL
, NULL
);
2726 if (ErrorCode
!= ERROR_SUCCESS
)
2729 /* Allocate the buffer for the unicode name */
2730 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize
* sizeof(WCHAR
));
2731 if (NameBuffer
== NULL
)
2733 return ERROR_NOT_ENOUGH_MEMORY
;
2737 * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
2738 * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
2739 * is an overflow on the data or on the name during the the second call. So the first time, we make the
2740 * call with the supplied value. This is merdique, but this is how it is.
2742 NameLength
= *lpcbName
;
2743 ErrorCode
= RegEnumValueW(
2752 if (ErrorCode
!= ERROR_SUCCESS
)
2754 if (ErrorCode
== ERROR_MORE_DATA
)
2755 NameOverflow
= TRUE
;
2760 if (is_string(LocalType
) && lpcbData
)
2762 /* We must allocate a buffer to get the unicode data */
2763 DWORD DataBufferSize
= *lpcbData
* sizeof(WCHAR
);
2764 WCHAR
* DataBuffer
= NULL
;
2765 DWORD DataLength
= *lpcbData
;
2766 LPSTR DataStr
= (LPSTR
)lpData
;
2769 DataBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData
* sizeof(WCHAR
));
2771 /* Do the real call */
2772 ErrorCode
= RegEnumValueW(
2782 *lpcbData
= DataBufferSize
/ sizeof(WCHAR
);
2784 if (ErrorCode
!= ERROR_SUCCESS
)
2786 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer
);
2790 /* Copy the data whatever the error code is */
2793 /* Do the data conversion */
2794 RtlUnicodeToMultiByteN(DataStr
, DataLength
, 0, DataBuffer
, DataBufferSize
);
2795 /* NULL-terminate if there is enough room */
2796 if ((DataLength
> *lpcbData
) && (DataStr
[*lpcbData
- 1] != '\0'))
2797 DataStr
[*lpcbData
] = '\0';
2800 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer
);
2804 /* No data conversion needed. Do the call with provided buffers */
2805 ErrorCode
= RegEnumValueW(
2815 if (ErrorCode
!= ERROR_SUCCESS
)
2823 ErrorCode
= ERROR_MORE_DATA
;
2827 /* Convert the name string */
2828 RtlUnicodeToMultiByteN(lpName
, *lpcbName
, lpcbName
, NameBuffer
, NameBufferSize
* sizeof(WCHAR
));
2829 ((PSTR
)lpName
)[*lpcbName
] = '\0';
2833 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2839 /******************************************************************************
2840 * RegEnumValueW [ADVAPI32.@]
2844 * hkey [I] Handle to key to query
2845 * index [I] Index of value to query
2846 * value [O] Value string
2847 * val_count [I/O] Size of value buffer (in wchars)
2848 * reserved [I] Reserved
2849 * type [O] Type code
2850 * data [O] Value data
2851 * count [I/O] Size of data buffer (in bytes)
2854 * Success: ERROR_SUCCESS
2855 * Failure: nonzero error code from Winerror.h
2863 _Inout_ PDWORD val_count
,
2864 _Reserved_ PDWORD reserved
,
2865 _Out_opt_ PDWORD type
,
2866 _Out_opt_ LPBYTE data
,
2867 _Inout_opt_ PDWORD count
)
2872 char buffer
[256], *buf_ptr
= buffer
;
2873 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2874 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2876 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2877 hKey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2879 if (!value
|| !val_count
)
2880 return ERROR_INVALID_PARAMETER
;
2882 if ((data
&& !count
) || reserved
)
2883 return ERROR_INVALID_PARAMETER
;
2885 status
= MapDefaultKey(&KeyHandle
, hKey
);
2886 if (!NT_SUCCESS(status
))
2888 return RtlNtStatusToDosError(status
);
2891 if (IsHKCRKey(KeyHandle
))
2893 LONG ErrorCode
= EnumHKCRValue(
2902 ClosePredefKey(KeyHandle
);
2906 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2907 if (data
) total_size
+= *count
;
2908 total_size
= min( sizeof(buffer
), total_size
);
2910 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2911 buffer
, total_size
, &total_size
);
2912 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2916 /* retry with a dynamically allocated buffer */
2917 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2919 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2920 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2922 status
= ERROR_NOT_ENOUGH_MEMORY
;
2925 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2926 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2927 buf_ptr
, total_size
, &total_size
);
2930 if (status
) goto done
;
2934 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2936 status
= STATUS_BUFFER_OVERFLOW
;
2939 memcpy( value
, info
->Name
, info
->NameLength
);
2940 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2941 value
[*val_count
] = 0;
2946 if (info
->DataLength
> *count
)
2948 status
= STATUS_BUFFER_OVERFLOW
;
2951 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2952 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
2954 /* if the type is REG_SZ and data is not 0-terminated
2955 * and there is enough space in the buffer NT appends a \0 */
2956 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
2957 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2961 else status
= STATUS_SUCCESS
;
2964 if (type
) *type
= info
->Type
;
2965 if (count
) *count
= info
->DataLength
;
2968 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2969 ClosePredefKey(KeyHandle
);
2970 return RtlNtStatusToDosError(status
);
2974 /************************************************************************
2980 RegFlushKey(HKEY hKey
)
2985 if (hKey
== HKEY_PERFORMANCE_DATA
)
2987 return ERROR_SUCCESS
;
2990 Status
= MapDefaultKey(&KeyHandle
,
2992 if (!NT_SUCCESS(Status
))
2994 return RtlNtStatusToDosError(Status
);
2997 Status
= NtFlushKey(KeyHandle
);
2999 ClosePredefKey(KeyHandle
);
3001 if (!NT_SUCCESS(Status
))
3003 return RtlNtStatusToDosError(Status
);
3006 return ERROR_SUCCESS
;
3010 /************************************************************************
3016 RegGetKeySecurity(HKEY hKey
,
3017 SECURITY_INFORMATION SecurityInformation
,
3018 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3019 LPDWORD lpcbSecurityDescriptor
)
3024 if (hKey
== HKEY_PERFORMANCE_DATA
)
3026 return ERROR_INVALID_HANDLE
;
3029 Status
= MapDefaultKey(&KeyHandle
,
3031 if (!NT_SUCCESS(Status
))
3033 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3034 return RtlNtStatusToDosError(Status
);
3037 Status
= NtQuerySecurityObject(KeyHandle
,
3038 SecurityInformation
,
3039 pSecurityDescriptor
,
3040 *lpcbSecurityDescriptor
,
3041 lpcbSecurityDescriptor
);
3043 ClosePredefKey(KeyHandle
);
3045 if (!NT_SUCCESS(Status
))
3047 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3048 return RtlNtStatusToDosError(Status
);
3051 return ERROR_SUCCESS
;
3055 /************************************************************************
3061 RegLoadKeyA(HKEY hKey
,
3065 UNICODE_STRING FileName
;
3066 UNICODE_STRING KeyName
;
3069 RtlInitEmptyUnicodeString(&KeyName
, NULL
, 0);
3070 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
3074 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName
, lpSubKey
))
3076 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3083 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
3085 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3090 ErrorCode
= RegLoadKeyW(hKey
,
3095 RtlFreeUnicodeString(&FileName
);
3096 RtlFreeUnicodeString(&KeyName
);
3102 /************************************************************************
3108 RegLoadKeyW(HKEY hKey
,
3112 OBJECT_ATTRIBUTES FileObjectAttributes
;
3113 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3114 UNICODE_STRING FileName
;
3115 UNICODE_STRING KeyName
;
3118 LONG ErrorCode
= ERROR_SUCCESS
;
3120 if (hKey
== HKEY_PERFORMANCE_DATA
)
3122 return ERROR_INVALID_HANDLE
;
3125 Status
= MapDefaultKey(&KeyHandle
,
3127 if (!NT_SUCCESS(Status
))
3129 return RtlNtStatusToDosError(Status
);
3132 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3137 ErrorCode
= ERROR_BAD_PATHNAME
;
3141 InitializeObjectAttributes(&FileObjectAttributes
,
3143 OBJ_CASE_INSENSITIVE
,
3147 RtlInitUnicodeString(&KeyName
,
3150 InitializeObjectAttributes(&KeyObjectAttributes
,
3152 OBJ_CASE_INSENSITIVE
,
3156 Status
= NtLoadKey(&KeyObjectAttributes
,
3157 &FileObjectAttributes
);
3159 RtlFreeHeap(RtlGetProcessHeap(),
3163 if (!NT_SUCCESS(Status
))
3165 ErrorCode
= RtlNtStatusToDosError(Status
);
3170 ClosePredefKey(KeyHandle
);
3176 /************************************************************************
3177 * RegNotifyChangeKeyValue
3182 RegNotifyChangeKeyValue(HKEY hKey
,
3184 DWORD dwNotifyFilter
,
3188 IO_STATUS_BLOCK IoStatusBlock
;
3191 LONG ErrorCode
= ERROR_SUCCESS
;
3193 if (hKey
== HKEY_PERFORMANCE_DATA
)
3195 return ERROR_INVALID_HANDLE
;
3198 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3200 return ERROR_INVALID_PARAMETER
;
3203 Status
= MapDefaultKey(&KeyHandle
,
3205 if (!NT_SUCCESS(Status
))
3207 return RtlNtStatusToDosError(Status
);
3210 /* FIXME: Remote key handles must fail */
3212 Status
= NtNotifyChangeKey(KeyHandle
,
3222 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3224 ErrorCode
= RtlNtStatusToDosError(Status
);
3227 ClosePredefKey(KeyHandle
);
3233 /************************************************************************
3234 * RegOpenCurrentUser
3239 RegOpenCurrentUser(IN REGSAM samDesired
,
3240 OUT PHKEY phkResult
)
3244 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3245 (PHANDLE
)phkResult
);
3246 if (!NT_SUCCESS(Status
))
3248 /* NOTE - don't set the last error code! just return the error! */
3249 return RtlNtStatusToDosError(Status
);
3252 return ERROR_SUCCESS
;
3256 /************************************************************************
3259 * 20050503 Fireball - imported from WINE
3264 RegOpenKeyA(HKEY hKey
,
3268 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3269 hKey
, lpSubKey
, phkResult
);
3272 return ERROR_INVALID_PARAMETER
;
3274 if (!hKey
&& lpSubKey
&& phkResult
)
3276 return ERROR_INVALID_HANDLE
;
3279 if (!lpSubKey
|| !*lpSubKey
)
3282 return ERROR_SUCCESS
;
3285 return RegOpenKeyExA(hKey
,
3293 /************************************************************************
3298 * 20050503 Fireball - imported from WINE
3303 RegOpenKeyW(HKEY hKey
,
3307 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3308 hKey
, lpSubKey
, phkResult
);
3311 return ERROR_INVALID_PARAMETER
;
3313 if (!hKey
&& lpSubKey
&& phkResult
)
3315 return ERROR_INVALID_HANDLE
;
3318 if (!lpSubKey
|| !*lpSubKey
)
3321 return ERROR_SUCCESS
;
3324 return RegOpenKeyExW(hKey
,
3332 /************************************************************************
3340 _In_ LPCSTR lpSubKey
,
3341 _In_ DWORD ulOptions
,
3342 _In_ REGSAM samDesired
,
3343 _Out_ PHKEY phkResult
)
3345 UNICODE_STRING SubKeyString
;
3348 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3349 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3353 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, lpSubKey
))
3354 return ERROR_NOT_ENOUGH_MEMORY
;
3357 RtlInitEmptyUnicodeString(&SubKeyString
, NULL
, 0);
3359 ErrorCode
= RegOpenKeyExW(hKey
, SubKeyString
.Buffer
, ulOptions
, samDesired
, phkResult
);
3361 RtlFreeUnicodeString(&SubKeyString
);
3367 /************************************************************************
3373 RegOpenKeyExW(HKEY hKey
,
3379 OBJECT_ATTRIBUTES ObjectAttributes
;
3380 UNICODE_STRING SubKeyString
;
3383 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3384 LONG ErrorCode
= ERROR_SUCCESS
;
3386 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3387 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3390 return ERROR_INVALID_PARAMETER
;
3393 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3394 if (!NT_SUCCESS(Status
))
3396 return RtlNtStatusToDosError(Status
);
3399 if (IsHKCRKey(KeyHandle
))
3401 ErrorCode
= OpenHKCRKey(KeyHandle
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3402 ClosePredefKey(KeyHandle
);
3406 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3407 Attributes
|= OBJ_OPENLINK
;
3409 if (lpSubKey
!= NULL
)
3410 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3412 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3414 InitializeObjectAttributes(&ObjectAttributes
,
3420 Status
= NtOpenKey((PHANDLE
)phkResult
,
3424 if (!NT_SUCCESS(Status
))
3426 ErrorCode
= RtlNtStatusToDosError(Status
);
3430 ClosePredefKey(KeyHandle
);
3436 /************************************************************************
3437 * RegOpenUserClassesRoot
3442 RegOpenUserClassesRoot(IN HANDLE hToken
,
3444 IN REGSAM samDesired
,
3445 OUT PHKEY phkResult
)
3447 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3448 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3449 PTOKEN_USER TokenUserData
;
3450 ULONG RequiredLength
;
3451 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3452 OBJECT_ATTRIBUTES ObjectAttributes
;
3455 /* check parameters */
3456 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3458 return ERROR_INVALID_PARAMETER
;
3462 * Get the user sid from the token
3466 /* determine how much memory we need */
3467 Status
= NtQueryInformationToken(hToken
,
3472 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3474 /* NOTE - as opposed to all other registry functions windows does indeed
3475 change the last error code in case the caller supplied a invalid
3476 handle for example! */
3477 return RtlNtStatusToDosError(Status
);
3479 RegInitialize(); /* HACK until delay-loading is implemented */
3480 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3483 if (TokenUserData
== NULL
)
3485 return ERROR_NOT_ENOUGH_MEMORY
;
3488 /* attempt to read the information */
3489 Status
= NtQueryInformationToken(hToken
,
3494 if (!NT_SUCCESS(Status
))
3496 RtlFreeHeap(ProcessHeap
,
3499 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3501 /* the information appears to have changed?! try again */
3505 /* NOTE - as opposed to all other registry functions windows does indeed
3506 change the last error code in case the caller supplied a invalid
3507 handle for example! */
3508 return RtlNtStatusToDosError(Status
);
3512 * Build the absolute path for the user's registry in the form
3513 * "\Registry\User\<SID>_Classes"
3515 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3516 TokenUserData
->User
.Sid
,
3519 /* we don't need the user data anymore, free it */
3520 RtlFreeHeap(ProcessHeap
,
3524 if (!NT_SUCCESS(Status
))
3526 return RtlNtStatusToDosError(Status
);
3529 /* allocate enough memory for the entire key string */
3530 UserClassesKeyRoot
.Length
= 0;
3531 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3532 sizeof(UserClassesKeyPrefix
) +
3533 sizeof(UserClassesKeySuffix
);
3534 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3536 UserClassesKeyRoot
.MaximumLength
);
3537 if (UserClassesKeyRoot
.Buffer
== NULL
)
3539 RtlFreeUnicodeString(&UserSidString
);
3540 return RtlNtStatusToDosError(Status
);
3543 /* build the string */
3544 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3545 UserClassesKeyPrefix
);
3546 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3548 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3549 UserClassesKeySuffix
);
3551 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3556 InitializeObjectAttributes(&ObjectAttributes
,
3557 &UserClassesKeyRoot
,
3558 OBJ_CASE_INSENSITIVE
,
3562 Status
= NtOpenKey((PHANDLE
)phkResult
,
3566 RtlFreeUnicodeString(&UserSidString
);
3567 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3569 if (!NT_SUCCESS(Status
))
3571 return RtlNtStatusToDosError(Status
);
3574 return ERROR_SUCCESS
;
3578 /************************************************************************
3584 RegQueryInfoKeyA(HKEY hKey
,
3589 LPDWORD lpcbMaxSubKeyLen
,
3590 LPDWORD lpcbMaxClassLen
,
3592 LPDWORD lpcbMaxValueNameLen
,
3593 LPDWORD lpcbMaxValueLen
,
3594 LPDWORD lpcbSecurityDescriptor
,
3595 PFILETIME lpftLastWriteTime
)
3597 WCHAR ClassName
[MAX_PATH
];
3598 UNICODE_STRING UnicodeString
;
3599 ANSI_STRING AnsiString
;
3602 RtlInitUnicodeString(&UnicodeString
,
3604 if (lpClass
!= NULL
)
3606 UnicodeString
.Buffer
= &ClassName
[0];
3607 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3608 AnsiString
.MaximumLength
= *lpcbClass
;
3611 ErrorCode
= RegQueryInfoKeyW(hKey
,
3612 UnicodeString
.Buffer
,
3619 lpcbMaxValueNameLen
,
3621 lpcbSecurityDescriptor
,
3623 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3625 AnsiString
.Buffer
= lpClass
;
3626 AnsiString
.Length
= 0;
3627 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3628 RtlUnicodeStringToAnsiString(&AnsiString
,
3631 *lpcbClass
= AnsiString
.Length
;
3632 lpClass
[AnsiString
.Length
] = 0;
3639 /************************************************************************
3645 RegQueryInfoKeyW(HKEY hKey
,
3650 LPDWORD lpcbMaxSubKeyLen
,
3651 LPDWORD lpcbMaxClassLen
,
3653 LPDWORD lpcbMaxValueNameLen
,
3654 LPDWORD lpcbMaxValueLen
,
3655 LPDWORD lpcbSecurityDescriptor
,
3656 PFILETIME lpftLastWriteTime
)
3658 KEY_FULL_INFORMATION FullInfoBuffer
;
3659 PKEY_FULL_INFORMATION FullInfo
;
3661 ULONG ClassLength
= 0;
3665 LONG ErrorCode
= ERROR_SUCCESS
;
3667 if ((lpClass
) && (!lpcbClass
))
3669 return ERROR_INVALID_PARAMETER
;
3672 Status
= MapDefaultKey(&KeyHandle
,
3674 if (!NT_SUCCESS(Status
))
3676 return RtlNtStatusToDosError(Status
);
3679 if (lpClass
!= NULL
)
3683 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3690 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3691 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3694 if (FullInfo
== NULL
)
3696 ErrorCode
= ERROR_OUTOFMEMORY
;
3700 FullInfo
->ClassLength
= ClassLength
;
3704 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3705 FullInfo
= &FullInfoBuffer
;
3706 FullInfo
->ClassLength
= 0;
3708 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3710 Status
= NtQueryKey(KeyHandle
,
3715 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3716 if (!NT_SUCCESS(Status
))
3718 if (lpClass
!= NULL
)
3720 RtlFreeHeap(ProcessHeap
,
3725 ErrorCode
= RtlNtStatusToDosError(Status
);
3729 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3730 if (lpcSubKeys
!= NULL
)
3732 *lpcSubKeys
= FullInfo
->SubKeys
;
3735 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3736 if (lpcbMaxSubKeyLen
!= NULL
)
3738 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3741 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3742 if (lpcbMaxClassLen
!= NULL
)
3744 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3747 TRACE("Values %lu\n", FullInfo
->Values
);
3748 if (lpcValues
!= NULL
)
3750 *lpcValues
= FullInfo
->Values
;
3753 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3754 if (lpcbMaxValueNameLen
!= NULL
)
3756 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3759 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3760 if (lpcbMaxValueLen
!= NULL
)
3762 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3765 if (lpcbSecurityDescriptor
!= NULL
)
3767 Status
= NtQuerySecurityObject(KeyHandle
,
3768 OWNER_SECURITY_INFORMATION
|
3769 GROUP_SECURITY_INFORMATION
|
3770 DACL_SECURITY_INFORMATION
,
3773 lpcbSecurityDescriptor
);
3774 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
3776 if (lpClass
!= NULL
)
3778 RtlFreeHeap(ProcessHeap
,
3783 ErrorCode
= RtlNtStatusToDosError(Status
);
3788 if (lpftLastWriteTime
!= NULL
)
3790 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3791 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3794 if (lpClass
!= NULL
)
3796 if (FullInfo
->ClassLength
> ClassLength
)
3798 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3802 RtlCopyMemory(lpClass
,
3804 FullInfo
->ClassLength
);
3805 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3806 lpClass
[*lpcbClass
] = 0;
3809 RtlFreeHeap(ProcessHeap
,
3815 ClosePredefKey(KeyHandle
);
3821 /************************************************************************
3822 * RegQueryMultipleValuesA
3827 RegQueryMultipleValuesA(HKEY hKey
,
3834 DWORD maxBytes
= *ldwTotsize
;
3835 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3838 if (maxBytes
>= (1024*1024))
3839 return ERROR_TRANSFER_TOO_LONG
;
3843 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3844 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3846 for (i
= 0; i
< num_vals
; i
++)
3848 val_list
[i
].ve_valuelen
= 0;
3849 ErrorCode
= RegQueryValueExA(hKey
,
3850 val_list
[i
].ve_valuename
,
3854 &val_list
[i
].ve_valuelen
);
3855 if (ErrorCode
!= ERROR_SUCCESS
)
3860 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3862 ErrorCode
= RegQueryValueExA(hKey
,
3863 val_list
[i
].ve_valuename
,
3865 &val_list
[i
].ve_type
,
3867 &val_list
[i
].ve_valuelen
);
3868 if (ErrorCode
!= ERROR_SUCCESS
)
3873 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3875 bufptr
+= val_list
[i
].ve_valuelen
;
3878 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3881 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3885 /************************************************************************
3886 * RegQueryMultipleValuesW
3891 RegQueryMultipleValuesW(HKEY hKey
,
3898 DWORD maxBytes
= *ldwTotsize
;
3899 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3902 if (maxBytes
>= (1024*1024))
3903 return ERROR_TRANSFER_TOO_LONG
;
3907 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3908 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3910 for (i
= 0; i
< num_vals
; i
++)
3912 val_list
[i
].ve_valuelen
= 0;
3913 ErrorCode
= RegQueryValueExW(hKey
,
3914 val_list
[i
].ve_valuename
,
3918 &val_list
[i
].ve_valuelen
);
3919 if (ErrorCode
!= ERROR_SUCCESS
)
3924 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3926 ErrorCode
= RegQueryValueExW(hKey
,
3927 val_list
[i
].ve_valuename
,
3929 &val_list
[i
].ve_type
,
3931 &val_list
[i
].ve_valuelen
);
3932 if (ErrorCode
!= ERROR_SUCCESS
)
3937 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3939 bufptr
+= val_list
[i
].ve_valuelen
;
3942 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3945 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3949 /************************************************************************
3950 * RegQueryReflectionKey
3955 RegQueryReflectionKey(IN HKEY hBase
,
3956 OUT BOOL
* bIsReflectionDisabled
)
3958 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3959 hBase
, bIsReflectionDisabled
);
3960 return ERROR_CALL_NOT_IMPLEMENTED
;
3964 /******************************************************************************
3965 * RegQueryValueExA [ADVAPI32.@]
3967 * Get the type and contents of a specified value under with a key.
3970 * hkey [I] Handle of the key to query
3971 * name [I] Name of value under hkey to query
3972 * reserved [I] Reserved - must be NULL
3973 * type [O] Destination for the value type, or NULL if not required
3974 * data [O] Destination for the values contents, or NULL if not required
3975 * count [I/O] Size of data, updated with the number of bytes returned
3978 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
3979 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
3980 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
3981 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
3984 * MSDN states that if data is too small it is partially filled. In reality
3985 * it remains untouched.
3992 _In_ LPDWORD reserved
,
3993 _Out_opt_ LPDWORD type
,
3994 _Out_opt_ LPBYTE data
,
3995 _Inout_opt_ LPDWORD count
)
3997 UNICODE_STRING nameW
;
4000 DWORD BufferSize
= 0;
4002 CHAR
* DataStr
= (CHAR
*)data
;
4005 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4006 if ((data
&& !count
) || reserved
)
4007 return ERROR_INVALID_PARAMETER
;
4011 if (!RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
4012 return ERROR_NOT_ENOUGH_MEMORY
;
4015 RtlInitEmptyUnicodeString(&nameW
, NULL
, 0);
4017 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, NULL
, &LocalType
, NULL
, &BufferSize
);
4018 if (ErrorCode
!= ERROR_SUCCESS
)
4020 if ((!data
) && count
)
4022 RtlFreeUnicodeString(&nameW
);
4026 /* See if we can directly handle the call without caring for conversion */
4027 if (!is_string(LocalType
) || !count
)
4029 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, reserved
, type
, data
, count
);
4030 RtlFreeUnicodeString(&nameW
);
4034 /* Allocate a unicode string to get the data */
4035 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
4038 RtlFreeUnicodeString(&nameW
);
4039 return ERROR_NOT_ENOUGH_MEMORY
;
4042 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, reserved
, type
, (LPBYTE
)Buffer
, &BufferSize
);
4043 if (ErrorCode
!= ERROR_SUCCESS
)
4045 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4046 RtlFreeUnicodeString(&nameW
);
4050 /* We don't need this anymore */
4051 RtlFreeUnicodeString(&nameW
);
4053 DataLength
= *count
;
4054 RtlUnicodeToMultiByteSize(count
, Buffer
, BufferSize
);
4056 if ((!data
) || (DataLength
< *count
))
4058 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4059 return data
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
4062 /* We can finally do the conversion */
4063 RtlUnicodeToMultiByteN(DataStr
, DataLength
, NULL
, Buffer
, BufferSize
);
4065 /* NULL-terminate if there is enough room */
4066 if ((DataLength
> *count
) && (DataStr
[*count
- 1] != '\0'))
4067 DataStr
[*count
] = '\0';
4069 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4071 return ERROR_SUCCESS
;
4075 /************************************************************************
4085 _In_ LPDWORD reserved
,
4092 UNICODE_STRING name_str
;
4094 char buffer
[256], *buf_ptr
= buffer
;
4095 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4096 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4098 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4099 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4100 (count
&& data
) ? *count
: 0 );
4102 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4104 status
= MapDefaultKey(&hkey
, hkeyorg
);
4105 if (!NT_SUCCESS(status
))
4107 return RtlNtStatusToDosError(status
);
4110 if (IsHKCRKey(hkey
))
4112 LONG ErrorCode
= QueryHKCRValue(hkey
, name
, reserved
, type
, data
, count
);
4113 ClosePredefKey(hkey
);
4117 RtlInitUnicodeString( &name_str
, name
);
4119 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4122 total_size
= info_size
;
4123 if (count
) *count
= 0;
4126 /* this matches Win9x behaviour - NT sets *type to a random value */
4127 if (type
) *type
= REG_NONE
;
4129 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4130 buffer
, total_size
, &total_size
);
4131 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4135 /* retry with a dynamically allocated buffer */
4136 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4138 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4139 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4141 ClosePredefKey(hkey
);
4142 return ERROR_NOT_ENOUGH_MEMORY
;
4144 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4145 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4146 buf_ptr
, total_size
, &total_size
);
4149 if (NT_SUCCESS(status
))
4151 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4152 /* if the type is REG_SZ and data is not 0-terminated
4153 * and there is enough space in the buffer NT appends a \0 */
4154 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4156 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4157 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4160 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4162 else status
= STATUS_SUCCESS
;
4164 if (type
) *type
= info
->Type
;
4165 if (count
) *count
= total_size
- info_size
;
4168 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4169 ClosePredefKey(hkey
);
4170 return RtlNtStatusToDosError(status
);
4174 /************************************************************************
4179 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4184 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4186 if (name
&& name
[0])
4188 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4190 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4191 if (subkey
!= hkey
) RegCloseKey( subkey
);
4192 if (ret
== ERROR_FILE_NOT_FOUND
)
4194 /* return empty string if default value not found */
4195 if (data
) *data
= 0;
4196 if (count
) *count
= 1;
4197 ret
= ERROR_SUCCESS
;
4203 /************************************************************************
4208 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4213 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4216 return ERROR_INVALID_HANDLE
;
4218 if (name
&& name
[0])
4220 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4221 if (ret
!= ERROR_SUCCESS
)
4227 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4231 RegCloseKey( subkey
);
4234 if (ret
== ERROR_FILE_NOT_FOUND
)
4236 /* return empty string if default value not found */
4240 *count
= sizeof(WCHAR
);
4241 ret
= ERROR_SUCCESS
;
4247 /************************************************************************
4253 RegReplaceKeyA(HKEY hKey
,
4258 UNICODE_STRING SubKey
;
4259 UNICODE_STRING NewFile
;
4260 UNICODE_STRING OldFile
;
4263 RtlInitEmptyUnicodeString(&SubKey
, NULL
, 0);
4264 RtlInitEmptyUnicodeString(&OldFile
, NULL
, 0);
4265 RtlInitEmptyUnicodeString(&NewFile
, NULL
, 0);
4269 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey
, lpSubKey
))
4271 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4278 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile
, lpOldFile
))
4280 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4287 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile
, lpNewFile
))
4289 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4294 ErrorCode
= RegReplaceKeyW(hKey
,
4300 RtlFreeUnicodeString(&OldFile
);
4301 RtlFreeUnicodeString(&NewFile
);
4302 RtlFreeUnicodeString(&SubKey
);
4308 /************************************************************************
4314 RegReplaceKeyW(HKEY hKey
,
4319 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4320 OBJECT_ATTRIBUTES NewObjectAttributes
;
4321 OBJECT_ATTRIBUTES OldObjectAttributes
;
4322 UNICODE_STRING SubKeyName
;
4323 UNICODE_STRING NewFileName
;
4324 UNICODE_STRING OldFileName
;
4325 BOOLEAN CloseRealKey
;
4326 HANDLE RealKeyHandle
;
4329 LONG ErrorCode
= ERROR_SUCCESS
;
4331 if (hKey
== HKEY_PERFORMANCE_DATA
)
4333 return ERROR_INVALID_HANDLE
;
4336 Status
= MapDefaultKey(&KeyHandle
,
4338 if (!NT_SUCCESS(Status
))
4340 return RtlNtStatusToDosError(Status
);
4343 /* Open the real key */
4344 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4346 RtlInitUnicodeString(&SubKeyName
,
4348 InitializeObjectAttributes(&KeyObjectAttributes
,
4350 OBJ_CASE_INSENSITIVE
,
4353 Status
= NtOpenKey(&RealKeyHandle
,
4355 &KeyObjectAttributes
);
4356 if (!NT_SUCCESS(Status
))
4358 ErrorCode
= RtlNtStatusToDosError(Status
);
4362 CloseRealKey
= TRUE
;
4366 RealKeyHandle
= KeyHandle
;
4367 CloseRealKey
= FALSE
;
4370 /* Convert new file name */
4371 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4378 NtClose(RealKeyHandle
);
4381 ErrorCode
= ERROR_INVALID_PARAMETER
;
4385 InitializeObjectAttributes(&NewObjectAttributes
,
4387 OBJ_CASE_INSENSITIVE
,
4391 /* Convert old file name */
4392 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4397 RtlFreeHeap(RtlGetProcessHeap (),
4399 NewFileName
.Buffer
);
4402 NtClose(RealKeyHandle
);
4405 ErrorCode
= ERROR_INVALID_PARAMETER
;
4409 InitializeObjectAttributes(&OldObjectAttributes
,
4411 OBJ_CASE_INSENSITIVE
,
4415 Status
= NtReplaceKey(&NewObjectAttributes
,
4417 &OldObjectAttributes
);
4419 RtlFreeHeap(RtlGetProcessHeap(),
4421 OldFileName
.Buffer
);
4422 RtlFreeHeap(RtlGetProcessHeap(),
4424 NewFileName
.Buffer
);
4428 NtClose(RealKeyHandle
);
4431 if (!NT_SUCCESS(Status
))
4433 return RtlNtStatusToDosError(Status
);
4437 ClosePredefKey(KeyHandle
);
4443 /************************************************************************
4449 RegRestoreKeyA(HKEY hKey
,
4453 UNICODE_STRING FileName
;
4458 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4459 return ERROR_NOT_ENOUGH_MEMORY
;
4462 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4464 ErrorCode
= RegRestoreKeyW(hKey
,
4468 RtlFreeUnicodeString(&FileName
);
4474 /************************************************************************
4480 RegRestoreKeyW(HKEY hKey
,
4484 OBJECT_ATTRIBUTES ObjectAttributes
;
4485 IO_STATUS_BLOCK IoStatusBlock
;
4486 UNICODE_STRING FileName
;
4491 if (hKey
== HKEY_PERFORMANCE_DATA
)
4493 return ERROR_INVALID_HANDLE
;
4496 Status
= MapDefaultKey(&KeyHandle
,
4498 if (!NT_SUCCESS(Status
))
4500 return RtlNtStatusToDosError(Status
);
4503 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4508 Status
= STATUS_INVALID_PARAMETER
;
4512 InitializeObjectAttributes(&ObjectAttributes
,
4514 OBJ_CASE_INSENSITIVE
,
4518 Status
= NtOpenFile(&FileHandle
,
4523 FILE_SYNCHRONOUS_IO_NONALERT
);
4524 RtlFreeHeap(RtlGetProcessHeap(),
4527 if (!NT_SUCCESS(Status
))
4532 Status
= NtRestoreKey(KeyHandle
,
4535 NtClose (FileHandle
);
4538 ClosePredefKey(KeyHandle
);
4540 if (!NT_SUCCESS(Status
))
4542 return RtlNtStatusToDosError(Status
);
4545 return ERROR_SUCCESS
;
4549 /************************************************************************
4555 RegSaveKeyA(HKEY hKey
,
4557 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4559 UNICODE_STRING FileName
;
4564 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4565 return ERROR_NOT_ENOUGH_MEMORY
;
4568 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4570 ErrorCode
= RegSaveKeyW(hKey
,
4572 lpSecurityAttributes
);
4573 RtlFreeUnicodeString(&FileName
);
4579 /************************************************************************
4585 RegSaveKeyW(HKEY hKey
,
4587 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4589 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4590 OBJECT_ATTRIBUTES ObjectAttributes
;
4591 UNICODE_STRING FileName
;
4592 IO_STATUS_BLOCK IoStatusBlock
;
4597 Status
= MapDefaultKey(&KeyHandle
,
4599 if (!NT_SUCCESS(Status
))
4601 return RtlNtStatusToDosError(Status
);
4604 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4609 Status
= STATUS_INVALID_PARAMETER
;
4613 if (lpSecurityAttributes
!= NULL
)
4615 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4618 InitializeObjectAttributes(&ObjectAttributes
,
4620 OBJ_CASE_INSENSITIVE
,
4622 SecurityDescriptor
);
4623 Status
= NtCreateFile(&FileHandle
,
4624 GENERIC_WRITE
| SYNCHRONIZE
,
4628 FILE_ATTRIBUTE_NORMAL
,
4631 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4634 RtlFreeHeap(RtlGetProcessHeap(),
4637 if (!NT_SUCCESS(Status
))
4642 Status
= NtSaveKey(KeyHandle
,
4644 NtClose (FileHandle
);
4647 ClosePredefKey(KeyHandle
);
4649 if (!NT_SUCCESS(Status
))
4651 return RtlNtStatusToDosError(Status
);
4654 return ERROR_SUCCESS
;
4658 /************************************************************************
4665 RegSaveKeyExA(HKEY hKey
,
4667 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4670 UNICODE_STRING FileName
;
4675 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4676 return ERROR_NOT_ENOUGH_MEMORY
;
4679 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4681 ErrorCode
= RegSaveKeyExW(hKey
,
4683 lpSecurityAttributes
,
4685 RtlFreeUnicodeString(&FileName
);
4691 /************************************************************************
4698 RegSaveKeyExW(HKEY hKey
,
4700 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4705 case REG_STANDARD_FORMAT
:
4706 case REG_LATEST_FORMAT
:
4707 case REG_NO_COMPRESSION
:
4710 return ERROR_INVALID_PARAMETER
;
4713 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4715 return RegSaveKeyW(hKey
,
4717 lpSecurityAttributes
);
4721 /************************************************************************
4727 RegSetKeySecurity(HKEY hKey
,
4728 SECURITY_INFORMATION SecurityInformation
,
4729 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4734 if (hKey
== HKEY_PERFORMANCE_DATA
)
4736 return ERROR_INVALID_HANDLE
;
4739 Status
= MapDefaultKey(&KeyHandle
,
4741 if (!NT_SUCCESS(Status
))
4743 return RtlNtStatusToDosError(Status
);
4746 Status
= NtSetSecurityObject(KeyHandle
,
4747 SecurityInformation
,
4748 pSecurityDescriptor
);
4750 ClosePredefKey(KeyHandle
);
4752 if (!NT_SUCCESS(Status
))
4754 return RtlNtStatusToDosError(Status
);
4757 return ERROR_SUCCESS
;
4761 /************************************************************************
4767 RegSetValueExA(HKEY hKey
,
4774 UNICODE_STRING ValueName
;
4776 ANSI_STRING AnsiString
;
4777 UNICODE_STRING Data
;
4783 /* Convert SubKey name to Unicode */
4784 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4787 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4790 return ERROR_NOT_ENOUGH_MEMORY
;
4794 ValueName
.Buffer
= NULL
;
4797 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4800 if (is_string(dwType
) && (cbData
!= 0))
4802 /* Convert ANSI string Data to Unicode */
4803 /* If last character NOT zero then increment length */
4804 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4805 AnsiString
.Buffer
= (PSTR
)lpData
;
4806 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4807 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4808 Status
= RtlAnsiStringToUnicodeString(&Data
,
4812 if (!NT_SUCCESS(Status
))
4814 if (pValueName
!= NULL
)
4815 RtlFreeUnicodeString(&ValueName
);
4817 return RtlNtStatusToDosError(Status
);
4819 pData
= (LPBYTE
)Data
.Buffer
;
4820 DataSize
= cbData
* sizeof(WCHAR
);
4825 pData
= (LPBYTE
)lpData
;
4829 ErrorCode
= RegSetValueExW(hKey
,
4836 if (pValueName
!= NULL
)
4837 RtlFreeUnicodeString(&ValueName
);
4839 if (Data
.Buffer
!= NULL
)
4840 RtlFreeUnicodeString(&Data
);
4846 /************************************************************************
4855 _In_ LPCWSTR lpValueName
,
4856 _In_ DWORD Reserved
,
4858 _In_ CONST BYTE
* lpData
,
4861 UNICODE_STRING ValueName
;
4865 Status
= MapDefaultKey(&KeyHandle
,
4867 if (!NT_SUCCESS(Status
))
4869 return RtlNtStatusToDosError(Status
);
4872 if (IsHKCRKey(KeyHandle
))
4874 LONG ErrorCode
= SetHKCRValue(KeyHandle
, lpValueName
, Reserved
, dwType
, lpData
, cbData
);
4875 ClosePredefKey(KeyHandle
);
4879 if (is_string(dwType
) && (cbData
!= 0))
4881 PWSTR pwsData
= (PWSTR
)lpData
;
4885 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4886 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4888 /* Increment length if last character is not zero and next is zero */
4889 cbData
+= sizeof(WCHAR
);
4892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4894 ClosePredefKey(KeyHandle
);
4895 return ERROR_NOACCESS
;
4900 RtlInitUnicodeString(&ValueName
, lpValueName
);
4902 Status
= NtSetValueKey(KeyHandle
,
4909 ClosePredefKey(KeyHandle
);
4911 if (!NT_SUCCESS(Status
))
4913 return RtlNtStatusToDosError(Status
);
4916 return ERROR_SUCCESS
;
4920 /************************************************************************
4926 RegSetValueA(HKEY hKeyOriginal
,
4937 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4939 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4941 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4942 if (!NT_SUCCESS(Status
))
4944 return RtlNtStatusToDosError (Status
);
4948 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4950 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
4951 if (ret
!= ERROR_SUCCESS
)
4955 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4957 RegCloseKey(subkey
);
4960 ClosePredefKey(hKey
);
4966 /************************************************************************
4972 RegSetValueW(HKEY hKeyOriginal
,
4983 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4985 if (dwType
!= REG_SZ
|| !lpData
)
4986 return ERROR_INVALID_PARAMETER
;
4988 Status
= MapDefaultKey(&hKey
,
4990 if (!NT_SUCCESS(Status
))
4992 return RtlNtStatusToDosError(Status
);
4996 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4998 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
4999 if (ret
!= ERROR_SUCCESS
)
5003 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
5004 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
5006 RegCloseKey(subkey
);
5009 ClosePredefKey(hKey
);
5015 /************************************************************************
5021 RegUnLoadKeyA(HKEY hKey
,
5024 UNICODE_STRING KeyName
;
5029 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName
, lpSubKey
))
5030 return ERROR_NOT_ENOUGH_MEMORY
;
5033 RtlInitEmptyUnicodeString(&KeyName
, NULL
, 0);
5035 ErrorCode
= RegUnLoadKeyW(hKey
,
5038 RtlFreeUnicodeString (&KeyName
);
5044 /************************************************************************
5050 RegUnLoadKeyW(HKEY hKey
,
5053 OBJECT_ATTRIBUTES ObjectAttributes
;
5054 UNICODE_STRING KeyName
;
5058 if (hKey
== HKEY_PERFORMANCE_DATA
)
5060 return ERROR_INVALID_HANDLE
;
5063 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5064 if (!NT_SUCCESS(Status
))
5066 return RtlNtStatusToDosError(Status
);
5069 RtlInitUnicodeString(&KeyName
,
5072 InitializeObjectAttributes(&ObjectAttributes
,
5074 OBJ_CASE_INSENSITIVE
,
5078 Status
= NtUnloadKey(&ObjectAttributes
);
5080 ClosePredefKey(KeyHandle
);
5082 if (!NT_SUCCESS(Status
))
5084 return RtlNtStatusToDosError(Status
);
5087 return ERROR_SUCCESS
;
5091 /******************************************************************************
5092 * load_string [Internal]
5094 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5095 * avoid importing user32, which is higher level than advapi32. Helper for
5098 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5105 /* Negative values have to be inverted. */
5106 if (HIWORD(resId
) == 0xffff)
5107 resId
= (UINT
)(-((INT
)resId
));
5109 /* Load the resource into memory and get a pointer to it. */
5110 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5111 if (!hResource
) return 0;
5112 hMemory
= LoadResource(hModule
, hResource
);
5113 if (!hMemory
) return 0;
5114 pString
= LockResource(hMemory
);
5116 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5117 idxString
= resId
& 0xf;
5118 while (idxString
--) pString
+= *pString
+ 1;
5120 /* If no buffer is given, return length of the string. */
5121 if (!pwszBuffer
) return *pString
;
5123 /* Else copy over the string, respecting the buffer size. */
5124 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5127 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5128 pwszBuffer
[cMaxChars
] = L
'\0';
5135 /************************************************************************
5141 RegLoadMUIStringW(IN HKEY hKey
,
5142 IN LPCWSTR pszValue OPTIONAL
,
5143 OUT LPWSTR pszOutBuf
,
5145 OUT LPDWORD pcbData OPTIONAL
,
5147 IN LPCWSTR pszDirectory OPTIONAL
)
5149 DWORD dwValueType
, cbData
;
5150 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5153 /* Parameter sanity checks. */
5154 if (!hKey
|| !pszOutBuf
)
5155 return ERROR_INVALID_PARAMETER
;
5157 if (pszDirectory
&& *pszDirectory
)
5159 FIXME("BaseDir parameter not yet supported!\n");
5160 return ERROR_INVALID_PARAMETER
;
5163 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5164 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5165 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5166 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5168 result
= ERROR_FILE_NOT_FOUND
;
5171 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5172 if (!pwszTempBuffer
)
5174 result
= ERROR_NOT_ENOUGH_MEMORY
;
5177 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5178 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5180 /* Expand environment variables, if appropriate, or copy the original string over. */
5181 if (dwValueType
== REG_EXPAND_SZ
)
5183 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5184 if (!cbData
) goto cleanup
;
5185 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5186 if (!pwszExpandedBuffer
)
5188 result
= ERROR_NOT_ENOUGH_MEMORY
;
5191 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5195 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5196 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5199 /* If the value references a resource based string, parse the value and load the string.
5200 * Else just copy over the original value. */
5201 result
= ERROR_SUCCESS
;
5202 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5204 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5208 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5212 /* Format of the expanded value is 'path_to_dll,-resId' */
5213 if (!pComma
|| pComma
[1] != L
'-')
5215 result
= ERROR_BADKEY
;
5219 uiStringId
= _wtoi(pComma
+2);
5222 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5223 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5224 result
= ERROR_BADKEY
;
5225 FreeLibrary(hModule
);
5229 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5230 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5235 /************************************************************************
5241 RegLoadMUIStringA(IN HKEY hKey
,
5242 IN LPCSTR pszValue OPTIONAL
,
5243 OUT LPSTR pszOutBuf
,
5245 OUT LPDWORD pcbData OPTIONAL
,
5247 IN LPCSTR pszDirectory OPTIONAL
)
5249 UNICODE_STRING valueW
, baseDirW
;
5251 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5254 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5255 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5256 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5257 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5259 result
= ERROR_NOT_ENOUGH_MEMORY
;
5263 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5266 if (result
== ERROR_SUCCESS
)
5268 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5274 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5275 RtlFreeUnicodeString(&baseDirW
);
5276 RtlFreeUnicodeString(&valueW
);