2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
17 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
19 /* DEFINES ******************************************************************/
21 #define MAX_DEFAULT_HANDLES 6
22 #define REG_MAX_NAME_SIZE 256
23 #define REG_MAX_DATA_SIZE 2048
25 /* GLOBALS ******************************************************************/
27 static RTL_CRITICAL_SECTION HandleTableCS
;
28 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
29 static HANDLE ProcessHeap
;
30 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
31 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
32 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
34 /* PROTOTYPES ***************************************************************/
36 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
37 static VOID
CloseDefaultKeys(VOID
);
38 #define ClosePredefKey(Handle) \
39 if ((ULONG_PTR)Handle & 0x1) { \
42 #define IsPredefKey(HKey) \
43 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
44 #define GetPredefKeyIndex(HKey) \
45 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
47 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
48 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
49 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
53 /* FUNCTIONS ****************************************************************/
54 /* check if value type needs string conversion (Ansi<->Unicode) */
55 __inline
static int is_string( DWORD type
)
57 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
60 /************************************************************************
61 * RegInitDefaultHandles
66 TRACE("RegInitialize()\n");
71 ProcessHeap
= RtlGetProcessHeap();
72 RtlZeroMemory(DefaultHandleTable
,
73 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
74 RtlInitializeCriticalSection(&HandleTableCS
);
76 DllInitialized
= TRUE
;
83 /************************************************************************
89 TRACE("RegCleanup()\n");
92 RtlDeleteCriticalSection(&HandleTableCS
);
99 OpenPredefinedKey(IN ULONG Index
,
106 case 0: /* HKEY_CLASSES_ROOT */
107 Status
= OpenClassesRootKey (Handle
);
110 case 1: /* HKEY_CURRENT_USER */
111 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
115 case 2: /* HKEY_LOCAL_MACHINE */
116 Status
= OpenLocalMachineKey (Handle
);
119 case 3: /* HKEY_USERS */
120 Status
= OpenUsersKey (Handle
);
123 case 4: /* HKEY_PERFORMANCE_DATA */
124 Status
= OpenPerformanceDataKey (Handle
);
128 case 5: /* HKEY_CURRENT_CONFIG */
129 Status
= OpenCurrentConfigKey (Handle
);
132 case 6: /* HKEY_DYN_DATA */
133 Status
= STATUS_NOT_IMPLEMENTED
;
137 WARN("MapDefaultHandle() no handle creator\n");
138 Status
= STATUS_INVALID_PARAMETER
;
147 MapDefaultKey(OUT PHANDLE RealKey
,
152 BOOLEAN DoOpen
, DefDisabled
;
153 NTSTATUS Status
= STATUS_SUCCESS
;
155 TRACE("MapDefaultKey (Key %x)\n", Key
);
157 if (!IsPredefKey(Key
))
159 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
160 return STATUS_SUCCESS
;
163 /* Handle special cases here */
164 Index
= GetPredefKeyIndex(Key
);
165 if (Index
>= MAX_DEFAULT_HANDLES
)
167 return STATUS_INVALID_PARAMETER
;
169 RegInitialize(); /* HACK until delay-loading is implemented */
170 RtlEnterCriticalSection (&HandleTableCS
);
172 if (Key
== HKEY_CURRENT_USER
)
173 DefDisabled
= DefaultHandleHKUDisabled
;
175 DefDisabled
= DefaultHandlesDisabled
;
179 Handle
= &DefaultHandleTable
[Index
];
180 DoOpen
= (*Handle
== NULL
);
190 /* create/open the default handle */
191 Status
= OpenPredefinedKey(Index
,
195 if (NT_SUCCESS(Status
))
200 *(PULONG_PTR
)Handle
|= 0x1;
203 RtlLeaveCriticalSection (&HandleTableCS
);
210 CloseDefaultKeys(VOID
)
213 RegInitialize(); /* HACK until delay-loading is implemented */
214 RtlEnterCriticalSection(&HandleTableCS
);
216 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
218 if (DefaultHandleTable
[i
] != NULL
)
220 NtClose(DefaultHandleTable
[i
]);
221 DefaultHandleTable
[i
] = NULL
;
225 RtlLeaveCriticalSection(&HandleTableCS
);
230 OpenClassesRootKey(PHANDLE KeyHandle
)
232 OBJECT_ATTRIBUTES Attributes
;
233 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
235 TRACE("OpenClassesRootKey()\n");
237 InitializeObjectAttributes(&Attributes
,
239 OBJ_CASE_INSENSITIVE
,
242 return NtOpenKey(KeyHandle
,
249 OpenLocalMachineKey(PHANDLE KeyHandle
)
251 OBJECT_ATTRIBUTES Attributes
;
252 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
255 TRACE("OpenLocalMachineKey()\n");
257 InitializeObjectAttributes(&Attributes
,
259 OBJ_CASE_INSENSITIVE
,
262 Status
= NtOpenKey(KeyHandle
,
266 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
273 OpenUsersKey(PHANDLE KeyHandle
)
275 OBJECT_ATTRIBUTES Attributes
;
276 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
278 TRACE("OpenUsersKey()\n");
280 InitializeObjectAttributes(&Attributes
,
282 OBJ_CASE_INSENSITIVE
,
285 return NtOpenKey(KeyHandle
,
292 OpenCurrentConfigKey (PHANDLE KeyHandle
)
294 OBJECT_ATTRIBUTES Attributes
;
295 UNICODE_STRING KeyName
=
296 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
298 TRACE("OpenCurrentConfigKey()\n");
300 InitializeObjectAttributes(&Attributes
,
302 OBJ_CASE_INSENSITIVE
,
305 return NtOpenKey(KeyHandle
,
311 /************************************************************************
312 * RegDisablePredefinedCache
317 RegDisablePredefinedCache(VOID
)
319 RegInitialize(); /* HACK until delay-loading is implemented */
320 RtlEnterCriticalSection(&HandleTableCS
);
321 DefaultHandleHKUDisabled
= TRUE
;
322 RtlLeaveCriticalSection(&HandleTableCS
);
323 return ERROR_SUCCESS
;
327 /************************************************************************
328 * RegDisablePredefinedCacheEx
333 RegDisablePredefinedCacheEx(VOID
)
335 RegInitialize(); /* HACK until delay-loading is implemented */
336 RtlEnterCriticalSection(&HandleTableCS
);
337 DefaultHandlesDisabled
= TRUE
;
338 DefaultHandleHKUDisabled
= TRUE
;
339 RtlLeaveCriticalSection(&HandleTableCS
);
340 return ERROR_SUCCESS
;
344 /************************************************************************
345 * RegOverridePredefKey
350 RegOverridePredefKey(IN HKEY hKey
,
351 IN HKEY hNewHKey OPTIONAL
)
353 LONG ErrorCode
= ERROR_SUCCESS
;
355 if ((hKey
== HKEY_CLASSES_ROOT
||
356 hKey
== HKEY_CURRENT_CONFIG
||
357 hKey
== HKEY_CURRENT_USER
||
358 hKey
== HKEY_LOCAL_MACHINE
||
359 hKey
== HKEY_PERFORMANCE_DATA
||
360 hKey
== HKEY_USERS
) &&
361 !IsPredefKey(hNewHKey
))
366 Index
= GetPredefKeyIndex(hKey
);
367 Handle
= &DefaultHandleTable
[Index
];
369 if (hNewHKey
== NULL
)
371 /* restore the default mapping */
372 NTSTATUS Status
= OpenPredefinedKey(Index
,
374 if (!NT_SUCCESS(Status
))
376 return RtlNtStatusToDosError(Status
);
379 ASSERT(hNewHKey
!= NULL
);
381 RegInitialize(); /* HACK until delay-loading is implemented */
382 RtlEnterCriticalSection(&HandleTableCS
);
384 /* close the currently mapped handle if existing */
390 /* update the mapping */
393 RtlLeaveCriticalSection(&HandleTableCS
);
396 ErrorCode
= ERROR_INVALID_HANDLE
;
402 /************************************************************************
408 RegCloseKey(HKEY hKey
)
412 /* don't close null handle or a pseudo handle */
413 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
415 return ERROR_INVALID_HANDLE
;
418 Status
= NtClose(hKey
);
419 if (!NT_SUCCESS(Status
))
421 return RtlNtStatusToDosError(Status
);
424 return ERROR_SUCCESS
;
429 RegpCopyTree(IN HKEY hKeySrc
,
434 LIST_ENTRY ListEntry
;
437 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
439 LIST_ENTRY copyQueueHead
;
440 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
443 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
444 KEY_NODE_INFORMATION
*KeyNode
;
447 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
448 NTSTATUS Status
= STATUS_SUCCESS
;
449 NTSTATUS Status2
= STATUS_SUCCESS
;
451 InitializeListHead(©QueueHead
);
453 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
456 if (Info
.Buffer
== NULL
)
458 return STATUS_INSUFFICIENT_RESOURCES
;
461 copyKeys
= RtlAllocateHeap(ProcessHeap
,
463 sizeof(REGP_COPY_KEYS
));
464 if (copyKeys
!= NULL
)
466 copyKeys
->hKeySrc
= hKeySrc
;
467 copyKeys
->hKeyDest
= hKeyDest
;
468 InsertHeadList(©QueueHead
,
469 ©Keys
->ListEntry
);
471 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
475 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
479 /* enumerate all values and copy them */
483 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
485 KeyValueFullInformation
,
488 &BufferSizeRequired
);
489 if (NT_SUCCESS(Status2
))
491 UNICODE_STRING ValueName
;
494 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
495 ValueName
.Length
= Info
.KeyValue
->NameLength
;
496 ValueName
.MaximumLength
= ValueName
.Length
;
497 ValueName
.Buffer
= Info
.KeyValue
->Name
;
499 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
501 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
503 Info
.KeyValue
->TitleIndex
,
506 Info
.KeyValue
->DataLength
);
508 /* don't break, let's try to copy as many values as possible */
509 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
516 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
520 ASSERT(BufferSize
< BufferSizeRequired
);
522 Buffer
= RtlReAllocateHeap(ProcessHeap
,
528 Info
.Buffer
= Buffer
;
533 /* don't break, let's try to copy as many values as possible */
534 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
537 if (NT_SUCCESS(Status
))
545 /* break to avoid an infinite loop in case of denied access or
547 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
556 /* enumerate all subkeys and open and enqueue them */
560 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
565 &BufferSizeRequired
);
566 if (NT_SUCCESS(Status2
))
568 HANDLE KeyHandle
, NewKeyHandle
;
569 OBJECT_ATTRIBUTES ObjectAttributes
;
570 UNICODE_STRING SubKeyName
, ClassName
;
572 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
573 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
574 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
575 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
576 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
577 ClassName
.MaximumLength
= ClassName
.Length
;
578 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
580 /* open the subkey with sufficient rights */
582 InitializeObjectAttributes(&ObjectAttributes
,
584 OBJ_CASE_INSENSITIVE
,
588 Status2
= NtOpenKey(&KeyHandle
,
589 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
591 if (NT_SUCCESS(Status2
))
593 /* FIXME - attempt to query the security information */
595 InitializeObjectAttributes(&ObjectAttributes
,
597 OBJ_CASE_INSENSITIVE
,
601 Status2
= NtCreateKey(&NewKeyHandle
,
604 Info
.KeyNode
->TitleIndex
,
608 if (NT_SUCCESS(Status2
))
610 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
612 sizeof(REGP_COPY_KEYS
));
613 if (newCopyKeys
!= NULL
)
615 /* save the handles and enqueue the subkey */
616 newCopyKeys
->hKeySrc
= KeyHandle
;
617 newCopyKeys
->hKeyDest
= NewKeyHandle
;
618 InsertTailList(©QueueHead
,
619 &newCopyKeys
->ListEntry
);
624 NtClose(NewKeyHandle
);
626 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
635 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
642 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
646 ASSERT(BufferSize
< BufferSizeRequired
);
648 Buffer
= RtlReAllocateHeap(ProcessHeap
,
654 Info
.Buffer
= Buffer
;
659 /* don't break, let's try to copy as many keys as possible */
660 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
663 if (NT_SUCCESS(Status
))
671 /* break to avoid an infinite loop in case of denied access or
673 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
682 /* close the handles and remove the entry from the list */
683 if (copyKeys
->hKeySrc
!= hKeySrc
)
685 NtClose(copyKeys
->hKeySrc
);
687 if (copyKeys
->hKeyDest
!= hKeyDest
)
689 NtClose(copyKeys
->hKeyDest
);
692 RemoveEntryList(©Keys
->ListEntry
);
694 RtlFreeHeap(ProcessHeap
,
697 } while (!IsListEmpty(©QueueHead
));
700 Status
= STATUS_INSUFFICIENT_RESOURCES
;
702 RtlFreeHeap(ProcessHeap
,
710 /************************************************************************
716 RegCopyTreeW(IN HKEY hKeySrc
,
717 IN LPCWSTR lpSubKey OPTIONAL
,
720 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
723 Status
= MapDefaultKey(&KeyHandle
,
725 if (!NT_SUCCESS(Status
))
727 return RtlNtStatusToDosError(Status
);
730 Status
= MapDefaultKey(&DestKeyHandle
,
732 if (!NT_SUCCESS(Status
))
737 if (lpSubKey
!= NULL
)
739 OBJECT_ATTRIBUTES ObjectAttributes
;
740 UNICODE_STRING SubKeyName
;
742 RtlInitUnicodeString(&SubKeyName
,
745 InitializeObjectAttributes(&ObjectAttributes
,
747 OBJ_CASE_INSENSITIVE
,
751 Status
= NtOpenKey(&SubKeyHandle
,
752 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
754 if (!NT_SUCCESS(Status
))
759 CurKey
= SubKeyHandle
;
764 Status
= RegpCopyTree(CurKey
,
767 if (SubKeyHandle
!= NULL
)
769 NtClose(SubKeyHandle
);
773 ClosePredefKey(DestKeyHandle
);
775 ClosePredefKey(KeyHandle
);
777 if (!NT_SUCCESS(Status
))
779 return RtlNtStatusToDosError(Status
);
782 return ERROR_SUCCESS
;
786 /************************************************************************
792 RegCopyTreeA(IN HKEY hKeySrc
,
793 IN LPCSTR lpSubKey OPTIONAL
,
796 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
799 if (lpSubKey
!= NULL
&&
800 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
803 return ERROR_NOT_ENOUGH_MEMORY
;
806 Ret
= RegCopyTreeW(hKeySrc
,
810 RtlFreeUnicodeString(&SubKeyName
);
816 /************************************************************************
817 * RegConnectRegistryA
822 RegConnectRegistryA(IN LPCSTR lpMachineName
,
826 UNICODE_STRING MachineName
= { 0, 0, NULL
};
829 if (lpMachineName
!= NULL
&&
830 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
831 (LPSTR
)lpMachineName
))
833 return ERROR_NOT_ENOUGH_MEMORY
;
836 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
840 RtlFreeUnicodeString(&MachineName
);
846 /************************************************************************
847 * RegConnectRegistryW
852 RegConnectRegistryW(LPCWSTR lpMachineName
,
858 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
860 if (!lpMachineName
|| !*lpMachineName
)
862 /* Use the local machine name */
863 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
867 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
868 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
870 /* MSDN says lpMachineName must start with \\ : not so */
871 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
874 if (GetComputerNameW(compName
, &len
))
876 if (!_wcsicmp(lpMachineName
, compName
))
877 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
880 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
881 ret
= ERROR_BAD_NETPATH
;
885 ret
= GetLastError();
892 /************************************************************************
895 * Create key and all necessary intermediate keys
898 CreateNestedKey(PHKEY KeyHandle
,
899 POBJECT_ATTRIBUTES ObjectAttributes
,
900 PUNICODE_STRING ClassString
,
903 DWORD
*lpdwDisposition
)
905 OBJECT_ATTRIBUTES LocalObjectAttributes
;
906 UNICODE_STRING LocalKeyName
;
909 ULONG FullNameLength
;
912 HANDLE LocalKeyHandle
;
914 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
920 (PULONG
)lpdwDisposition
);
921 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
922 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
925 /* Copy object attributes */
926 RtlCopyMemory(&LocalObjectAttributes
,
928 sizeof(OBJECT_ATTRIBUTES
));
929 RtlCreateUnicodeString(&LocalKeyName
,
930 ObjectAttributes
->ObjectName
->Buffer
);
931 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
932 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
934 LocalKeyHandle
= NULL
;
936 /* Remove the last part of the key name and try to create the key again. */
937 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
939 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
940 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
942 Status
= STATUS_UNSUCCESSFUL
;
947 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
949 Status
= NtCreateKey(&LocalKeyHandle
,
951 &LocalObjectAttributes
,
956 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
959 if (!NT_SUCCESS(Status
))
961 RtlFreeUnicodeString(&LocalKeyName
);
965 /* Add removed parts of the key name and create them too. */
966 Length
= wcslen(LocalKeyName
.Buffer
);
970 NtClose (LocalKeyHandle
);
972 LocalKeyName
.Buffer
[Length
] = L
'\\';
973 Length
= wcslen (LocalKeyName
.Buffer
);
974 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
976 if (Length
== FullNameLength
)
978 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
984 (PULONG
)lpdwDisposition
);
988 Status
= NtCreateKey(&LocalKeyHandle
,
990 &LocalObjectAttributes
,
995 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
996 if (!NT_SUCCESS(Status
))
1000 RtlFreeUnicodeString(&LocalKeyName
);
1006 /************************************************************************
1012 RegCreateKeyExA(HKEY hKey
,
1018 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1020 LPDWORD lpdwDisposition
)
1022 UNICODE_STRING SubKeyString
;
1023 UNICODE_STRING ClassString
;
1024 OBJECT_ATTRIBUTES ObjectAttributes
;
1026 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1029 TRACE("RegCreateKeyExA() called\n");
1031 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1032 return ERROR_INVALID_USER_BUFFER
;
1034 /* get the real parent key */
1035 Status
= MapDefaultKey(&ParentKey
,
1037 if (!NT_SUCCESS(Status
))
1039 return RtlNtStatusToDosError(Status
);
1042 TRACE("ParentKey %p\n", ParentKey
);
1044 if (lpClass
!= NULL
)
1046 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1050 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1051 Attributes
|= OBJ_OPENLINK
;
1053 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1055 InitializeObjectAttributes(&ObjectAttributes
,
1059 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1060 Status
= CreateNestedKey(phkResult
,
1062 (lpClass
== NULL
)? NULL
: &ClassString
,
1066 RtlFreeUnicodeString(&SubKeyString
);
1067 if (lpClass
!= NULL
)
1069 RtlFreeUnicodeString(&ClassString
);
1072 ClosePredefKey(ParentKey
);
1074 TRACE("Status %x\n", Status
);
1075 if (!NT_SUCCESS(Status
))
1077 return RtlNtStatusToDosError(Status
);
1080 return ERROR_SUCCESS
;
1084 /************************************************************************
1090 RegCreateKeyExW(HKEY hKey
,
1096 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1098 LPDWORD lpdwDisposition
)
1100 UNICODE_STRING SubKeyString
;
1101 UNICODE_STRING ClassString
;
1102 OBJECT_ATTRIBUTES ObjectAttributes
;
1104 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1107 TRACE("RegCreateKeyExW() called\n");
1109 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1110 return ERROR_INVALID_USER_BUFFER
;
1112 /* get the real parent key */
1113 Status
= MapDefaultKey(&ParentKey
,
1115 if (!NT_SUCCESS(Status
))
1117 return RtlNtStatusToDosError(Status
);
1120 TRACE("ParentKey %p\n", ParentKey
);
1122 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1123 Attributes
|= OBJ_OPENLINK
;
1125 RtlInitUnicodeString(&ClassString
,
1127 RtlInitUnicodeString(&SubKeyString
,
1129 InitializeObjectAttributes(&ObjectAttributes
,
1133 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1134 Status
= CreateNestedKey(phkResult
,
1136 (lpClass
== NULL
)? NULL
: &ClassString
,
1141 ClosePredefKey(ParentKey
);
1143 TRACE("Status %x\n", Status
);
1144 if (!NT_SUCCESS(Status
))
1146 return RtlNtStatusToDosError(Status
);
1149 return ERROR_SUCCESS
;
1153 /************************************************************************
1159 RegCreateKeyA(HKEY hKey
,
1163 return RegCreateKeyExA(hKey
,
1175 /************************************************************************
1181 RegCreateKeyW(HKEY hKey
,
1185 return RegCreateKeyExW(hKey
,
1197 /************************************************************************
1203 RegDeleteKeyA(HKEY hKey
,
1206 OBJECT_ATTRIBUTES ObjectAttributes
;
1207 UNICODE_STRING SubKeyName
;
1212 /* Make sure we got a subkey */
1216 return ERROR_INVALID_PARAMETER
;
1219 Status
= MapDefaultKey(&ParentKey
,
1221 if (!NT_SUCCESS(Status
))
1223 return RtlNtStatusToDosError(Status
);
1226 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1228 InitializeObjectAttributes(&ObjectAttributes
,
1230 OBJ_CASE_INSENSITIVE
,
1234 Status
= NtOpenKey(&TargetKey
,
1237 RtlFreeUnicodeString(&SubKeyName
);
1238 if (!NT_SUCCESS(Status
))
1243 Status
= NtDeleteKey(TargetKey
);
1244 NtClose (TargetKey
);
1247 ClosePredefKey(ParentKey
);
1249 if (!NT_SUCCESS(Status
))
1251 return RtlNtStatusToDosError(Status
);
1254 return ERROR_SUCCESS
;
1258 /************************************************************************
1264 RegDeleteKeyW(HKEY hKey
,
1267 OBJECT_ATTRIBUTES ObjectAttributes
;
1268 UNICODE_STRING SubKeyName
;
1273 /* Make sure we got a subkey */
1277 return ERROR_INVALID_PARAMETER
;
1280 Status
= MapDefaultKey(&ParentKey
,
1282 if (!NT_SUCCESS(Status
))
1284 return RtlNtStatusToDosError(Status
);
1287 RtlInitUnicodeString(&SubKeyName
,
1289 InitializeObjectAttributes(&ObjectAttributes
,
1291 OBJ_CASE_INSENSITIVE
,
1294 Status
= NtOpenKey(&TargetKey
,
1297 if (!NT_SUCCESS(Status
))
1302 Status
= NtDeleteKey(TargetKey
);
1306 ClosePredefKey(ParentKey
);
1308 if (!NT_SUCCESS(Status
))
1310 return RtlNtStatusToDosError(Status
);
1313 return ERROR_SUCCESS
;
1317 /************************************************************************
1324 RegDeleteKeyExA(HKEY hKey
,
1329 OBJECT_ATTRIBUTES ObjectAttributes
;
1330 UNICODE_STRING SubKeyName
;
1335 /* Make sure we got a subkey */
1339 return ERROR_INVALID_PARAMETER
;
1342 Status
= MapDefaultKey(&ParentKey
,
1344 if (!NT_SUCCESS(Status
))
1346 return RtlNtStatusToDosError(Status
);
1349 if (samDesired
& KEY_WOW64_32KEY
)
1350 ERR("Wow64 not yet supported!\n");
1352 if (samDesired
& KEY_WOW64_64KEY
)
1353 ERR("Wow64 not yet supported!\n");
1355 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1357 InitializeObjectAttributes(&ObjectAttributes
,
1359 OBJ_CASE_INSENSITIVE
,
1363 Status
= NtOpenKey(&TargetKey
,
1366 RtlFreeUnicodeString(&SubKeyName
);
1367 if (!NT_SUCCESS(Status
))
1372 Status
= NtDeleteKey(TargetKey
);
1373 NtClose (TargetKey
);
1376 ClosePredefKey(ParentKey
);
1378 if (!NT_SUCCESS(Status
))
1380 return RtlNtStatusToDosError(Status
);
1383 return ERROR_SUCCESS
;
1387 /************************************************************************
1394 RegDeleteKeyExW(HKEY hKey
,
1399 OBJECT_ATTRIBUTES ObjectAttributes
;
1400 UNICODE_STRING SubKeyName
;
1405 /* Make sure we got a subkey */
1409 return ERROR_INVALID_PARAMETER
;
1412 Status
= MapDefaultKey(&ParentKey
,
1414 if (!NT_SUCCESS(Status
))
1416 return RtlNtStatusToDosError(Status
);
1419 if (samDesired
& KEY_WOW64_32KEY
)
1420 ERR("Wow64 not yet supported!\n");
1422 if (samDesired
& KEY_WOW64_64KEY
)
1423 ERR("Wow64 not yet supported!\n");
1426 RtlInitUnicodeString(&SubKeyName
,
1428 InitializeObjectAttributes(&ObjectAttributes
,
1430 OBJ_CASE_INSENSITIVE
,
1433 Status
= NtOpenKey(&TargetKey
,
1436 if (!NT_SUCCESS(Status
))
1441 Status
= NtDeleteKey(TargetKey
);
1445 ClosePredefKey(ParentKey
);
1447 if (!NT_SUCCESS(Status
))
1449 return RtlNtStatusToDosError(Status
);
1452 return ERROR_SUCCESS
;
1456 /************************************************************************
1457 * RegDeleteKeyValueW
1462 RegDeleteKeyValueW(IN HKEY hKey
,
1463 IN LPCWSTR lpSubKey OPTIONAL
,
1464 IN LPCWSTR lpValueName OPTIONAL
)
1466 UNICODE_STRING ValueName
;
1467 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1470 Status
= MapDefaultKey(&KeyHandle
,
1472 if (!NT_SUCCESS(Status
))
1474 return RtlNtStatusToDosError(Status
);
1477 if (lpSubKey
!= NULL
)
1479 OBJECT_ATTRIBUTES ObjectAttributes
;
1480 UNICODE_STRING SubKeyName
;
1482 RtlInitUnicodeString(&SubKeyName
,
1485 InitializeObjectAttributes(&ObjectAttributes
,
1487 OBJ_CASE_INSENSITIVE
,
1491 Status
= NtOpenKey(&SubKeyHandle
,
1494 if (!NT_SUCCESS(Status
))
1499 CurKey
= SubKeyHandle
;
1504 RtlInitUnicodeString(&ValueName
,
1505 (LPWSTR
)lpValueName
);
1507 Status
= NtDeleteValueKey(CurKey
,
1510 if (SubKeyHandle
!= NULL
)
1512 NtClose(SubKeyHandle
);
1516 ClosePredefKey(KeyHandle
);
1518 if (!NT_SUCCESS(Status
))
1520 return RtlNtStatusToDosError(Status
);
1523 return ERROR_SUCCESS
;
1527 /************************************************************************
1528 * RegDeleteKeyValueA
1533 RegDeleteKeyValueA(IN HKEY hKey
,
1534 IN LPCSTR lpSubKey OPTIONAL
,
1535 IN LPCSTR lpValueName OPTIONAL
)
1537 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1540 if (lpSubKey
!= NULL
&&
1541 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1544 return ERROR_NOT_ENOUGH_MEMORY
;
1547 if (lpValueName
!= NULL
&&
1548 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1549 (LPSTR
)lpValueName
))
1551 RtlFreeUnicodeString(&SubKey
);
1552 return ERROR_NOT_ENOUGH_MEMORY
;
1555 Ret
= RegDeleteKeyValueW(hKey
,
1559 RtlFreeUnicodeString(&SubKey
);
1560 RtlFreeUnicodeString(&ValueName
);
1566 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1568 RegpDeleteTree(IN HKEY hKey
)
1572 LIST_ENTRY ListEntry
;
1574 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1576 LIST_ENTRY delQueueHead
;
1577 PREG_DEL_KEYS delKeys
, newDelKeys
;
1580 PKEY_BASIC_INFORMATION BasicInfo
;
1581 PREG_DEL_KEYS KeyDelRoot
;
1582 NTSTATUS Status
= STATUS_SUCCESS
;
1583 NTSTATUS Status2
= STATUS_SUCCESS
;
1585 InitializeListHead(&delQueueHead
);
1587 ProcessHeap
= RtlGetProcessHeap();
1589 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1590 structure for the root key, we only do that for subkeys as we need to
1591 allocate REGP_DEL_KEYS structures anyway! */
1592 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1594 sizeof(REGP_DEL_KEYS
));
1595 if (KeyDelRoot
!= NULL
)
1597 KeyDelRoot
->KeyHandle
= hKey
;
1598 InsertTailList(&delQueueHead
,
1599 &KeyDelRoot
->ListEntry
);
1603 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1612 /* check if this key contains subkeys and delete them first by queuing
1613 them at the head of the list */
1614 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1616 KeyBasicInformation
,
1621 if (NT_SUCCESS(Status2
))
1623 OBJECT_ATTRIBUTES ObjectAttributes
;
1624 UNICODE_STRING SubKeyName
;
1626 ASSERT(newDelKeys
!= NULL
);
1627 ASSERT(BasicInfo
!= NULL
);
1629 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1630 SubKeyName
.Length
= BasicInfo
->NameLength
;
1631 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1632 SubKeyName
.Buffer
= BasicInfo
->Name
;
1634 InitializeObjectAttributes(&ObjectAttributes
,
1636 OBJ_CASE_INSENSITIVE
,
1640 /* open the subkey */
1641 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1642 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1644 if (!NT_SUCCESS(Status2
))
1649 /* enqueue this key to the head of the deletion queue */
1650 InsertHeadList(&delQueueHead
,
1651 &newDelKeys
->ListEntry
);
1653 /* try again from the head of the list */
1658 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1660 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1662 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1663 if (newDelKeys
!= NULL
)
1665 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1668 goto ReadFirstSubKey
;
1672 /* don't break, let's try to delete as many keys as possible */
1673 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1674 goto SubKeyFailureNoFree
;
1677 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1679 PREG_DEL_KEYS newDelKeys2
;
1681 ASSERT(newDelKeys
!= NULL
);
1683 /* we need more memory to query the key name */
1684 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1687 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1688 if (newDelKeys2
!= NULL
)
1690 newDelKeys
= newDelKeys2
;
1691 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1694 goto ReadFirstSubKey
;
1698 /* don't break, let's try to delete as many keys as possible */
1699 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1702 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1704 /* in some race conditions where another thread would delete
1705 the same tree at the same time, newDelKeys could actually
1707 if (newDelKeys
!= NULL
)
1709 RtlFreeHeap(ProcessHeap
,
1717 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1718 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1719 if (newDelKeys
!= NULL
)
1721 RtlFreeHeap(ProcessHeap
,
1726 SubKeyFailureNoFree
:
1727 /* don't break, let's try to delete as many keys as possible */
1728 if (NT_SUCCESS(Status
))
1734 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1736 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1738 if (!NT_SUCCESS(Status2
))
1740 /* close the key handle so we don't leak handles for keys we were
1741 unable to delete. But only do this for handles not supplied
1744 if (delKeys
->KeyHandle
!= hKey
)
1746 NtClose(delKeys
->KeyHandle
);
1749 if (NT_SUCCESS(Status
))
1751 /* don't break, let's try to delete as many keys as possible */
1756 /* remove the entry from the list */
1757 RemoveEntryList(&delKeys
->ListEntry
);
1759 RtlFreeHeap(ProcessHeap
,
1762 } while (!IsListEmpty(&delQueueHead
));
1765 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1771 /************************************************************************
1777 RegDeleteTreeW(IN HKEY hKey
,
1778 IN LPCWSTR lpSubKey OPTIONAL
)
1780 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1783 Status
= MapDefaultKey(&KeyHandle
,
1785 if (!NT_SUCCESS(Status
))
1787 return RtlNtStatusToDosError(Status
);
1790 if (lpSubKey
!= NULL
)
1792 OBJECT_ATTRIBUTES ObjectAttributes
;
1793 UNICODE_STRING SubKeyName
;
1795 RtlInitUnicodeString(&SubKeyName
,
1798 InitializeObjectAttributes(&ObjectAttributes
,
1800 OBJ_CASE_INSENSITIVE
,
1804 Status
= NtOpenKey(&SubKeyHandle
,
1805 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1807 if (!NT_SUCCESS(Status
))
1812 CurKey
= SubKeyHandle
;
1817 Status
= RegpDeleteTree(CurKey
);
1819 if (NT_SUCCESS(Status
))
1821 /* make sure we only close hKey (KeyHandle) when the caller specified a
1822 subkey, because the handle would be invalid already! */
1823 if (CurKey
!= KeyHandle
)
1825 ClosePredefKey(KeyHandle
);
1828 return ERROR_SUCCESS
;
1832 /* make sure we close all handles we created! */
1833 if (SubKeyHandle
!= NULL
)
1835 NtClose(SubKeyHandle
);
1839 ClosePredefKey(KeyHandle
);
1841 return RtlNtStatusToDosError(Status
);
1847 /************************************************************************
1854 RegDeleteTreeW(HKEY hKey
,
1858 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1859 DWORD dwMaxLen
, dwSize
;
1863 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1865 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1867 Status
= MapDefaultKey(&KeyHandle
,
1869 if (!NT_SUCCESS(Status
))
1871 return RtlNtStatusToDosError(Status
);
1874 hSubKey
= KeyHandle
;
1878 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1881 ClosePredefKey(KeyHandle
);
1886 /* Get highest length for keys, values */
1887 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1888 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1889 if (ret
) goto cleanup
;
1893 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1894 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1896 /* Name too big: alloc a buffer for it */
1897 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1899 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1905 /* Recursively delete all the subkeys */
1909 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1910 NULL
, NULL
, NULL
)) break;
1912 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1913 if (ret
) goto cleanup
;
1917 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1922 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1923 NULL
, NULL
, NULL
, NULL
)) break;
1925 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1926 if (ret
) goto cleanup
;
1930 /* Free buffer if allocated */
1931 if (lpszName
!= szNameBuf
)
1932 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1934 RegCloseKey(hSubKey
);
1936 ClosePredefKey(KeyHandle
);
1942 /************************************************************************
1948 RegDeleteTreeA(IN HKEY hKey
,
1949 IN LPCSTR lpSubKey OPTIONAL
)
1951 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1954 if (lpSubKey
!= NULL
&&
1955 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1958 return ERROR_NOT_ENOUGH_MEMORY
;
1961 Ret
= RegDeleteTreeW(hKey
,
1964 RtlFreeUnicodeString(&SubKeyName
);
1970 /************************************************************************
1971 * RegDisableReflectionKey
1976 RegDisableReflectionKey(IN HKEY hBase
)
1978 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1979 return ERROR_CALL_NOT_IMPLEMENTED
;
1983 /************************************************************************
1984 * RegEnableReflectionKey
1989 RegEnableReflectionKey(IN HKEY hBase
)
1991 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1992 return ERROR_CALL_NOT_IMPLEMENTED
;
1996 /******************************************************************************
1997 * RegpApplyRestrictions [internal]
1999 * Helper function for RegGetValueA/W.
2002 RegpApplyRestrictions(DWORD dwFlags
,
2007 /* Check if the type is restricted by the passed flags */
2008 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
2014 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
2015 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
2016 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
2017 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
2018 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
2019 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
2020 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
2023 if (dwFlags
& dwMask
)
2025 /* Type is not restricted, check for size mismatch */
2026 if (dwType
== REG_BINARY
)
2030 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2032 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2035 if (cbExpect
&& cbData
!= cbExpect
)
2036 *ret
= ERROR_DATATYPE_MISMATCH
;
2039 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2044 /******************************************************************************
2045 * RegGetValueW [ADVAPI32.@]
2047 * Retrieves the type and data for a value name associated with a key,
2048 * optionally expanding its content and restricting its type.
2051 * hKey [I] Handle to an open key.
2052 * pszSubKey [I] Name of the subkey of hKey.
2053 * pszValue [I] Name of value under hKey/szSubKey to query.
2054 * dwFlags [I] Flags restricting the value type to retrieve.
2055 * pdwType [O] Destination for the values type, may be NULL.
2056 * pvData [O] Destination for the values content, may be NULL.
2057 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2058 * retrieve the whole content, including the trailing '\0'
2062 * Success: ERROR_SUCCESS
2063 * Failure: nonzero error code from Winerror.h
2066 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2067 * expanded and pdwType is set to REG_SZ instead.
2068 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2069 * without RRF_NOEXPAND is thus not allowed.
2070 * An exception is the case where RRF_RT_ANY is specified, because then
2071 * RRF_NOEXPAND is allowed.
2074 RegGetValueW(HKEY hKey
,
2082 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2086 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2087 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2088 pvData
, pcbData
, cbData
);
2090 if (pvData
&& !pcbData
)
2091 return ERROR_INVALID_PARAMETER
;
2092 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2093 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2094 return ERROR_INVALID_PARAMETER
;
2096 if (pszSubKey
&& pszSubKey
[0])
2098 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2099 if (ret
!= ERROR_SUCCESS
) return ret
;
2102 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2104 /* If we are going to expand we need to read in the whole the value even
2105 * if the passed buffer was too small as the expanded string might be
2106 * smaller than the unexpanded one and could fit into cbData bytes. */
2107 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2108 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2112 HeapFree(GetProcessHeap(), 0, pvBuf
);
2114 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2117 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2121 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2122 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2123 &dwType
, pvBuf
, &cbData
);
2126 /* Even if cbData was large enough we have to copy the
2127 * string since ExpandEnvironmentStrings can't handle
2128 * overlapping buffers. */
2129 CopyMemory(pvBuf
, pvData
, cbData
);
2132 /* Both the type or the value itself could have been modified in
2133 * between so we have to keep retrying until the buffer is large
2134 * enough or we no longer have to expand the value. */
2136 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2138 if (ret
== ERROR_SUCCESS
)
2140 /* Recheck dwType in case it changed since the first call */
2141 if (dwType
== REG_EXPAND_SZ
)
2143 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2144 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2146 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2147 ret
= ERROR_MORE_DATA
;
2150 CopyMemory(pvData
, pvBuf
, *pcbData
);
2153 HeapFree(GetProcessHeap(), 0, pvBuf
);
2156 if (pszSubKey
&& pszSubKey
[0])
2159 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2161 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2162 ZeroMemory(pvData
, *pcbData
);
2174 /******************************************************************************
2175 * RegGetValueA [ADVAPI32.@]
2180 RegGetValueA(HKEY hKey
,
2188 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2192 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2193 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2196 if (pvData
&& !pcbData
)
2197 return ERROR_INVALID_PARAMETER
;
2198 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2199 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2200 return ERROR_INVALID_PARAMETER
;
2202 if (pszSubKey
&& pszSubKey
[0])
2204 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2205 if (ret
!= ERROR_SUCCESS
) return ret
;
2208 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2210 /* If we are going to expand we need to read in the whole the value even
2211 * if the passed buffer was too small as the expanded string might be
2212 * smaller than the unexpanded one and could fit into cbData bytes. */
2213 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2214 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2217 HeapFree(GetProcessHeap(), 0, pvBuf
);
2219 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2222 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2226 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2227 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2228 &dwType
, pvBuf
, &cbData
);
2231 /* Even if cbData was large enough we have to copy the
2232 * string since ExpandEnvironmentStrings can't handle
2233 * overlapping buffers. */
2234 CopyMemory(pvBuf
, pvData
, cbData
);
2237 /* Both the type or the value itself could have been modified in
2238 * between so we have to keep retrying until the buffer is large
2239 * enough or we no longer have to expand the value. */
2240 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2242 if (ret
== ERROR_SUCCESS
)
2244 /* Recheck dwType in case it changed since the first call */
2245 if (dwType
== REG_EXPAND_SZ
)
2247 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2248 pcbData
? *pcbData
: 0);
2250 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2251 ret
= ERROR_MORE_DATA
;
2254 CopyMemory(pvData
, pvBuf
, *pcbData
);
2257 HeapFree(GetProcessHeap(), 0, pvBuf
);
2260 if (pszSubKey
&& pszSubKey
[0])
2263 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2265 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2266 ZeroMemory(pvData
, *pcbData
);
2268 if (pdwType
) *pdwType
= dwType
;
2269 if (pcbData
) *pcbData
= cbData
;
2275 /************************************************************************
2281 RegSetKeyValueW(IN HKEY hKey
,
2282 IN LPCWSTR lpSubKey OPTIONAL
,
2283 IN LPCWSTR lpValueName OPTIONAL
,
2285 IN LPCVOID lpData OPTIONAL
,
2288 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2292 Status
= MapDefaultKey(&KeyHandle
,
2294 if (!NT_SUCCESS(Status
))
2296 return RtlNtStatusToDosError(Status
);
2299 if (lpSubKey
!= NULL
)
2301 OBJECT_ATTRIBUTES ObjectAttributes
;
2302 UNICODE_STRING SubKeyName
;
2304 RtlInitUnicodeString(&SubKeyName
,
2307 InitializeObjectAttributes(&ObjectAttributes
,
2309 OBJ_CASE_INSENSITIVE
,
2313 Status
= NtOpenKey(&SubKeyHandle
,
2316 if (!NT_SUCCESS(Status
))
2318 Ret
= RtlNtStatusToDosError(Status
);
2322 CurKey
= SubKeyHandle
;
2327 Ret
= RegSetValueExW(CurKey
,
2334 if (SubKeyHandle
!= NULL
)
2336 NtClose(SubKeyHandle
);
2340 ClosePredefKey(KeyHandle
);
2346 /************************************************************************
2352 RegSetKeyValueA(IN HKEY hKey
,
2353 IN LPCSTR lpSubKey OPTIONAL
,
2354 IN LPCSTR lpValueName OPTIONAL
,
2356 IN LPCVOID lpData OPTIONAL
,
2359 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2363 Status
= MapDefaultKey(&KeyHandle
,
2365 if (!NT_SUCCESS(Status
))
2367 return RtlNtStatusToDosError(Status
);
2370 if (lpSubKey
!= NULL
)
2372 OBJECT_ATTRIBUTES ObjectAttributes
;
2373 UNICODE_STRING SubKeyName
;
2375 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2378 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2382 InitializeObjectAttributes(&ObjectAttributes
,
2384 OBJ_CASE_INSENSITIVE
,
2388 Status
= NtOpenKey(&SubKeyHandle
,
2392 RtlFreeUnicodeString(&SubKeyName
);
2394 if (!NT_SUCCESS(Status
))
2396 Ret
= RtlNtStatusToDosError(Status
);
2400 CurKey
= SubKeyHandle
;
2405 Ret
= RegSetValueExA(CurKey
,
2412 if (SubKeyHandle
!= NULL
)
2414 NtClose(SubKeyHandle
);
2418 ClosePredefKey(KeyHandle
);
2424 /************************************************************************
2430 RegDeleteValueA(HKEY hKey
,
2433 UNICODE_STRING ValueName
;
2437 Status
= MapDefaultKey(&KeyHandle
,
2439 if (!NT_SUCCESS(Status
))
2441 return RtlNtStatusToDosError(Status
);
2444 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2445 (LPSTR
)lpValueName
);
2446 Status
= NtDeleteValueKey(KeyHandle
,
2448 RtlFreeUnicodeString (&ValueName
);
2450 ClosePredefKey(KeyHandle
);
2452 if (!NT_SUCCESS(Status
))
2454 return RtlNtStatusToDosError(Status
);
2457 return ERROR_SUCCESS
;
2461 /************************************************************************
2467 RegDeleteValueW(HKEY hKey
,
2468 LPCWSTR lpValueName
)
2470 UNICODE_STRING ValueName
;
2474 Status
= MapDefaultKey(&KeyHandle
,
2476 if (!NT_SUCCESS(Status
))
2478 return RtlNtStatusToDosError(Status
);
2481 RtlInitUnicodeString(&ValueName
,
2482 (LPWSTR
)lpValueName
);
2484 Status
= NtDeleteValueKey(KeyHandle
,
2487 ClosePredefKey(KeyHandle
);
2489 if (!NT_SUCCESS(Status
))
2491 return RtlNtStatusToDosError(Status
);
2494 return ERROR_SUCCESS
;
2498 /************************************************************************
2504 RegEnumKeyA(HKEY hKey
,
2512 return RegEnumKeyExA(hKey
,
2523 /************************************************************************
2529 RegEnumKeyW(HKEY hKey
,
2537 return RegEnumKeyExW(hKey
,
2548 /************************************************************************
2554 RegEnumKeyExA(HKEY hKey
,
2561 PFILETIME lpftLastWriteTime
)
2565 KEY_NODE_INFORMATION Node
;
2566 KEY_BASIC_INFORMATION Basic
;
2569 UNICODE_STRING StringU
;
2570 ANSI_STRING StringA
;
2571 LONG ErrorCode
= ERROR_SUCCESS
;
2573 DWORD ClassLength
= 0;
2579 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2580 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2582 if ((lpClass
) && (!lpcbClass
))
2584 return ERROR_INVALID_PARAMETER
;
2587 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2588 if (!NT_SUCCESS(Status
))
2590 return RtlNtStatusToDosError(Status
);
2595 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2606 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2613 /* The class name should start at a dword boundary */
2614 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2618 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2621 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2622 if (KeyInfo
== NULL
)
2624 ErrorCode
= ERROR_OUTOFMEMORY
;
2628 Status
= NtEnumerateKey(KeyHandle
,
2630 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2634 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2635 if (!NT_SUCCESS(Status
))
2637 ErrorCode
= RtlNtStatusToDosError (Status
);
2641 if (lpClass
== NULL
)
2643 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2645 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2649 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2650 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2651 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2656 if (KeyInfo
->Node
.NameLength
> NameLength
||
2657 KeyInfo
->Node
.ClassLength
> ClassLength
)
2659 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2663 StringA
.Buffer
= lpClass
;
2665 StringA
.MaximumLength
= *lpcbClass
;
2666 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2667 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2668 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2669 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2670 lpClass
[StringA
.Length
] = 0;
2671 *lpcbClass
= StringA
.Length
;
2672 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2673 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2674 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2678 if (ErrorCode
== ERROR_SUCCESS
)
2680 StringA
.Buffer
= lpName
;
2682 StringA
.MaximumLength
= *lpcbName
;
2683 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2684 lpName
[StringA
.Length
] = 0;
2685 *lpcbName
= StringA
.Length
;
2686 if (lpftLastWriteTime
!= NULL
)
2688 if (lpClass
== NULL
)
2690 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2691 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2695 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2696 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2702 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2703 TRACE("Key Name1 Length %d\n", NameLength
);
2704 TRACE("Key Name Length %d\n", *lpcbName
);
2705 TRACE("Key Name %s\n", lpName
);
2707 RtlFreeHeap(ProcessHeap
,
2712 ClosePredefKey(KeyHandle
);
2718 /************************************************************************
2724 RegEnumKeyExW(HKEY hKey
,
2731 PFILETIME lpftLastWriteTime
)
2735 KEY_NODE_INFORMATION Node
;
2736 KEY_BASIC_INFORMATION Basic
;
2742 ULONG ClassLength
= 0;
2744 LONG ErrorCode
= ERROR_SUCCESS
;
2747 Status
= MapDefaultKey(&KeyHandle
,
2749 if (!NT_SUCCESS(Status
))
2751 return RtlNtStatusToDosError(Status
);
2756 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2767 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2774 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2778 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2781 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2784 if (KeyInfo
== NULL
)
2786 ErrorCode
= ERROR_OUTOFMEMORY
;
2790 Status
= NtEnumerateKey(KeyHandle
,
2792 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2796 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2797 if (!NT_SUCCESS(Status
))
2799 ErrorCode
= RtlNtStatusToDosError (Status
);
2803 if (lpClass
== NULL
)
2805 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2807 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2811 RtlCopyMemory(lpName
,
2812 KeyInfo
->Basic
.Name
,
2813 KeyInfo
->Basic
.NameLength
);
2814 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2815 lpName
[*lpcbName
] = 0;
2820 if (KeyInfo
->Node
.NameLength
> NameLength
||
2821 KeyInfo
->Node
.ClassLength
> ClassLength
)
2823 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2827 RtlCopyMemory(lpName
,
2829 KeyInfo
->Node
.NameLength
);
2830 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2831 lpName
[*lpcbName
] = 0;
2832 RtlCopyMemory(lpClass
,
2833 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2834 KeyInfo
->Node
.ClassLength
);
2835 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2836 lpClass
[*lpcbClass
] = 0;
2840 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2842 if (lpClass
== NULL
)
2844 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2845 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2849 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2850 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2855 RtlFreeHeap(ProcessHeap
,
2860 ClosePredefKey(KeyHandle
);
2866 /************************************************************************
2872 RegEnumValueA(HKEY hKey
,
2884 char buffer
[256], *buf_ptr
= buffer
;
2885 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2886 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2888 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2889 // hkey, index, value, val_count, reserved, type, data, count );
2891 /* NT only checks count, not val_count */
2892 if ((data
&& !count
) || reserved
)
2893 return ERROR_INVALID_PARAMETER
;
2895 status
= MapDefaultKey(&KeyHandle
, hKey
);
2896 if (!NT_SUCCESS(status
))
2898 return RtlNtStatusToDosError(status
);
2901 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2902 if (data
) total_size
+= *count
;
2903 total_size
= min( sizeof(buffer
), total_size
);
2905 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2906 buffer
, total_size
, &total_size
);
2907 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2909 /* we need to fetch the contents for a string type even if not requested,
2910 * because we need to compute the length of the ASCII string. */
2911 if (value
|| data
|| is_string(info
->Type
))
2913 /* retry with a dynamically allocated buffer */
2914 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2916 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2917 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2919 status
= STATUS_INSUFFICIENT_RESOURCES
;
2922 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2923 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2924 buf_ptr
, total_size
, &total_size
);
2927 if (status
) goto done
;
2929 if (is_string(info
->Type
))
2932 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2936 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2939 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2941 /* if the type is REG_SZ and data is not 0-terminated
2942 * and there is enough space in the buffer NT appends a \0 */
2943 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2946 info
->DataLength
= len
;
2950 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2951 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2954 if (value
&& !status
)
2958 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2959 if (len
>= *val_count
)
2961 status
= STATUS_BUFFER_OVERFLOW
;
2964 len
= *val_count
- 1;
2965 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2971 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2977 else status
= STATUS_SUCCESS
;
2979 if (type
) *type
= info
->Type
;
2980 if (count
) *count
= info
->DataLength
;
2983 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2984 ClosePredefKey(KeyHandle
);
2985 return RtlNtStatusToDosError(status
);
2989 /******************************************************************************
2990 * RegEnumValueW [ADVAPI32.@]
2994 * hkey [I] Handle to key to query
2995 * index [I] Index of value to query
2996 * value [O] Value string
2997 * val_count [I/O] Size of value buffer (in wchars)
2998 * reserved [I] Reserved
2999 * type [O] Type code
3000 * data [O] Value data
3001 * count [I/O] Size of data buffer (in bytes)
3004 * Success: ERROR_SUCCESS
3005 * Failure: nonzero error code from Winerror.h
3008 RegEnumValueW(HKEY hKey
,
3020 char buffer
[256], *buf_ptr
= buffer
;
3021 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
3022 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
3024 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
3025 // hkey, index, value, val_count, reserved, type, data, count );
3027 /* NT only checks count, not val_count */
3028 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
3030 status
= MapDefaultKey(&KeyHandle
, hKey
);
3031 if (!NT_SUCCESS(status
))
3033 return RtlNtStatusToDosError(status
);
3036 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
3037 if (data
) total_size
+= *count
;
3038 total_size
= min( sizeof(buffer
), total_size
);
3040 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3041 buffer
, total_size
, &total_size
);
3042 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
3046 /* retry with a dynamically allocated buffer */
3047 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
3049 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3050 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
3052 status
= ERROR_NOT_ENOUGH_MEMORY
;
3055 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
3056 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
3057 buf_ptr
, total_size
, &total_size
);
3060 if (status
) goto done
;
3064 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
3066 status
= STATUS_BUFFER_OVERFLOW
;
3069 memcpy( value
, info
->Name
, info
->NameLength
);
3070 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
3071 value
[*val_count
] = 0;
3076 if (info
->DataLength
> *count
)
3078 status
= STATUS_BUFFER_OVERFLOW
;
3081 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
3082 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
3084 /* if the type is REG_SZ and data is not 0-terminated
3085 * and there is enough space in the buffer NT appends a \0 */
3086 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
3087 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
3091 else status
= STATUS_SUCCESS
;
3094 if (type
) *type
= info
->Type
;
3095 if (count
) *count
= info
->DataLength
;
3098 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
3099 ClosePredefKey(KeyHandle
);
3100 return RtlNtStatusToDosError(status
);
3104 /************************************************************************
3110 RegFlushKey(HKEY hKey
)
3115 if (hKey
== HKEY_PERFORMANCE_DATA
)
3117 return ERROR_SUCCESS
;
3120 Status
= MapDefaultKey(&KeyHandle
,
3122 if (!NT_SUCCESS(Status
))
3124 return RtlNtStatusToDosError(Status
);
3127 Status
= NtFlushKey(KeyHandle
);
3129 ClosePredefKey(KeyHandle
);
3131 if (!NT_SUCCESS(Status
))
3133 return RtlNtStatusToDosError(Status
);
3136 return ERROR_SUCCESS
;
3140 /************************************************************************
3146 RegGetKeySecurity(HKEY hKey
,
3147 SECURITY_INFORMATION SecurityInformation
,
3148 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3149 LPDWORD lpcbSecurityDescriptor
)
3154 if (hKey
== HKEY_PERFORMANCE_DATA
)
3156 return ERROR_INVALID_HANDLE
;
3159 Status
= MapDefaultKey(&KeyHandle
,
3161 if (!NT_SUCCESS(Status
))
3163 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3164 return RtlNtStatusToDosError(Status
);
3168 Status
= NtQuerySecurityObject(KeyHandle
,
3169 SecurityInformation
,
3170 pSecurityDescriptor
,
3171 *lpcbSecurityDescriptor
,
3172 lpcbSecurityDescriptor
);
3175 ClosePredefKey(KeyHandle
);
3177 if (!NT_SUCCESS(Status
))
3179 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3180 return RtlNtStatusToDosError(Status
);
3183 return ERROR_SUCCESS
;
3187 /************************************************************************
3193 RegLoadKeyA(HKEY hKey
,
3197 UNICODE_STRING FileName
;
3198 UNICODE_STRING KeyName
;
3201 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3203 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3206 ErrorCode
= RegLoadKeyW(hKey
,
3210 RtlFreeUnicodeString(&FileName
);
3211 RtlFreeUnicodeString(&KeyName
);
3217 /************************************************************************
3223 RegLoadKeyW(HKEY hKey
,
3227 OBJECT_ATTRIBUTES FileObjectAttributes
;
3228 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3229 UNICODE_STRING FileName
;
3230 UNICODE_STRING KeyName
;
3233 LONG ErrorCode
= ERROR_SUCCESS
;
3235 if (hKey
== HKEY_PERFORMANCE_DATA
)
3237 return ERROR_INVALID_HANDLE
;
3240 Status
= MapDefaultKey(&KeyHandle
,
3242 if (!NT_SUCCESS(Status
))
3244 return RtlNtStatusToDosError(Status
);
3247 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3252 ErrorCode
= ERROR_BAD_PATHNAME
;
3256 InitializeObjectAttributes(&FileObjectAttributes
,
3258 OBJ_CASE_INSENSITIVE
,
3262 RtlInitUnicodeString(&KeyName
,
3265 InitializeObjectAttributes(&KeyObjectAttributes
,
3267 OBJ_CASE_INSENSITIVE
,
3271 Status
= NtLoadKey(&KeyObjectAttributes
,
3272 &FileObjectAttributes
);
3274 RtlFreeHeap(RtlGetProcessHeap(),
3278 if (!NT_SUCCESS(Status
))
3280 ErrorCode
= RtlNtStatusToDosError(Status
);
3285 ClosePredefKey(KeyHandle
);
3291 /************************************************************************
3292 * RegNotifyChangeKeyValue
3297 RegNotifyChangeKeyValue(HKEY hKey
,
3299 DWORD dwNotifyFilter
,
3303 IO_STATUS_BLOCK IoStatusBlock
;
3306 LONG ErrorCode
= ERROR_SUCCESS
;
3308 if (hKey
== HKEY_PERFORMANCE_DATA
)
3310 return ERROR_INVALID_HANDLE
;
3313 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3315 return ERROR_INVALID_PARAMETER
;
3318 Status
= MapDefaultKey(&KeyHandle
,
3320 if (!NT_SUCCESS(Status
))
3322 return RtlNtStatusToDosError(Status
);
3325 /* FIXME: Remote key handles must fail */
3327 Status
= NtNotifyChangeKey(KeyHandle
,
3337 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3339 ErrorCode
= RtlNtStatusToDosError(Status
);
3342 ClosePredefKey(KeyHandle
);
3348 /************************************************************************
3349 * RegOpenCurrentUser
3354 RegOpenCurrentUser(IN REGSAM samDesired
,
3355 OUT PHKEY phkResult
)
3359 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3360 (PHANDLE
)phkResult
);
3361 if (!NT_SUCCESS(Status
))
3363 /* NOTE - don't set the last error code! just return the error! */
3364 return RtlNtStatusToDosError(Status
);
3367 return ERROR_SUCCESS
;
3371 /************************************************************************
3374 * 20050503 Fireball - imported from WINE
3379 RegOpenKeyA(HKEY hKey
,
3383 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3384 hKey
, lpSubKey
, phkResult
);
3387 return ERROR_INVALID_PARAMETER
;
3389 if (!hKey
&& lpSubKey
&& phkResult
)
3391 return ERROR_INVALID_HANDLE
;
3394 if (!lpSubKey
|| !*lpSubKey
)
3397 return ERROR_SUCCESS
;
3400 return RegOpenKeyExA(hKey
,
3408 /************************************************************************
3413 * 20050503 Fireball - imported from WINE
3418 RegOpenKeyW(HKEY hKey
,
3422 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3423 hKey
, lpSubKey
, phkResult
);
3426 return ERROR_INVALID_PARAMETER
;
3428 if (!hKey
&& lpSubKey
&& phkResult
)
3430 return ERROR_INVALID_HANDLE
;
3433 if (!lpSubKey
|| !*lpSubKey
)
3436 return ERROR_SUCCESS
;
3439 return RegOpenKeyExW(hKey
,
3447 /************************************************************************
3453 RegOpenKeyExA(HKEY hKey
,
3459 OBJECT_ATTRIBUTES ObjectAttributes
;
3460 UNICODE_STRING SubKeyString
;
3463 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3464 LONG ErrorCode
= ERROR_SUCCESS
;
3466 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3467 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3470 return ERROR_INVALID_PARAMETER
;
3473 Status
= MapDefaultKey(&KeyHandle
,
3475 if (!NT_SUCCESS(Status
))
3477 return RtlNtStatusToDosError(Status
);
3480 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3481 Attributes
|= OBJ_OPENLINK
;
3483 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3485 InitializeObjectAttributes(&ObjectAttributes
,
3491 Status
= NtOpenKey((PHANDLE
)phkResult
,
3494 RtlFreeUnicodeString(&SubKeyString
);
3495 if (!NT_SUCCESS(Status
))
3497 ErrorCode
= RtlNtStatusToDosError(Status
);
3500 ClosePredefKey(KeyHandle
);
3506 /************************************************************************
3512 RegOpenKeyExW(HKEY hKey
,
3518 OBJECT_ATTRIBUTES ObjectAttributes
;
3519 UNICODE_STRING SubKeyString
;
3522 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3523 LONG ErrorCode
= ERROR_SUCCESS
;
3525 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3526 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3529 return ERROR_INVALID_PARAMETER
;
3532 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3533 if (!NT_SUCCESS(Status
))
3535 return RtlNtStatusToDosError(Status
);
3538 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3539 Attributes
|= OBJ_OPENLINK
;
3541 if (lpSubKey
!= NULL
)
3542 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3544 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3546 InitializeObjectAttributes(&ObjectAttributes
,
3552 Status
= NtOpenKey((PHANDLE
)phkResult
,
3555 if (!NT_SUCCESS(Status
))
3557 ErrorCode
= RtlNtStatusToDosError(Status
);
3560 ClosePredefKey(KeyHandle
);
3566 /************************************************************************
3567 * RegOpenUserClassesRoot
3572 RegOpenUserClassesRoot(IN HANDLE hToken
,
3574 IN REGSAM samDesired
,
3575 OUT PHKEY phkResult
)
3577 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3578 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3579 PTOKEN_USER TokenUserData
;
3580 ULONG RequiredLength
;
3581 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3582 OBJECT_ATTRIBUTES ObjectAttributes
;
3585 /* check parameters */
3586 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3588 return ERROR_INVALID_PARAMETER
;
3592 * Get the user sid from the token
3596 /* determine how much memory we need */
3597 Status
= NtQueryInformationToken(hToken
,
3602 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3604 /* NOTE - as opposed to all other registry functions windows does indeed
3605 change the last error code in case the caller supplied a invalid
3606 handle for example! */
3607 return RtlNtStatusToDosError(Status
);
3609 RegInitialize(); /* HACK until delay-loading is implemented */
3610 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3613 if (TokenUserData
== NULL
)
3615 return ERROR_NOT_ENOUGH_MEMORY
;
3618 /* attempt to read the information */
3619 Status
= NtQueryInformationToken(hToken
,
3624 if (!NT_SUCCESS(Status
))
3626 RtlFreeHeap(ProcessHeap
,
3629 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3631 /* the information appears to have changed?! try again */
3635 /* NOTE - as opposed to all other registry functions windows does indeed
3636 change the last error code in case the caller supplied a invalid
3637 handle for example! */
3638 return RtlNtStatusToDosError(Status
);
3642 * Build the absolute path for the user's registry in the form
3643 * "\Registry\User\<SID>_Classes"
3645 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3646 TokenUserData
->User
.Sid
,
3649 /* we don't need the user data anymore, free it */
3650 RtlFreeHeap(ProcessHeap
,
3654 if (!NT_SUCCESS(Status
))
3656 return RtlNtStatusToDosError(Status
);
3659 /* allocate enough memory for the entire key string */
3660 UserClassesKeyRoot
.Length
= 0;
3661 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3662 sizeof(UserClassesKeyPrefix
) +
3663 sizeof(UserClassesKeySuffix
);
3664 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3666 UserClassesKeyRoot
.MaximumLength
);
3667 if (UserClassesKeyRoot
.Buffer
== NULL
)
3669 RtlFreeUnicodeString(&UserSidString
);
3670 return RtlNtStatusToDosError(Status
);
3673 /* build the string */
3674 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3675 UserClassesKeyPrefix
);
3676 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3678 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3679 UserClassesKeySuffix
);
3681 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3686 InitializeObjectAttributes(&ObjectAttributes
,
3687 &UserClassesKeyRoot
,
3688 OBJ_CASE_INSENSITIVE
,
3692 Status
= NtOpenKey((PHANDLE
)phkResult
,
3696 RtlFreeUnicodeString(&UserSidString
);
3697 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3699 if (!NT_SUCCESS(Status
))
3701 return RtlNtStatusToDosError(Status
);
3704 return ERROR_SUCCESS
;
3708 /************************************************************************
3714 RegQueryInfoKeyA(HKEY hKey
,
3719 LPDWORD lpcbMaxSubKeyLen
,
3720 LPDWORD lpcbMaxClassLen
,
3722 LPDWORD lpcbMaxValueNameLen
,
3723 LPDWORD lpcbMaxValueLen
,
3724 LPDWORD lpcbSecurityDescriptor
,
3725 PFILETIME lpftLastWriteTime
)
3727 WCHAR ClassName
[MAX_PATH
];
3728 UNICODE_STRING UnicodeString
;
3729 ANSI_STRING AnsiString
;
3732 RtlInitUnicodeString(&UnicodeString
,
3734 if (lpClass
!= NULL
)
3736 UnicodeString
.Buffer
= &ClassName
[0];
3737 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3738 AnsiString
.MaximumLength
= *lpcbClass
;
3741 ErrorCode
= RegQueryInfoKeyW(hKey
,
3742 UnicodeString
.Buffer
,
3749 lpcbMaxValueNameLen
,
3751 lpcbSecurityDescriptor
,
3753 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3755 AnsiString
.Buffer
= lpClass
;
3756 AnsiString
.Length
= 0;
3757 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3758 RtlUnicodeStringToAnsiString(&AnsiString
,
3761 *lpcbClass
= AnsiString
.Length
;
3762 lpClass
[AnsiString
.Length
] = 0;
3769 /************************************************************************
3775 RegQueryInfoKeyW(HKEY hKey
,
3780 LPDWORD lpcbMaxSubKeyLen
,
3781 LPDWORD lpcbMaxClassLen
,
3783 LPDWORD lpcbMaxValueNameLen
,
3784 LPDWORD lpcbMaxValueLen
,
3785 LPDWORD lpcbSecurityDescriptor
,
3786 PFILETIME lpftLastWriteTime
)
3788 KEY_FULL_INFORMATION FullInfoBuffer
;
3789 PKEY_FULL_INFORMATION FullInfo
;
3791 ULONG ClassLength
= 0;
3795 LONG ErrorCode
= ERROR_SUCCESS
;
3797 if ((lpClass
) && (!lpcbClass
))
3799 return ERROR_INVALID_PARAMETER
;
3802 Status
= MapDefaultKey(&KeyHandle
,
3804 if (!NT_SUCCESS(Status
))
3806 return RtlNtStatusToDosError(Status
);
3809 if (lpClass
!= NULL
)
3813 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3820 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3821 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3824 if (FullInfo
== NULL
)
3826 ErrorCode
= ERROR_OUTOFMEMORY
;
3830 FullInfo
->ClassLength
= ClassLength
;
3834 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3835 FullInfo
= &FullInfoBuffer
;
3836 FullInfo
->ClassLength
= 0;
3838 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3840 Status
= NtQueryKey(KeyHandle
,
3845 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3846 if (!NT_SUCCESS(Status
))
3848 if (lpClass
!= NULL
)
3850 RtlFreeHeap(ProcessHeap
,
3855 ErrorCode
= RtlNtStatusToDosError(Status
);
3859 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3860 if (lpcSubKeys
!= NULL
)
3862 *lpcSubKeys
= FullInfo
->SubKeys
;
3865 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3866 if (lpcbMaxSubKeyLen
!= NULL
)
3868 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3871 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3872 if (lpcbMaxClassLen
!= NULL
)
3874 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3877 TRACE("Values %lu\n", FullInfo
->Values
);
3878 if (lpcValues
!= NULL
)
3880 *lpcValues
= FullInfo
->Values
;
3883 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3884 if (lpcbMaxValueNameLen
!= NULL
)
3886 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3889 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3890 if (lpcbMaxValueLen
!= NULL
)
3892 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3896 if (lpcbSecurityDescriptor
!= NULL
)
3898 Status
= NtQuerySecurityObject(KeyHandle
,
3899 OWNER_SECURITY_INFORMATION
|
3900 GROUP_SECURITY_INFORMATION
|
3901 DACL_SECURITY_INFORMATION
,
3904 lpcbSecurityDescriptor
);
3905 if (!NT_SUCCESS(Status
))
3907 if (lpClass
!= NULL
)
3909 RtlFreeHeap(ProcessHeap
,
3914 ErrorCode
= RtlNtStatusToDosError(Status
);
3920 if (lpftLastWriteTime
!= NULL
)
3922 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3923 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3926 if (lpClass
!= NULL
)
3928 if (FullInfo
->ClassLength
> ClassLength
)
3930 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3934 RtlCopyMemory(lpClass
,
3936 FullInfo
->ClassLength
);
3937 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3938 lpClass
[*lpcbClass
] = 0;
3941 RtlFreeHeap(ProcessHeap
,
3947 ClosePredefKey(KeyHandle
);
3953 /************************************************************************
3954 * RegQueryMultipleValuesA
3959 RegQueryMultipleValuesA(HKEY hKey
,
3966 DWORD maxBytes
= *ldwTotsize
;
3967 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3970 if (maxBytes
>= (1024*1024))
3971 return ERROR_TRANSFER_TOO_LONG
;
3975 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3976 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3978 for (i
= 0; i
< num_vals
; i
++)
3980 val_list
[i
].ve_valuelen
= 0;
3981 ErrorCode
= RegQueryValueExA(hKey
,
3982 val_list
[i
].ve_valuename
,
3986 &val_list
[i
].ve_valuelen
);
3987 if (ErrorCode
!= ERROR_SUCCESS
)
3992 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3994 ErrorCode
= RegQueryValueExA(hKey
,
3995 val_list
[i
].ve_valuename
,
3997 &val_list
[i
].ve_type
,
3999 &val_list
[i
].ve_valuelen
);
4000 if (ErrorCode
!= ERROR_SUCCESS
)
4005 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
4007 bufptr
+= val_list
[i
].ve_valuelen
;
4010 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
4013 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
4017 /************************************************************************
4018 * RegQueryMultipleValuesW
4023 RegQueryMultipleValuesW(HKEY hKey
,
4030 DWORD maxBytes
= *ldwTotsize
;
4031 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
4034 if (maxBytes
>= (1024*1024))
4035 return ERROR_TRANSFER_TOO_LONG
;
4039 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
4040 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
4042 for (i
= 0; i
< num_vals
; i
++)
4044 val_list
[i
].ve_valuelen
= 0;
4045 ErrorCode
= RegQueryValueExW(hKey
,
4046 val_list
[i
].ve_valuename
,
4050 &val_list
[i
].ve_valuelen
);
4051 if (ErrorCode
!= ERROR_SUCCESS
)
4056 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
4058 ErrorCode
= RegQueryValueExW(hKey
,
4059 val_list
[i
].ve_valuename
,
4061 &val_list
[i
].ve_type
,
4063 &val_list
[i
].ve_valuelen
);
4064 if (ErrorCode
!= ERROR_SUCCESS
)
4069 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
4071 bufptr
+= val_list
[i
].ve_valuelen
;
4074 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
4077 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
4081 /************************************************************************
4082 * RegQueryReflectionKey
4087 RegQueryReflectionKey(IN HKEY hBase
,
4088 OUT BOOL
* bIsReflectionDisabled
)
4090 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
4091 hBase
, bIsReflectionDisabled
);
4092 return ERROR_CALL_NOT_IMPLEMENTED
;
4096 /******************************************************************************
4097 * RegQueryValueExA [ADVAPI32.@]
4099 * Get the type and contents of a specified value under with a key.
4102 * hkey [I] Handle of the key to query
4103 * name [I] Name of value under hkey to query
4104 * reserved [I] Reserved - must be NULL
4105 * type [O] Destination for the value type, or NULL if not required
4106 * data [O] Destination for the values contents, or NULL if not required
4107 * count [I/O] Size of data, updated with the number of bytes returned
4110 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
4111 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
4112 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
4113 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
4116 * MSDN states that if data is too small it is partially filled. In reality
4117 * it remains untouched.
4121 RegQueryValueExA(HKEY hkeyorg
,
4131 UNICODE_STRING nameW
;
4132 DWORD total_size
, datalen
= 0;
4133 char buffer
[256], *buf_ptr
= buffer
;
4134 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4135 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4137 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4138 hkeyorg
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
4140 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4141 status
= MapDefaultKey(&hkey
, hkeyorg
);
4142 if (!NT_SUCCESS(status
))
4144 return RtlNtStatusToDosError(status
);
4147 if (count
) datalen
= *count
;
4148 if (!data
&& count
) *count
= 0;
4150 RtlInitAnsiString( &nameA
, name
);
4151 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
4153 ClosePredefKey(hkey
);
4154 return RtlNtStatusToDosError(status
);
4157 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4158 buffer
, sizeof(buffer
), &total_size
);
4159 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4161 /* we need to fetch the contents for a string type even if not requested,
4162 * because we need to compute the length of the ASCII string. */
4163 if (data
|| is_string(info
->Type
))
4165 /* retry with a dynamically allocated buffer */
4166 while (status
== STATUS_BUFFER_OVERFLOW
)
4168 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4169 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4171 status
= STATUS_NO_MEMORY
;
4174 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4175 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
4176 buf_ptr
, total_size
, &total_size
);
4179 if (status
) goto done
;
4181 if (is_string(info
->Type
))
4185 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
4186 total_size
- info_size
);
4189 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4192 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
4193 total_size
- info_size
);
4194 /* if the type is REG_SZ and data is not 0-terminated
4195 * and there is enough space in the buffer NT appends a \0 */
4196 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
4199 total_size
= len
+ info_size
;
4203 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
4204 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4207 else status
= STATUS_SUCCESS
;
4209 if (type
) *type
= info
->Type
;
4210 if (count
) *count
= total_size
- info_size
;
4213 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4214 RtlFreeUnicodeString( &nameW
);
4215 ClosePredefKey(hkey
);
4216 return RtlNtStatusToDosError(status
);
4220 /************************************************************************
4227 RegQueryValueExW(HKEY hkeyorg
,
4236 UNICODE_STRING name_str
;
4238 char buffer
[256], *buf_ptr
= buffer
;
4239 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4240 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4242 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4243 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4244 (count
&& data
) ? *count
: 0 );
4246 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4248 status
= MapDefaultKey(&hkey
, hkeyorg
);
4249 if (!NT_SUCCESS(status
))
4251 return RtlNtStatusToDosError(status
);
4254 RtlInitUnicodeString( &name_str
, name
);
4256 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4259 total_size
= info_size
;
4260 if (count
) *count
= 0;
4263 /* this matches Win9x behaviour - NT sets *type to a random value */
4264 if (type
) *type
= REG_NONE
;
4266 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4267 buffer
, total_size
, &total_size
);
4268 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4272 /* retry with a dynamically allocated buffer */
4273 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4275 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4276 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4278 ClosePredefKey(hkey
);
4279 return ERROR_NOT_ENOUGH_MEMORY
;
4281 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4282 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4283 buf_ptr
, total_size
, &total_size
);
4286 if (NT_SUCCESS(status
))
4288 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4289 /* if the type is REG_SZ and data is not 0-terminated
4290 * and there is enough space in the buffer NT appends a \0 */
4291 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4293 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4294 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4297 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4299 else status
= STATUS_SUCCESS
;
4301 if (type
) *type
= info
->Type
;
4302 if (count
) *count
= total_size
- info_size
;
4305 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4306 ClosePredefKey(hkey
);
4307 return RtlNtStatusToDosError(status
);
4311 /************************************************************************
4316 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4321 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4323 if (name
&& name
[0])
4325 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4327 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4328 if (subkey
!= hkey
) RegCloseKey( subkey
);
4329 if (ret
== ERROR_FILE_NOT_FOUND
)
4331 /* return empty string if default value not found */
4332 if (data
) *data
= 0;
4333 if (count
) *count
= 1;
4334 ret
= ERROR_SUCCESS
;
4340 /************************************************************************
4345 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4350 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4353 return ERROR_INVALID_HANDLE
;
4355 if (name
&& name
[0])
4357 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4358 if (ret
!= ERROR_SUCCESS
)
4364 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4368 RegCloseKey( subkey
);
4371 if (ret
== ERROR_FILE_NOT_FOUND
)
4373 /* return empty string if default value not found */
4377 *count
= sizeof(WCHAR
);
4378 ret
= ERROR_SUCCESS
;
4384 /************************************************************************
4390 RegReplaceKeyA(HKEY hKey
,
4395 UNICODE_STRING SubKey
;
4396 UNICODE_STRING NewFile
;
4397 UNICODE_STRING OldFile
;
4400 RtlCreateUnicodeStringFromAsciiz(&SubKey
,
4402 RtlCreateUnicodeStringFromAsciiz(&OldFile
,
4404 RtlCreateUnicodeStringFromAsciiz(&NewFile
,
4407 ErrorCode
= RegReplaceKeyW(hKey
,
4412 RtlFreeUnicodeString(&OldFile
);
4413 RtlFreeUnicodeString(&NewFile
);
4414 RtlFreeUnicodeString(&SubKey
);
4420 /************************************************************************
4426 RegReplaceKeyW(HKEY hKey
,
4431 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4432 OBJECT_ATTRIBUTES NewObjectAttributes
;
4433 OBJECT_ATTRIBUTES OldObjectAttributes
;
4434 UNICODE_STRING SubKeyName
;
4435 UNICODE_STRING NewFileName
;
4436 UNICODE_STRING OldFileName
;
4437 BOOLEAN CloseRealKey
;
4438 HANDLE RealKeyHandle
;
4441 LONG ErrorCode
= ERROR_SUCCESS
;
4443 if (hKey
== HKEY_PERFORMANCE_DATA
)
4445 return ERROR_INVALID_HANDLE
;
4448 Status
= MapDefaultKey(&KeyHandle
,
4450 if (!NT_SUCCESS(Status
))
4452 return RtlNtStatusToDosError(Status
);
4455 /* Open the real key */
4456 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4458 RtlInitUnicodeString(&SubKeyName
,
4460 InitializeObjectAttributes(&KeyObjectAttributes
,
4462 OBJ_CASE_INSENSITIVE
,
4465 Status
= NtOpenKey(&RealKeyHandle
,
4467 &KeyObjectAttributes
);
4468 if (!NT_SUCCESS(Status
))
4470 ErrorCode
= RtlNtStatusToDosError(Status
);
4474 CloseRealKey
= TRUE
;
4478 RealKeyHandle
= KeyHandle
;
4479 CloseRealKey
= FALSE
;
4482 /* Convert new file name */
4483 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4490 NtClose(RealKeyHandle
);
4493 ErrorCode
= ERROR_INVALID_PARAMETER
;
4497 InitializeObjectAttributes(&NewObjectAttributes
,
4499 OBJ_CASE_INSENSITIVE
,
4503 /* Convert old file name */
4504 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4509 RtlFreeHeap(RtlGetProcessHeap (),
4511 NewFileName
.Buffer
);
4514 NtClose(RealKeyHandle
);
4517 ErrorCode
= ERROR_INVALID_PARAMETER
;
4521 InitializeObjectAttributes(&OldObjectAttributes
,
4523 OBJ_CASE_INSENSITIVE
,
4527 Status
= NtReplaceKey(&NewObjectAttributes
,
4529 &OldObjectAttributes
);
4531 RtlFreeHeap(RtlGetProcessHeap(),
4533 OldFileName
.Buffer
);
4534 RtlFreeHeap(RtlGetProcessHeap(),
4536 NewFileName
.Buffer
);
4540 NtClose(RealKeyHandle
);
4543 if (!NT_SUCCESS(Status
))
4545 return RtlNtStatusToDosError(Status
);
4549 ClosePredefKey(KeyHandle
);
4555 /************************************************************************
4561 RegRestoreKeyA(HKEY hKey
,
4565 UNICODE_STRING FileName
;
4568 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4571 ErrorCode
= RegRestoreKeyW(hKey
,
4575 RtlFreeUnicodeString(&FileName
);
4581 /************************************************************************
4587 RegRestoreKeyW(HKEY hKey
,
4591 OBJECT_ATTRIBUTES ObjectAttributes
;
4592 IO_STATUS_BLOCK IoStatusBlock
;
4593 UNICODE_STRING FileName
;
4598 if (hKey
== HKEY_PERFORMANCE_DATA
)
4600 return ERROR_INVALID_HANDLE
;
4603 Status
= MapDefaultKey(&KeyHandle
,
4605 if (!NT_SUCCESS(Status
))
4607 return RtlNtStatusToDosError(Status
);
4610 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4615 Status
= STATUS_INVALID_PARAMETER
;
4619 InitializeObjectAttributes(&ObjectAttributes
,
4621 OBJ_CASE_INSENSITIVE
,
4625 Status
= NtOpenFile(&FileHandle
,
4630 FILE_SYNCHRONOUS_IO_NONALERT
);
4631 RtlFreeHeap(RtlGetProcessHeap(),
4634 if (!NT_SUCCESS(Status
))
4639 Status
= NtRestoreKey(KeyHandle
,
4642 NtClose (FileHandle
);
4645 ClosePredefKey(KeyHandle
);
4647 if (!NT_SUCCESS(Status
))
4649 return RtlNtStatusToDosError(Status
);
4652 return ERROR_SUCCESS
;
4656 /************************************************************************
4662 RegSaveKeyA(HKEY hKey
,
4664 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4666 UNICODE_STRING FileName
;
4669 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4671 ErrorCode
= RegSaveKeyW(hKey
,
4673 lpSecurityAttributes
);
4674 RtlFreeUnicodeString(&FileName
);
4680 /************************************************************************
4686 RegSaveKeyW(HKEY hKey
,
4688 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4690 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4691 OBJECT_ATTRIBUTES ObjectAttributes
;
4692 UNICODE_STRING FileName
;
4693 IO_STATUS_BLOCK IoStatusBlock
;
4698 Status
= MapDefaultKey(&KeyHandle
,
4700 if (!NT_SUCCESS(Status
))
4702 return RtlNtStatusToDosError(Status
);
4705 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4710 Status
= STATUS_INVALID_PARAMETER
;
4714 if (lpSecurityAttributes
!= NULL
)
4716 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4719 InitializeObjectAttributes(&ObjectAttributes
,
4721 OBJ_CASE_INSENSITIVE
,
4723 SecurityDescriptor
);
4724 Status
= NtCreateFile(&FileHandle
,
4725 GENERIC_WRITE
| SYNCHRONIZE
,
4729 FILE_ATTRIBUTE_NORMAL
,
4732 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4735 RtlFreeHeap(RtlGetProcessHeap(),
4738 if (!NT_SUCCESS(Status
))
4743 Status
= NtSaveKey(KeyHandle
,
4745 NtClose (FileHandle
);
4748 ClosePredefKey(KeyHandle
);
4750 if (!NT_SUCCESS(Status
))
4752 return RtlNtStatusToDosError(Status
);
4755 return ERROR_SUCCESS
;
4759 /************************************************************************
4766 RegSaveKeyExA(HKEY hKey
,
4768 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4771 UNICODE_STRING FileName
;
4774 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4776 ErrorCode
= RegSaveKeyExW(hKey
,
4778 lpSecurityAttributes
,
4780 RtlFreeUnicodeString(&FileName
);
4786 /************************************************************************
4793 RegSaveKeyExW(HKEY hKey
,
4795 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4800 case REG_STANDARD_FORMAT
:
4801 case REG_LATEST_FORMAT
:
4802 case REG_NO_COMPRESSION
:
4805 return ERROR_INVALID_PARAMETER
;
4808 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4810 return RegSaveKeyW(hKey
,
4812 lpSecurityAttributes
);
4816 /************************************************************************
4822 RegSetKeySecurity(HKEY hKey
,
4823 SECURITY_INFORMATION SecurityInformation
,
4824 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4829 if (hKey
== HKEY_PERFORMANCE_DATA
)
4831 return ERROR_INVALID_HANDLE
;
4834 Status
= MapDefaultKey(&KeyHandle
,
4836 if (!NT_SUCCESS(Status
))
4838 return RtlNtStatusToDosError(Status
);
4841 Status
= NtSetSecurityObject(KeyHandle
,
4842 SecurityInformation
,
4843 pSecurityDescriptor
);
4845 ClosePredefKey(KeyHandle
);
4847 if (!NT_SUCCESS(Status
))
4849 return RtlNtStatusToDosError(Status
);
4852 return ERROR_SUCCESS
;
4856 /************************************************************************
4862 RegSetValueExA(HKEY hKey
,
4869 UNICODE_STRING ValueName
;
4871 ANSI_STRING AnsiString
;
4872 UNICODE_STRING Data
;
4878 /* Convert SubKey name to Unicode */
4879 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4882 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4885 return ERROR_NOT_ENOUGH_MEMORY
;
4889 ValueName
.Buffer
= NULL
;
4892 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4895 if (is_string(dwType
) && (cbData
!= 0))
4897 /* Convert ANSI string Data to Unicode */
4898 /* If last character NOT zero then increment length */
4899 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4900 AnsiString
.Buffer
= (PSTR
)lpData
;
4901 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4902 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4903 Status
= RtlAnsiStringToUnicodeString(&Data
,
4907 if (!NT_SUCCESS(Status
))
4909 if (pValueName
!= NULL
)
4910 RtlFreeUnicodeString(&ValueName
);
4912 return RtlNtStatusToDosError(Status
);
4914 pData
= (LPBYTE
)Data
.Buffer
;
4915 DataSize
= cbData
* sizeof(WCHAR
);
4920 pData
= (LPBYTE
)lpData
;
4924 ErrorCode
= RegSetValueExW(hKey
,
4931 if (pValueName
!= NULL
)
4932 RtlFreeUnicodeString(&ValueName
);
4934 if (Data
.Buffer
!= NULL
)
4935 RtlFreeUnicodeString(&Data
);
4941 /************************************************************************
4947 RegSetValueExW(HKEY hKey
,
4948 LPCWSTR lpValueName
,
4954 UNICODE_STRING ValueName
;
4955 PUNICODE_STRING pValueName
;
4959 Status
= MapDefaultKey(&KeyHandle
,
4961 if (!NT_SUCCESS(Status
))
4963 return RtlNtStatusToDosError(Status
);
4966 RtlInitUnicodeString(&ValueName
, lpValueName
);
4967 pValueName
= &ValueName
;
4969 if (is_string(dwType
) && (cbData
!= 0))
4971 PWSTR pwsData
= (PWSTR
)lpData
;
4973 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4974 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4976 /* Increment length if last character is not zero and next is zero */
4977 cbData
+= sizeof(WCHAR
);
4981 Status
= NtSetValueKey(KeyHandle
,
4988 ClosePredefKey(KeyHandle
);
4990 if (!NT_SUCCESS(Status
))
4992 return RtlNtStatusToDosError(Status
);
4995 return ERROR_SUCCESS
;
4999 /************************************************************************
5005 RegSetValueA(HKEY hKeyOriginal
,
5016 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
5018 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
5020 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
5021 if (!NT_SUCCESS(Status
))
5023 return RtlNtStatusToDosError (Status
);
5027 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5029 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
5030 if (ret
!= ERROR_SUCCESS
)
5034 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
5036 RegCloseKey(subkey
);
5039 ClosePredefKey(hKey
);
5045 /************************************************************************
5051 RegSetValueW(HKEY hKeyOriginal
,
5062 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
5064 if (dwType
!= REG_SZ
|| !lpData
)
5065 return ERROR_INVALID_PARAMETER
;
5067 Status
= MapDefaultKey(&hKey
,
5069 if (!NT_SUCCESS(Status
))
5071 return RtlNtStatusToDosError(Status
);
5075 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
5077 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
5078 if (ret
!= ERROR_SUCCESS
)
5082 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
5083 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
5085 RegCloseKey(subkey
);
5088 ClosePredefKey(hKey
);
5094 /************************************************************************
5100 RegUnLoadKeyA(HKEY hKey
,
5103 UNICODE_STRING KeyName
;
5106 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
5109 ErrorCode
= RegUnLoadKeyW(hKey
,
5112 RtlFreeUnicodeString (&KeyName
);
5118 /************************************************************************
5124 RegUnLoadKeyW(HKEY hKey
,
5127 OBJECT_ATTRIBUTES ObjectAttributes
;
5128 UNICODE_STRING KeyName
;
5132 if (hKey
== HKEY_PERFORMANCE_DATA
)
5134 return ERROR_INVALID_HANDLE
;
5137 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5138 if (!NT_SUCCESS(Status
))
5140 return RtlNtStatusToDosError(Status
);
5143 RtlInitUnicodeString(&KeyName
,
5146 InitializeObjectAttributes(&ObjectAttributes
,
5148 OBJ_CASE_INSENSITIVE
,
5152 Status
= NtUnloadKey(&ObjectAttributes
);
5154 ClosePredefKey(KeyHandle
);
5156 if (!NT_SUCCESS(Status
))
5158 return RtlNtStatusToDosError(Status
);
5161 return ERROR_SUCCESS
;
5165 /******************************************************************************
5166 * load_string [Internal]
5168 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5169 * avoid importing user32, which is higher level than advapi32. Helper for
5172 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5179 /* Negative values have to be inverted. */
5180 if (HIWORD(resId
) == 0xffff)
5181 resId
= (UINT
)(-((INT
)resId
));
5183 /* Load the resource into memory and get a pointer to it. */
5184 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5185 if (!hResource
) return 0;
5186 hMemory
= LoadResource(hModule
, hResource
);
5187 if (!hMemory
) return 0;
5188 pString
= LockResource(hMemory
);
5190 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5191 idxString
= resId
& 0xf;
5192 while (idxString
--) pString
+= *pString
+ 1;
5194 /* If no buffer is given, return length of the string. */
5195 if (!pwszBuffer
) return *pString
;
5197 /* Else copy over the string, respecting the buffer size. */
5198 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5201 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5202 pwszBuffer
[cMaxChars
] = L
'\0';
5209 /************************************************************************
5215 RegLoadMUIStringW(IN HKEY hKey
,
5216 IN LPCWSTR pszValue OPTIONAL
,
5217 OUT LPWSTR pszOutBuf
,
5219 OUT LPDWORD pcbData OPTIONAL
,
5221 IN LPCWSTR pszDirectory OPTIONAL
)
5223 DWORD dwValueType
, cbData
;
5224 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5227 /* Parameter sanity checks. */
5228 if (!hKey
|| !pszOutBuf
)
5229 return ERROR_INVALID_PARAMETER
;
5231 if (pszDirectory
&& *pszDirectory
)
5233 FIXME("BaseDir parameter not yet supported!\n");
5234 return ERROR_INVALID_PARAMETER
;
5237 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5238 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5239 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5240 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5242 result
= ERROR_FILE_NOT_FOUND
;
5245 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5246 if (!pwszTempBuffer
)
5248 result
= ERROR_NOT_ENOUGH_MEMORY
;
5251 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5252 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5254 /* Expand environment variables, if appropriate, or copy the original string over. */
5255 if (dwValueType
== REG_EXPAND_SZ
)
5257 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5258 if (!cbData
) goto cleanup
;
5259 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5260 if (!pwszExpandedBuffer
)
5262 result
= ERROR_NOT_ENOUGH_MEMORY
;
5265 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5269 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5270 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5273 /* If the value references a resource based string, parse the value and load the string.
5274 * Else just copy over the original value. */
5275 result
= ERROR_SUCCESS
;
5276 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5278 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5282 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5286 /* Format of the expanded value is 'path_to_dll,-resId' */
5287 if (!pComma
|| pComma
[1] != L
'-')
5289 result
= ERROR_BADKEY
;
5293 uiStringId
= _wtoi(pComma
+2);
5296 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5297 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5298 result
= ERROR_BADKEY
;
5299 FreeLibrary(hModule
);
5303 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5304 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5309 /************************************************************************
5315 RegLoadMUIStringA(IN HKEY hKey
,
5316 IN LPCSTR pszValue OPTIONAL
,
5317 OUT LPSTR pszOutBuf
,
5319 OUT LPDWORD pcbData OPTIONAL
,
5321 IN LPCSTR pszDirectory OPTIONAL
)
5323 UNICODE_STRING valueW
, baseDirW
;
5325 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5328 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5329 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5330 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5331 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5333 result
= ERROR_NOT_ENOUGH_MEMORY
;
5337 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5340 if (result
== ERROR_SUCCESS
)
5342 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5348 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5349 RtlFreeUnicodeString(&baseDirW
);
5350 RtlFreeUnicodeString(&valueW
);