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 */
430 return ERROR_INVALID_HANDLE
;
433 if (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000)
435 return ERROR_SUCCESS
;
438 Status
= NtClose(hKey
);
439 if (!NT_SUCCESS(Status
))
441 return RtlNtStatusToDosError(Status
);
444 return ERROR_SUCCESS
;
449 RegpCopyTree(IN HKEY hKeySrc
,
454 LIST_ENTRY ListEntry
;
457 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
459 LIST_ENTRY copyQueueHead
;
460 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
463 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
464 KEY_NODE_INFORMATION
*KeyNode
;
467 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
468 NTSTATUS Status
= STATUS_SUCCESS
;
469 NTSTATUS Status2
= STATUS_SUCCESS
;
471 InitializeListHead(©QueueHead
);
473 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
476 if (Info
.Buffer
== NULL
)
478 return STATUS_INSUFFICIENT_RESOURCES
;
481 copyKeys
= RtlAllocateHeap(ProcessHeap
,
483 sizeof(REGP_COPY_KEYS
));
484 if (copyKeys
!= NULL
)
486 copyKeys
->hKeySrc
= hKeySrc
;
487 copyKeys
->hKeyDest
= hKeyDest
;
488 InsertHeadList(©QueueHead
,
489 ©Keys
->ListEntry
);
491 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
495 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
499 /* enumerate all values and copy them */
503 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
505 KeyValueFullInformation
,
508 &BufferSizeRequired
);
509 if (NT_SUCCESS(Status2
))
511 UNICODE_STRING ValueName
;
514 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
515 ValueName
.Length
= Info
.KeyValue
->NameLength
;
516 ValueName
.MaximumLength
= ValueName
.Length
;
517 ValueName
.Buffer
= Info
.KeyValue
->Name
;
519 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
521 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
523 Info
.KeyValue
->TitleIndex
,
526 Info
.KeyValue
->DataLength
);
528 /* don't break, let's try to copy as many values as possible */
529 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
536 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
540 ASSERT(BufferSize
< BufferSizeRequired
);
542 Buffer
= RtlReAllocateHeap(ProcessHeap
,
548 Info
.Buffer
= Buffer
;
553 /* don't break, let's try to copy as many values as possible */
554 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
557 if (NT_SUCCESS(Status
))
565 /* break to avoid an infinite loop in case of denied access or
567 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
576 /* enumerate all subkeys and open and enqueue them */
580 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
585 &BufferSizeRequired
);
586 if (NT_SUCCESS(Status2
))
588 HANDLE KeyHandle
, NewKeyHandle
;
589 OBJECT_ATTRIBUTES ObjectAttributes
;
590 UNICODE_STRING SubKeyName
, ClassName
;
592 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
593 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
594 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
595 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
596 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
597 ClassName
.MaximumLength
= ClassName
.Length
;
598 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
600 /* open the subkey with sufficient rights */
602 InitializeObjectAttributes(&ObjectAttributes
,
604 OBJ_CASE_INSENSITIVE
,
608 Status2
= NtOpenKey(&KeyHandle
,
609 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
611 if (NT_SUCCESS(Status2
))
613 /* FIXME - attempt to query the security information */
615 InitializeObjectAttributes(&ObjectAttributes
,
617 OBJ_CASE_INSENSITIVE
,
621 Status2
= NtCreateKey(&NewKeyHandle
,
624 Info
.KeyNode
->TitleIndex
,
628 if (NT_SUCCESS(Status2
))
630 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
632 sizeof(REGP_COPY_KEYS
));
633 if (newCopyKeys
!= NULL
)
635 /* save the handles and enqueue the subkey */
636 newCopyKeys
->hKeySrc
= KeyHandle
;
637 newCopyKeys
->hKeyDest
= NewKeyHandle
;
638 InsertTailList(©QueueHead
,
639 &newCopyKeys
->ListEntry
);
644 NtClose(NewKeyHandle
);
646 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
655 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
662 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
666 ASSERT(BufferSize
< BufferSizeRequired
);
668 Buffer
= RtlReAllocateHeap(ProcessHeap
,
674 Info
.Buffer
= Buffer
;
679 /* don't break, let's try to copy as many keys as possible */
680 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
683 if (NT_SUCCESS(Status
))
691 /* break to avoid an infinite loop in case of denied access or
693 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
702 /* close the handles and remove the entry from the list */
703 if (copyKeys
->hKeySrc
!= hKeySrc
)
705 NtClose(copyKeys
->hKeySrc
);
707 if (copyKeys
->hKeyDest
!= hKeyDest
)
709 NtClose(copyKeys
->hKeyDest
);
712 RemoveEntryList(©Keys
->ListEntry
);
714 RtlFreeHeap(ProcessHeap
,
717 } while (!IsListEmpty(©QueueHead
));
720 Status
= STATUS_INSUFFICIENT_RESOURCES
;
722 RtlFreeHeap(ProcessHeap
,
730 /************************************************************************
736 RegCopyTreeW(IN HKEY hKeySrc
,
737 IN LPCWSTR lpSubKey OPTIONAL
,
740 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
743 Status
= MapDefaultKey(&KeyHandle
,
745 if (!NT_SUCCESS(Status
))
747 return RtlNtStatusToDosError(Status
);
750 Status
= MapDefaultKey(&DestKeyHandle
,
752 if (!NT_SUCCESS(Status
))
757 if (lpSubKey
!= NULL
)
759 OBJECT_ATTRIBUTES ObjectAttributes
;
760 UNICODE_STRING SubKeyName
;
762 RtlInitUnicodeString(&SubKeyName
,
765 InitializeObjectAttributes(&ObjectAttributes
,
767 OBJ_CASE_INSENSITIVE
,
771 Status
= NtOpenKey(&SubKeyHandle
,
772 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
774 if (!NT_SUCCESS(Status
))
779 CurKey
= SubKeyHandle
;
784 Status
= RegpCopyTree(CurKey
,
787 if (SubKeyHandle
!= NULL
)
789 NtClose(SubKeyHandle
);
793 ClosePredefKey(DestKeyHandle
);
795 ClosePredefKey(KeyHandle
);
797 if (!NT_SUCCESS(Status
))
799 return RtlNtStatusToDosError(Status
);
802 return ERROR_SUCCESS
;
806 /************************************************************************
812 RegCopyTreeA(IN HKEY hKeySrc
,
813 IN LPCSTR lpSubKey OPTIONAL
,
816 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
819 if (lpSubKey
!= NULL
&&
820 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
823 return ERROR_NOT_ENOUGH_MEMORY
;
826 Ret
= RegCopyTreeW(hKeySrc
,
830 RtlFreeUnicodeString(&SubKeyName
);
836 /************************************************************************
837 * RegConnectRegistryA
842 RegConnectRegistryA(IN LPCSTR lpMachineName
,
846 UNICODE_STRING MachineName
= { 0, 0, NULL
};
849 if (lpMachineName
!= NULL
&&
850 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
851 (LPSTR
)lpMachineName
))
853 return ERROR_NOT_ENOUGH_MEMORY
;
856 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
860 RtlFreeUnicodeString(&MachineName
);
866 /************************************************************************
867 * RegConnectRegistryW
872 RegConnectRegistryW(LPCWSTR lpMachineName
,
878 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
880 if (!lpMachineName
|| !*lpMachineName
)
882 /* Use the local machine name */
883 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
887 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
888 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
890 /* MSDN says lpMachineName must start with \\ : not so */
891 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
894 if (GetComputerNameW(compName
, &len
))
896 if (!_wcsicmp(lpMachineName
, compName
))
897 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
900 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
901 ret
= ERROR_BAD_NETPATH
;
905 ret
= GetLastError();
912 /************************************************************************
915 * Create key and all necessary intermediate keys
918 CreateNestedKey(PHKEY KeyHandle
,
919 POBJECT_ATTRIBUTES ObjectAttributes
,
920 PUNICODE_STRING ClassString
,
923 DWORD
*lpdwDisposition
)
925 OBJECT_ATTRIBUTES LocalObjectAttributes
;
926 UNICODE_STRING LocalKeyName
;
929 ULONG FullNameLength
;
932 HANDLE LocalKeyHandle
;
934 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
940 (PULONG
)lpdwDisposition
);
941 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
942 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
945 /* Copy object attributes */
946 RtlCopyMemory(&LocalObjectAttributes
,
948 sizeof(OBJECT_ATTRIBUTES
));
949 RtlCreateUnicodeString(&LocalKeyName
,
950 ObjectAttributes
->ObjectName
->Buffer
);
951 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
952 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
954 LocalKeyHandle
= NULL
;
956 /* Remove the last part of the key name and try to create the key again. */
957 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
959 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
960 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
962 Status
= STATUS_UNSUCCESSFUL
;
967 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
969 Status
= NtCreateKey(&LocalKeyHandle
,
971 &LocalObjectAttributes
,
976 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
979 if (!NT_SUCCESS(Status
))
981 RtlFreeUnicodeString(&LocalKeyName
);
985 /* Add removed parts of the key name and create them too. */
986 Length
= wcslen(LocalKeyName
.Buffer
);
990 NtClose (LocalKeyHandle
);
992 LocalKeyName
.Buffer
[Length
] = L
'\\';
993 Length
= wcslen (LocalKeyName
.Buffer
);
994 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
996 if (Length
== FullNameLength
)
998 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
1004 (PULONG
)lpdwDisposition
);
1008 Status
= NtCreateKey(&LocalKeyHandle
,
1010 &LocalObjectAttributes
,
1015 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
1016 if (!NT_SUCCESS(Status
))
1020 RtlFreeUnicodeString(&LocalKeyName
);
1026 /************************************************************************
1034 _In_ LPCSTR lpSubKey
,
1035 _In_ DWORD Reserved
,
1037 _In_ DWORD dwOptions
,
1038 _In_ REGSAM samDesired
,
1039 _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1040 _Out_ PHKEY phkResult
,
1041 _Out_ LPDWORD lpdwDisposition
)
1043 UNICODE_STRING SubKeyString
;
1044 UNICODE_STRING ClassString
;
1047 RtlInitEmptyUnicodeString(&ClassString
, NULL
, 0);
1048 RtlInitEmptyUnicodeString(&SubKeyString
, NULL
, 0);
1052 if (!RtlCreateUnicodeStringFromAsciiz(&ClassString
, lpClass
))
1054 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1061 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, lpSubKey
))
1063 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
1068 ErrorCode
= RegCreateKeyExW(
1070 SubKeyString
.Buffer
,
1075 lpSecurityAttributes
,
1080 RtlFreeUnicodeString(&SubKeyString
);
1081 RtlFreeUnicodeString(&ClassString
);
1087 /************************************************************************
1096 _In_ LPCWSTR lpSubKey
,
1097 _In_ DWORD Reserved
,
1098 _In_opt_ LPWSTR lpClass
,
1099 _In_ DWORD dwOptions
,
1100 _In_ REGSAM samDesired
,
1101 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1102 _Out_ PHKEY phkResult
,
1103 _Out_opt_ LPDWORD lpdwDisposition
)
1105 UNICODE_STRING SubKeyString
;
1106 UNICODE_STRING ClassString
;
1107 OBJECT_ATTRIBUTES ObjectAttributes
;
1109 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1112 TRACE("RegCreateKeyExW() called\n");
1114 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1115 return ERROR_INVALID_USER_BUFFER
;
1117 /* get the real parent key */
1118 Status
= MapDefaultKey(&ParentKey
,
1120 if (!NT_SUCCESS(Status
))
1122 return RtlNtStatusToDosError(Status
);
1125 TRACE("ParentKey %p\n", ParentKey
);
1127 if (IsHKCRKey(ParentKey
))
1129 LONG ErrorCode
= CreateHKCRKey(
1136 lpSecurityAttributes
,
1139 ClosePredefKey(ParentKey
);
1143 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1144 Attributes
|= OBJ_OPENLINK
;
1146 RtlInitUnicodeString(&ClassString
,
1148 RtlInitUnicodeString(&SubKeyString
,
1150 InitializeObjectAttributes(&ObjectAttributes
,
1154 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1155 Status
= CreateNestedKey(phkResult
,
1157 (lpClass
== NULL
)? NULL
: &ClassString
,
1162 ClosePredefKey(ParentKey
);
1164 TRACE("Status %x\n", Status
);
1165 if (!NT_SUCCESS(Status
))
1167 return RtlNtStatusToDosError(Status
);
1170 return ERROR_SUCCESS
;
1174 /************************************************************************
1180 RegCreateKeyA(HKEY hKey
,
1184 return RegCreateKeyExA(hKey
,
1196 /************************************************************************
1202 RegCreateKeyW(HKEY hKey
,
1206 return RegCreateKeyExW(hKey
,
1218 /************************************************************************
1227 _In_ LPCSTR lpSubKey
)
1229 return RegDeleteKeyExA(hKey
, lpSubKey
, 0, 0);
1233 /************************************************************************
1242 _In_ LPCWSTR lpSubKey
)
1244 return RegDeleteKeyExW(hKey
, lpSubKey
, 0, 0);
1248 /************************************************************************
1257 _In_ LPCSTR lpSubKey
,
1258 _In_ REGSAM samDesired
,
1259 _In_ DWORD Reserved
)
1262 UNICODE_STRING SubKeyName
;
1266 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
, lpSubKey
))
1267 return ERROR_NOT_ENOUGH_MEMORY
;
1270 RtlInitEmptyUnicodeString(&SubKeyName
, NULL
, 0);
1272 ErrorCode
= RegDeleteKeyExW(hKey
, SubKeyName
.Buffer
, samDesired
, Reserved
);
1274 RtlFreeUnicodeString(&SubKeyName
);
1280 /************************************************************************
1289 _In_ LPCWSTR lpSubKey
,
1290 _In_ REGSAM samDesired
,
1291 _In_ DWORD Reserved
)
1293 OBJECT_ATTRIBUTES ObjectAttributes
;
1294 UNICODE_STRING SubKeyName
;
1299 /* Make sure we got a subkey */
1303 return ERROR_INVALID_PARAMETER
;
1306 Status
= MapDefaultKey(&ParentKey
,
1308 if (!NT_SUCCESS(Status
))
1310 return RtlNtStatusToDosError(Status
);
1313 if (IsHKCRKey(ParentKey
))
1315 LONG ErrorCode
= DeleteHKCRKey(ParentKey
, lpSubKey
, samDesired
, Reserved
);
1316 ClosePredefKey(ParentKey
);
1320 if (samDesired
& KEY_WOW64_32KEY
)
1321 ERR("Wow64 not yet supported!\n");
1323 if (samDesired
& KEY_WOW64_64KEY
)
1324 ERR("Wow64 not yet supported!\n");
1327 RtlInitUnicodeString(&SubKeyName
,
1329 InitializeObjectAttributes(&ObjectAttributes
,
1331 OBJ_CASE_INSENSITIVE
,
1334 Status
= NtOpenKey(&TargetKey
,
1337 if (!NT_SUCCESS(Status
))
1342 Status
= NtDeleteKey(TargetKey
);
1346 ClosePredefKey(ParentKey
);
1348 if (!NT_SUCCESS(Status
))
1350 return RtlNtStatusToDosError(Status
);
1353 return ERROR_SUCCESS
;
1357 /************************************************************************
1358 * RegDeleteKeyValueW
1363 RegDeleteKeyValueW(IN HKEY hKey
,
1364 IN LPCWSTR lpSubKey OPTIONAL
,
1365 IN LPCWSTR lpValueName OPTIONAL
)
1367 UNICODE_STRING ValueName
;
1368 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1371 Status
= MapDefaultKey(&KeyHandle
,
1373 if (!NT_SUCCESS(Status
))
1375 return RtlNtStatusToDosError(Status
);
1378 if (lpSubKey
!= NULL
)
1380 OBJECT_ATTRIBUTES ObjectAttributes
;
1381 UNICODE_STRING SubKeyName
;
1383 RtlInitUnicodeString(&SubKeyName
,
1386 InitializeObjectAttributes(&ObjectAttributes
,
1388 OBJ_CASE_INSENSITIVE
,
1392 Status
= NtOpenKey(&SubKeyHandle
,
1395 if (!NT_SUCCESS(Status
))
1400 CurKey
= SubKeyHandle
;
1405 RtlInitUnicodeString(&ValueName
,
1406 (LPWSTR
)lpValueName
);
1408 Status
= NtDeleteValueKey(CurKey
,
1411 if (SubKeyHandle
!= NULL
)
1413 NtClose(SubKeyHandle
);
1417 ClosePredefKey(KeyHandle
);
1419 if (!NT_SUCCESS(Status
))
1421 return RtlNtStatusToDosError(Status
);
1424 return ERROR_SUCCESS
;
1428 /************************************************************************
1429 * RegDeleteKeyValueA
1434 RegDeleteKeyValueA(IN HKEY hKey
,
1435 IN LPCSTR lpSubKey OPTIONAL
,
1436 IN LPCSTR lpValueName OPTIONAL
)
1438 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1441 if (lpSubKey
!= NULL
&&
1442 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1445 return ERROR_NOT_ENOUGH_MEMORY
;
1448 if (lpValueName
!= NULL
&&
1449 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1450 (LPSTR
)lpValueName
))
1452 RtlFreeUnicodeString(&SubKey
);
1453 return ERROR_NOT_ENOUGH_MEMORY
;
1456 Ret
= RegDeleteKeyValueW(hKey
,
1460 RtlFreeUnicodeString(&SubKey
);
1461 RtlFreeUnicodeString(&ValueName
);
1467 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1469 RegpDeleteTree(IN HKEY hKey
)
1473 LIST_ENTRY ListEntry
;
1475 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1477 LIST_ENTRY delQueueHead
;
1478 PREG_DEL_KEYS delKeys
, newDelKeys
;
1481 PKEY_BASIC_INFORMATION BasicInfo
;
1482 PREG_DEL_KEYS KeyDelRoot
;
1483 NTSTATUS Status
= STATUS_SUCCESS
;
1484 NTSTATUS Status2
= STATUS_SUCCESS
;
1486 InitializeListHead(&delQueueHead
);
1488 ProcessHeap
= RtlGetProcessHeap();
1490 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1491 structure for the root key, we only do that for subkeys as we need to
1492 allocate REGP_DEL_KEYS structures anyway! */
1493 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1495 sizeof(REGP_DEL_KEYS
));
1496 if (KeyDelRoot
!= NULL
)
1498 KeyDelRoot
->KeyHandle
= hKey
;
1499 InsertTailList(&delQueueHead
,
1500 &KeyDelRoot
->ListEntry
);
1504 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1513 /* check if this key contains subkeys and delete them first by queuing
1514 them at the head of the list */
1515 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1517 KeyBasicInformation
,
1522 if (NT_SUCCESS(Status2
))
1524 OBJECT_ATTRIBUTES ObjectAttributes
;
1525 UNICODE_STRING SubKeyName
;
1527 ASSERT(newDelKeys
!= NULL
);
1528 ASSERT(BasicInfo
!= NULL
);
1530 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1531 SubKeyName
.Length
= BasicInfo
->NameLength
;
1532 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1533 SubKeyName
.Buffer
= BasicInfo
->Name
;
1535 InitializeObjectAttributes(&ObjectAttributes
,
1537 OBJ_CASE_INSENSITIVE
,
1541 /* open the subkey */
1542 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1543 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1545 if (!NT_SUCCESS(Status2
))
1550 /* enqueue this key to the head of the deletion queue */
1551 InsertHeadList(&delQueueHead
,
1552 &newDelKeys
->ListEntry
);
1554 /* try again from the head of the list */
1559 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1561 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1563 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1564 if (newDelKeys
!= NULL
)
1566 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1569 goto ReadFirstSubKey
;
1573 /* don't break, let's try to delete as many keys as possible */
1574 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1575 goto SubKeyFailureNoFree
;
1578 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1580 PREG_DEL_KEYS newDelKeys2
;
1582 ASSERT(newDelKeys
!= NULL
);
1584 /* we need more memory to query the key name */
1585 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1588 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1589 if (newDelKeys2
!= NULL
)
1591 newDelKeys
= newDelKeys2
;
1592 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1595 goto ReadFirstSubKey
;
1599 /* don't break, let's try to delete as many keys as possible */
1600 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1603 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1605 /* in some race conditions where another thread would delete
1606 the same tree at the same time, newDelKeys could actually
1608 if (newDelKeys
!= NULL
)
1610 RtlFreeHeap(ProcessHeap
,
1618 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1619 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1620 if (newDelKeys
!= NULL
)
1622 RtlFreeHeap(ProcessHeap
,
1627 SubKeyFailureNoFree
:
1628 /* don't break, let's try to delete as many keys as possible */
1629 if (NT_SUCCESS(Status
))
1635 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1637 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1639 if (!NT_SUCCESS(Status2
))
1641 /* close the key handle so we don't leak handles for keys we were
1642 unable to delete. But only do this for handles not supplied
1645 if (delKeys
->KeyHandle
!= hKey
)
1647 NtClose(delKeys
->KeyHandle
);
1650 if (NT_SUCCESS(Status
))
1652 /* don't break, let's try to delete as many keys as possible */
1657 /* remove the entry from the list */
1658 RemoveEntryList(&delKeys
->ListEntry
);
1660 RtlFreeHeap(ProcessHeap
,
1663 } while (!IsListEmpty(&delQueueHead
));
1666 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1672 /************************************************************************
1678 RegDeleteTreeW(IN HKEY hKey
,
1679 IN LPCWSTR lpSubKey OPTIONAL
)
1681 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1684 Status
= MapDefaultKey(&KeyHandle
,
1686 if (!NT_SUCCESS(Status
))
1688 return RtlNtStatusToDosError(Status
);
1691 if (lpSubKey
!= NULL
)
1693 OBJECT_ATTRIBUTES ObjectAttributes
;
1694 UNICODE_STRING SubKeyName
;
1696 RtlInitUnicodeString(&SubKeyName
,
1699 InitializeObjectAttributes(&ObjectAttributes
,
1701 OBJ_CASE_INSENSITIVE
,
1705 Status
= NtOpenKey(&SubKeyHandle
,
1706 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1708 if (!NT_SUCCESS(Status
))
1713 CurKey
= SubKeyHandle
;
1718 Status
= RegpDeleteTree(CurKey
);
1720 if (NT_SUCCESS(Status
))
1722 /* make sure we only close hKey (KeyHandle) when the caller specified a
1723 subkey, because the handle would be invalid already! */
1724 if (CurKey
!= KeyHandle
)
1726 ClosePredefKey(KeyHandle
);
1729 return ERROR_SUCCESS
;
1733 /* make sure we close all handles we created! */
1734 if (SubKeyHandle
!= NULL
)
1736 NtClose(SubKeyHandle
);
1740 ClosePredefKey(KeyHandle
);
1742 return RtlNtStatusToDosError(Status
);
1748 /************************************************************************
1755 RegDeleteTreeW(HKEY hKey
,
1759 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1760 DWORD dwMaxLen
, dwSize
;
1764 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1766 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1768 Status
= MapDefaultKey(&KeyHandle
,
1770 if (!NT_SUCCESS(Status
))
1772 return RtlNtStatusToDosError(Status
);
1775 hSubKey
= KeyHandle
;
1779 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1782 ClosePredefKey(KeyHandle
);
1787 /* Get highest length for keys, values */
1788 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1789 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1790 if (ret
) goto cleanup
;
1794 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1795 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1797 /* Name too big: alloc a buffer for it */
1798 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1800 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1806 /* Recursively delete all the subkeys */
1810 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1811 NULL
, NULL
, NULL
)) break;
1813 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1814 if (ret
) goto cleanup
;
1818 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1823 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1824 NULL
, NULL
, NULL
, NULL
)) break;
1826 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1827 if (ret
) goto cleanup
;
1831 /* Free buffer if allocated */
1832 if (lpszName
!= szNameBuf
)
1833 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1835 RegCloseKey(hSubKey
);
1837 ClosePredefKey(KeyHandle
);
1843 /************************************************************************
1849 RegDeleteTreeA(IN HKEY hKey
,
1850 IN LPCSTR lpSubKey OPTIONAL
)
1852 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1855 if (lpSubKey
!= NULL
&&
1856 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1859 return ERROR_NOT_ENOUGH_MEMORY
;
1862 Ret
= RegDeleteTreeW(hKey
,
1865 RtlFreeUnicodeString(&SubKeyName
);
1871 /************************************************************************
1872 * RegDisableReflectionKey
1877 RegDisableReflectionKey(IN HKEY hBase
)
1879 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1880 return ERROR_CALL_NOT_IMPLEMENTED
;
1884 /************************************************************************
1885 * RegEnableReflectionKey
1890 RegEnableReflectionKey(IN HKEY hBase
)
1892 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1893 return ERROR_CALL_NOT_IMPLEMENTED
;
1897 /******************************************************************************
1898 * RegpApplyRestrictions [internal]
1900 * Helper function for RegGetValueA/W.
1903 RegpApplyRestrictions(DWORD dwFlags
,
1908 /* Check if the type is restricted by the passed flags */
1909 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1915 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1916 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1917 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1918 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1919 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1920 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1921 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1924 if (dwFlags
& dwMask
)
1926 /* Type is not restricted, check for size mismatch */
1927 if (dwType
== REG_BINARY
)
1931 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1933 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1936 if (cbExpect
&& cbData
!= cbExpect
)
1937 *ret
= ERROR_DATATYPE_MISMATCH
;
1940 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1945 /******************************************************************************
1946 * RegGetValueW [ADVAPI32.@]
1948 * Retrieves the type and data for a value name associated with a key,
1949 * optionally expanding its content and restricting its type.
1952 * hKey [I] Handle to an open key.
1953 * pszSubKey [I] Name of the subkey of hKey.
1954 * pszValue [I] Name of value under hKey/szSubKey to query.
1955 * dwFlags [I] Flags restricting the value type to retrieve.
1956 * pdwType [O] Destination for the values type, may be NULL.
1957 * pvData [O] Destination for the values content, may be NULL.
1958 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1959 * retrieve the whole content, including the trailing '\0'
1963 * Success: ERROR_SUCCESS
1964 * Failure: nonzero error code from Winerror.h
1967 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1968 * expanded and pdwType is set to REG_SZ instead.
1969 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1970 * without RRF_NOEXPAND is thus not allowed.
1971 * An exception is the case where RRF_RT_ANY is specified, because then
1972 * RRF_NOEXPAND is allowed.
1975 RegGetValueW(HKEY hKey
,
1983 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1987 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1988 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1989 pvData
, pcbData
, cbData
);
1991 if (pvData
&& !pcbData
)
1992 return ERROR_INVALID_PARAMETER
;
1993 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1994 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1995 return ERROR_INVALID_PARAMETER
;
1997 if (pszSubKey
&& pszSubKey
[0])
1999 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2000 if (ret
!= ERROR_SUCCESS
) return ret
;
2003 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2005 /* If we are going to expand we need to read in the whole the value even
2006 * if the passed buffer was too small as the expanded string might be
2007 * smaller than the unexpanded one and could fit into cbData bytes. */
2008 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2009 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2013 HeapFree(GetProcessHeap(), 0, pvBuf
);
2015 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2018 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2022 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2023 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2024 &dwType
, pvBuf
, &cbData
);
2027 /* Even if cbData was large enough we have to copy the
2028 * string since ExpandEnvironmentStrings can't handle
2029 * overlapping buffers. */
2030 CopyMemory(pvBuf
, pvData
, cbData
);
2033 /* Both the type or the value itself could have been modified in
2034 * between so we have to keep retrying until the buffer is large
2035 * enough or we no longer have to expand the value. */
2037 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2039 if (ret
== ERROR_SUCCESS
)
2041 /* Recheck dwType in case it changed since the first call */
2042 if (dwType
== REG_EXPAND_SZ
)
2044 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2045 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2047 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2048 ret
= ERROR_MORE_DATA
;
2051 CopyMemory(pvData
, pvBuf
, *pcbData
);
2054 HeapFree(GetProcessHeap(), 0, pvBuf
);
2057 if (pszSubKey
&& pszSubKey
[0])
2060 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2062 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2063 ZeroMemory(pvData
, *pcbData
);
2075 /******************************************************************************
2076 * RegGetValueA [ADVAPI32.@]
2081 RegGetValueA(HKEY hKey
,
2089 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2093 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2094 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2097 if (pvData
&& !pcbData
)
2098 return ERROR_INVALID_PARAMETER
;
2099 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2100 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2101 return ERROR_INVALID_PARAMETER
;
2103 if (pszSubKey
&& pszSubKey
[0])
2105 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2106 if (ret
!= ERROR_SUCCESS
) return ret
;
2109 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2111 /* If we are going to expand we need to read in the whole the value even
2112 * if the passed buffer was too small as the expanded string might be
2113 * smaller than the unexpanded one and could fit into cbData bytes. */
2114 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2115 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2118 HeapFree(GetProcessHeap(), 0, pvBuf
);
2120 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2123 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2127 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2128 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2129 &dwType
, pvBuf
, &cbData
);
2132 /* Even if cbData was large enough we have to copy the
2133 * string since ExpandEnvironmentStrings can't handle
2134 * overlapping buffers. */
2135 CopyMemory(pvBuf
, pvData
, cbData
);
2138 /* Both the type or the value itself could have been modified in
2139 * between so we have to keep retrying until the buffer is large
2140 * enough or we no longer have to expand the value. */
2141 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2143 if (ret
== ERROR_SUCCESS
)
2145 /* Recheck dwType in case it changed since the first call */
2146 if (dwType
== REG_EXPAND_SZ
)
2148 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2149 pcbData
? *pcbData
: 0);
2151 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2152 ret
= ERROR_MORE_DATA
;
2155 CopyMemory(pvData
, pvBuf
, *pcbData
);
2158 HeapFree(GetProcessHeap(), 0, pvBuf
);
2161 if (pszSubKey
&& pszSubKey
[0])
2164 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2166 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2167 ZeroMemory(pvData
, *pcbData
);
2169 if (pdwType
) *pdwType
= dwType
;
2170 if (pcbData
) *pcbData
= cbData
;
2176 /************************************************************************
2182 RegSetKeyValueW(IN HKEY hKey
,
2183 IN LPCWSTR lpSubKey OPTIONAL
,
2184 IN LPCWSTR lpValueName OPTIONAL
,
2186 IN LPCVOID lpData OPTIONAL
,
2189 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2193 Status
= MapDefaultKey(&KeyHandle
,
2195 if (!NT_SUCCESS(Status
))
2197 return RtlNtStatusToDosError(Status
);
2200 if (lpSubKey
!= NULL
)
2202 OBJECT_ATTRIBUTES ObjectAttributes
;
2203 UNICODE_STRING SubKeyName
;
2205 RtlInitUnicodeString(&SubKeyName
,
2208 InitializeObjectAttributes(&ObjectAttributes
,
2210 OBJ_CASE_INSENSITIVE
,
2214 Status
= NtOpenKey(&SubKeyHandle
,
2217 if (!NT_SUCCESS(Status
))
2219 Ret
= RtlNtStatusToDosError(Status
);
2223 CurKey
= SubKeyHandle
;
2228 Ret
= RegSetValueExW(CurKey
,
2235 if (SubKeyHandle
!= NULL
)
2237 NtClose(SubKeyHandle
);
2241 ClosePredefKey(KeyHandle
);
2247 /************************************************************************
2253 RegSetKeyValueA(IN HKEY hKey
,
2254 IN LPCSTR lpSubKey OPTIONAL
,
2255 IN LPCSTR lpValueName OPTIONAL
,
2257 IN LPCVOID lpData OPTIONAL
,
2260 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2264 Status
= MapDefaultKey(&KeyHandle
,
2266 if (!NT_SUCCESS(Status
))
2268 return RtlNtStatusToDosError(Status
);
2271 if (lpSubKey
!= NULL
)
2273 OBJECT_ATTRIBUTES ObjectAttributes
;
2274 UNICODE_STRING SubKeyName
;
2276 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2279 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2283 InitializeObjectAttributes(&ObjectAttributes
,
2285 OBJ_CASE_INSENSITIVE
,
2289 Status
= NtOpenKey(&SubKeyHandle
,
2293 RtlFreeUnicodeString(&SubKeyName
);
2295 if (!NT_SUCCESS(Status
))
2297 Ret
= RtlNtStatusToDosError(Status
);
2301 CurKey
= SubKeyHandle
;
2306 Ret
= RegSetValueExA(CurKey
,
2313 if (SubKeyHandle
!= NULL
)
2315 NtClose(SubKeyHandle
);
2319 ClosePredefKey(KeyHandle
);
2325 /************************************************************************
2331 RegDeleteValueA(HKEY hKey
,
2334 UNICODE_STRING ValueName
;
2338 Status
= MapDefaultKey(&KeyHandle
,
2340 if (!NT_SUCCESS(Status
))
2342 return RtlNtStatusToDosError(Status
);
2345 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2346 (LPSTR
)lpValueName
);
2347 Status
= NtDeleteValueKey(KeyHandle
,
2349 RtlFreeUnicodeString (&ValueName
);
2351 ClosePredefKey(KeyHandle
);
2353 if (!NT_SUCCESS(Status
))
2355 return RtlNtStatusToDosError(Status
);
2358 return ERROR_SUCCESS
;
2362 /************************************************************************
2368 RegDeleteValueW(HKEY hKey
,
2369 LPCWSTR lpValueName
)
2371 UNICODE_STRING ValueName
;
2375 Status
= MapDefaultKey(&KeyHandle
,
2377 if (!NT_SUCCESS(Status
))
2379 return RtlNtStatusToDosError(Status
);
2382 RtlInitUnicodeString(&ValueName
,
2383 (LPWSTR
)lpValueName
);
2385 Status
= NtDeleteValueKey(KeyHandle
,
2388 ClosePredefKey(KeyHandle
);
2390 if (!NT_SUCCESS(Status
))
2392 return RtlNtStatusToDosError(Status
);
2395 return ERROR_SUCCESS
;
2399 /************************************************************************
2405 RegEnumKeyA(HKEY hKey
,
2413 return RegEnumKeyExA(hKey
,
2424 /************************************************************************
2430 RegEnumKeyW(HKEY hKey
,
2438 return RegEnumKeyExW(hKey
,
2449 /************************************************************************
2460 _Inout_ LPDWORD lpcbName
,
2461 _Reserved_ LPDWORD lpReserved
,
2462 _Out_opt_ LPSTR lpClass
,
2463 _Inout_opt_ LPDWORD lpcbClass
,
2464 _Out_opt_ PFILETIME lpftLastWriteTime
)
2466 WCHAR
* NameBuffer
= NULL
;
2467 WCHAR
* ClassBuffer
= NULL
;
2468 DWORD NameLength
, ClassLength
;
2471 /* Allocate our buffers */
2474 NameLength
= *lpcbName
;
2475 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName
* sizeof(WCHAR
));
2476 if (NameBuffer
== NULL
)
2478 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2487 ClassLength
= *lpcbClass
;
2488 ClassBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass
* sizeof(WCHAR
));
2489 if (ClassBuffer
== NULL
)
2491 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
2497 /* Do the actual call */
2498 ErrorCode
= RegEnumKeyExW(
2508 if (ErrorCode
!= ERROR_SUCCESS
)
2511 /* Convert the strings */
2512 RtlUnicodeToMultiByteN(lpName
, *lpcbName
, 0, NameBuffer
, *lpcbName
* sizeof(WCHAR
));
2513 /* NULL terminate if we can */
2514 if (NameLength
> *lpcbName
)
2515 lpName
[*lpcbName
] = '\0';
2519 RtlUnicodeToMultiByteN(lpClass
, *lpcbClass
, 0, NameBuffer
, *lpcbClass
* sizeof(WCHAR
));
2520 if (ClassLength
> *lpcbClass
)
2521 lpClass
[*lpcbClass
] = '\0';
2526 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2528 RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer
);
2534 /************************************************************************
2544 _Out_ LPWSTR lpName
,
2545 _Inout_ LPDWORD lpcbName
,
2546 _Reserved_ LPDWORD lpReserved
,
2547 _Out_opt_ LPWSTR lpClass
,
2548 _Inout_opt_ LPDWORD lpcbClass
,
2549 _Out_opt_ PFILETIME lpftLastWriteTime
)
2553 KEY_NODE_INFORMATION Node
;
2554 KEY_BASIC_INFORMATION Basic
;
2560 ULONG ClassLength
= 0;
2562 LONG ErrorCode
= ERROR_SUCCESS
;
2565 Status
= MapDefaultKey(&KeyHandle
,
2567 if (!NT_SUCCESS(Status
))
2569 return RtlNtStatusToDosError(Status
);
2572 if (IsHKCRKey(KeyHandle
))
2574 ErrorCode
= EnumHKCRKey(
2583 ClosePredefKey(KeyHandle
);
2589 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2600 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2607 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2611 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2614 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2617 if (KeyInfo
== NULL
)
2619 ErrorCode
= ERROR_OUTOFMEMORY
;
2623 Status
= NtEnumerateKey(KeyHandle
,
2625 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2629 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2630 if (!NT_SUCCESS(Status
))
2632 ErrorCode
= RtlNtStatusToDosError (Status
);
2636 if (lpClass
== NULL
)
2638 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2640 ErrorCode
= ERROR_MORE_DATA
;
2644 RtlCopyMemory(lpName
,
2645 KeyInfo
->Basic
.Name
,
2646 KeyInfo
->Basic
.NameLength
);
2647 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2648 lpName
[*lpcbName
] = 0;
2653 if (KeyInfo
->Node
.NameLength
> NameLength
||
2654 KeyInfo
->Node
.ClassLength
> ClassLength
)
2656 ErrorCode
= ERROR_MORE_DATA
;
2660 RtlCopyMemory(lpName
,
2662 KeyInfo
->Node
.NameLength
);
2663 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2664 lpName
[*lpcbName
] = 0;
2665 RtlCopyMemory(lpClass
,
2666 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2667 KeyInfo
->Node
.ClassLength
);
2668 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2669 lpClass
[*lpcbClass
] = 0;
2673 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2675 if (lpClass
== NULL
)
2677 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2678 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2682 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2683 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2688 RtlFreeHeap(ProcessHeap
,
2693 ClosePredefKey(KeyHandle
);
2699 /************************************************************************
2709 _Inout_ LPDWORD lpcbName
,
2710 _Reserved_ LPDWORD lpdwReserved
,
2711 _Out_opt_ LPDWORD lpdwType
,
2712 _Out_opt_ LPBYTE lpData
,
2713 _Inout_opt_ LPDWORD lpcbData
)
2716 DWORD NameBufferSize
, NameLength
;
2718 DWORD LocalType
= REG_NONE
;
2719 BOOL NameOverflow
= FALSE
;
2721 /* Do parameter checks now, once and for all. */
2722 if (!lpName
|| !lpcbName
)
2723 return ERROR_INVALID_PARAMETER
;
2725 if ((lpData
&& !lpcbData
) || lpdwReserved
)
2726 return ERROR_INVALID_PARAMETER
;
2728 /* Get the size of the buffer we must use for the first call to RegEnumValueW */
2729 ErrorCode
= RegQueryInfoKeyW(
2730 hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &NameBufferSize
, NULL
, NULL
, NULL
);
2731 if (ErrorCode
!= ERROR_SUCCESS
)
2734 /* Add space for the null terminator */
2737 /* Allocate the buffer for the unicode name */
2738 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize
* sizeof(WCHAR
));
2739 if (NameBuffer
== NULL
)
2741 return ERROR_NOT_ENOUGH_MEMORY
;
2745 * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
2746 * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
2747 * is an overflow on the data or on the name during the the second call. So the first time, we make the
2748 * call with the supplied value. This is merdique, but this is how it is.
2750 NameLength
= *lpcbName
;
2751 ErrorCode
= RegEnumValueW(
2760 if (ErrorCode
!= ERROR_SUCCESS
)
2762 if (ErrorCode
== ERROR_MORE_DATA
)
2763 NameOverflow
= TRUE
;
2768 if (is_string(LocalType
) && lpcbData
)
2770 /* We must allocate a buffer to get the unicode data */
2771 DWORD DataBufferSize
= *lpcbData
* sizeof(WCHAR
);
2772 WCHAR
* DataBuffer
= NULL
;
2773 DWORD DataLength
= *lpcbData
;
2774 LPSTR DataStr
= (LPSTR
)lpData
;
2777 DataBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData
* sizeof(WCHAR
));
2779 /* Do the real call */
2780 ErrorCode
= RegEnumValueW(
2790 *lpcbData
= DataBufferSize
/ sizeof(WCHAR
);
2792 if (ErrorCode
!= ERROR_SUCCESS
)
2794 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer
);
2798 /* Copy the data whatever the error code is */
2801 /* Do the data conversion */
2802 RtlUnicodeToMultiByteN(DataStr
, DataLength
, 0, DataBuffer
, DataBufferSize
);
2803 /* NULL-terminate if there is enough room */
2804 if ((DataLength
> *lpcbData
) && (DataStr
[*lpcbData
- 1] != '\0'))
2805 DataStr
[*lpcbData
] = '\0';
2808 RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer
);
2812 /* No data conversion needed. Do the call with provided buffers */
2813 ErrorCode
= RegEnumValueW(
2823 if (ErrorCode
!= ERROR_SUCCESS
)
2831 ErrorCode
= ERROR_MORE_DATA
;
2835 /* Convert the name string */
2836 RtlUnicodeToMultiByteN(lpName
, *lpcbName
, lpcbName
, NameBuffer
, NameBufferSize
* sizeof(WCHAR
));
2837 ((PSTR
)lpName
)[*lpcbName
] = '\0';
2841 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2847 /******************************************************************************
2848 * RegEnumValueW [ADVAPI32.@]
2852 * hkey [I] Handle to key to query
2853 * index [I] Index of value to query
2854 * value [O] Value string
2855 * val_count [I/O] Size of value buffer (in wchars)
2856 * reserved [I] Reserved
2857 * type [O] Type code
2858 * data [O] Value data
2859 * count [I/O] Size of data buffer (in bytes)
2862 * Success: ERROR_SUCCESS
2863 * Failure: nonzero error code from Winerror.h
2871 _Inout_ PDWORD val_count
,
2872 _Reserved_ PDWORD reserved
,
2873 _Out_opt_ PDWORD type
,
2874 _Out_opt_ LPBYTE data
,
2875 _Inout_opt_ PDWORD count
)
2880 char buffer
[256], *buf_ptr
= buffer
;
2881 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2882 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2884 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2885 hKey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2887 if (!value
|| !val_count
)
2888 return ERROR_INVALID_PARAMETER
;
2890 if ((data
&& !count
) || reserved
)
2891 return ERROR_INVALID_PARAMETER
;
2893 status
= MapDefaultKey(&KeyHandle
, hKey
);
2894 if (!NT_SUCCESS(status
))
2896 return RtlNtStatusToDosError(status
);
2899 if (IsHKCRKey(KeyHandle
))
2901 LONG ErrorCode
= EnumHKCRValue(
2910 ClosePredefKey(KeyHandle
);
2914 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2915 if (data
) total_size
+= *count
;
2916 total_size
= min( sizeof(buffer
), total_size
);
2918 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2919 buffer
, total_size
, &total_size
);
2920 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2924 /* retry with a dynamically allocated buffer */
2925 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2927 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2928 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2930 status
= ERROR_NOT_ENOUGH_MEMORY
;
2933 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2934 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2935 buf_ptr
, total_size
, &total_size
);
2938 if (status
) goto done
;
2942 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2944 status
= STATUS_BUFFER_OVERFLOW
;
2947 memcpy( value
, info
->Name
, info
->NameLength
);
2948 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2949 value
[*val_count
] = 0;
2954 if (info
->DataLength
> *count
)
2956 status
= STATUS_BUFFER_OVERFLOW
;
2959 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2960 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
2962 /* if the type is REG_SZ and data is not 0-terminated
2963 * and there is enough space in the buffer NT appends a \0 */
2964 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
2965 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2969 else status
= STATUS_SUCCESS
;
2972 if (type
) *type
= info
->Type
;
2973 if (count
) *count
= info
->DataLength
;
2976 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2977 ClosePredefKey(KeyHandle
);
2978 return RtlNtStatusToDosError(status
);
2982 /************************************************************************
2988 RegFlushKey(HKEY hKey
)
2993 if (hKey
== HKEY_PERFORMANCE_DATA
)
2995 return ERROR_SUCCESS
;
2998 Status
= MapDefaultKey(&KeyHandle
,
3000 if (!NT_SUCCESS(Status
))
3002 return RtlNtStatusToDosError(Status
);
3005 Status
= NtFlushKey(KeyHandle
);
3007 ClosePredefKey(KeyHandle
);
3009 if (!NT_SUCCESS(Status
))
3011 return RtlNtStatusToDosError(Status
);
3014 return ERROR_SUCCESS
;
3018 /************************************************************************
3024 RegGetKeySecurity(HKEY hKey
,
3025 SECURITY_INFORMATION SecurityInformation
,
3026 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3027 LPDWORD lpcbSecurityDescriptor
)
3032 if (hKey
== HKEY_PERFORMANCE_DATA
)
3034 return ERROR_INVALID_HANDLE
;
3037 Status
= MapDefaultKey(&KeyHandle
,
3039 if (!NT_SUCCESS(Status
))
3041 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3042 return RtlNtStatusToDosError(Status
);
3045 Status
= NtQuerySecurityObject(KeyHandle
,
3046 SecurityInformation
,
3047 pSecurityDescriptor
,
3048 *lpcbSecurityDescriptor
,
3049 lpcbSecurityDescriptor
);
3051 ClosePredefKey(KeyHandle
);
3053 if (!NT_SUCCESS(Status
))
3055 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3056 return RtlNtStatusToDosError(Status
);
3059 return ERROR_SUCCESS
;
3063 /************************************************************************
3069 RegLoadKeyA(HKEY hKey
,
3073 UNICODE_STRING FileName
;
3074 UNICODE_STRING KeyName
;
3077 RtlInitEmptyUnicodeString(&KeyName
, NULL
, 0);
3078 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
3082 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName
, lpSubKey
))
3084 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3091 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
3093 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
3098 ErrorCode
= RegLoadKeyW(hKey
,
3103 RtlFreeUnicodeString(&FileName
);
3104 RtlFreeUnicodeString(&KeyName
);
3110 /************************************************************************
3116 RegLoadKeyW(HKEY hKey
,
3120 OBJECT_ATTRIBUTES FileObjectAttributes
;
3121 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3122 UNICODE_STRING FileName
;
3123 UNICODE_STRING KeyName
;
3126 LONG ErrorCode
= ERROR_SUCCESS
;
3128 if (hKey
== HKEY_PERFORMANCE_DATA
)
3130 return ERROR_INVALID_HANDLE
;
3133 Status
= MapDefaultKey(&KeyHandle
,
3135 if (!NT_SUCCESS(Status
))
3137 return RtlNtStatusToDosError(Status
);
3140 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3145 ErrorCode
= ERROR_BAD_PATHNAME
;
3149 InitializeObjectAttributes(&FileObjectAttributes
,
3151 OBJ_CASE_INSENSITIVE
,
3155 RtlInitUnicodeString(&KeyName
,
3158 InitializeObjectAttributes(&KeyObjectAttributes
,
3160 OBJ_CASE_INSENSITIVE
,
3164 Status
= NtLoadKey(&KeyObjectAttributes
,
3165 &FileObjectAttributes
);
3167 RtlFreeHeap(RtlGetProcessHeap(),
3171 if (!NT_SUCCESS(Status
))
3173 ErrorCode
= RtlNtStatusToDosError(Status
);
3178 ClosePredefKey(KeyHandle
);
3184 /************************************************************************
3185 * RegNotifyChangeKeyValue
3190 RegNotifyChangeKeyValue(HKEY hKey
,
3192 DWORD dwNotifyFilter
,
3196 IO_STATUS_BLOCK IoStatusBlock
;
3199 LONG ErrorCode
= ERROR_SUCCESS
;
3201 if (hKey
== HKEY_PERFORMANCE_DATA
)
3203 return ERROR_INVALID_HANDLE
;
3206 if ((fAsynchronous
!= FALSE
) && (hEvent
== NULL
))
3208 return ERROR_INVALID_PARAMETER
;
3211 Status
= MapDefaultKey(&KeyHandle
,
3213 if (!NT_SUCCESS(Status
))
3215 return RtlNtStatusToDosError(Status
);
3218 /* FIXME: Remote key handles must fail */
3220 Status
= NtNotifyChangeKey(KeyHandle
,
3230 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3232 ErrorCode
= RtlNtStatusToDosError(Status
);
3235 ClosePredefKey(KeyHandle
);
3241 /************************************************************************
3242 * RegOpenCurrentUser
3247 RegOpenCurrentUser(IN REGSAM samDesired
,
3248 OUT PHKEY phkResult
)
3252 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3253 (PHANDLE
)phkResult
);
3254 if (!NT_SUCCESS(Status
))
3256 /* NOTE - don't set the last error code! just return the error! */
3257 return RtlNtStatusToDosError(Status
);
3260 return ERROR_SUCCESS
;
3264 /************************************************************************
3267 * 20050503 Fireball - imported from WINE
3272 RegOpenKeyA(HKEY hKey
,
3276 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3277 hKey
, lpSubKey
, phkResult
);
3280 return ERROR_INVALID_PARAMETER
;
3282 if (!hKey
&& lpSubKey
&& phkResult
)
3284 return ERROR_INVALID_HANDLE
;
3287 if (!lpSubKey
|| !*lpSubKey
)
3290 return ERROR_SUCCESS
;
3293 return RegOpenKeyExA(hKey
,
3301 /************************************************************************
3306 * 20050503 Fireball - imported from WINE
3311 RegOpenKeyW(HKEY hKey
,
3315 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3316 hKey
, lpSubKey
, phkResult
);
3319 return ERROR_INVALID_PARAMETER
;
3321 if (!hKey
&& lpSubKey
&& phkResult
)
3323 return ERROR_INVALID_HANDLE
;
3326 if (!lpSubKey
|| !*lpSubKey
)
3329 return ERROR_SUCCESS
;
3332 return RegOpenKeyExW(hKey
,
3340 /************************************************************************
3348 _In_ LPCSTR lpSubKey
,
3349 _In_ DWORD ulOptions
,
3350 _In_ REGSAM samDesired
,
3351 _Out_ PHKEY phkResult
)
3353 UNICODE_STRING SubKeyString
;
3356 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3357 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3361 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString
, lpSubKey
))
3362 return ERROR_NOT_ENOUGH_MEMORY
;
3365 RtlInitEmptyUnicodeString(&SubKeyString
, NULL
, 0);
3367 ErrorCode
= RegOpenKeyExW(hKey
, SubKeyString
.Buffer
, ulOptions
, samDesired
, phkResult
);
3369 RtlFreeUnicodeString(&SubKeyString
);
3375 /************************************************************************
3381 RegOpenKeyExW(HKEY hKey
,
3387 OBJECT_ATTRIBUTES ObjectAttributes
;
3388 UNICODE_STRING SubKeyString
;
3391 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3392 LONG ErrorCode
= ERROR_SUCCESS
;
3394 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3395 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3398 return ERROR_INVALID_PARAMETER
;
3401 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3402 if (!NT_SUCCESS(Status
))
3404 return RtlNtStatusToDosError(Status
);
3407 if (IsHKCRKey(KeyHandle
))
3409 ErrorCode
= OpenHKCRKey(KeyHandle
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3410 ClosePredefKey(KeyHandle
);
3414 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3415 Attributes
|= OBJ_OPENLINK
;
3417 if (lpSubKey
!= NULL
)
3418 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3420 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3422 InitializeObjectAttributes(&ObjectAttributes
,
3428 Status
= NtOpenKey((PHANDLE
)phkResult
,
3432 if (Status
== STATUS_DATATYPE_MISALIGNMENT
)
3435 UNICODE_STRING AlignedString
;
3437 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
3440 if (NT_SUCCESS(Status
))
3442 /* Try again with aligned parameters */
3443 InitializeObjectAttributes(&ObjectAttributes
,
3449 Status
= NtOpenKey(&hAligned
,
3453 RtlFreeUnicodeString(&AlignedString
);
3455 if (NT_SUCCESS(Status
))
3456 *phkResult
= hAligned
;
3460 /* Restore the original error */
3461 Status
= STATUS_DATATYPE_MISALIGNMENT
;
3465 if (!NT_SUCCESS(Status
))
3467 ErrorCode
= RtlNtStatusToDosError(Status
);
3471 ClosePredefKey(KeyHandle
);
3477 /************************************************************************
3478 * RegOpenUserClassesRoot
3483 RegOpenUserClassesRoot(IN HANDLE hToken
,
3485 IN REGSAM samDesired
,
3486 OUT PHKEY phkResult
)
3488 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3489 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3490 PTOKEN_USER TokenUserData
;
3491 ULONG RequiredLength
;
3492 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3493 OBJECT_ATTRIBUTES ObjectAttributes
;
3496 /* check parameters */
3497 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3499 return ERROR_INVALID_PARAMETER
;
3503 * Get the user sid from the token
3507 /* determine how much memory we need */
3508 Status
= NtQueryInformationToken(hToken
,
3513 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3515 /* NOTE - as opposed to all other registry functions windows does indeed
3516 change the last error code in case the caller supplied a invalid
3517 handle for example! */
3518 return RtlNtStatusToDosError(Status
);
3520 RegInitialize(); /* HACK until delay-loading is implemented */
3521 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3524 if (TokenUserData
== NULL
)
3526 return ERROR_NOT_ENOUGH_MEMORY
;
3529 /* attempt to read the information */
3530 Status
= NtQueryInformationToken(hToken
,
3535 if (!NT_SUCCESS(Status
))
3537 RtlFreeHeap(ProcessHeap
,
3540 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3542 /* the information appears to have changed?! try again */
3546 /* NOTE - as opposed to all other registry functions windows does indeed
3547 change the last error code in case the caller supplied a invalid
3548 handle for example! */
3549 return RtlNtStatusToDosError(Status
);
3553 * Build the absolute path for the user's registry in the form
3554 * "\Registry\User\<SID>_Classes"
3556 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3557 TokenUserData
->User
.Sid
,
3560 /* we don't need the user data anymore, free it */
3561 RtlFreeHeap(ProcessHeap
,
3565 if (!NT_SUCCESS(Status
))
3567 return RtlNtStatusToDosError(Status
);
3570 /* allocate enough memory for the entire key string */
3571 UserClassesKeyRoot
.Length
= 0;
3572 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3573 sizeof(UserClassesKeyPrefix
) +
3574 sizeof(UserClassesKeySuffix
);
3575 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3577 UserClassesKeyRoot
.MaximumLength
);
3578 if (UserClassesKeyRoot
.Buffer
== NULL
)
3580 RtlFreeUnicodeString(&UserSidString
);
3581 return RtlNtStatusToDosError(Status
);
3584 /* build the string */
3585 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3586 UserClassesKeyPrefix
);
3587 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3589 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3590 UserClassesKeySuffix
);
3592 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3597 InitializeObjectAttributes(&ObjectAttributes
,
3598 &UserClassesKeyRoot
,
3599 OBJ_CASE_INSENSITIVE
,
3603 Status
= NtOpenKey((PHANDLE
)phkResult
,
3607 RtlFreeUnicodeString(&UserSidString
);
3608 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3610 if (!NT_SUCCESS(Status
))
3612 return RtlNtStatusToDosError(Status
);
3615 return ERROR_SUCCESS
;
3619 /************************************************************************
3625 RegQueryInfoKeyA(HKEY hKey
,
3630 LPDWORD lpcMaxSubKeyLen
,
3631 LPDWORD lpcMaxClassLen
,
3633 LPDWORD lpcMaxValueNameLen
,
3634 LPDWORD lpcMaxValueLen
,
3635 LPDWORD lpcbSecurityDescriptor
,
3636 PFILETIME lpftLastWriteTime
)
3638 WCHAR ClassName
[MAX_PATH
];
3639 UNICODE_STRING UnicodeString
;
3640 ANSI_STRING AnsiString
;
3645 if ((lpClass
) && (!lpcClass
))
3647 return ERROR_INVALID_PARAMETER
;
3650 RtlInitUnicodeString(&UnicodeString
,
3652 if (lpClass
!= NULL
)
3654 RtlInitEmptyUnicodeString(&UnicodeString
,
3657 cClass
= sizeof(ClassName
) / sizeof(WCHAR
);
3660 ErrorCode
= RegQueryInfoKeyW(hKey
,
3661 UnicodeString
.Buffer
,
3670 lpcbSecurityDescriptor
,
3672 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3679 RtlInitEmptyAnsiString(&AnsiString
, lpClass
, *lpcClass
);
3680 UnicodeString
.Length
= cClass
* sizeof(WCHAR
);
3681 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
3684 ErrorCode
= RtlNtStatusToDosError(Status
);
3685 cClass
= AnsiString
.Length
;
3686 lpClass
[cClass
] = ANSI_NULL
;
3689 if (lpcClass
!= NULL
)
3698 /************************************************************************
3704 RegQueryInfoKeyW(HKEY hKey
,
3709 LPDWORD lpcMaxSubKeyLen
,
3710 LPDWORD lpcMaxClassLen
,
3712 LPDWORD lpcMaxValueNameLen
,
3713 LPDWORD lpcMaxValueLen
,
3714 LPDWORD lpcbSecurityDescriptor
,
3715 PFILETIME lpftLastWriteTime
)
3717 KEY_FULL_INFORMATION FullInfoBuffer
;
3718 PKEY_FULL_INFORMATION FullInfo
;
3720 ULONG ClassLength
= 0;
3724 LONG ErrorCode
= ERROR_SUCCESS
;
3726 if ((lpClass
) && (!lpcClass
))
3728 return ERROR_INVALID_PARAMETER
;
3731 Status
= MapDefaultKey(&KeyHandle
,
3733 if (!NT_SUCCESS(Status
))
3735 return RtlNtStatusToDosError(Status
);
3738 if (lpClass
!= NULL
)
3742 ClassLength
= min(*lpcClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3749 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3750 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3753 if (FullInfo
== NULL
)
3755 ErrorCode
= ERROR_OUTOFMEMORY
;
3761 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3762 FullInfo
= &FullInfoBuffer
;
3765 if (lpcbSecurityDescriptor
!= NULL
)
3766 *lpcbSecurityDescriptor
= 0;
3768 Status
= NtQueryKey(KeyHandle
,
3773 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3774 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
3776 ErrorCode
= RtlNtStatusToDosError(Status
);
3780 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3781 if (lpcSubKeys
!= NULL
)
3783 *lpcSubKeys
= FullInfo
->SubKeys
;
3786 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3787 if (lpcMaxSubKeyLen
!= NULL
)
3789 *lpcMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
);
3792 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3793 if (lpcMaxClassLen
!= NULL
)
3795 *lpcMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
);
3798 TRACE("Values %lu\n", FullInfo
->Values
);
3799 if (lpcValues
!= NULL
)
3801 *lpcValues
= FullInfo
->Values
;
3804 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3805 if (lpcMaxValueNameLen
!= NULL
)
3807 *lpcMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
);
3810 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3811 if (lpcMaxValueLen
!= NULL
)
3813 *lpcMaxValueLen
= FullInfo
->MaxValueDataLen
;
3816 if (lpcbSecurityDescriptor
!= NULL
)
3818 Status
= NtQuerySecurityObject(KeyHandle
,
3819 OWNER_SECURITY_INFORMATION
|
3820 GROUP_SECURITY_INFORMATION
|
3821 DACL_SECURITY_INFORMATION
,
3824 lpcbSecurityDescriptor
);
3825 TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status
);
3828 if (lpftLastWriteTime
!= NULL
)
3830 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3831 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3834 if (lpClass
!= NULL
)
3841 if (FullInfo
->ClassLength
> ClassLength
)
3843 ErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
3847 RtlCopyMemory(lpClass
,
3849 FullInfo
->ClassLength
);
3850 lpClass
[FullInfo
->ClassLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3854 if (lpcClass
!= NULL
)
3856 *lpcClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3860 if (lpClass
!= NULL
)
3862 RtlFreeHeap(ProcessHeap
,
3867 ClosePredefKey(KeyHandle
);
3873 /************************************************************************
3874 * RegQueryMultipleValuesA
3879 RegQueryMultipleValuesA(HKEY hKey
,
3886 DWORD maxBytes
= *ldwTotsize
;
3887 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3890 if (maxBytes
>= (1024*1024))
3891 return ERROR_MORE_DATA
;
3895 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3896 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3898 for (i
= 0; i
< num_vals
; i
++)
3900 val_list
[i
].ve_valuelen
= 0;
3901 ErrorCode
= RegQueryValueExA(hKey
,
3902 val_list
[i
].ve_valuename
,
3906 &val_list
[i
].ve_valuelen
);
3907 if (ErrorCode
!= ERROR_SUCCESS
)
3912 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3914 ErrorCode
= RegQueryValueExA(hKey
,
3915 val_list
[i
].ve_valuename
,
3917 &val_list
[i
].ve_type
,
3919 &val_list
[i
].ve_valuelen
);
3920 if (ErrorCode
!= ERROR_SUCCESS
)
3925 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3927 bufptr
+= val_list
[i
].ve_valuelen
;
3930 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3933 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3937 /************************************************************************
3938 * RegQueryMultipleValuesW
3943 RegQueryMultipleValuesW(HKEY hKey
,
3950 DWORD maxBytes
= *ldwTotsize
;
3951 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3954 if (maxBytes
>= (1024*1024))
3955 return ERROR_MORE_DATA
;
3959 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3960 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3962 for (i
= 0; i
< num_vals
; i
++)
3964 val_list
[i
].ve_valuelen
= 0;
3965 ErrorCode
= RegQueryValueExW(hKey
,
3966 val_list
[i
].ve_valuename
,
3970 &val_list
[i
].ve_valuelen
);
3971 if (ErrorCode
!= ERROR_SUCCESS
)
3976 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3978 ErrorCode
= RegQueryValueExW(hKey
,
3979 val_list
[i
].ve_valuename
,
3981 &val_list
[i
].ve_type
,
3983 &val_list
[i
].ve_valuelen
);
3984 if (ErrorCode
!= ERROR_SUCCESS
)
3989 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3991 bufptr
+= val_list
[i
].ve_valuelen
;
3994 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3997 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
4001 /************************************************************************
4002 * RegQueryReflectionKey
4007 RegQueryReflectionKey(IN HKEY hBase
,
4008 OUT BOOL
* bIsReflectionDisabled
)
4010 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4011 hBase
, bIsReflectionDisabled
);
4012 return ERROR_CALL_NOT_IMPLEMENTED
;
4016 /******************************************************************************
4017 * RegQueryValueExA [ADVAPI32.@]
4019 * Get the type and contents of a specified value under with a key.
4022 * hkey [I] Handle of the key to query
4023 * name [I] Name of value under hkey to query
4024 * reserved [I] Reserved - must be NULL
4025 * type [O] Destination for the value type, or NULL if not required
4026 * data [O] Destination for the values contents, or NULL if not required
4027 * count [I/O] Size of data, updated with the number of bytes returned
4030 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4031 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4032 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4033 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4036 * MSDN states that if data is too small it is partially filled. In reality
4037 * it remains untouched.
4044 _In_ LPDWORD reserved
,
4045 _Out_opt_ LPDWORD type
,
4046 _Out_opt_ LPBYTE data
,
4047 _Inout_opt_ LPDWORD count
)
4049 UNICODE_STRING nameW
;
4052 DWORD BufferSize
= 0;
4054 CHAR
* DataStr
= (CHAR
*)data
;
4057 /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
4058 if ((data
&& !count
) || reserved
)
4059 return ERROR_INVALID_PARAMETER
;
4063 if (!RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
4064 return ERROR_NOT_ENOUGH_MEMORY
;
4067 RtlInitEmptyUnicodeString(&nameW
, NULL
, 0);
4069 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, NULL
, &LocalType
, NULL
, &BufferSize
);
4070 if (ErrorCode
!= ERROR_SUCCESS
)
4072 if ((!data
) && count
)
4074 RtlFreeUnicodeString(&nameW
);
4078 /* See if we can directly handle the call without caring for conversion */
4079 if (!is_string(LocalType
) || !count
)
4081 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, reserved
, type
, data
, count
);
4082 RtlFreeUnicodeString(&nameW
);
4086 /* Allocate a unicode string to get the data */
4087 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
4090 RtlFreeUnicodeString(&nameW
);
4091 return ERROR_NOT_ENOUGH_MEMORY
;
4094 ErrorCode
= RegQueryValueExW(hkeyorg
, nameW
.Buffer
, reserved
, type
, (LPBYTE
)Buffer
, &BufferSize
);
4095 if (ErrorCode
!= ERROR_SUCCESS
)
4097 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4098 RtlFreeUnicodeString(&nameW
);
4102 /* We don't need this anymore */
4103 RtlFreeUnicodeString(&nameW
);
4105 DataLength
= *count
;
4106 RtlUnicodeToMultiByteSize(count
, Buffer
, BufferSize
);
4108 if ((!data
) || (DataLength
< *count
))
4110 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4111 return data
? ERROR_MORE_DATA
: ERROR_SUCCESS
;
4114 /* We can finally do the conversion */
4115 RtlUnicodeToMultiByteN(DataStr
, DataLength
, NULL
, Buffer
, BufferSize
);
4117 /* NULL-terminate if there is enough room */
4118 if ((DataLength
> *count
) && (DataStr
[*count
- 1] != '\0'))
4119 DataStr
[*count
] = '\0';
4121 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
4123 return ERROR_SUCCESS
;
4127 /************************************************************************
4137 _In_ LPDWORD reserved
,
4144 UNICODE_STRING name_str
;
4146 char buffer
[256], *buf_ptr
= buffer
;
4147 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4148 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4150 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4151 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4152 (count
&& data
) ? *count
: 0 );
4154 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4156 status
= MapDefaultKey(&hkey
, hkeyorg
);
4157 if (!NT_SUCCESS(status
))
4159 return RtlNtStatusToDosError(status
);
4162 if (IsHKCRKey(hkey
))
4164 LONG ErrorCode
= QueryHKCRValue(hkey
, name
, reserved
, type
, data
, count
);
4165 ClosePredefKey(hkey
);
4169 RtlInitUnicodeString( &name_str
, name
);
4172 total_size
= min( sizeof(buffer
), *count
+ info_size
);
4174 total_size
= info_size
;
4177 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4178 buffer
, total_size
, &total_size
);
4180 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
)
4182 // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
4183 // On windows these conditions are likely to be side effects of the implementation...
4184 if (status
== STATUS_INVALID_HANDLE
&& hkey
)
4186 if (type
) *type
= REG_NONE
;
4187 if (count
) *count
= 0;
4189 else if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
4191 if (type
) *type
= REG_NONE
;
4192 if (data
== NULL
&& count
) *count
= 0;
4199 /* retry with a dynamically allocated buffer */
4200 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4202 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4203 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4205 ClosePredefKey(hkey
);
4206 return ERROR_NOT_ENOUGH_MEMORY
;
4208 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4209 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4210 buf_ptr
, total_size
, &total_size
);
4213 if (NT_SUCCESS(status
))
4215 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4216 /* if the type is REG_SZ and data is not 0-terminated
4217 * and there is enough space in the buffer NT appends a \0 */
4218 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4220 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4221 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4224 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4226 else status
= STATUS_SUCCESS
;
4228 if (type
) *type
= info
->Type
;
4229 if (count
) *count
= total_size
- info_size
;
4232 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4233 ClosePredefKey(hkey
);
4234 return RtlNtStatusToDosError(status
);
4238 /************************************************************************
4243 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4248 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4250 if (name
&& name
[0])
4252 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4254 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4255 if (subkey
!= hkey
) RegCloseKey( subkey
);
4256 if (ret
== ERROR_FILE_NOT_FOUND
)
4258 /* return empty string if default value not found */
4259 if (data
) *data
= 0;
4260 if (count
) *count
= 1;
4261 ret
= ERROR_SUCCESS
;
4267 /************************************************************************
4272 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4277 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4280 return ERROR_INVALID_HANDLE
;
4282 if (name
&& name
[0])
4284 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4285 if (ret
!= ERROR_SUCCESS
)
4291 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4295 RegCloseKey( subkey
);
4298 if (ret
== ERROR_FILE_NOT_FOUND
)
4300 /* return empty string if default value not found */
4304 *count
= sizeof(WCHAR
);
4305 ret
= ERROR_SUCCESS
;
4311 /************************************************************************
4317 RegReplaceKeyA(HKEY hKey
,
4322 UNICODE_STRING SubKey
;
4323 UNICODE_STRING NewFile
;
4324 UNICODE_STRING OldFile
;
4327 RtlInitEmptyUnicodeString(&SubKey
, NULL
, 0);
4328 RtlInitEmptyUnicodeString(&OldFile
, NULL
, 0);
4329 RtlInitEmptyUnicodeString(&NewFile
, NULL
, 0);
4333 if (!RtlCreateUnicodeStringFromAsciiz(&SubKey
, lpSubKey
))
4335 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4342 if (!RtlCreateUnicodeStringFromAsciiz(&OldFile
, lpOldFile
))
4344 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4351 if (!RtlCreateUnicodeStringFromAsciiz(&NewFile
, lpNewFile
))
4353 ErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
4358 ErrorCode
= RegReplaceKeyW(hKey
,
4364 RtlFreeUnicodeString(&OldFile
);
4365 RtlFreeUnicodeString(&NewFile
);
4366 RtlFreeUnicodeString(&SubKey
);
4372 /************************************************************************
4378 RegReplaceKeyW(HKEY hKey
,
4383 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4384 OBJECT_ATTRIBUTES NewObjectAttributes
;
4385 OBJECT_ATTRIBUTES OldObjectAttributes
;
4386 UNICODE_STRING SubKeyName
;
4387 UNICODE_STRING NewFileName
;
4388 UNICODE_STRING OldFileName
;
4389 BOOLEAN CloseRealKey
;
4390 HANDLE RealKeyHandle
;
4393 LONG ErrorCode
= ERROR_SUCCESS
;
4395 if (hKey
== HKEY_PERFORMANCE_DATA
)
4397 return ERROR_INVALID_HANDLE
;
4400 Status
= MapDefaultKey(&KeyHandle
,
4402 if (!NT_SUCCESS(Status
))
4404 return RtlNtStatusToDosError(Status
);
4407 /* Open the real key */
4408 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4410 RtlInitUnicodeString(&SubKeyName
,
4412 InitializeObjectAttributes(&KeyObjectAttributes
,
4414 OBJ_CASE_INSENSITIVE
,
4417 Status
= NtOpenKey(&RealKeyHandle
,
4419 &KeyObjectAttributes
);
4420 if (!NT_SUCCESS(Status
))
4422 ErrorCode
= RtlNtStatusToDosError(Status
);
4426 CloseRealKey
= TRUE
;
4430 RealKeyHandle
= KeyHandle
;
4431 CloseRealKey
= FALSE
;
4434 /* Convert new file name */
4435 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4442 NtClose(RealKeyHandle
);
4445 ErrorCode
= ERROR_INVALID_PARAMETER
;
4449 InitializeObjectAttributes(&NewObjectAttributes
,
4451 OBJ_CASE_INSENSITIVE
,
4455 /* Convert old file name */
4456 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4461 RtlFreeHeap(RtlGetProcessHeap (),
4463 NewFileName
.Buffer
);
4466 NtClose(RealKeyHandle
);
4469 ErrorCode
= ERROR_INVALID_PARAMETER
;
4473 InitializeObjectAttributes(&OldObjectAttributes
,
4475 OBJ_CASE_INSENSITIVE
,
4479 Status
= NtReplaceKey(&NewObjectAttributes
,
4481 &OldObjectAttributes
);
4483 RtlFreeHeap(RtlGetProcessHeap(),
4485 OldFileName
.Buffer
);
4486 RtlFreeHeap(RtlGetProcessHeap(),
4488 NewFileName
.Buffer
);
4492 NtClose(RealKeyHandle
);
4495 if (!NT_SUCCESS(Status
))
4497 return RtlNtStatusToDosError(Status
);
4501 ClosePredefKey(KeyHandle
);
4507 /************************************************************************
4513 RegRestoreKeyA(HKEY hKey
,
4517 UNICODE_STRING FileName
;
4522 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4523 return ERROR_NOT_ENOUGH_MEMORY
;
4526 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4528 ErrorCode
= RegRestoreKeyW(hKey
,
4532 RtlFreeUnicodeString(&FileName
);
4538 /************************************************************************
4544 RegRestoreKeyW(HKEY hKey
,
4548 OBJECT_ATTRIBUTES ObjectAttributes
;
4549 IO_STATUS_BLOCK IoStatusBlock
;
4550 UNICODE_STRING FileName
;
4555 if (hKey
== HKEY_PERFORMANCE_DATA
)
4557 return ERROR_INVALID_HANDLE
;
4560 Status
= MapDefaultKey(&KeyHandle
,
4562 if (!NT_SUCCESS(Status
))
4564 return RtlNtStatusToDosError(Status
);
4567 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4572 Status
= STATUS_INVALID_PARAMETER
;
4576 InitializeObjectAttributes(&ObjectAttributes
,
4578 OBJ_CASE_INSENSITIVE
,
4582 Status
= NtOpenFile(&FileHandle
,
4587 FILE_SYNCHRONOUS_IO_NONALERT
);
4588 RtlFreeHeap(RtlGetProcessHeap(),
4591 if (!NT_SUCCESS(Status
))
4596 Status
= NtRestoreKey(KeyHandle
,
4599 NtClose (FileHandle
);
4602 ClosePredefKey(KeyHandle
);
4604 if (!NT_SUCCESS(Status
))
4606 return RtlNtStatusToDosError(Status
);
4609 return ERROR_SUCCESS
;
4613 /************************************************************************
4619 RegSaveKeyA(HKEY hKey
,
4621 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4623 UNICODE_STRING FileName
;
4628 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4629 return ERROR_NOT_ENOUGH_MEMORY
;
4632 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4634 ErrorCode
= RegSaveKeyW(hKey
,
4636 lpSecurityAttributes
);
4637 RtlFreeUnicodeString(&FileName
);
4643 /************************************************************************
4649 RegSaveKeyW(HKEY hKey
,
4651 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4653 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4654 OBJECT_ATTRIBUTES ObjectAttributes
;
4655 UNICODE_STRING FileName
;
4656 IO_STATUS_BLOCK IoStatusBlock
;
4661 Status
= MapDefaultKey(&KeyHandle
,
4663 if (!NT_SUCCESS(Status
))
4665 return RtlNtStatusToDosError(Status
);
4668 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4673 Status
= STATUS_INVALID_PARAMETER
;
4677 if (lpSecurityAttributes
!= NULL
)
4679 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4682 InitializeObjectAttributes(&ObjectAttributes
,
4684 OBJ_CASE_INSENSITIVE
,
4686 SecurityDescriptor
);
4687 Status
= NtCreateFile(&FileHandle
,
4688 GENERIC_WRITE
| SYNCHRONIZE
,
4692 FILE_ATTRIBUTE_NORMAL
,
4695 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4698 RtlFreeHeap(RtlGetProcessHeap(),
4701 if (!NT_SUCCESS(Status
))
4706 Status
= NtSaveKey(KeyHandle
,
4708 NtClose (FileHandle
);
4711 ClosePredefKey(KeyHandle
);
4713 if (!NT_SUCCESS(Status
))
4715 return RtlNtStatusToDosError(Status
);
4718 return ERROR_SUCCESS
;
4722 /************************************************************************
4729 RegSaveKeyExA(HKEY hKey
,
4731 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4734 UNICODE_STRING FileName
;
4739 if (!RtlCreateUnicodeStringFromAsciiz(&FileName
, lpFile
))
4740 return ERROR_NOT_ENOUGH_MEMORY
;
4743 RtlInitEmptyUnicodeString(&FileName
, NULL
, 0);
4745 ErrorCode
= RegSaveKeyExW(hKey
,
4747 lpSecurityAttributes
,
4749 RtlFreeUnicodeString(&FileName
);
4755 /************************************************************************
4762 RegSaveKeyExW(HKEY hKey
,
4764 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4769 case REG_STANDARD_FORMAT
:
4770 case REG_LATEST_FORMAT
:
4771 case REG_NO_COMPRESSION
:
4774 return ERROR_INVALID_PARAMETER
;
4777 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4779 return RegSaveKeyW(hKey
,
4781 lpSecurityAttributes
);
4785 /************************************************************************
4791 RegSetKeySecurity(HKEY hKey
,
4792 SECURITY_INFORMATION SecurityInformation
,
4793 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4798 if (hKey
== HKEY_PERFORMANCE_DATA
)
4800 return ERROR_INVALID_HANDLE
;
4803 Status
= MapDefaultKey(&KeyHandle
,
4805 if (!NT_SUCCESS(Status
))
4807 return RtlNtStatusToDosError(Status
);
4810 Status
= NtSetSecurityObject(KeyHandle
,
4811 SecurityInformation
,
4812 pSecurityDescriptor
);
4814 ClosePredefKey(KeyHandle
);
4816 if (!NT_SUCCESS(Status
))
4818 return RtlNtStatusToDosError(Status
);
4821 return ERROR_SUCCESS
;
4825 /************************************************************************
4831 RegSetValueExA(HKEY hKey
,
4838 UNICODE_STRING ValueName
;
4840 ANSI_STRING AnsiString
;
4841 UNICODE_STRING Data
;
4847 /* Convert SubKey name to Unicode */
4848 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4851 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4854 return ERROR_NOT_ENOUGH_MEMORY
;
4858 ValueName
.Buffer
= NULL
;
4861 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4864 if (is_string(dwType
) && (cbData
!= 0))
4866 /* Convert ANSI string Data to Unicode */
4867 /* If last character NOT zero then increment length */
4868 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4869 AnsiString
.Buffer
= (PSTR
)lpData
;
4870 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4871 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4872 Status
= RtlAnsiStringToUnicodeString(&Data
,
4876 if (!NT_SUCCESS(Status
))
4878 if (pValueName
!= NULL
)
4879 RtlFreeUnicodeString(&ValueName
);
4881 return RtlNtStatusToDosError(Status
);
4883 pData
= (LPBYTE
)Data
.Buffer
;
4884 DataSize
= cbData
* sizeof(WCHAR
);
4889 pData
= (LPBYTE
)lpData
;
4893 ErrorCode
= RegSetValueExW(hKey
,
4900 if (pValueName
!= NULL
)
4901 RtlFreeUnicodeString(&ValueName
);
4903 if (Data
.Buffer
!= NULL
)
4904 RtlFreeUnicodeString(&Data
);
4910 /************************************************************************
4919 _In_ LPCWSTR lpValueName
,
4920 _In_ DWORD Reserved
,
4922 _In_ CONST BYTE
* lpData
,
4925 UNICODE_STRING ValueName
;
4929 Status
= MapDefaultKey(&KeyHandle
,
4931 if (!NT_SUCCESS(Status
))
4933 return RtlNtStatusToDosError(Status
);
4936 if (IsHKCRKey(KeyHandle
))
4938 LONG ErrorCode
= SetHKCRValue(KeyHandle
, lpValueName
, Reserved
, dwType
, lpData
, cbData
);
4939 ClosePredefKey(KeyHandle
);
4943 if (is_string(dwType
) && (cbData
!= 0))
4945 PWSTR pwsData
= (PWSTR
)lpData
;
4949 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4950 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4952 /* Increment length if last character is not zero and next is zero */
4953 cbData
+= sizeof(WCHAR
);
4956 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4958 ClosePredefKey(KeyHandle
);
4959 return ERROR_NOACCESS
;
4964 RtlInitUnicodeString(&ValueName
, lpValueName
);
4966 Status
= NtSetValueKey(KeyHandle
,
4973 ClosePredefKey(KeyHandle
);
4975 if (!NT_SUCCESS(Status
))
4977 return RtlNtStatusToDosError(Status
);
4980 return ERROR_SUCCESS
;
4984 /************************************************************************
4990 RegSetValueA(HKEY hKeyOriginal
,
5001 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
5003 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
5005 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
5006 if (!NT_SUCCESS(Status
))
5008 return RtlNtStatusToDosError (Status
);
5012 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5014 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
5015 if (ret
!= ERROR_SUCCESS
)
5019 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
5021 RegCloseKey(subkey
);
5024 ClosePredefKey(hKey
);
5030 /************************************************************************
5036 RegSetValueW(HKEY hKeyOriginal
,
5047 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
5049 if (dwType
!= REG_SZ
|| !lpData
)
5050 return ERROR_INVALID_PARAMETER
;
5052 Status
= MapDefaultKey(&hKey
,
5054 if (!NT_SUCCESS(Status
))
5056 return RtlNtStatusToDosError(Status
);
5060 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5062 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
5063 if (ret
!= ERROR_SUCCESS
)
5067 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
5068 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
5070 RegCloseKey(subkey
);
5073 ClosePredefKey(hKey
);
5079 /************************************************************************
5085 RegUnLoadKeyA(HKEY hKey
,
5088 UNICODE_STRING KeyName
;
5093 if (!RtlCreateUnicodeStringFromAsciiz(&KeyName
, lpSubKey
))
5094 return ERROR_NOT_ENOUGH_MEMORY
;
5097 RtlInitEmptyUnicodeString(&KeyName
, NULL
, 0);
5099 ErrorCode
= RegUnLoadKeyW(hKey
,
5102 RtlFreeUnicodeString (&KeyName
);
5108 /************************************************************************
5114 RegUnLoadKeyW(HKEY hKey
,
5117 OBJECT_ATTRIBUTES ObjectAttributes
;
5118 UNICODE_STRING KeyName
;
5122 if (hKey
== HKEY_PERFORMANCE_DATA
)
5124 return ERROR_INVALID_HANDLE
;
5127 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5128 if (!NT_SUCCESS(Status
))
5130 return RtlNtStatusToDosError(Status
);
5133 RtlInitUnicodeString(&KeyName
,
5136 InitializeObjectAttributes(&ObjectAttributes
,
5138 OBJ_CASE_INSENSITIVE
,
5142 Status
= NtUnloadKey(&ObjectAttributes
);
5144 ClosePredefKey(KeyHandle
);
5146 if (!NT_SUCCESS(Status
))
5148 return RtlNtStatusToDosError(Status
);
5151 return ERROR_SUCCESS
;
5155 /******************************************************************************
5156 * load_string [Internal]
5158 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5159 * avoid importing user32, which is higher level than advapi32. Helper for
5162 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5169 /* Negative values have to be inverted. */
5170 if (HIWORD(resId
) == 0xffff)
5171 resId
= (UINT
)(-((INT
)resId
));
5173 /* Load the resource into memory and get a pointer to it. */
5174 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5175 if (!hResource
) return 0;
5176 hMemory
= LoadResource(hModule
, hResource
);
5177 if (!hMemory
) return 0;
5178 pString
= LockResource(hMemory
);
5180 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5181 idxString
= resId
& 0xf;
5182 while (idxString
--) pString
+= *pString
+ 1;
5184 /* If no buffer is given, return length of the string. */
5185 if (!pwszBuffer
) return *pString
;
5187 /* Else copy over the string, respecting the buffer size. */
5188 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5191 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5192 pwszBuffer
[cMaxChars
] = L
'\0';
5199 /************************************************************************
5205 RegLoadMUIStringW(IN HKEY hKey
,
5206 IN LPCWSTR pszValue OPTIONAL
,
5207 OUT LPWSTR pszOutBuf
,
5209 OUT LPDWORD pcbData OPTIONAL
,
5211 IN LPCWSTR pszDirectory OPTIONAL
)
5213 DWORD dwValueType
, cbData
;
5214 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5217 /* Parameter sanity checks. */
5218 if (!hKey
|| !pszOutBuf
)
5219 return ERROR_INVALID_PARAMETER
;
5221 if (pszDirectory
&& *pszDirectory
)
5223 FIXME("BaseDir parameter not yet supported!\n");
5224 return ERROR_INVALID_PARAMETER
;
5227 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5228 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5229 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5230 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5232 result
= ERROR_FILE_NOT_FOUND
;
5235 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5236 if (!pwszTempBuffer
)
5238 result
= ERROR_NOT_ENOUGH_MEMORY
;
5241 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5242 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5244 /* Expand environment variables, if appropriate, or copy the original string over. */
5245 if (dwValueType
== REG_EXPAND_SZ
)
5247 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5248 if (!cbData
) goto cleanup
;
5249 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5250 if (!pwszExpandedBuffer
)
5252 result
= ERROR_NOT_ENOUGH_MEMORY
;
5255 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5259 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5260 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5263 /* If the value references a resource based string, parse the value and load the string.
5264 * Else just copy over the original value. */
5265 result
= ERROR_SUCCESS
;
5266 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5268 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5272 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5276 /* Format of the expanded value is 'path_to_dll,-resId' */
5277 if (!pComma
|| pComma
[1] != L
'-')
5279 result
= ERROR_BADKEY
;
5283 uiStringId
= _wtoi(pComma
+2);
5286 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5287 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5288 result
= ERROR_BADKEY
;
5289 FreeLibrary(hModule
);
5293 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5294 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5299 /************************************************************************
5305 RegLoadMUIStringA(IN HKEY hKey
,
5306 IN LPCSTR pszValue OPTIONAL
,
5307 OUT LPSTR pszOutBuf
,
5309 OUT LPDWORD pcbData OPTIONAL
,
5311 IN LPCSTR pszDirectory OPTIONAL
)
5313 UNICODE_STRING valueW
, baseDirW
;
5315 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5318 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5319 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5320 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5321 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5323 result
= ERROR_NOT_ENOUGH_MEMORY
;
5327 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5330 if (result
== ERROR_SUCCESS
)
5332 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5338 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5339 RtlFreeUnicodeString(&baseDirW
);
5340 RtlFreeUnicodeString(&valueW
);