2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
17 #include <wine/debug.h>
19 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
21 /* DEFINES ******************************************************************/
23 #define MAX_DEFAULT_HANDLES 6
24 #define REG_MAX_NAME_SIZE 256
25 #define REG_MAX_DATA_SIZE 2048
27 /* GLOBALS ******************************************************************/
29 static RTL_CRITICAL_SECTION HandleTableCS
;
30 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
31 static HANDLE ProcessHeap
;
32 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
33 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
35 /* PROTOTYPES ***************************************************************/
37 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
38 static VOID
CloseDefaultKeys(VOID
);
39 #define ClosePredefKey(Handle) \
40 if ((ULONG_PTR)Handle & 0x1) { \
43 #define IsPredefKey(HKey) \
44 (((ULONG)(HKey) & 0xF0000000) == 0x80000000)
45 #define GetPredefKeyIndex(HKey) \
46 ((ULONG)(HKey) & 0x0FFFFFFF)
48 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
49 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
54 /* FUNCTIONS ****************************************************************/
55 /* check if value type needs string conversion (Ansi<->Unicode) */
56 __inline
static int is_string( DWORD type
)
58 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
61 /************************************************************************
62 * RegInitDefaultHandles
67 TRACE("RegInitialize()\n");
69 ProcessHeap
= RtlGetProcessHeap();
70 RtlZeroMemory(DefaultHandleTable
,
71 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
72 RtlInitializeCriticalSection(&HandleTableCS
);
78 /************************************************************************
84 TRACE("RegCleanup()\n");
87 RtlDeleteCriticalSection(&HandleTableCS
);
94 OpenPredefinedKey(IN ULONG Index
,
101 case 0: /* HKEY_CLASSES_ROOT */
102 Status
= OpenClassesRootKey (Handle
);
105 case 1: /* HKEY_CURRENT_USER */
106 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
110 case 2: /* HKEY_LOCAL_MACHINE */
111 Status
= OpenLocalMachineKey (Handle
);
114 case 3: /* HKEY_USERS */
115 Status
= OpenUsersKey (Handle
);
118 case 4: /* HKEY_PERFORMANCE_DATA */
119 Status
= OpenPerformanceDataKey (Handle
);
123 case 5: /* HKEY_CURRENT_CONFIG */
124 Status
= OpenCurrentConfigKey (Handle
);
127 case 6: /* HKEY_DYN_DATA */
128 Status
= STATUS_NOT_IMPLEMENTED
;
132 WARN("MapDefaultHandle() no handle creator\n");
133 Status
= STATUS_INVALID_PARAMETER
;
142 MapDefaultKey(OUT PHANDLE RealKey
,
147 BOOLEAN DoOpen
, DefDisabled
;
148 NTSTATUS Status
= STATUS_SUCCESS
;
150 TRACE("MapDefaultKey (Key %x)\n", Key
);
152 if (!IsPredefKey(Key
))
154 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
155 return STATUS_SUCCESS
;
158 /* Handle special cases here */
159 Index
= GetPredefKeyIndex(Key
);
160 if (Index
>= MAX_DEFAULT_HANDLES
)
162 return STATUS_INVALID_PARAMETER
;
165 RtlEnterCriticalSection (&HandleTableCS
);
167 if (Key
== HKEY_CURRENT_USER
)
168 DefDisabled
= DefaultHandleHKUDisabled
;
170 DefDisabled
= DefaultHandlesDisabled
;
174 Handle
= &DefaultHandleTable
[Index
];
175 DoOpen
= (*Handle
== NULL
);
185 /* create/open the default handle */
186 Status
= OpenPredefinedKey(Index
,
190 if (NT_SUCCESS(Status
))
195 *(PULONG_PTR
)Handle
|= 0x1;
198 RtlLeaveCriticalSection (&HandleTableCS
);
205 CloseDefaultKeys(VOID
)
209 RtlEnterCriticalSection(&HandleTableCS
);
211 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
213 if (DefaultHandleTable
[i
] != NULL
)
215 NtClose(DefaultHandleTable
[i
]);
216 DefaultHandleTable
[i
] = NULL
;
220 RtlLeaveCriticalSection(&HandleTableCS
);
225 OpenClassesRootKey(PHANDLE KeyHandle
)
227 OBJECT_ATTRIBUTES Attributes
;
228 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
230 TRACE("OpenClassesRootKey()\n");
232 InitializeObjectAttributes(&Attributes
,
234 OBJ_CASE_INSENSITIVE
,
237 return NtOpenKey(KeyHandle
,
244 OpenLocalMachineKey(PHANDLE KeyHandle
)
246 OBJECT_ATTRIBUTES Attributes
;
247 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
250 TRACE("OpenLocalMachineKey()\n");
252 InitializeObjectAttributes(&Attributes
,
254 OBJ_CASE_INSENSITIVE
,
257 Status
= NtOpenKey(KeyHandle
,
261 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
268 OpenUsersKey(PHANDLE KeyHandle
)
270 OBJECT_ATTRIBUTES Attributes
;
271 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
273 TRACE("OpenUsersKey()\n");
275 InitializeObjectAttributes(&Attributes
,
277 OBJ_CASE_INSENSITIVE
,
280 return NtOpenKey(KeyHandle
,
287 OpenCurrentConfigKey (PHANDLE KeyHandle
)
289 OBJECT_ATTRIBUTES Attributes
;
290 UNICODE_STRING KeyName
=
291 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
293 TRACE("OpenCurrentConfigKey()\n");
295 InitializeObjectAttributes(&Attributes
,
297 OBJ_CASE_INSENSITIVE
,
300 return NtOpenKey(KeyHandle
,
306 /************************************************************************
307 * RegDisablePredefinedCache
312 RegDisablePredefinedCache(VOID
)
314 RtlEnterCriticalSection(&HandleTableCS
);
315 DefaultHandleHKUDisabled
= TRUE
;
316 RtlLeaveCriticalSection(&HandleTableCS
);
317 return ERROR_SUCCESS
;
321 /************************************************************************
322 * RegDisablePredefinedCacheEx
327 RegDisablePredefinedCacheEx(VOID
)
329 RtlEnterCriticalSection(&HandleTableCS
);
330 DefaultHandlesDisabled
= TRUE
;
331 DefaultHandleHKUDisabled
= TRUE
;
332 RtlLeaveCriticalSection(&HandleTableCS
);
333 return ERROR_SUCCESS
;
337 /************************************************************************
338 * RegOverridePredefKey
343 RegOverridePredefKey(IN HKEY hKey
,
344 IN HKEY hNewHKey OPTIONAL
)
346 LONG ErrorCode
= ERROR_SUCCESS
;
348 if ((hKey
== HKEY_CLASSES_ROOT
||
349 hKey
== HKEY_CURRENT_CONFIG
||
350 hKey
== HKEY_CURRENT_USER
||
351 hKey
== HKEY_LOCAL_MACHINE
||
352 hKey
== HKEY_PERFORMANCE_DATA
||
353 hKey
== HKEY_USERS
) &&
354 !IsPredefKey(hNewHKey
))
359 Index
= GetPredefKeyIndex(hKey
);
360 Handle
= &DefaultHandleTable
[Index
];
362 if (hNewHKey
== NULL
)
364 /* restore the default mapping */
365 NTSTATUS Status
= OpenPredefinedKey(Index
,
367 if (!NT_SUCCESS(Status
))
369 return RtlNtStatusToDosError(Status
);
372 ASSERT(hNewHKey
!= NULL
);
375 RtlEnterCriticalSection(&HandleTableCS
);
377 /* close the currently mapped handle if existing */
383 /* update the mapping */
386 RtlLeaveCriticalSection(&HandleTableCS
);
389 ErrorCode
= ERROR_INVALID_HANDLE
;
395 /************************************************************************
401 RegCloseKey(HKEY hKey
)
405 /* don't close null handle or a pseudo handle */
406 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
408 return ERROR_INVALID_HANDLE
;
411 Status
= NtClose(hKey
);
412 if (!NT_SUCCESS(Status
))
414 return RtlNtStatusToDosError(Status
);
417 return ERROR_SUCCESS
;
422 RegpCopyTree(IN HKEY hKeySrc
,
427 LIST_ENTRY ListEntry
;
430 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
432 LIST_ENTRY copyQueueHead
;
433 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
436 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
437 KEY_NODE_INFORMATION
*KeyNode
;
440 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
441 NTSTATUS Status
= STATUS_SUCCESS
;
442 NTSTATUS Status2
= STATUS_SUCCESS
;
444 InitializeListHead(©QueueHead
);
446 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
449 if (Info
.Buffer
== NULL
)
451 return STATUS_INSUFFICIENT_RESOURCES
;
454 copyKeys
= RtlAllocateHeap(ProcessHeap
,
456 sizeof(REGP_COPY_KEYS
));
457 if (copyKeys
!= NULL
)
459 copyKeys
->hKeySrc
= hKeySrc
;
460 copyKeys
->hKeyDest
= hKeyDest
;
461 InsertHeadList(©QueueHead
,
462 ©Keys
->ListEntry
);
464 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
468 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
472 /* enumerate all values and copy them */
476 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
478 KeyValueFullInformation
,
481 &BufferSizeRequired
);
482 if (NT_SUCCESS(Status2
))
484 UNICODE_STRING ValueName
;
487 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
488 ValueName
.Length
= Info
.KeyValue
->NameLength
;
489 ValueName
.MaximumLength
= ValueName
.Length
;
490 ValueName
.Buffer
= Info
.KeyValue
->Name
;
492 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
494 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
496 Info
.KeyValue
->TitleIndex
,
499 Info
.KeyValue
->DataLength
);
501 /* don't break, let's try to copy as many values as possible */
502 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
509 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
513 ASSERT(BufferSize
< BufferSizeRequired
);
515 Buffer
= RtlReAllocateHeap(ProcessHeap
,
521 Info
.Buffer
= Buffer
;
526 /* don't break, let's try to copy as many values as possible */
527 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
530 if (NT_SUCCESS(Status
))
538 /* break to avoid an infinite loop in case of denied access or
540 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
549 /* enumerate all subkeys and open and enqueue them */
553 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
558 &BufferSizeRequired
);
559 if (NT_SUCCESS(Status2
))
561 HANDLE KeyHandle
, NewKeyHandle
;
562 OBJECT_ATTRIBUTES ObjectAttributes
;
563 UNICODE_STRING SubKeyName
, ClassName
;
565 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
566 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
567 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
568 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
569 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
570 ClassName
.MaximumLength
= ClassName
.Length
;
571 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
573 /* open the subkey with sufficient rights */
575 InitializeObjectAttributes(&ObjectAttributes
,
577 OBJ_CASE_INSENSITIVE
,
581 Status2
= NtOpenKey(&KeyHandle
,
582 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
584 if (NT_SUCCESS(Status2
))
586 /* FIXME - attempt to query the security information */
588 InitializeObjectAttributes(&ObjectAttributes
,
590 OBJ_CASE_INSENSITIVE
,
594 Status2
= NtCreateKey(&NewKeyHandle
,
597 Info
.KeyNode
->TitleIndex
,
601 if (NT_SUCCESS(Status2
))
603 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
605 sizeof(REGP_COPY_KEYS
));
606 if (newCopyKeys
!= NULL
)
608 /* save the handles and enqueue the subkey */
609 newCopyKeys
->hKeySrc
= KeyHandle
;
610 newCopyKeys
->hKeyDest
= NewKeyHandle
;
611 InsertTailList(©QueueHead
,
612 &newCopyKeys
->ListEntry
);
617 NtClose(NewKeyHandle
);
619 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
628 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
635 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
639 ASSERT(BufferSize
< BufferSizeRequired
);
641 Buffer
= RtlReAllocateHeap(ProcessHeap
,
647 Info
.Buffer
= Buffer
;
652 /* don't break, let's try to copy as many keys as possible */
653 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
656 if (NT_SUCCESS(Status
))
664 /* break to avoid an infinite loop in case of denied access or
666 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
675 /* close the handles and remove the entry from the list */
676 if (copyKeys
->hKeySrc
!= hKeySrc
)
678 NtClose(copyKeys
->hKeySrc
);
680 if (copyKeys
->hKeyDest
!= hKeyDest
)
682 NtClose(copyKeys
->hKeyDest
);
685 RemoveEntryList(©Keys
->ListEntry
);
687 RtlFreeHeap(ProcessHeap
,
690 } while (!IsListEmpty(©QueueHead
));
693 Status
= STATUS_INSUFFICIENT_RESOURCES
;
695 RtlFreeHeap(ProcessHeap
,
703 /************************************************************************
709 RegCopyTreeW(IN HKEY hKeySrc
,
710 IN LPCWSTR lpSubKey OPTIONAL
,
713 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
716 Status
= MapDefaultKey(&KeyHandle
,
718 if (!NT_SUCCESS(Status
))
720 return RtlNtStatusToDosError(Status
);
723 Status
= MapDefaultKey(&DestKeyHandle
,
725 if (!NT_SUCCESS(Status
))
730 if (lpSubKey
!= NULL
)
732 OBJECT_ATTRIBUTES ObjectAttributes
;
733 UNICODE_STRING SubKeyName
;
735 RtlInitUnicodeString(&SubKeyName
,
738 InitializeObjectAttributes(&ObjectAttributes
,
740 OBJ_CASE_INSENSITIVE
,
744 Status
= NtOpenKey(&SubKeyHandle
,
745 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
747 if (!NT_SUCCESS(Status
))
752 CurKey
= SubKeyHandle
;
757 Status
= RegpCopyTree(CurKey
,
760 if (SubKeyHandle
!= NULL
)
762 NtClose(SubKeyHandle
);
766 ClosePredefKey(DestKeyHandle
);
768 ClosePredefKey(KeyHandle
);
770 if (!NT_SUCCESS(Status
))
772 return RtlNtStatusToDosError(Status
);
775 return ERROR_SUCCESS
;
779 /************************************************************************
785 RegCopyTreeA(IN HKEY hKeySrc
,
786 IN LPCSTR lpSubKey OPTIONAL
,
789 UNICODE_STRING SubKeyName
= {0};
792 if (lpSubKey
!= NULL
&&
793 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
796 return ERROR_NOT_ENOUGH_MEMORY
;
799 Ret
= RegCopyTreeW(hKeySrc
,
803 RtlFreeUnicodeString(&SubKeyName
);
809 /************************************************************************
810 * RegConnectRegistryA
815 RegConnectRegistryA(IN LPCSTR lpMachineName
,
819 UNICODE_STRING MachineName
= {0};
822 if (lpMachineName
!= NULL
&&
823 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
824 (LPSTR
)lpMachineName
))
826 return ERROR_NOT_ENOUGH_MEMORY
;
829 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
833 RtlFreeUnicodeString(&MachineName
);
839 /************************************************************************
840 * RegConnectRegistryW
845 RegConnectRegistryW(LPCWSTR lpMachineName
,
851 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
853 if (!lpMachineName
|| !*lpMachineName
)
855 /* Use the local machine name */
856 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
860 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
861 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
863 /* MSDN says lpMachineName must start with \\ : not so */
864 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
867 if (GetComputerNameW(compName
, &len
))
869 if (!_wcsicmp(lpMachineName
, compName
))
870 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
873 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
874 ret
= ERROR_BAD_NETPATH
;
878 ret
= GetLastError();
885 /************************************************************************
888 * Create key and all necessary intermediate keys
891 CreateNestedKey(PHKEY KeyHandle
,
892 POBJECT_ATTRIBUTES ObjectAttributes
,
893 PUNICODE_STRING ClassString
,
896 DWORD
*lpdwDisposition
)
898 OBJECT_ATTRIBUTES LocalObjectAttributes
;
899 UNICODE_STRING LocalKeyName
;
902 ULONG FullNameLength
;
905 HANDLE LocalKeyHandle
;
907 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
913 (PULONG
)lpdwDisposition
);
914 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
915 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
918 /* Copy object attributes */
919 RtlCopyMemory(&LocalObjectAttributes
,
921 sizeof(OBJECT_ATTRIBUTES
));
922 RtlCreateUnicodeString(&LocalKeyName
,
923 ObjectAttributes
->ObjectName
->Buffer
);
924 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
925 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
927 LocalKeyHandle
= NULL
;
929 /* Remove the last part of the key name and try to create the key again. */
930 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
932 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
933 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
935 Status
= STATUS_UNSUCCESSFUL
;
940 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
942 Status
= NtCreateKey(&LocalKeyHandle
,
944 &LocalObjectAttributes
,
949 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
952 if (!NT_SUCCESS(Status
))
954 RtlFreeUnicodeString(&LocalKeyName
);
958 /* Add removed parts of the key name and create them too. */
959 Length
= wcslen(LocalKeyName
.Buffer
);
963 NtClose (LocalKeyHandle
);
965 LocalKeyName
.Buffer
[Length
] = L
'\\';
966 Length
= wcslen (LocalKeyName
.Buffer
);
967 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
969 if (Length
== FullNameLength
)
971 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
977 (PULONG
)lpdwDisposition
);
981 Status
= NtCreateKey(&LocalKeyHandle
,
983 &LocalObjectAttributes
,
988 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
989 if (!NT_SUCCESS(Status
))
993 RtlFreeUnicodeString(&LocalKeyName
);
999 /************************************************************************
1005 RegCreateKeyExA(HKEY hKey
,
1011 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1013 LPDWORD lpdwDisposition
)
1015 UNICODE_STRING SubKeyString
;
1016 UNICODE_STRING ClassString
;
1017 OBJECT_ATTRIBUTES Attributes
;
1021 TRACE("RegCreateKeyExA() called\n");
1023 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1024 return ERROR_INVALID_USER_BUFFER
;
1026 /* get the real parent key */
1027 Status
= MapDefaultKey(&ParentKey
,
1029 if (!NT_SUCCESS(Status
))
1031 return RtlNtStatusToDosError(Status
);
1034 TRACE("ParentKey %p\n", ParentKey
);
1036 if (lpClass
!= NULL
)
1038 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1042 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1044 InitializeObjectAttributes(&Attributes
,
1046 OBJ_CASE_INSENSITIVE
,
1048 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1049 Status
= CreateNestedKey(phkResult
,
1051 (lpClass
== NULL
)? NULL
: &ClassString
,
1055 RtlFreeUnicodeString(&SubKeyString
);
1056 if (lpClass
!= NULL
)
1058 RtlFreeUnicodeString(&ClassString
);
1061 ClosePredefKey(ParentKey
);
1063 TRACE("Status %x\n", Status
);
1064 if (!NT_SUCCESS(Status
))
1066 return RtlNtStatusToDosError(Status
);
1069 return ERROR_SUCCESS
;
1073 /************************************************************************
1079 RegCreateKeyExW(HKEY hKey
,
1085 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1087 LPDWORD lpdwDisposition
)
1089 UNICODE_STRING SubKeyString
;
1090 UNICODE_STRING ClassString
;
1091 OBJECT_ATTRIBUTES Attributes
;
1095 TRACE("RegCreateKeyExW() called\n");
1097 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1098 return ERROR_INVALID_USER_BUFFER
;
1100 /* get the real parent key */
1101 Status
= MapDefaultKey(&ParentKey
,
1103 if (!NT_SUCCESS(Status
))
1105 return RtlNtStatusToDosError(Status
);
1108 TRACE("ParentKey %p\n", ParentKey
);
1110 RtlInitUnicodeString(&ClassString
,
1112 RtlInitUnicodeString(&SubKeyString
,
1114 InitializeObjectAttributes(&Attributes
,
1116 OBJ_CASE_INSENSITIVE
,
1118 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1119 Status
= CreateNestedKey(phkResult
,
1121 (lpClass
== NULL
)? NULL
: &ClassString
,
1126 ClosePredefKey(ParentKey
);
1128 TRACE("Status %x\n", Status
);
1129 if (!NT_SUCCESS(Status
))
1131 return RtlNtStatusToDosError(Status
);
1134 return ERROR_SUCCESS
;
1138 /************************************************************************
1144 RegCreateKeyA(HKEY hKey
,
1148 return RegCreateKeyExA(hKey
,
1160 /************************************************************************
1166 RegCreateKeyW(HKEY hKey
,
1170 return RegCreateKeyExW(hKey
,
1182 /************************************************************************
1188 RegDeleteKeyA(HKEY hKey
,
1191 OBJECT_ATTRIBUTES ObjectAttributes
;
1192 UNICODE_STRING SubKeyName
;
1197 /* Make sure we got a subkey */
1201 return ERROR_INVALID_PARAMETER
;
1204 Status
= MapDefaultKey(&ParentKey
,
1206 if (!NT_SUCCESS(Status
))
1208 return RtlNtStatusToDosError(Status
);
1211 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1213 InitializeObjectAttributes(&ObjectAttributes
,
1215 OBJ_CASE_INSENSITIVE
,
1219 Status
= NtOpenKey(&TargetKey
,
1222 RtlFreeUnicodeString(&SubKeyName
);
1223 if (!NT_SUCCESS(Status
))
1228 Status
= NtDeleteKey(TargetKey
);
1229 NtClose (TargetKey
);
1232 ClosePredefKey(ParentKey
);
1234 if (!NT_SUCCESS(Status
))
1236 return RtlNtStatusToDosError(Status
);
1239 return ERROR_SUCCESS
;
1243 /************************************************************************
1249 RegDeleteKeyW(HKEY hKey
,
1252 OBJECT_ATTRIBUTES ObjectAttributes
;
1253 UNICODE_STRING SubKeyName
;
1258 /* Make sure we got a subkey */
1262 return ERROR_INVALID_PARAMETER
;
1265 Status
= MapDefaultKey(&ParentKey
,
1267 if (!NT_SUCCESS(Status
))
1269 return RtlNtStatusToDosError(Status
);
1272 RtlInitUnicodeString(&SubKeyName
,
1274 InitializeObjectAttributes(&ObjectAttributes
,
1276 OBJ_CASE_INSENSITIVE
,
1279 Status
= NtOpenKey(&TargetKey
,
1282 if (!NT_SUCCESS(Status
))
1287 Status
= NtDeleteKey(TargetKey
);
1291 ClosePredefKey(ParentKey
);
1293 if (!NT_SUCCESS(Status
))
1295 return RtlNtStatusToDosError(Status
);
1298 return ERROR_SUCCESS
;
1302 /************************************************************************
1309 RegDeleteKeyExA(HKEY hKey
,
1314 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1315 return ERROR_CALL_NOT_IMPLEMENTED
;
1319 /************************************************************************
1326 RegDeleteKeyExW(HKEY hKey
,
1331 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1332 return ERROR_CALL_NOT_IMPLEMENTED
;
1336 /************************************************************************
1337 * RegDeleteKeyValueW
1342 RegDeleteKeyValueW(IN HKEY hKey
,
1343 IN LPCWSTR lpSubKey OPTIONAL
,
1344 IN LPCWSTR lpValueName OPTIONAL
)
1346 UNICODE_STRING ValueName
;
1347 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1350 Status
= MapDefaultKey(&KeyHandle
,
1352 if (!NT_SUCCESS(Status
))
1354 return RtlNtStatusToDosError(Status
);
1357 if (lpSubKey
!= NULL
)
1359 OBJECT_ATTRIBUTES ObjectAttributes
;
1360 UNICODE_STRING SubKeyName
;
1362 RtlInitUnicodeString(&SubKeyName
,
1365 InitializeObjectAttributes(&ObjectAttributes
,
1367 OBJ_CASE_INSENSITIVE
,
1371 Status
= NtOpenKey(&SubKeyHandle
,
1374 if (!NT_SUCCESS(Status
))
1379 CurKey
= SubKeyHandle
;
1384 RtlInitUnicodeString(&ValueName
,
1385 (LPWSTR
)lpValueName
);
1387 Status
= NtDeleteValueKey(CurKey
,
1390 if (SubKeyHandle
!= NULL
)
1392 NtClose(SubKeyHandle
);
1396 ClosePredefKey(KeyHandle
);
1398 if (!NT_SUCCESS(Status
))
1400 return RtlNtStatusToDosError(Status
);
1403 return ERROR_SUCCESS
;
1407 /************************************************************************
1408 * RegDeleteKeyValueA
1413 RegDeleteKeyValueA(IN HKEY hKey
,
1414 IN LPCSTR lpSubKey OPTIONAL
,
1415 IN LPCSTR lpValueName OPTIONAL
)
1417 UNICODE_STRING SubKey
= {0}, ValueName
= {0};
1420 if (lpSubKey
!= NULL
&&
1421 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1424 return ERROR_NOT_ENOUGH_MEMORY
;
1427 if (lpValueName
!= NULL
&&
1428 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1429 (LPSTR
)lpValueName
))
1431 RtlFreeUnicodeString(&SubKey
);
1432 return ERROR_NOT_ENOUGH_MEMORY
;
1435 Ret
= RegDeleteKeyValueW(hKey
,
1439 RtlFreeUnicodeString(&SubKey
);
1440 RtlFreeUnicodeString(&ValueName
);
1446 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1448 RegpDeleteTree(IN HKEY hKey
)
1452 LIST_ENTRY ListEntry
;
1454 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1456 LIST_ENTRY delQueueHead
;
1457 PREG_DEL_KEYS delKeys
, newDelKeys
;
1460 PKEY_BASIC_INFORMATION BasicInfo
;
1461 PREG_DEL_KEYS KeyDelRoot
;
1462 NTSTATUS Status
= STATUS_SUCCESS
;
1463 NTSTATUS Status2
= STATUS_SUCCESS
;
1465 InitializeListHead(&delQueueHead
);
1467 ProcessHeap
= RtlGetProcessHeap();
1469 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1470 structure for the root key, we only do that for subkeys as we need to
1471 allocate REGP_DEL_KEYS structures anyway! */
1472 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1474 sizeof(REGP_DEL_KEYS
));
1475 if (KeyDelRoot
!= NULL
)
1477 KeyDelRoot
->KeyHandle
= hKey
;
1478 InsertTailList(&delQueueHead
,
1479 &KeyDelRoot
->ListEntry
);
1483 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1492 /* check if this key contains subkeys and delete them first by queuing
1493 them at the head of the list */
1494 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1496 KeyBasicInformation
,
1501 if (NT_SUCCESS(Status2
))
1503 OBJECT_ATTRIBUTES ObjectAttributes
;
1504 UNICODE_STRING SubKeyName
;
1506 ASSERT(newDelKeys
!= NULL
);
1507 ASSERT(BasicInfo
!= NULL
);
1509 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1510 SubKeyName
.Length
= BasicInfo
->NameLength
;
1511 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1512 SubKeyName
.Buffer
= BasicInfo
->Name
;
1514 InitializeObjectAttributes(&ObjectAttributes
,
1516 OBJ_CASE_INSENSITIVE
,
1520 /* open the subkey */
1521 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1522 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1524 if (!NT_SUCCESS(Status2
))
1529 /* enqueue this key to the head of the deletion queue */
1530 InsertHeadList(&delQueueHead
,
1531 &newDelKeys
->ListEntry
);
1533 /* try again from the head of the list */
1538 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1540 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1542 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1543 if (newDelKeys
!= NULL
)
1545 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1548 goto ReadFirstSubKey
;
1552 /* don't break, let's try to delete as many keys as possible */
1553 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1554 goto SubKeyFailureNoFree
;
1557 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1559 PREG_DEL_KEYS newDelKeys2
;
1561 ASSERT(newDelKeys
!= NULL
);
1563 /* we need more memory to query the key name */
1564 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1567 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1568 if (newDelKeys2
!= NULL
)
1570 newDelKeys
= newDelKeys2
;
1571 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1574 goto ReadFirstSubKey
;
1578 /* don't break, let's try to delete as many keys as possible */
1579 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1582 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1584 /* in some race conditions where another thread would delete
1585 the same tree at the same time, newDelKeys could actually
1587 if (newDelKeys
!= NULL
)
1589 RtlFreeHeap(ProcessHeap
,
1597 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1598 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1599 if (newDelKeys
!= NULL
)
1601 RtlFreeHeap(ProcessHeap
,
1606 SubKeyFailureNoFree
:
1607 /* don't break, let's try to delete as many keys as possible */
1608 if (NT_SUCCESS(Status
))
1614 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1616 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1618 if (!NT_SUCCESS(Status2
))
1620 /* close the key handle so we don't leak handles for keys we were
1621 unable to delete. But only do this for handles not supplied
1624 if (delKeys
->KeyHandle
!= hKey
)
1626 NtClose(delKeys
->KeyHandle
);
1629 if (NT_SUCCESS(Status
))
1631 /* don't break, let's try to delete as many keys as possible */
1636 /* remove the entry from the list */
1637 RemoveEntryList(&delKeys
->ListEntry
);
1639 RtlFreeHeap(ProcessHeap
,
1642 } while (!IsListEmpty(&delQueueHead
));
1645 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1651 /************************************************************************
1657 RegDeleteTreeW(IN HKEY hKey
,
1658 IN LPCWSTR lpSubKey OPTIONAL
)
1660 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1663 Status
= MapDefaultKey(&KeyHandle
,
1665 if (!NT_SUCCESS(Status
))
1667 return RtlNtStatusToDosError(Status
);
1670 if (lpSubKey
!= NULL
)
1672 OBJECT_ATTRIBUTES ObjectAttributes
;
1673 UNICODE_STRING SubKeyName
;
1675 RtlInitUnicodeString(&SubKeyName
,
1678 InitializeObjectAttributes(&ObjectAttributes
,
1680 OBJ_CASE_INSENSITIVE
,
1684 Status
= NtOpenKey(&SubKeyHandle
,
1685 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1687 if (!NT_SUCCESS(Status
))
1692 CurKey
= SubKeyHandle
;
1697 Status
= RegpDeleteTree(CurKey
);
1699 if (NT_SUCCESS(Status
))
1701 /* make sure we only close hKey (KeyHandle) when the caller specified a
1702 subkey, because the handle would be invalid already! */
1703 if (CurKey
!= KeyHandle
)
1705 ClosePredefKey(KeyHandle
);
1708 return ERROR_SUCCESS
;
1712 /* make sure we close all handles we created! */
1713 if (SubKeyHandle
!= NULL
)
1715 NtClose(SubKeyHandle
);
1719 ClosePredefKey(KeyHandle
);
1721 return RtlNtStatusToDosError(Status
);
1727 /************************************************************************
1734 RegDeleteTreeW(HKEY hKey
,
1738 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1739 DWORD dwMaxLen
, dwSize
;
1743 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1745 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1747 Status
= MapDefaultKey(&KeyHandle
,
1749 if (!NT_SUCCESS(Status
))
1751 return RtlNtStatusToDosError(Status
);
1754 hSubKey
= KeyHandle
;
1758 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1761 ClosePredefKey(KeyHandle
);
1766 /* Get highest length for keys, values */
1767 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1768 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1769 if (ret
) goto cleanup
;
1773 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1774 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1776 /* Name too big: alloc a buffer for it */
1777 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1779 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1785 /* Recursively delete all the subkeys */
1789 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1790 NULL
, NULL
, NULL
)) break;
1792 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1793 if (ret
) goto cleanup
;
1797 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1802 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1803 NULL
, NULL
, NULL
, NULL
)) break;
1805 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1806 if (ret
) goto cleanup
;
1810 /* Free buffer if allocated */
1811 if (lpszName
!= szNameBuf
)
1812 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1814 RegCloseKey(hSubKey
);
1816 ClosePredefKey(KeyHandle
);
1822 /************************************************************************
1828 RegDeleteTreeA(IN HKEY hKey
,
1829 IN LPCSTR lpSubKey OPTIONAL
)
1831 UNICODE_STRING SubKeyName
= {0};
1834 if (lpSubKey
!= NULL
&&
1835 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1838 return ERROR_NOT_ENOUGH_MEMORY
;
1841 Ret
= RegDeleteTreeW(hKey
,
1844 RtlFreeUnicodeString(&SubKeyName
);
1850 /************************************************************************
1851 * RegDisableReflectionKey
1856 RegDisableReflectionKey(IN HKEY hBase
)
1858 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1859 return ERROR_CALL_NOT_IMPLEMENTED
;
1863 /************************************************************************
1864 * RegEnableReflectionKey
1869 RegEnableReflectionKey(IN HKEY hBase
)
1871 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1872 return ERROR_CALL_NOT_IMPLEMENTED
;
1876 /******************************************************************************
1877 * RegpApplyRestrictions [internal]
1879 * Helper function for RegGetValueA/W.
1882 RegpApplyRestrictions(DWORD dwFlags
,
1887 /* Check if the type is restricted by the passed flags */
1888 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1894 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1895 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1896 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1897 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1898 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1899 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1900 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1903 if (dwFlags
& dwMask
)
1905 /* Type is not restricted, check for size mismatch */
1906 if (dwType
== REG_BINARY
)
1910 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1912 else if ((dwFlags
& RRF_RT_QWORD
) == RRF_RT_QWORD
)
1915 if (cbExpect
&& cbData
!= cbExpect
)
1916 *ret
= ERROR_DATATYPE_MISMATCH
;
1919 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1924 /******************************************************************************
1925 * RegGetValueW [ADVAPI32.@]
1927 * Retrieves the type and data for a value name associated with a key,
1928 * optionally expanding its content and restricting its type.
1931 * hKey [I] Handle to an open key.
1932 * pszSubKey [I] Name of the subkey of hKey.
1933 * pszValue [I] Name of value under hKey/szSubKey to query.
1934 * dwFlags [I] Flags restricting the value type to retrieve.
1935 * pdwType [O] Destination for the values type, may be NULL.
1936 * pvData [O] Destination for the values content, may be NULL.
1937 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1938 * retrieve the whole content, including the trailing '\0'
1942 * Success: ERROR_SUCCESS
1943 * Failure: nonzero error code from Winerror.h
1946 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1947 * expanded and pdwType is set to REG_SZ instead.
1948 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1949 * without RRF_NOEXPAND is thus not allowed.
1950 * An exception is the case where RRF_RT_ANY is specified, because then
1951 * RRF_NOEXPAND is allowed.
1954 RegGetValueW(HKEY hKey
,
1962 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1966 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1967 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1968 pvData
, pcbData
, cbData
);
1970 if (pvData
&& !pcbData
)
1971 return ERROR_INVALID_PARAMETER
;
1972 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1973 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1974 return ERROR_INVALID_PARAMETER
;
1976 if (pszSubKey
&& pszSubKey
[0])
1978 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1979 if (ret
!= ERROR_SUCCESS
) return ret
;
1982 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1984 /* If we are going to expand we need to read in the whole the value even
1985 * if the passed buffer was too small as the expanded string might be
1986 * smaller than the unexpanded one and could fit into cbData bytes. */
1987 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1988 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1992 HeapFree(GetProcessHeap(), 0, pvBuf
);
1994 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1997 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2001 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2002 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2003 &dwType
, pvBuf
, &cbData
);
2006 /* Even if cbData was large enough we have to copy the
2007 * string since ExpandEnvironmentStrings can't handle
2008 * overlapping buffers. */
2009 CopyMemory(pvBuf
, pvData
, cbData
);
2012 /* Both the type or the value itself could have been modified in
2013 * between so we have to keep retrying until the buffer is large
2014 * enough or we no longer have to expand the value. */
2016 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2018 if (ret
== ERROR_SUCCESS
)
2020 /* Recheck dwType in case it changed since the first call */
2021 if (dwType
== REG_EXPAND_SZ
)
2023 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2024 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2026 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2027 ret
= ERROR_MORE_DATA
;
2030 CopyMemory(pvData
, pvBuf
, *pcbData
);
2033 HeapFree(GetProcessHeap(), 0, pvBuf
);
2036 if (pszSubKey
&& pszSubKey
[0])
2039 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2041 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2042 ZeroMemory(pvData
, *pcbData
);
2054 /******************************************************************************
2055 * RegGetValueA [ADVAPI32.@]
2060 RegGetValueA(HKEY hKey
,
2068 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2072 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2073 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2076 if (pvData
&& !pcbData
)
2077 return ERROR_INVALID_PARAMETER
;
2078 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2079 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2080 return ERROR_INVALID_PARAMETER
;
2082 if (pszSubKey
&& pszSubKey
[0])
2084 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2085 if (ret
!= ERROR_SUCCESS
) return ret
;
2088 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2090 /* If we are going to expand we need to read in the whole the value even
2091 * if the passed buffer was too small as the expanded string might be
2092 * smaller than the unexpanded one and could fit into cbData bytes. */
2093 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2094 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2097 HeapFree(GetProcessHeap(), 0, pvBuf
);
2099 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2102 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2106 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2107 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2108 &dwType
, pvBuf
, &cbData
);
2111 /* Even if cbData was large enough we have to copy the
2112 * string since ExpandEnvironmentStrings can't handle
2113 * overlapping buffers. */
2114 CopyMemory(pvBuf
, pvData
, cbData
);
2117 /* Both the type or the value itself could have been modified in
2118 * between so we have to keep retrying until the buffer is large
2119 * enough or we no longer have to expand the value. */
2120 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2122 if (ret
== ERROR_SUCCESS
)
2124 /* Recheck dwType in case it changed since the first call */
2125 if (dwType
== REG_EXPAND_SZ
)
2127 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2128 pcbData
? *pcbData
: 0);
2130 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2131 ret
= ERROR_MORE_DATA
;
2134 CopyMemory(pvData
, pvBuf
, *pcbData
);
2137 HeapFree(GetProcessHeap(), 0, pvBuf
);
2140 if (pszSubKey
&& pszSubKey
[0])
2143 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2145 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2146 ZeroMemory(pvData
, *pcbData
);
2148 if (pdwType
) *pdwType
= dwType
;
2149 if (pcbData
) *pcbData
= cbData
;
2155 /************************************************************************
2161 RegSetKeyValueW(IN HKEY hKey
,
2162 IN LPCWSTR lpSubKey OPTIONAL
,
2163 IN LPCWSTR lpValueName OPTIONAL
,
2165 IN LPCVOID lpData OPTIONAL
,
2168 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2172 Status
= MapDefaultKey(&KeyHandle
,
2174 if (!NT_SUCCESS(Status
))
2176 return RtlNtStatusToDosError(Status
);
2179 if (lpSubKey
!= NULL
)
2181 OBJECT_ATTRIBUTES ObjectAttributes
;
2182 UNICODE_STRING SubKeyName
;
2184 RtlInitUnicodeString(&SubKeyName
,
2187 InitializeObjectAttributes(&ObjectAttributes
,
2189 OBJ_CASE_INSENSITIVE
,
2193 Status
= NtOpenKey(&SubKeyHandle
,
2196 if (!NT_SUCCESS(Status
))
2198 Ret
= RtlNtStatusToDosError(Status
);
2202 CurKey
= SubKeyHandle
;
2207 Ret
= RegSetValueExW(CurKey
,
2214 if (SubKeyHandle
!= NULL
)
2216 NtClose(SubKeyHandle
);
2220 ClosePredefKey(KeyHandle
);
2226 /************************************************************************
2232 RegSetKeyValueA(IN HKEY hKey
,
2233 IN LPCSTR lpSubKey OPTIONAL
,
2234 IN LPCSTR lpValueName OPTIONAL
,
2236 IN LPCVOID lpData OPTIONAL
,
2239 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2243 Status
= MapDefaultKey(&KeyHandle
,
2245 if (!NT_SUCCESS(Status
))
2247 return RtlNtStatusToDosError(Status
);
2250 if (lpSubKey
!= NULL
)
2252 OBJECT_ATTRIBUTES ObjectAttributes
;
2253 UNICODE_STRING SubKeyName
;
2255 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2258 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2262 InitializeObjectAttributes(&ObjectAttributes
,
2264 OBJ_CASE_INSENSITIVE
,
2268 Status
= NtOpenKey(&SubKeyHandle
,
2272 RtlFreeUnicodeString(&SubKeyName
);
2274 if (!NT_SUCCESS(Status
))
2276 Ret
= RtlNtStatusToDosError(Status
);
2280 CurKey
= SubKeyHandle
;
2285 Ret
= RegSetValueExA(CurKey
,
2292 if (SubKeyHandle
!= NULL
)
2294 NtClose(SubKeyHandle
);
2298 ClosePredefKey(KeyHandle
);
2304 /************************************************************************
2310 RegDeleteValueA(HKEY hKey
,
2313 UNICODE_STRING ValueName
;
2317 Status
= MapDefaultKey(&KeyHandle
,
2319 if (!NT_SUCCESS(Status
))
2321 return RtlNtStatusToDosError(Status
);
2324 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2325 (LPSTR
)lpValueName
);
2326 Status
= NtDeleteValueKey(KeyHandle
,
2328 RtlFreeUnicodeString (&ValueName
);
2330 ClosePredefKey(KeyHandle
);
2332 if (!NT_SUCCESS(Status
))
2334 return RtlNtStatusToDosError(Status
);
2337 return ERROR_SUCCESS
;
2341 /************************************************************************
2347 RegDeleteValueW(HKEY hKey
,
2348 LPCWSTR lpValueName
)
2350 UNICODE_STRING ValueName
;
2354 Status
= MapDefaultKey(&KeyHandle
,
2356 if (!NT_SUCCESS(Status
))
2358 return RtlNtStatusToDosError(Status
);
2361 RtlInitUnicodeString(&ValueName
,
2362 (LPWSTR
)lpValueName
);
2364 Status
= NtDeleteValueKey(KeyHandle
,
2367 ClosePredefKey(KeyHandle
);
2369 if (!NT_SUCCESS(Status
))
2371 return RtlNtStatusToDosError(Status
);
2374 return ERROR_SUCCESS
;
2378 /************************************************************************
2384 RegEnumKeyA(HKEY hKey
,
2392 return RegEnumKeyExA(hKey
,
2403 /************************************************************************
2409 RegEnumKeyW(HKEY hKey
,
2417 return RegEnumKeyExW(hKey
,
2428 /************************************************************************
2434 RegEnumKeyExA(HKEY hKey
,
2441 PFILETIME lpftLastWriteTime
)
2445 KEY_NODE_INFORMATION Node
;
2446 KEY_BASIC_INFORMATION Basic
;
2449 UNICODE_STRING StringU
;
2450 ANSI_STRING StringA
;
2451 LONG ErrorCode
= ERROR_SUCCESS
;
2453 DWORD ClassLength
= 0;
2459 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2460 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2462 if ((lpClass
) && (!lpcbClass
))
2464 return ERROR_INVALID_PARAMETER
;
2467 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2468 if (!NT_SUCCESS(Status
))
2470 return RtlNtStatusToDosError(Status
);
2475 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2486 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2493 /* The class name should start at a dword boundary */
2494 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2498 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2501 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2502 if (KeyInfo
== NULL
)
2504 ErrorCode
= ERROR_OUTOFMEMORY
;
2508 Status
= NtEnumerateKey(KeyHandle
,
2510 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2514 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2515 if (!NT_SUCCESS(Status
))
2517 ErrorCode
= RtlNtStatusToDosError (Status
);
2521 if (lpClass
== NULL
)
2523 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2525 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2529 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2530 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2531 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2536 if (KeyInfo
->Node
.NameLength
> NameLength
||
2537 KeyInfo
->Node
.ClassLength
> ClassLength
)
2539 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2543 StringA
.Buffer
= lpClass
;
2545 StringA
.MaximumLength
= *lpcbClass
;
2546 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2547 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2548 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2549 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2550 lpClass
[StringA
.Length
] = 0;
2551 *lpcbClass
= StringA
.Length
;
2552 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2553 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2554 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2558 if (ErrorCode
== ERROR_SUCCESS
)
2560 StringA
.Buffer
= lpName
;
2562 StringA
.MaximumLength
= *lpcbName
;
2563 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2564 lpName
[StringA
.Length
] = 0;
2565 *lpcbName
= StringA
.Length
;
2566 if (lpftLastWriteTime
!= NULL
)
2568 if (lpClass
== NULL
)
2570 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2571 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2575 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2576 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2582 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2583 TRACE("Key Namea1 Length %d\n", NameLength
);
2584 TRACE("Key Namea Length %d\n", *lpcbName
);
2585 TRACE("Key Namea %s\n", lpName
);
2587 RtlFreeHeap(ProcessHeap
,
2592 ClosePredefKey(KeyHandle
);
2598 /************************************************************************
2604 RegEnumKeyExW(HKEY hKey
,
2611 PFILETIME lpftLastWriteTime
)
2615 KEY_NODE_INFORMATION Node
;
2616 KEY_BASIC_INFORMATION Basic
;
2622 ULONG ClassLength
= 0;
2624 LONG ErrorCode
= ERROR_SUCCESS
;
2627 Status
= MapDefaultKey(&KeyHandle
,
2629 if (!NT_SUCCESS(Status
))
2631 return RtlNtStatusToDosError(Status
);
2636 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2647 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2654 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2658 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2661 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2664 if (KeyInfo
== NULL
)
2666 ErrorCode
= ERROR_OUTOFMEMORY
;
2670 Status
= NtEnumerateKey(KeyHandle
,
2672 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2676 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2677 if (!NT_SUCCESS(Status
))
2679 ErrorCode
= RtlNtStatusToDosError (Status
);
2683 if (lpClass
== NULL
)
2685 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2687 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2691 RtlCopyMemory(lpName
,
2692 KeyInfo
->Basic
.Name
,
2693 KeyInfo
->Basic
.NameLength
);
2694 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2695 lpName
[*lpcbName
] = 0;
2700 if (KeyInfo
->Node
.NameLength
> NameLength
||
2701 KeyInfo
->Node
.ClassLength
> ClassLength
)
2703 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2707 RtlCopyMemory(lpName
,
2709 KeyInfo
->Node
.NameLength
);
2710 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2711 lpName
[*lpcbName
] = 0;
2712 RtlCopyMemory(lpClass
,
2713 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2714 KeyInfo
->Node
.ClassLength
);
2715 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2716 lpClass
[*lpcbClass
] = 0;
2720 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2722 if (lpClass
== NULL
)
2724 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2725 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2729 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2730 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2735 RtlFreeHeap(ProcessHeap
,
2740 ClosePredefKey(KeyHandle
);
2746 /************************************************************************
2752 RegEnumValueA(HKEY hKey
,
2764 char buffer
[256], *buf_ptr
= buffer
;
2765 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2766 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2768 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2769 // hkey, index, value, val_count, reserved, type, data, count );
2771 /* NT only checks count, not val_count */
2772 if ((data
&& !count
) || reserved
)
2773 return ERROR_INVALID_PARAMETER
;
2775 status
= MapDefaultKey(&KeyHandle
, hKey
);
2776 if (!NT_SUCCESS(status
))
2778 return RtlNtStatusToDosError(status
);
2781 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2782 if (data
) total_size
+= *count
;
2783 total_size
= min( sizeof(buffer
), total_size
);
2785 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2786 buffer
, total_size
, &total_size
);
2787 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2789 /* we need to fetch the contents for a string type even if not requested,
2790 * because we need to compute the length of the ASCII string. */
2791 if (value
|| data
|| is_string(info
->Type
))
2793 /* retry with a dynamically allocated buffer */
2794 while (status
== STATUS_BUFFER_OVERFLOW
)
2796 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2797 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2799 status
= STATUS_INSUFFICIENT_RESOURCES
;
2802 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2803 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2804 buf_ptr
, total_size
, &total_size
);
2807 if (status
) goto done
;
2809 if (is_string(info
->Type
))
2812 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2813 total_size
- info
->DataOffset
);
2816 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2819 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2820 total_size
- info
->DataOffset
);
2821 /* if the type is REG_SZ and data is not 0-terminated
2822 * and there is enough space in the buffer NT appends a \0 */
2823 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2826 info
->DataLength
= len
;
2830 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2831 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2834 if (value
&& !status
)
2838 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2839 if (len
>= *val_count
)
2841 status
= STATUS_BUFFER_OVERFLOW
;
2844 len
= *val_count
- 1;
2845 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2851 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2857 else status
= STATUS_SUCCESS
;
2859 if (type
) *type
= info
->Type
;
2860 if (count
) *count
= info
->DataLength
;
2863 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2864 ClosePredefKey(KeyHandle
);
2865 return RtlNtStatusToDosError(status
);
2869 /******************************************************************************
2870 * RegEnumValueW [ADVAPI32.@]
2874 * hkey [I] Handle to key to query
2875 * index [I] Index of value to query
2876 * value [O] Value string
2877 * val_count [I/O] Size of value buffer (in wchars)
2878 * reserved [I] Reserved
2879 * type [O] Type code
2880 * data [O] Value data
2881 * count [I/O] Size of data buffer (in bytes)
2884 * Success: ERROR_SUCCESS
2885 * Failure: nonzero error code from Winerror.h
2888 RegEnumValueW(HKEY hKey
,
2900 char buffer
[256], *buf_ptr
= buffer
;
2901 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2902 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2904 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2905 // hkey, index, value, val_count, reserved, type, data, count );
2907 /* NT only checks count, not val_count */
2908 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2910 status
= MapDefaultKey(&KeyHandle
, hKey
);
2911 if (!NT_SUCCESS(status
))
2913 return RtlNtStatusToDosError(status
);
2916 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2917 if (data
) total_size
+= *count
;
2918 total_size
= min( sizeof(buffer
), total_size
);
2920 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2921 buffer
, total_size
, &total_size
);
2922 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2926 /* retry with a dynamically allocated buffer */
2927 while (status
== STATUS_BUFFER_OVERFLOW
)
2929 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2930 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2932 status
= ERROR_NOT_ENOUGH_MEMORY
;
2935 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2936 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2937 buf_ptr
, total_size
, &total_size
);
2940 if (status
) goto done
;
2944 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2946 status
= STATUS_BUFFER_OVERFLOW
;
2949 memcpy( value
, info
->Name
, info
->NameLength
);
2950 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2951 value
[*val_count
] = 0;
2956 if (total_size
- info
->DataOffset
> *count
)
2958 status
= STATUS_BUFFER_OVERFLOW
;
2961 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2962 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2964 /* if the type is REG_SZ and data is not 0-terminated
2965 * and there is enough space in the buffer NT appends a \0 */
2966 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2967 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2971 else status
= STATUS_SUCCESS
;
2974 if (type
) *type
= info
->Type
;
2975 if (count
) *count
= info
->DataLength
;
2978 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2979 ClosePredefKey(KeyHandle
);
2980 return RtlNtStatusToDosError(status
);
2984 /************************************************************************
2990 RegFlushKey(HKEY hKey
)
2995 if (hKey
== HKEY_PERFORMANCE_DATA
)
2997 return ERROR_SUCCESS
;
3000 Status
= MapDefaultKey(&KeyHandle
,
3002 if (!NT_SUCCESS(Status
))
3004 return RtlNtStatusToDosError(Status
);
3007 Status
= NtFlushKey(KeyHandle
);
3009 ClosePredefKey(KeyHandle
);
3011 if (!NT_SUCCESS(Status
))
3013 return RtlNtStatusToDosError(Status
);
3016 return ERROR_SUCCESS
;
3020 /************************************************************************
3026 RegGetKeySecurity(HKEY hKey
,
3027 SECURITY_INFORMATION SecurityInformation
,
3028 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3029 LPDWORD lpcbSecurityDescriptor
)
3034 if (hKey
== HKEY_PERFORMANCE_DATA
)
3036 return ERROR_INVALID_HANDLE
;
3039 Status
= MapDefaultKey(&KeyHandle
,
3041 if (!NT_SUCCESS(Status
))
3043 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3044 return RtlNtStatusToDosError(Status
);
3048 Status
= NtQuerySecurityObject(KeyHandle
,
3049 SecurityInformation
,
3050 pSecurityDescriptor
,
3051 *lpcbSecurityDescriptor
,
3052 lpcbSecurityDescriptor
);
3055 ClosePredefKey(KeyHandle
);
3057 if (!NT_SUCCESS(Status
))
3059 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3060 return RtlNtStatusToDosError(Status
);
3063 return ERROR_SUCCESS
;
3067 /************************************************************************
3073 RegLoadKeyA(HKEY hKey
,
3077 UNICODE_STRING FileName
;
3078 UNICODE_STRING KeyName
;
3081 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3083 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3086 ErrorCode
= RegLoadKeyW(hKey
,
3090 RtlFreeUnicodeString(&FileName
);
3091 RtlFreeUnicodeString(&KeyName
);
3097 /************************************************************************
3103 RegLoadKeyW(HKEY hKey
,
3107 OBJECT_ATTRIBUTES FileObjectAttributes
;
3108 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3109 UNICODE_STRING FileName
;
3110 UNICODE_STRING KeyName
;
3113 LONG ErrorCode
= ERROR_SUCCESS
;
3115 if (hKey
== HKEY_PERFORMANCE_DATA
)
3117 return ERROR_INVALID_HANDLE
;
3120 Status
= MapDefaultKey(&KeyHandle
,
3122 if (!NT_SUCCESS(Status
))
3124 return RtlNtStatusToDosError(Status
);
3127 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3132 ErrorCode
= ERROR_BAD_PATHNAME
;
3136 InitializeObjectAttributes(&FileObjectAttributes
,
3138 OBJ_CASE_INSENSITIVE
,
3142 RtlInitUnicodeString(&KeyName
,
3145 InitializeObjectAttributes(&KeyObjectAttributes
,
3147 OBJ_CASE_INSENSITIVE
,
3151 Status
= NtLoadKey(&KeyObjectAttributes
,
3152 &FileObjectAttributes
);
3154 RtlFreeHeap(RtlGetProcessHeap(),
3158 if (!NT_SUCCESS(Status
))
3160 ErrorCode
= RtlNtStatusToDosError(Status
);
3165 ClosePredefKey(KeyHandle
);
3171 /************************************************************************
3172 * RegNotifyChangeKeyValue
3177 RegNotifyChangeKeyValue(HKEY hKey
,
3179 DWORD dwNotifyFilter
,
3183 IO_STATUS_BLOCK IoStatusBlock
;
3186 LONG ErrorCode
= ERROR_SUCCESS
;
3188 if (hKey
== HKEY_PERFORMANCE_DATA
)
3190 return ERROR_INVALID_HANDLE
;
3193 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3195 return ERROR_INVALID_PARAMETER
;
3198 Status
= MapDefaultKey(&KeyHandle
,
3200 if (!NT_SUCCESS(Status
))
3202 return RtlNtStatusToDosError(Status
);
3205 /* FIXME: Remote key handles must fail */
3207 Status
= NtNotifyChangeKey(KeyHandle
,
3217 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3219 ErrorCode
= RtlNtStatusToDosError(Status
);
3222 ClosePredefKey(KeyHandle
);
3228 /************************************************************************
3229 * RegOpenCurrentUser
3234 RegOpenCurrentUser(IN REGSAM samDesired
,
3235 OUT PHKEY phkResult
)
3239 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3240 (PHANDLE
)phkResult
);
3241 if (!NT_SUCCESS(Status
))
3243 /* NOTE - don't set the last error code! just return the error! */
3244 return RtlNtStatusToDosError(Status
);
3247 return ERROR_SUCCESS
;
3251 /************************************************************************
3254 * 20050503 Fireball - imported from WINE
3259 RegOpenKeyA(HKEY hKey
,
3263 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3264 hKey
, lpSubKey
, phkResult
);
3266 if (!hKey
&& lpSubKey
&& phkResult
)
3268 return ERROR_INVALID_HANDLE
;
3271 if (!lpSubKey
|| !*lpSubKey
)
3274 return ERROR_SUCCESS
;
3277 return RegOpenKeyExA(hKey
,
3285 /************************************************************************
3290 * 20050503 Fireball - imported from WINE
3295 RegOpenKeyW(HKEY hKey
,
3299 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3300 hKey
, lpSubKey
, phkResult
);
3302 if (!hKey
&& lpSubKey
&& phkResult
)
3304 return ERROR_INVALID_HANDLE
;
3307 if (!lpSubKey
|| !*lpSubKey
)
3310 return ERROR_SUCCESS
;
3313 return RegOpenKeyExW(hKey
,
3321 /************************************************************************
3327 RegOpenKeyExA(HKEY hKey
,
3333 OBJECT_ATTRIBUTES ObjectAttributes
;
3334 UNICODE_STRING SubKeyString
;
3337 LONG ErrorCode
= ERROR_SUCCESS
;
3339 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3340 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3342 Status
= MapDefaultKey(&KeyHandle
,
3344 if (!NT_SUCCESS(Status
))
3346 return RtlNtStatusToDosError(Status
);
3349 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3351 InitializeObjectAttributes(&ObjectAttributes
,
3353 OBJ_CASE_INSENSITIVE
,
3357 Status
= NtOpenKey((PHANDLE
)phkResult
,
3360 RtlFreeUnicodeString(&SubKeyString
);
3361 if (!NT_SUCCESS(Status
))
3363 ErrorCode
= RtlNtStatusToDosError(Status
);
3366 ClosePredefKey(KeyHandle
);
3372 /************************************************************************
3378 RegOpenKeyExW(HKEY hKey
,
3384 OBJECT_ATTRIBUTES ObjectAttributes
;
3385 UNICODE_STRING SubKeyString
;
3388 LONG ErrorCode
= ERROR_SUCCESS
;
3390 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3391 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3393 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3394 if (!NT_SUCCESS(Status
))
3396 return RtlNtStatusToDosError(Status
);
3399 if (lpSubKey
!= NULL
)
3400 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3402 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3404 InitializeObjectAttributes(&ObjectAttributes
,
3406 OBJ_CASE_INSENSITIVE
,
3410 Status
= NtOpenKey((PHANDLE
)phkResult
,
3413 if (!NT_SUCCESS(Status
))
3415 ErrorCode
= RtlNtStatusToDosError(Status
);
3418 ClosePredefKey(KeyHandle
);
3424 /************************************************************************
3425 * RegOpenUserClassesRoot
3430 RegOpenUserClassesRoot(IN HANDLE hToken
,
3432 IN REGSAM samDesired
,
3433 OUT PHKEY phkResult
)
3435 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3436 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3437 PTOKEN_USER TokenUserData
;
3438 ULONG RequiredLength
;
3439 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3440 OBJECT_ATTRIBUTES ObjectAttributes
;
3443 /* check parameters */
3444 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3446 return ERROR_INVALID_PARAMETER
;
3450 * Get the user sid from the token
3454 /* determine how much memory we need */
3455 Status
= NtQueryInformationToken(hToken
,
3460 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3462 /* NOTE - as opposed to all other registry functions windows does indeed
3463 change the last error code in case the caller supplied a invalid
3464 handle for example! */
3465 return RtlNtStatusToDosError(Status
);
3468 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3471 if (TokenUserData
== NULL
)
3473 return ERROR_NOT_ENOUGH_MEMORY
;
3476 /* attempt to read the information */
3477 Status
= NtQueryInformationToken(hToken
,
3482 if (!NT_SUCCESS(Status
))
3484 RtlFreeHeap(ProcessHeap
,
3487 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3489 /* the information appears to have changed?! try again */
3493 /* NOTE - as opposed to all other registry functions windows does indeed
3494 change the last error code in case the caller supplied a invalid
3495 handle for example! */
3496 return RtlNtStatusToDosError(Status
);
3500 * Build the absolute path for the user's registry in the form
3501 * "\Registry\User\<SID>_Classes"
3503 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3504 TokenUserData
->User
.Sid
,
3507 /* we don't need the user data anymore, free it */
3508 RtlFreeHeap(ProcessHeap
,
3512 if (!NT_SUCCESS(Status
))
3514 return RtlNtStatusToDosError(Status
);
3517 /* allocate enough memory for the entire key string */
3518 UserClassesKeyRoot
.Length
= 0;
3519 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3520 sizeof(UserClassesKeyPrefix
) +
3521 sizeof(UserClassesKeySuffix
);
3522 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3524 UserClassesKeyRoot
.MaximumLength
);
3525 if (UserClassesKeyRoot
.Buffer
== NULL
)
3527 RtlFreeUnicodeString(&UserSidString
);
3528 return RtlNtStatusToDosError(Status
);
3531 /* build the string */
3532 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3533 UserClassesKeyPrefix
);
3534 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3536 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3537 UserClassesKeySuffix
);
3539 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3544 InitializeObjectAttributes(&ObjectAttributes
,
3545 &UserClassesKeyRoot
,
3546 OBJ_CASE_INSENSITIVE
,
3550 Status
= NtOpenKey((PHANDLE
)phkResult
,
3554 RtlFreeUnicodeString(&UserSidString
);
3555 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3557 if (!NT_SUCCESS(Status
))
3559 return RtlNtStatusToDosError(Status
);
3562 return ERROR_SUCCESS
;
3566 /************************************************************************
3572 RegQueryInfoKeyA(HKEY hKey
,
3577 LPDWORD lpcbMaxSubKeyLen
,
3578 LPDWORD lpcbMaxClassLen
,
3580 LPDWORD lpcbMaxValueNameLen
,
3581 LPDWORD lpcbMaxValueLen
,
3582 LPDWORD lpcbSecurityDescriptor
,
3583 PFILETIME lpftLastWriteTime
)
3585 WCHAR ClassName
[MAX_PATH
];
3586 UNICODE_STRING UnicodeString
;
3587 ANSI_STRING AnsiString
;
3590 RtlInitUnicodeString(&UnicodeString
,
3592 if (lpClass
!= NULL
)
3594 UnicodeString
.Buffer
= &ClassName
[0];
3595 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3596 AnsiString
.MaximumLength
= *lpcbClass
;
3599 ErrorCode
= RegQueryInfoKeyW(hKey
,
3600 UnicodeString
.Buffer
,
3607 lpcbMaxValueNameLen
,
3609 lpcbSecurityDescriptor
,
3611 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3613 AnsiString
.Buffer
= lpClass
;
3614 AnsiString
.Length
= 0;
3615 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3616 RtlUnicodeStringToAnsiString(&AnsiString
,
3619 *lpcbClass
= AnsiString
.Length
;
3620 lpClass
[AnsiString
.Length
] = 0;
3627 /************************************************************************
3633 RegQueryInfoKeyW(HKEY hKey
,
3638 LPDWORD lpcbMaxSubKeyLen
,
3639 LPDWORD lpcbMaxClassLen
,
3641 LPDWORD lpcbMaxValueNameLen
,
3642 LPDWORD lpcbMaxValueLen
,
3643 LPDWORD lpcbSecurityDescriptor
,
3644 PFILETIME lpftLastWriteTime
)
3646 KEY_FULL_INFORMATION FullInfoBuffer
;
3647 PKEY_FULL_INFORMATION FullInfo
;
3649 ULONG ClassLength
= 0;
3653 LONG ErrorCode
= ERROR_SUCCESS
;
3655 if ((lpClass
) && (!lpcbClass
))
3657 return ERROR_INVALID_PARAMETER
;
3660 Status
= MapDefaultKey(&KeyHandle
,
3662 if (!NT_SUCCESS(Status
))
3664 return RtlNtStatusToDosError(Status
);
3667 if (lpClass
!= NULL
)
3671 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3678 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3679 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3682 if (FullInfo
== NULL
)
3684 ErrorCode
= ERROR_OUTOFMEMORY
;
3688 FullInfo
->ClassLength
= ClassLength
;
3692 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3693 FullInfo
= &FullInfoBuffer
;
3694 FullInfo
->ClassLength
= 0;
3696 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3698 Status
= NtQueryKey(KeyHandle
,
3703 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3704 if (!NT_SUCCESS(Status
))
3706 if (lpClass
!= NULL
)
3708 RtlFreeHeap(ProcessHeap
,
3713 ErrorCode
= RtlNtStatusToDosError(Status
);
3717 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3718 if (lpcSubKeys
!= NULL
)
3720 *lpcSubKeys
= FullInfo
->SubKeys
;
3723 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3724 if (lpcbMaxSubKeyLen
!= NULL
)
3726 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3729 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3730 if (lpcbMaxClassLen
!= NULL
)
3732 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3735 TRACE("Values %lu\n", FullInfo
->Values
);
3736 if (lpcValues
!= NULL
)
3738 *lpcValues
= FullInfo
->Values
;
3741 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3742 if (lpcbMaxValueNameLen
!= NULL
)
3744 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3747 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3748 if (lpcbMaxValueLen
!= NULL
)
3750 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3754 if (lpcbSecurityDescriptor
!= NULL
)
3756 Status
= NtQuerySecurityObject(KeyHandle
,
3757 OWNER_SECURITY_INFORMATION
|
3758 GROUP_SECURITY_INFORMATION
|
3759 DACL_SECURITY_INFORMATION
,
3762 lpcbSecurityDescriptor
);
3763 if (!NT_SUCCESS(Status
))
3765 if (lpClass
!= NULL
)
3767 RtlFreeHeap(ProcessHeap
,
3772 ErrorCode
= RtlNtStatusToDosError(Status
);
3778 if (lpftLastWriteTime
!= NULL
)
3780 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3781 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3784 if (lpClass
!= NULL
)
3786 if (FullInfo
->ClassLength
> ClassLength
)
3788 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3792 RtlCopyMemory(lpClass
,
3794 FullInfo
->ClassLength
);
3795 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3796 lpClass
[*lpcbClass
] = 0;
3799 RtlFreeHeap(ProcessHeap
,
3805 ClosePredefKey(KeyHandle
);
3811 /************************************************************************
3812 * RegQueryMultipleValuesA
3817 RegQueryMultipleValuesA(HKEY hKey
,
3824 DWORD maxBytes
= *ldwTotsize
;
3825 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3828 if (maxBytes
>= (1024*1024))
3829 return ERROR_TRANSFER_TOO_LONG
;
3833 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3834 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3836 for (i
= 0; i
< num_vals
; i
++)
3838 val_list
[i
].ve_valuelen
= 0;
3839 ErrorCode
= RegQueryValueExA(hKey
,
3840 val_list
[i
].ve_valuename
,
3844 &val_list
[i
].ve_valuelen
);
3845 if (ErrorCode
!= ERROR_SUCCESS
)
3850 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3852 ErrorCode
= RegQueryValueExA(hKey
,
3853 val_list
[i
].ve_valuename
,
3855 &val_list
[i
].ve_type
,
3857 &val_list
[i
].ve_valuelen
);
3858 if (ErrorCode
!= ERROR_SUCCESS
)
3863 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3865 bufptr
+= val_list
[i
].ve_valuelen
;
3868 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3871 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3875 /************************************************************************
3876 * RegQueryMultipleValuesW
3881 RegQueryMultipleValuesW(HKEY hKey
,
3888 DWORD maxBytes
= *ldwTotsize
;
3889 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3892 if (maxBytes
>= (1024*1024))
3893 return ERROR_TRANSFER_TOO_LONG
;
3897 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3898 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3900 for (i
= 0; i
< num_vals
; i
++)
3902 val_list
[i
].ve_valuelen
= 0;
3903 ErrorCode
= RegQueryValueExW(hKey
,
3904 val_list
[i
].ve_valuename
,
3908 &val_list
[i
].ve_valuelen
);
3909 if (ErrorCode
!= ERROR_SUCCESS
)
3914 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3916 ErrorCode
= RegQueryValueExW(hKey
,
3917 val_list
[i
].ve_valuename
,
3919 &val_list
[i
].ve_type
,
3921 &val_list
[i
].ve_valuelen
);
3922 if (ErrorCode
!= ERROR_SUCCESS
)
3927 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3929 bufptr
+= val_list
[i
].ve_valuelen
;
3932 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3935 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3939 /************************************************************************
3940 * RegQueryReflectionKey
3945 RegQueryReflectionKey(IN HKEY hBase
,
3946 OUT BOOL
* bIsReflectionDisabled
)
3948 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3949 hBase
, bIsReflectionDisabled
);
3950 return ERROR_CALL_NOT_IMPLEMENTED
;
3954 /************************************************************************
3960 RegQueryValueExA(HKEY hKey
,
3967 UNICODE_STRING ValueName
;
3968 UNICODE_STRING ValueData
;
3969 ANSI_STRING AnsiString
;
3974 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3975 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
3977 if (lpData
!= NULL
&& lpcbData
== NULL
)
3979 return ERROR_INVALID_PARAMETER
;
3984 ValueData
.Length
= 0;
3985 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
3986 ValueData
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3988 ValueData
.MaximumLength
);
3989 if (!ValueData
.Buffer
)
3991 return ERROR_OUTOFMEMORY
;
3996 ValueData
.Buffer
= NULL
;
3997 ValueData
.Length
= 0;
3998 ValueData
.MaximumLength
= 0;
4004 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4005 (LPSTR
)lpValueName
);
4007 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
4008 ErrorCode
= RegQueryValueExW(hKey
,
4012 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
4014 TRACE("ErrorCode %lu\n", ErrorCode
);
4015 RtlFreeUnicodeString(&ValueName
);
4017 if (ErrorCode
== ERROR_SUCCESS
||
4018 ErrorCode
== ERROR_MORE_DATA
)
4025 if ((Type
== REG_SZ
) || (Type
== REG_MULTI_SZ
) || (Type
== REG_EXPAND_SZ
))
4027 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4029 RtlInitAnsiString(&AnsiString
, NULL
);
4030 AnsiString
.Buffer
= (LPSTR
)lpData
;
4031 AnsiString
.MaximumLength
= *lpcbData
;
4032 ValueData
.Length
= Length
;
4033 ValueData
.MaximumLength
= ValueData
.Length
+ sizeof(WCHAR
);
4034 RtlUnicodeStringToAnsiString(&AnsiString
, &ValueData
, FALSE
);
4037 Length
= Length
/ sizeof(WCHAR
);
4039 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4041 if (*lpcbData
< Length
)
4043 ErrorCode
= ERROR_MORE_DATA
;
4047 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
4051 if (lpcbData
!= NULL
)
4057 if (ValueData
.Buffer
!= NULL
)
4059 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
4066 /************************************************************************
4073 RegQueryValueExW(HKEY hkeyorg
,
4082 UNICODE_STRING name_str
;
4084 char buffer
[256], *buf_ptr
= buffer
;
4085 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4086 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4088 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4089 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
4090 (count
&& data
) ? *count
: 0 );
4092 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4093 //if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
4095 status
= MapDefaultKey(&hkey
, hkeyorg
);
4096 if (!NT_SUCCESS(status
))
4098 return RtlNtStatusToDosError(status
);
4101 RtlInitUnicodeString( &name_str
, name
);
4103 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4106 total_size
= info_size
;
4107 if (count
) *count
= 0;
4110 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4111 buffer
, total_size
, &total_size
);
4112 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4116 /* retry with a dynamically allocated buffer */
4117 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4119 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4120 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4121 return ERROR_NOT_ENOUGH_MEMORY
;
4122 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4123 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4124 buf_ptr
, total_size
, &total_size
);
4129 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4130 /* if the type is REG_SZ and data is not 0-terminated
4131 * and there is enough space in the buffer NT appends a \0 */
4132 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
4134 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4135 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4138 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4140 else status
= STATUS_SUCCESS
;
4142 if (type
) *type
= info
->Type
;
4143 if (count
) *count
= total_size
- info_size
;
4146 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4147 ClosePredefKey(hkey
);
4148 return RtlNtStatusToDosError(status
);
4152 /************************************************************************
4158 RegQueryValueA(HKEY hKey
,
4163 WCHAR SubKeyNameBuffer
[MAX_PATH
+1];
4164 UNICODE_STRING SubKeyName
;
4165 UNICODE_STRING Value
;
4166 ANSI_STRING AnsiString
;
4170 TRACE("hKey 0x%X lpSubKey %s lpValue %p lpcbValue %d\n",
4171 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4173 if (lpValue
!= NULL
&&
4176 return ERROR_INVALID_PARAMETER
;
4179 RtlInitUnicodeString(&SubKeyName
,
4181 RtlInitUnicodeString(&Value
,
4183 if (lpSubKey
!= NULL
&&
4184 strlen(lpSubKey
) != 0)
4186 RtlInitAnsiString(&AnsiString
,
4188 SubKeyName
.Buffer
= &SubKeyNameBuffer
[0];
4189 SubKeyName
.MaximumLength
= sizeof(SubKeyNameBuffer
);
4190 RtlAnsiStringToUnicodeString(&SubKeyName
,
4195 if (lpValue
!= NULL
)
4197 ValueSize
= *lpcbValue
* sizeof(WCHAR
);
4198 Value
.MaximumLength
= ValueSize
;
4199 Value
.Buffer
= RtlAllocateHeap(ProcessHeap
,
4202 if (Value
.Buffer
== NULL
)
4204 return ERROR_OUTOFMEMORY
;
4212 ErrorCode
= RegQueryValueW(hKey
,
4213 (LPCWSTR
)SubKeyName
.Buffer
,
4216 if (ErrorCode
== ERROR_SUCCESS
)
4218 if (lpValue
!= NULL
)
4220 Value
.Length
= ValueSize
;
4221 RtlInitAnsiString(&AnsiString
,
4223 AnsiString
.Buffer
= lpValue
;
4224 AnsiString
.MaximumLength
= *lpcbValue
;
4225 RtlUnicodeStringToAnsiString(&AnsiString
,
4228 *lpcbValue
= ValueSize
;
4230 else if (lpcbValue
!= NULL
)
4232 *lpcbValue
= ValueSize
;
4236 if (Value
.Buffer
!= NULL
)
4238 RtlFreeHeap(ProcessHeap
,
4247 /************************************************************************
4253 RegQueryValueW(HKEY hKey
,
4258 OBJECT_ATTRIBUTES ObjectAttributes
;
4259 UNICODE_STRING SubKeyString
;
4266 TRACE("hKey 0x%X lpSubKey %S lpValue %p lpcbValue %d\n",
4267 hKey
, lpSubKey
, lpValue
, lpcbValue
? *lpcbValue
: 0);
4269 Status
= MapDefaultKey(&KeyHandle
,
4271 if (!NT_SUCCESS(Status
))
4273 return RtlNtStatusToDosError(Status
);
4276 if (lpSubKey
!= NULL
&&
4277 wcslen(lpSubKey
) != 0)
4279 RtlInitUnicodeString(&SubKeyString
,
4281 InitializeObjectAttributes(&ObjectAttributes
,
4283 OBJ_CASE_INSENSITIVE
,
4286 Status
= NtOpenKey(&RealKey
,
4289 if (!NT_SUCCESS(Status
))
4291 ErrorCode
= RtlNtStatusToDosError(Status
);
4295 CloseRealKey
= TRUE
;
4300 CloseRealKey
= FALSE
;
4303 ErrorCode
= RegQueryValueExW(RealKey
,
4308 (LPDWORD
)lpcbValue
);
4315 ClosePredefKey(KeyHandle
);
4321 /************************************************************************
4327 RegReplaceKeyA(HKEY hKey
,
4332 UNICODE_STRING SubKey
;
4333 UNICODE_STRING NewFile
;
4334 UNICODE_STRING OldFile
;
4337 RtlCreateUnicodeStringFromAsciiz(&SubKey
,
4339 RtlCreateUnicodeStringFromAsciiz(&OldFile
,
4341 RtlCreateUnicodeStringFromAsciiz(&NewFile
,
4344 ErrorCode
= RegReplaceKeyW(hKey
,
4349 RtlFreeUnicodeString(&OldFile
);
4350 RtlFreeUnicodeString(&NewFile
);
4351 RtlFreeUnicodeString(&SubKey
);
4357 /************************************************************************
4363 RegReplaceKeyW(HKEY hKey
,
4368 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4369 OBJECT_ATTRIBUTES NewObjectAttributes
;
4370 OBJECT_ATTRIBUTES OldObjectAttributes
;
4371 UNICODE_STRING SubKeyName
;
4372 UNICODE_STRING NewFileName
;
4373 UNICODE_STRING OldFileName
;
4374 BOOLEAN CloseRealKey
;
4375 HANDLE RealKeyHandle
;
4378 LONG ErrorCode
= ERROR_SUCCESS
;
4380 if (hKey
== HKEY_PERFORMANCE_DATA
)
4382 return ERROR_INVALID_HANDLE
;
4385 Status
= MapDefaultKey(&KeyHandle
,
4387 if (!NT_SUCCESS(Status
))
4389 return RtlNtStatusToDosError(Status
);
4392 /* Open the real key */
4393 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4395 RtlInitUnicodeString(&SubKeyName
,
4397 InitializeObjectAttributes(&KeyObjectAttributes
,
4399 OBJ_CASE_INSENSITIVE
,
4402 Status
= NtOpenKey(&RealKeyHandle
,
4404 &KeyObjectAttributes
);
4405 if (!NT_SUCCESS(Status
))
4407 ErrorCode
= RtlNtStatusToDosError(Status
);
4411 CloseRealKey
= TRUE
;
4415 RealKeyHandle
= KeyHandle
;
4416 CloseRealKey
= FALSE
;
4419 /* Convert new file name */
4420 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4427 NtClose(RealKeyHandle
);
4430 ErrorCode
= ERROR_INVALID_PARAMETER
;
4434 InitializeObjectAttributes(&NewObjectAttributes
,
4436 OBJ_CASE_INSENSITIVE
,
4440 /* Convert old file name */
4441 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4446 RtlFreeHeap(RtlGetProcessHeap (),
4448 NewFileName
.Buffer
);
4451 NtClose(RealKeyHandle
);
4454 ErrorCode
= ERROR_INVALID_PARAMETER
;
4458 InitializeObjectAttributes(&OldObjectAttributes
,
4460 OBJ_CASE_INSENSITIVE
,
4464 Status
= NtReplaceKey(&NewObjectAttributes
,
4466 &OldObjectAttributes
);
4468 RtlFreeHeap(RtlGetProcessHeap(),
4470 OldFileName
.Buffer
);
4471 RtlFreeHeap(RtlGetProcessHeap(),
4473 NewFileName
.Buffer
);
4477 NtClose(RealKeyHandle
);
4480 if (!NT_SUCCESS(Status
))
4482 return RtlNtStatusToDosError(Status
);
4486 ClosePredefKey(KeyHandle
);
4492 /************************************************************************
4498 RegRestoreKeyA(HKEY hKey
,
4502 UNICODE_STRING FileName
;
4505 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4508 ErrorCode
= RegRestoreKeyW(hKey
,
4512 RtlFreeUnicodeString(&FileName
);
4518 /************************************************************************
4524 RegRestoreKeyW(HKEY hKey
,
4528 OBJECT_ATTRIBUTES ObjectAttributes
;
4529 IO_STATUS_BLOCK IoStatusBlock
;
4530 UNICODE_STRING FileName
;
4535 if (hKey
== HKEY_PERFORMANCE_DATA
)
4537 return ERROR_INVALID_HANDLE
;
4540 Status
= MapDefaultKey(&KeyHandle
,
4542 if (!NT_SUCCESS(Status
))
4544 return RtlNtStatusToDosError(Status
);
4547 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4552 Status
= STATUS_INVALID_PARAMETER
;
4556 InitializeObjectAttributes(&ObjectAttributes
,
4558 OBJ_CASE_INSENSITIVE
,
4562 Status
= NtOpenFile(&FileHandle
,
4567 FILE_SYNCHRONOUS_IO_NONALERT
);
4568 RtlFreeHeap(RtlGetProcessHeap(),
4571 if (!NT_SUCCESS(Status
))
4576 Status
= NtRestoreKey(KeyHandle
,
4579 NtClose (FileHandle
);
4582 ClosePredefKey(KeyHandle
);
4584 if (!NT_SUCCESS(Status
))
4586 return RtlNtStatusToDosError(Status
);
4589 return ERROR_SUCCESS
;
4593 /************************************************************************
4599 RegSaveKeyA(HKEY hKey
,
4601 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4603 UNICODE_STRING FileName
;
4606 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4608 ErrorCode
= RegSaveKeyW(hKey
,
4610 lpSecurityAttributes
);
4611 RtlFreeUnicodeString(&FileName
);
4617 /************************************************************************
4623 RegSaveKeyW(HKEY hKey
,
4625 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4627 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4628 OBJECT_ATTRIBUTES ObjectAttributes
;
4629 UNICODE_STRING FileName
;
4630 IO_STATUS_BLOCK IoStatusBlock
;
4635 Status
= MapDefaultKey(&KeyHandle
,
4637 if (!NT_SUCCESS(Status
))
4639 return RtlNtStatusToDosError(Status
);
4642 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4647 Status
= STATUS_INVALID_PARAMETER
;
4651 if (lpSecurityAttributes
!= NULL
)
4653 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4656 InitializeObjectAttributes(&ObjectAttributes
,
4658 OBJ_CASE_INSENSITIVE
,
4660 SecurityDescriptor
);
4661 Status
= NtCreateFile(&FileHandle
,
4662 GENERIC_WRITE
| SYNCHRONIZE
,
4666 FILE_ATTRIBUTE_NORMAL
,
4669 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4672 RtlFreeHeap(RtlGetProcessHeap(),
4675 if (!NT_SUCCESS(Status
))
4680 Status
= NtSaveKey(KeyHandle
,
4682 NtClose (FileHandle
);
4685 ClosePredefKey(KeyHandle
);
4687 if (!NT_SUCCESS(Status
))
4689 return RtlNtStatusToDosError(Status
);
4692 return ERROR_SUCCESS
;
4696 /************************************************************************
4702 RegSetKeySecurity(HKEY hKey
,
4703 SECURITY_INFORMATION SecurityInformation
,
4704 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4709 if (hKey
== HKEY_PERFORMANCE_DATA
)
4711 return ERROR_INVALID_HANDLE
;
4714 Status
= MapDefaultKey(&KeyHandle
,
4716 if (!NT_SUCCESS(Status
))
4718 return RtlNtStatusToDosError(Status
);
4721 Status
= NtSetSecurityObject(KeyHandle
,
4722 SecurityInformation
,
4723 pSecurityDescriptor
);
4725 ClosePredefKey(KeyHandle
);
4727 if (!NT_SUCCESS(Status
))
4729 return RtlNtStatusToDosError(Status
);
4732 return ERROR_SUCCESS
;
4736 /************************************************************************
4742 RegSetValueExA(HKEY hKey
,
4749 UNICODE_STRING ValueName
;
4751 ANSI_STRING AnsiString
;
4752 UNICODE_STRING Data
;
4757 if (lpValueName
!= NULL
&&
4758 strlen(lpValueName
) != 0)
4760 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4765 ValueName
.Buffer
= NULL
;
4768 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4770 if (((dwType
== REG_SZ
) ||
4771 (dwType
== REG_MULTI_SZ
) ||
4772 (dwType
== REG_EXPAND_SZ
)) &&
4775 /* NT adds one if the caller forgot the NULL-termination character */
4776 if (lpData
[cbData
- 1] != '\0')
4781 RtlInitAnsiString(&AnsiString
,
4783 AnsiString
.Buffer
= (PSTR
)lpData
;
4784 AnsiString
.Length
= cbData
- 1;
4785 AnsiString
.MaximumLength
= cbData
;
4786 RtlAnsiStringToUnicodeString(&Data
,
4789 pData
= (LPBYTE
)Data
.Buffer
;
4790 DataSize
= cbData
* sizeof(WCHAR
);
4794 RtlInitUnicodeString(&Data
,
4796 pData
= (LPBYTE
)lpData
;
4800 ErrorCode
= RegSetValueExW(hKey
,
4806 if (pValueName
!= NULL
)
4808 RtlFreeHeap(ProcessHeap
,
4813 if (Data
.Buffer
!= NULL
)
4815 RtlFreeHeap(ProcessHeap
,
4824 /************************************************************************
4830 RegSetValueExW(HKEY hKey
,
4831 LPCWSTR lpValueName
,
4837 UNICODE_STRING ValueName
;
4838 PUNICODE_STRING pValueName
;
4842 Status
= MapDefaultKey(&KeyHandle
,
4844 if (!NT_SUCCESS(Status
))
4846 return RtlNtStatusToDosError(Status
);
4849 if (lpValueName
!= NULL
)
4851 RtlInitUnicodeString(&ValueName
,
4856 RtlInitUnicodeString(&ValueName
, L
"");
4858 pValueName
= &ValueName
;
4860 if (((dwType
== REG_SZ
) ||
4861 (dwType
== REG_MULTI_SZ
) ||
4862 (dwType
== REG_EXPAND_SZ
)) &&
4863 (cbData
!= 0) && (*(((PWCHAR
)lpData
) + (cbData
/ sizeof(WCHAR
)) - 1) != L
'\0'))
4865 /* NT adds one if the caller forgot the NULL-termination character */
4866 cbData
+= sizeof(WCHAR
);
4869 Status
= NtSetValueKey(KeyHandle
,
4876 ClosePredefKey(KeyHandle
);
4878 if (!NT_SUCCESS(Status
))
4880 return RtlNtStatusToDosError(Status
);
4883 return ERROR_SUCCESS
;
4887 /************************************************************************
4893 RegSetValueA(HKEY hKeyOriginal
,
4904 TRACE("(%p,%s,%d,%s,%d)\n", hKey
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4906 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4908 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4909 if (!NT_SUCCESS(Status
))
4911 return RtlNtStatusToDosError (Status
);
4915 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4917 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
4918 if (ret
!= ERROR_SUCCESS
)
4922 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4924 RegCloseKey(subkey
);
4927 ClosePredefKey(hKey
);
4933 /************************************************************************
4939 RegSetValueW(HKEY hKeyOriginal
,
4950 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4952 if (dwType
!= REG_SZ
|| !lpData
)
4953 return ERROR_INVALID_PARAMETER
;
4955 Status
= MapDefaultKey(&hKey
,
4957 if (!NT_SUCCESS(Status
))
4959 return RtlNtStatusToDosError(Status
);
4963 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4965 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
4966 if (ret
!= ERROR_SUCCESS
)
4970 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
4971 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
4973 RegCloseKey(subkey
);
4976 ClosePredefKey(hKey
);
4982 /************************************************************************
4988 RegUnLoadKeyA(HKEY hKey
,
4991 UNICODE_STRING KeyName
;
4994 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
4997 ErrorCode
= RegUnLoadKeyW(hKey
,
5000 RtlFreeUnicodeString (&KeyName
);
5006 /************************************************************************
5012 RegUnLoadKeyW(HKEY hKey
,
5015 OBJECT_ATTRIBUTES ObjectAttributes
;
5016 UNICODE_STRING KeyName
;
5020 if (hKey
== HKEY_PERFORMANCE_DATA
)
5022 return ERROR_INVALID_HANDLE
;
5025 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5026 if (!NT_SUCCESS(Status
))
5028 return RtlNtStatusToDosError(Status
);
5031 RtlInitUnicodeString(&KeyName
,
5034 InitializeObjectAttributes(&ObjectAttributes
,
5036 OBJ_CASE_INSENSITIVE
,
5040 Status
= NtUnloadKey(&ObjectAttributes
);
5042 ClosePredefKey(KeyHandle
);
5044 if (!NT_SUCCESS(Status
))
5046 return RtlNtStatusToDosError(Status
);
5049 return ERROR_SUCCESS
;
5053 /******************************************************************************
5054 * load_string [Internal]
5056 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5057 * avoid importing user32, which is higher level than advapi32. Helper for
5060 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5067 /* Negative values have to be inverted. */
5068 if (HIWORD(resId
) == 0xffff)
5069 resId
= (UINT
)(-((INT
)resId
));
5071 /* Load the resource into memory and get a pointer to it. */
5072 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5073 if (!hResource
) return 0;
5074 hMemory
= LoadResource(hModule
, hResource
);
5075 if (!hMemory
) return 0;
5076 pString
= LockResource(hMemory
);
5078 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5079 idxString
= resId
& 0xf;
5080 while (idxString
--) pString
+= *pString
+ 1;
5082 /* If no buffer is given, return length of the string. */
5083 if (!pwszBuffer
) return *pString
;
5085 /* Else copy over the string, respecting the buffer size. */
5086 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5089 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5090 pwszBuffer
[cMaxChars
] = L
'\0';
5097 /************************************************************************
5103 RegLoadMUIStringW(IN HKEY hKey
,
5104 IN LPCWSTR pszValue OPTIONAL
,
5105 OUT LPWSTR pszOutBuf
,
5107 OUT LPDWORD pcbData OPTIONAL
,
5109 IN LPCWSTR pszDirectory OPTIONAL
)
5111 DWORD dwValueType
, cbData
;
5112 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5115 /* Parameter sanity checks. */
5116 if (!hKey
|| !pszOutBuf
)
5117 return ERROR_INVALID_PARAMETER
;
5119 if (pszDirectory
&& *pszDirectory
)
5121 FIXME("BaseDir parameter not yet supported!\n");
5122 return ERROR_INVALID_PARAMETER
;
5125 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5126 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5127 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5128 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5130 result
= ERROR_FILE_NOT_FOUND
;
5133 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5134 if (!pwszTempBuffer
)
5136 result
= ERROR_NOT_ENOUGH_MEMORY
;
5139 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5140 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5142 /* Expand environment variables, if appropriate, or copy the original string over. */
5143 if (dwValueType
== REG_EXPAND_SZ
)
5145 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5146 if (!cbData
) goto cleanup
;
5147 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5148 if (!pwszExpandedBuffer
)
5150 result
= ERROR_NOT_ENOUGH_MEMORY
;
5153 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5157 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5158 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5161 /* If the value references a resource based string, parse the value and load the string.
5162 * Else just copy over the original value. */
5163 result
= ERROR_SUCCESS
;
5164 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5166 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5170 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5174 /* Format of the expanded value is 'path_to_dll,-resId' */
5175 if (!pComma
|| pComma
[1] != L
'-')
5177 result
= ERROR_BADKEY
;
5181 uiStringId
= _wtoi(pComma
+2);
5184 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5185 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5186 result
= ERROR_BADKEY
;
5187 FreeLibrary(hModule
);
5191 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5192 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5197 /************************************************************************
5203 RegLoadMUIStringA(IN HKEY hKey
,
5204 IN LPCSTR pszValue OPTIONAL
,
5205 OUT LPSTR pszOutBuf
,
5207 OUT LPDWORD pcbData OPTIONAL
,
5209 IN LPCSTR pszDirectory OPTIONAL
)
5211 UNICODE_STRING valueW
, baseDirW
;
5213 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5216 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5217 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5218 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5219 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5221 result
= ERROR_NOT_ENOUGH_MEMORY
;
5225 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5228 if (result
== ERROR_SUCCESS
)
5230 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5236 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5237 RtlFreeUnicodeString(&baseDirW
);
5238 RtlFreeUnicodeString(&valueW
);