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
;
34 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
36 /* PROTOTYPES ***************************************************************/
38 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
39 static VOID
CloseDefaultKeys(VOID
);
40 #define ClosePredefKey(Handle) \
41 if ((ULONG_PTR)Handle & 0x1) { \
44 #define IsPredefKey(HKey) \
45 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
46 #define GetPredefKeyIndex(HKey) \
47 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
49 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
50 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
51 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
52 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
55 /* FUNCTIONS ****************************************************************/
56 /* check if value type needs string conversion (Ansi<->Unicode) */
57 __inline
static int is_string( DWORD type
)
59 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
62 /************************************************************************
63 * RegInitDefaultHandles
68 TRACE("RegInitialize()\n");
73 ProcessHeap
= RtlGetProcessHeap();
74 RtlZeroMemory(DefaultHandleTable
,
75 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
76 RtlInitializeCriticalSection(&HandleTableCS
);
78 DllInitialized
= TRUE
;
85 /************************************************************************
91 TRACE("RegCleanup()\n");
94 RtlDeleteCriticalSection(&HandleTableCS
);
101 OpenPredefinedKey(IN ULONG Index
,
108 case 0: /* HKEY_CLASSES_ROOT */
109 Status
= OpenClassesRootKey (Handle
);
112 case 1: /* HKEY_CURRENT_USER */
113 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
117 case 2: /* HKEY_LOCAL_MACHINE */
118 Status
= OpenLocalMachineKey (Handle
);
121 case 3: /* HKEY_USERS */
122 Status
= OpenUsersKey (Handle
);
125 case 4: /* HKEY_PERFORMANCE_DATA */
126 Status
= OpenPerformanceDataKey (Handle
);
130 case 5: /* HKEY_CURRENT_CONFIG */
131 Status
= OpenCurrentConfigKey (Handle
);
134 case 6: /* HKEY_DYN_DATA */
135 Status
= STATUS_NOT_IMPLEMENTED
;
139 WARN("MapDefaultHandle() no handle creator\n");
140 Status
= STATUS_INVALID_PARAMETER
;
149 MapDefaultKey(OUT PHANDLE RealKey
,
154 BOOLEAN DoOpen
, DefDisabled
;
155 NTSTATUS Status
= STATUS_SUCCESS
;
157 TRACE("MapDefaultKey (Key %x)\n", Key
);
159 if (!IsPredefKey(Key
))
161 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
162 return STATUS_SUCCESS
;
165 /* Handle special cases here */
166 Index
= GetPredefKeyIndex(Key
);
167 if (Index
>= MAX_DEFAULT_HANDLES
)
169 return STATUS_INVALID_PARAMETER
;
171 RegInitialize(); /* HACK until delay-loading is implemented */
172 RtlEnterCriticalSection (&HandleTableCS
);
174 if (Key
== HKEY_CURRENT_USER
)
175 DefDisabled
= DefaultHandleHKUDisabled
;
177 DefDisabled
= DefaultHandlesDisabled
;
181 Handle
= &DefaultHandleTable
[Index
];
182 DoOpen
= (*Handle
== NULL
);
192 /* create/open the default handle */
193 Status
= OpenPredefinedKey(Index
,
197 if (NT_SUCCESS(Status
))
202 *(PULONG_PTR
)Handle
|= 0x1;
205 RtlLeaveCriticalSection (&HandleTableCS
);
212 CloseDefaultKeys(VOID
)
215 RegInitialize(); /* HACK until delay-loading is implemented */
216 RtlEnterCriticalSection(&HandleTableCS
);
218 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
220 if (DefaultHandleTable
[i
] != NULL
)
222 NtClose(DefaultHandleTable
[i
]);
223 DefaultHandleTable
[i
] = NULL
;
227 RtlLeaveCriticalSection(&HandleTableCS
);
232 OpenClassesRootKey(PHANDLE KeyHandle
)
234 OBJECT_ATTRIBUTES Attributes
;
235 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
237 TRACE("OpenClassesRootKey()\n");
239 InitializeObjectAttributes(&Attributes
,
241 OBJ_CASE_INSENSITIVE
,
244 return NtOpenKey(KeyHandle
,
251 OpenLocalMachineKey(PHANDLE KeyHandle
)
253 OBJECT_ATTRIBUTES Attributes
;
254 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
257 TRACE("OpenLocalMachineKey()\n");
259 InitializeObjectAttributes(&Attributes
,
261 OBJ_CASE_INSENSITIVE
,
264 Status
= NtOpenKey(KeyHandle
,
268 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
275 OpenUsersKey(PHANDLE KeyHandle
)
277 OBJECT_ATTRIBUTES Attributes
;
278 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
280 TRACE("OpenUsersKey()\n");
282 InitializeObjectAttributes(&Attributes
,
284 OBJ_CASE_INSENSITIVE
,
287 return NtOpenKey(KeyHandle
,
294 OpenCurrentConfigKey (PHANDLE KeyHandle
)
296 OBJECT_ATTRIBUTES Attributes
;
297 UNICODE_STRING KeyName
=
298 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
300 TRACE("OpenCurrentConfigKey()\n");
302 InitializeObjectAttributes(&Attributes
,
304 OBJ_CASE_INSENSITIVE
,
307 return NtOpenKey(KeyHandle
,
313 /************************************************************************
314 * RegDisablePredefinedCache
319 RegDisablePredefinedCache(VOID
)
321 RegInitialize(); /* HACK until delay-loading is implemented */
322 RtlEnterCriticalSection(&HandleTableCS
);
323 DefaultHandleHKUDisabled
= TRUE
;
324 RtlLeaveCriticalSection(&HandleTableCS
);
325 return ERROR_SUCCESS
;
329 /************************************************************************
330 * RegDisablePredefinedCacheEx
335 RegDisablePredefinedCacheEx(VOID
)
337 RegInitialize(); /* HACK until delay-loading is implemented */
338 RtlEnterCriticalSection(&HandleTableCS
);
339 DefaultHandlesDisabled
= TRUE
;
340 DefaultHandleHKUDisabled
= TRUE
;
341 RtlLeaveCriticalSection(&HandleTableCS
);
342 return ERROR_SUCCESS
;
346 /************************************************************************
347 * RegOverridePredefKey
352 RegOverridePredefKey(IN HKEY hKey
,
353 IN HKEY hNewHKey OPTIONAL
)
355 LONG ErrorCode
= ERROR_SUCCESS
;
357 if ((hKey
== HKEY_CLASSES_ROOT
||
358 hKey
== HKEY_CURRENT_CONFIG
||
359 hKey
== HKEY_CURRENT_USER
||
360 hKey
== HKEY_LOCAL_MACHINE
||
361 hKey
== HKEY_PERFORMANCE_DATA
||
362 hKey
== HKEY_USERS
) &&
363 !IsPredefKey(hNewHKey
))
368 Index
= GetPredefKeyIndex(hKey
);
369 Handle
= &DefaultHandleTable
[Index
];
371 if (hNewHKey
== NULL
)
373 /* restore the default mapping */
374 NTSTATUS Status
= OpenPredefinedKey(Index
,
376 if (!NT_SUCCESS(Status
))
378 return RtlNtStatusToDosError(Status
);
381 ASSERT(hNewHKey
!= NULL
);
383 RegInitialize(); /* HACK until delay-loading is implemented */
384 RtlEnterCriticalSection(&HandleTableCS
);
386 /* close the currently mapped handle if existing */
392 /* update the mapping */
395 RtlLeaveCriticalSection(&HandleTableCS
);
398 ErrorCode
= ERROR_INVALID_HANDLE
;
404 /************************************************************************
410 RegCloseKey(HKEY hKey
)
414 /* don't close null handle or a pseudo handle */
415 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
417 return ERROR_INVALID_HANDLE
;
420 Status
= NtClose(hKey
);
421 if (!NT_SUCCESS(Status
))
423 return RtlNtStatusToDosError(Status
);
426 return ERROR_SUCCESS
;
431 RegpCopyTree(IN HKEY hKeySrc
,
436 LIST_ENTRY ListEntry
;
439 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
441 LIST_ENTRY copyQueueHead
;
442 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
445 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
446 KEY_NODE_INFORMATION
*KeyNode
;
449 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
450 NTSTATUS Status
= STATUS_SUCCESS
;
451 NTSTATUS Status2
= STATUS_SUCCESS
;
453 InitializeListHead(©QueueHead
);
455 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
458 if (Info
.Buffer
== NULL
)
460 return STATUS_INSUFFICIENT_RESOURCES
;
463 copyKeys
= RtlAllocateHeap(ProcessHeap
,
465 sizeof(REGP_COPY_KEYS
));
466 if (copyKeys
!= NULL
)
468 copyKeys
->hKeySrc
= hKeySrc
;
469 copyKeys
->hKeyDest
= hKeyDest
;
470 InsertHeadList(©QueueHead
,
471 ©Keys
->ListEntry
);
473 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
477 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
481 /* enumerate all values and copy them */
485 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
487 KeyValueFullInformation
,
490 &BufferSizeRequired
);
491 if (NT_SUCCESS(Status2
))
493 UNICODE_STRING ValueName
;
496 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
497 ValueName
.Length
= Info
.KeyValue
->NameLength
;
498 ValueName
.MaximumLength
= ValueName
.Length
;
499 ValueName
.Buffer
= Info
.KeyValue
->Name
;
501 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
503 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
505 Info
.KeyValue
->TitleIndex
,
508 Info
.KeyValue
->DataLength
);
510 /* don't break, let's try to copy as many values as possible */
511 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
518 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
522 ASSERT(BufferSize
< BufferSizeRequired
);
524 Buffer
= RtlReAllocateHeap(ProcessHeap
,
530 Info
.Buffer
= Buffer
;
535 /* don't break, let's try to copy as many values as possible */
536 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
539 if (NT_SUCCESS(Status
))
547 /* break to avoid an infinite loop in case of denied access or
549 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
558 /* enumerate all subkeys and open and enqueue them */
562 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
567 &BufferSizeRequired
);
568 if (NT_SUCCESS(Status2
))
570 HANDLE KeyHandle
, NewKeyHandle
;
571 OBJECT_ATTRIBUTES ObjectAttributes
;
572 UNICODE_STRING SubKeyName
, ClassName
;
574 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
575 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
576 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
577 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
578 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
579 ClassName
.MaximumLength
= ClassName
.Length
;
580 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
582 /* open the subkey with sufficient rights */
584 InitializeObjectAttributes(&ObjectAttributes
,
586 OBJ_CASE_INSENSITIVE
,
590 Status2
= NtOpenKey(&KeyHandle
,
591 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
593 if (NT_SUCCESS(Status2
))
595 /* FIXME - attempt to query the security information */
597 InitializeObjectAttributes(&ObjectAttributes
,
599 OBJ_CASE_INSENSITIVE
,
603 Status2
= NtCreateKey(&NewKeyHandle
,
606 Info
.KeyNode
->TitleIndex
,
610 if (NT_SUCCESS(Status2
))
612 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
614 sizeof(REGP_COPY_KEYS
));
615 if (newCopyKeys
!= NULL
)
617 /* save the handles and enqueue the subkey */
618 newCopyKeys
->hKeySrc
= KeyHandle
;
619 newCopyKeys
->hKeyDest
= NewKeyHandle
;
620 InsertTailList(©QueueHead
,
621 &newCopyKeys
->ListEntry
);
626 NtClose(NewKeyHandle
);
628 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
637 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
644 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
648 ASSERT(BufferSize
< BufferSizeRequired
);
650 Buffer
= RtlReAllocateHeap(ProcessHeap
,
656 Info
.Buffer
= Buffer
;
661 /* don't break, let's try to copy as many keys as possible */
662 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
665 if (NT_SUCCESS(Status
))
673 /* break to avoid an infinite loop in case of denied access or
675 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
684 /* close the handles and remove the entry from the list */
685 if (copyKeys
->hKeySrc
!= hKeySrc
)
687 NtClose(copyKeys
->hKeySrc
);
689 if (copyKeys
->hKeyDest
!= hKeyDest
)
691 NtClose(copyKeys
->hKeyDest
);
694 RemoveEntryList(©Keys
->ListEntry
);
696 RtlFreeHeap(ProcessHeap
,
699 } while (!IsListEmpty(©QueueHead
));
702 Status
= STATUS_INSUFFICIENT_RESOURCES
;
704 RtlFreeHeap(ProcessHeap
,
712 /************************************************************************
718 RegCopyTreeW(IN HKEY hKeySrc
,
719 IN LPCWSTR lpSubKey OPTIONAL
,
722 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
725 Status
= MapDefaultKey(&KeyHandle
,
727 if (!NT_SUCCESS(Status
))
729 return RtlNtStatusToDosError(Status
);
732 Status
= MapDefaultKey(&DestKeyHandle
,
734 if (!NT_SUCCESS(Status
))
739 if (lpSubKey
!= NULL
)
741 OBJECT_ATTRIBUTES ObjectAttributes
;
742 UNICODE_STRING SubKeyName
;
744 RtlInitUnicodeString(&SubKeyName
,
747 InitializeObjectAttributes(&ObjectAttributes
,
749 OBJ_CASE_INSENSITIVE
,
753 Status
= NtOpenKey(&SubKeyHandle
,
754 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
756 if (!NT_SUCCESS(Status
))
761 CurKey
= SubKeyHandle
;
766 Status
= RegpCopyTree(CurKey
,
769 if (SubKeyHandle
!= NULL
)
771 NtClose(SubKeyHandle
);
775 ClosePredefKey(DestKeyHandle
);
777 ClosePredefKey(KeyHandle
);
779 if (!NT_SUCCESS(Status
))
781 return RtlNtStatusToDosError(Status
);
784 return ERROR_SUCCESS
;
788 /************************************************************************
794 RegCopyTreeA(IN HKEY hKeySrc
,
795 IN LPCSTR lpSubKey OPTIONAL
,
798 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
801 if (lpSubKey
!= NULL
&&
802 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
805 return ERROR_NOT_ENOUGH_MEMORY
;
808 Ret
= RegCopyTreeW(hKeySrc
,
812 RtlFreeUnicodeString(&SubKeyName
);
818 /************************************************************************
819 * RegConnectRegistryA
824 RegConnectRegistryA(IN LPCSTR lpMachineName
,
828 UNICODE_STRING MachineName
= { 0, 0, NULL
};
831 if (lpMachineName
!= NULL
&&
832 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
833 (LPSTR
)lpMachineName
))
835 return ERROR_NOT_ENOUGH_MEMORY
;
838 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
842 RtlFreeUnicodeString(&MachineName
);
848 /************************************************************************
849 * RegConnectRegistryW
854 RegConnectRegistryW(LPCWSTR lpMachineName
,
860 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
862 if (!lpMachineName
|| !*lpMachineName
)
864 /* Use the local machine name */
865 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
869 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
870 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
872 /* MSDN says lpMachineName must start with \\ : not so */
873 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
876 if (GetComputerNameW(compName
, &len
))
878 if (!_wcsicmp(lpMachineName
, compName
))
879 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
882 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
883 ret
= ERROR_BAD_NETPATH
;
887 ret
= GetLastError();
894 /************************************************************************
897 * Create key and all necessary intermediate keys
900 CreateNestedKey(PHKEY KeyHandle
,
901 POBJECT_ATTRIBUTES ObjectAttributes
,
902 PUNICODE_STRING ClassString
,
905 DWORD
*lpdwDisposition
)
907 OBJECT_ATTRIBUTES LocalObjectAttributes
;
908 UNICODE_STRING LocalKeyName
;
911 ULONG FullNameLength
;
914 HANDLE LocalKeyHandle
;
916 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
922 (PULONG
)lpdwDisposition
);
923 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
924 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
927 /* Copy object attributes */
928 RtlCopyMemory(&LocalObjectAttributes
,
930 sizeof(OBJECT_ATTRIBUTES
));
931 RtlCreateUnicodeString(&LocalKeyName
,
932 ObjectAttributes
->ObjectName
->Buffer
);
933 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
934 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
936 LocalKeyHandle
= NULL
;
938 /* Remove the last part of the key name and try to create the key again. */
939 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
941 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
942 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
944 Status
= STATUS_UNSUCCESSFUL
;
949 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
951 Status
= NtCreateKey(&LocalKeyHandle
,
953 &LocalObjectAttributes
,
958 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
961 if (!NT_SUCCESS(Status
))
963 RtlFreeUnicodeString(&LocalKeyName
);
967 /* Add removed parts of the key name and create them too. */
968 Length
= wcslen(LocalKeyName
.Buffer
);
972 NtClose (LocalKeyHandle
);
974 LocalKeyName
.Buffer
[Length
] = L
'\\';
975 Length
= wcslen (LocalKeyName
.Buffer
);
976 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
978 if (Length
== FullNameLength
)
980 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
986 (PULONG
)lpdwDisposition
);
990 Status
= NtCreateKey(&LocalKeyHandle
,
992 &LocalObjectAttributes
,
997 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
998 if (!NT_SUCCESS(Status
))
1002 RtlFreeUnicodeString(&LocalKeyName
);
1008 /************************************************************************
1014 RegCreateKeyExA(HKEY hKey
,
1020 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1022 LPDWORD lpdwDisposition
)
1024 UNICODE_STRING SubKeyString
;
1025 UNICODE_STRING ClassString
;
1026 OBJECT_ATTRIBUTES Attributes
;
1030 TRACE("RegCreateKeyExA() called\n");
1032 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1033 return ERROR_INVALID_USER_BUFFER
;
1035 /* get the real parent key */
1036 Status
= MapDefaultKey(&ParentKey
,
1038 if (!NT_SUCCESS(Status
))
1040 return RtlNtStatusToDosError(Status
);
1043 TRACE("ParentKey %p\n", ParentKey
);
1045 if (lpClass
!= NULL
)
1047 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1051 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1053 InitializeObjectAttributes(&Attributes
,
1055 OBJ_CASE_INSENSITIVE
,
1057 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1058 Status
= CreateNestedKey(phkResult
,
1060 (lpClass
== NULL
)? NULL
: &ClassString
,
1064 RtlFreeUnicodeString(&SubKeyString
);
1065 if (lpClass
!= NULL
)
1067 RtlFreeUnicodeString(&ClassString
);
1070 ClosePredefKey(ParentKey
);
1072 TRACE("Status %x\n", Status
);
1073 if (!NT_SUCCESS(Status
))
1075 return RtlNtStatusToDosError(Status
);
1078 return ERROR_SUCCESS
;
1082 /************************************************************************
1088 RegCreateKeyExW(HKEY hKey
,
1094 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1096 LPDWORD lpdwDisposition
)
1098 UNICODE_STRING SubKeyString
;
1099 UNICODE_STRING ClassString
;
1100 OBJECT_ATTRIBUTES Attributes
;
1104 TRACE("RegCreateKeyExW() called\n");
1106 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1107 return ERROR_INVALID_USER_BUFFER
;
1109 /* get the real parent key */
1110 Status
= MapDefaultKey(&ParentKey
,
1112 if (!NT_SUCCESS(Status
))
1114 return RtlNtStatusToDosError(Status
);
1117 TRACE("ParentKey %p\n", ParentKey
);
1119 RtlInitUnicodeString(&ClassString
,
1121 RtlInitUnicodeString(&SubKeyString
,
1123 InitializeObjectAttributes(&Attributes
,
1125 OBJ_CASE_INSENSITIVE
,
1127 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1128 Status
= CreateNestedKey(phkResult
,
1130 (lpClass
== NULL
)? NULL
: &ClassString
,
1135 ClosePredefKey(ParentKey
);
1137 TRACE("Status %x\n", Status
);
1138 if (!NT_SUCCESS(Status
))
1140 return RtlNtStatusToDosError(Status
);
1143 return ERROR_SUCCESS
;
1147 /************************************************************************
1153 RegCreateKeyA(HKEY hKey
,
1157 return RegCreateKeyExA(hKey
,
1169 /************************************************************************
1175 RegCreateKeyW(HKEY hKey
,
1179 return RegCreateKeyExW(hKey
,
1191 /************************************************************************
1197 RegDeleteKeyA(HKEY hKey
,
1200 OBJECT_ATTRIBUTES ObjectAttributes
;
1201 UNICODE_STRING SubKeyName
;
1206 /* Make sure we got a subkey */
1210 return ERROR_INVALID_PARAMETER
;
1213 Status
= MapDefaultKey(&ParentKey
,
1215 if (!NT_SUCCESS(Status
))
1217 return RtlNtStatusToDosError(Status
);
1220 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1222 InitializeObjectAttributes(&ObjectAttributes
,
1224 OBJ_CASE_INSENSITIVE
,
1228 Status
= NtOpenKey(&TargetKey
,
1231 RtlFreeUnicodeString(&SubKeyName
);
1232 if (!NT_SUCCESS(Status
))
1237 Status
= NtDeleteKey(TargetKey
);
1238 NtClose (TargetKey
);
1241 ClosePredefKey(ParentKey
);
1243 if (!NT_SUCCESS(Status
))
1245 return RtlNtStatusToDosError(Status
);
1248 return ERROR_SUCCESS
;
1252 /************************************************************************
1258 RegDeleteKeyW(HKEY hKey
,
1261 OBJECT_ATTRIBUTES ObjectAttributes
;
1262 UNICODE_STRING SubKeyName
;
1267 /* Make sure we got a subkey */
1271 return ERROR_INVALID_PARAMETER
;
1274 Status
= MapDefaultKey(&ParentKey
,
1276 if (!NT_SUCCESS(Status
))
1278 return RtlNtStatusToDosError(Status
);
1281 RtlInitUnicodeString(&SubKeyName
,
1283 InitializeObjectAttributes(&ObjectAttributes
,
1285 OBJ_CASE_INSENSITIVE
,
1288 Status
= NtOpenKey(&TargetKey
,
1291 if (!NT_SUCCESS(Status
))
1296 Status
= NtDeleteKey(TargetKey
);
1300 ClosePredefKey(ParentKey
);
1302 if (!NT_SUCCESS(Status
))
1304 return RtlNtStatusToDosError(Status
);
1307 return ERROR_SUCCESS
;
1311 /************************************************************************
1318 RegDeleteKeyExA(HKEY hKey
,
1323 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1324 return ERROR_CALL_NOT_IMPLEMENTED
;
1328 /************************************************************************
1335 RegDeleteKeyExW(HKEY hKey
,
1340 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1341 return ERROR_CALL_NOT_IMPLEMENTED
;
1345 /************************************************************************
1346 * RegDeleteKeyValueW
1351 RegDeleteKeyValueW(IN HKEY hKey
,
1352 IN LPCWSTR lpSubKey OPTIONAL
,
1353 IN LPCWSTR lpValueName OPTIONAL
)
1355 UNICODE_STRING ValueName
;
1356 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1359 Status
= MapDefaultKey(&KeyHandle
,
1361 if (!NT_SUCCESS(Status
))
1363 return RtlNtStatusToDosError(Status
);
1366 if (lpSubKey
!= NULL
)
1368 OBJECT_ATTRIBUTES ObjectAttributes
;
1369 UNICODE_STRING SubKeyName
;
1371 RtlInitUnicodeString(&SubKeyName
,
1374 InitializeObjectAttributes(&ObjectAttributes
,
1376 OBJ_CASE_INSENSITIVE
,
1380 Status
= NtOpenKey(&SubKeyHandle
,
1383 if (!NT_SUCCESS(Status
))
1388 CurKey
= SubKeyHandle
;
1393 RtlInitUnicodeString(&ValueName
,
1394 (LPWSTR
)lpValueName
);
1396 Status
= NtDeleteValueKey(CurKey
,
1399 if (SubKeyHandle
!= NULL
)
1401 NtClose(SubKeyHandle
);
1405 ClosePredefKey(KeyHandle
);
1407 if (!NT_SUCCESS(Status
))
1409 return RtlNtStatusToDosError(Status
);
1412 return ERROR_SUCCESS
;
1416 /************************************************************************
1417 * RegDeleteKeyValueA
1422 RegDeleteKeyValueA(IN HKEY hKey
,
1423 IN LPCSTR lpSubKey OPTIONAL
,
1424 IN LPCSTR lpValueName OPTIONAL
)
1426 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1429 if (lpSubKey
!= NULL
&&
1430 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1433 return ERROR_NOT_ENOUGH_MEMORY
;
1436 if (lpValueName
!= NULL
&&
1437 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1438 (LPSTR
)lpValueName
))
1440 RtlFreeUnicodeString(&SubKey
);
1441 return ERROR_NOT_ENOUGH_MEMORY
;
1444 Ret
= RegDeleteKeyValueW(hKey
,
1448 RtlFreeUnicodeString(&SubKey
);
1449 RtlFreeUnicodeString(&ValueName
);
1455 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1457 RegpDeleteTree(IN HKEY hKey
)
1461 LIST_ENTRY ListEntry
;
1463 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1465 LIST_ENTRY delQueueHead
;
1466 PREG_DEL_KEYS delKeys
, newDelKeys
;
1469 PKEY_BASIC_INFORMATION BasicInfo
;
1470 PREG_DEL_KEYS KeyDelRoot
;
1471 NTSTATUS Status
= STATUS_SUCCESS
;
1472 NTSTATUS Status2
= STATUS_SUCCESS
;
1474 InitializeListHead(&delQueueHead
);
1476 ProcessHeap
= RtlGetProcessHeap();
1478 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1479 structure for the root key, we only do that for subkeys as we need to
1480 allocate REGP_DEL_KEYS structures anyway! */
1481 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1483 sizeof(REGP_DEL_KEYS
));
1484 if (KeyDelRoot
!= NULL
)
1486 KeyDelRoot
->KeyHandle
= hKey
;
1487 InsertTailList(&delQueueHead
,
1488 &KeyDelRoot
->ListEntry
);
1492 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1501 /* check if this key contains subkeys and delete them first by queuing
1502 them at the head of the list */
1503 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1505 KeyBasicInformation
,
1510 if (NT_SUCCESS(Status2
))
1512 OBJECT_ATTRIBUTES ObjectAttributes
;
1513 UNICODE_STRING SubKeyName
;
1515 ASSERT(newDelKeys
!= NULL
);
1516 ASSERT(BasicInfo
!= NULL
);
1518 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1519 SubKeyName
.Length
= BasicInfo
->NameLength
;
1520 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1521 SubKeyName
.Buffer
= BasicInfo
->Name
;
1523 InitializeObjectAttributes(&ObjectAttributes
,
1525 OBJ_CASE_INSENSITIVE
,
1529 /* open the subkey */
1530 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1531 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1533 if (!NT_SUCCESS(Status2
))
1538 /* enqueue this key to the head of the deletion queue */
1539 InsertHeadList(&delQueueHead
,
1540 &newDelKeys
->ListEntry
);
1542 /* try again from the head of the list */
1547 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1549 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1551 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1552 if (newDelKeys
!= NULL
)
1554 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1557 goto ReadFirstSubKey
;
1561 /* don't break, let's try to delete as many keys as possible */
1562 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1563 goto SubKeyFailureNoFree
;
1566 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1568 PREG_DEL_KEYS newDelKeys2
;
1570 ASSERT(newDelKeys
!= NULL
);
1572 /* we need more memory to query the key name */
1573 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1576 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1577 if (newDelKeys2
!= NULL
)
1579 newDelKeys
= newDelKeys2
;
1580 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1583 goto ReadFirstSubKey
;
1587 /* don't break, let's try to delete as many keys as possible */
1588 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1591 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1593 /* in some race conditions where another thread would delete
1594 the same tree at the same time, newDelKeys could actually
1596 if (newDelKeys
!= NULL
)
1598 RtlFreeHeap(ProcessHeap
,
1606 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1607 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1608 if (newDelKeys
!= NULL
)
1610 RtlFreeHeap(ProcessHeap
,
1615 SubKeyFailureNoFree
:
1616 /* don't break, let's try to delete as many keys as possible */
1617 if (NT_SUCCESS(Status
))
1623 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1625 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1627 if (!NT_SUCCESS(Status2
))
1629 /* close the key handle so we don't leak handles for keys we were
1630 unable to delete. But only do this for handles not supplied
1633 if (delKeys
->KeyHandle
!= hKey
)
1635 NtClose(delKeys
->KeyHandle
);
1638 if (NT_SUCCESS(Status
))
1640 /* don't break, let's try to delete as many keys as possible */
1645 /* remove the entry from the list */
1646 RemoveEntryList(&delKeys
->ListEntry
);
1648 RtlFreeHeap(ProcessHeap
,
1651 } while (!IsListEmpty(&delQueueHead
));
1654 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1660 /************************************************************************
1666 RegDeleteTreeW(IN HKEY hKey
,
1667 IN LPCWSTR lpSubKey OPTIONAL
)
1669 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1672 Status
= MapDefaultKey(&KeyHandle
,
1674 if (!NT_SUCCESS(Status
))
1676 return RtlNtStatusToDosError(Status
);
1679 if (lpSubKey
!= NULL
)
1681 OBJECT_ATTRIBUTES ObjectAttributes
;
1682 UNICODE_STRING SubKeyName
;
1684 RtlInitUnicodeString(&SubKeyName
,
1687 InitializeObjectAttributes(&ObjectAttributes
,
1689 OBJ_CASE_INSENSITIVE
,
1693 Status
= NtOpenKey(&SubKeyHandle
,
1694 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1696 if (!NT_SUCCESS(Status
))
1701 CurKey
= SubKeyHandle
;
1706 Status
= RegpDeleteTree(CurKey
);
1708 if (NT_SUCCESS(Status
))
1710 /* make sure we only close hKey (KeyHandle) when the caller specified a
1711 subkey, because the handle would be invalid already! */
1712 if (CurKey
!= KeyHandle
)
1714 ClosePredefKey(KeyHandle
);
1717 return ERROR_SUCCESS
;
1721 /* make sure we close all handles we created! */
1722 if (SubKeyHandle
!= NULL
)
1724 NtClose(SubKeyHandle
);
1728 ClosePredefKey(KeyHandle
);
1730 return RtlNtStatusToDosError(Status
);
1736 /************************************************************************
1743 RegDeleteTreeW(HKEY hKey
,
1747 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1748 DWORD dwMaxLen
, dwSize
;
1752 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1754 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1756 Status
= MapDefaultKey(&KeyHandle
,
1758 if (!NT_SUCCESS(Status
))
1760 return RtlNtStatusToDosError(Status
);
1763 hSubKey
= KeyHandle
;
1767 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1770 ClosePredefKey(KeyHandle
);
1775 /* Get highest length for keys, values */
1776 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1777 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1778 if (ret
) goto cleanup
;
1782 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1783 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1785 /* Name too big: alloc a buffer for it */
1786 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1788 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1794 /* Recursively delete all the subkeys */
1798 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1799 NULL
, NULL
, NULL
)) break;
1801 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1802 if (ret
) goto cleanup
;
1806 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1811 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1812 NULL
, NULL
, NULL
, NULL
)) break;
1814 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1815 if (ret
) goto cleanup
;
1819 /* Free buffer if allocated */
1820 if (lpszName
!= szNameBuf
)
1821 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1823 RegCloseKey(hSubKey
);
1825 ClosePredefKey(KeyHandle
);
1831 /************************************************************************
1837 RegDeleteTreeA(IN HKEY hKey
,
1838 IN LPCSTR lpSubKey OPTIONAL
)
1840 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1843 if (lpSubKey
!= NULL
&&
1844 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1847 return ERROR_NOT_ENOUGH_MEMORY
;
1850 Ret
= RegDeleteTreeW(hKey
,
1853 RtlFreeUnicodeString(&SubKeyName
);
1859 /************************************************************************
1860 * RegDisableReflectionKey
1865 RegDisableReflectionKey(IN HKEY hBase
)
1867 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1868 return ERROR_CALL_NOT_IMPLEMENTED
;
1872 /************************************************************************
1873 * RegEnableReflectionKey
1878 RegEnableReflectionKey(IN HKEY hBase
)
1880 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1881 return ERROR_CALL_NOT_IMPLEMENTED
;
1885 /******************************************************************************
1886 * RegpApplyRestrictions [internal]
1888 * Helper function for RegGetValueA/W.
1891 RegpApplyRestrictions(DWORD dwFlags
,
1896 /* Check if the type is restricted by the passed flags */
1897 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1903 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1904 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1905 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1906 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1907 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1908 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1909 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1912 if (dwFlags
& dwMask
)
1914 /* Type is not restricted, check for size mismatch */
1915 if (dwType
== REG_BINARY
)
1919 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1921 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1924 if (cbExpect
&& cbData
!= cbExpect
)
1925 *ret
= ERROR_DATATYPE_MISMATCH
;
1928 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1933 /******************************************************************************
1934 * RegGetValueW [ADVAPI32.@]
1936 * Retrieves the type and data for a value name associated with a key,
1937 * optionally expanding its content and restricting its type.
1940 * hKey [I] Handle to an open key.
1941 * pszSubKey [I] Name of the subkey of hKey.
1942 * pszValue [I] Name of value under hKey/szSubKey to query.
1943 * dwFlags [I] Flags restricting the value type to retrieve.
1944 * pdwType [O] Destination for the values type, may be NULL.
1945 * pvData [O] Destination for the values content, may be NULL.
1946 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1947 * retrieve the whole content, including the trailing '\0'
1951 * Success: ERROR_SUCCESS
1952 * Failure: nonzero error code from Winerror.h
1955 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1956 * expanded and pdwType is set to REG_SZ instead.
1957 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1958 * without RRF_NOEXPAND is thus not allowed.
1959 * An exception is the case where RRF_RT_ANY is specified, because then
1960 * RRF_NOEXPAND is allowed.
1963 RegGetValueW(HKEY hKey
,
1971 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1975 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1976 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1977 pvData
, pcbData
, cbData
);
1979 if (pvData
&& !pcbData
)
1980 return ERROR_INVALID_PARAMETER
;
1981 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1982 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1983 return ERROR_INVALID_PARAMETER
;
1985 if (pszSubKey
&& pszSubKey
[0])
1987 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1988 if (ret
!= ERROR_SUCCESS
) return ret
;
1991 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1993 /* If we are going to expand we need to read in the whole the value even
1994 * if the passed buffer was too small as the expanded string might be
1995 * smaller than the unexpanded one and could fit into cbData bytes. */
1996 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1997 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2001 HeapFree(GetProcessHeap(), 0, pvBuf
);
2003 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2006 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2010 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2011 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2012 &dwType
, pvBuf
, &cbData
);
2015 /* Even if cbData was large enough we have to copy the
2016 * string since ExpandEnvironmentStrings can't handle
2017 * overlapping buffers. */
2018 CopyMemory(pvBuf
, pvData
, cbData
);
2021 /* Both the type or the value itself could have been modified in
2022 * between so we have to keep retrying until the buffer is large
2023 * enough or we no longer have to expand the value. */
2025 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2027 if (ret
== ERROR_SUCCESS
)
2029 /* Recheck dwType in case it changed since the first call */
2030 if (dwType
== REG_EXPAND_SZ
)
2032 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2033 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2035 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2036 ret
= ERROR_MORE_DATA
;
2039 CopyMemory(pvData
, pvBuf
, *pcbData
);
2042 HeapFree(GetProcessHeap(), 0, pvBuf
);
2045 if (pszSubKey
&& pszSubKey
[0])
2048 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2050 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2051 ZeroMemory(pvData
, *pcbData
);
2063 /******************************************************************************
2064 * RegGetValueA [ADVAPI32.@]
2069 RegGetValueA(HKEY hKey
,
2077 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2081 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2082 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2085 if (pvData
&& !pcbData
)
2086 return ERROR_INVALID_PARAMETER
;
2087 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2088 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2089 return ERROR_INVALID_PARAMETER
;
2091 if (pszSubKey
&& pszSubKey
[0])
2093 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2094 if (ret
!= ERROR_SUCCESS
) return ret
;
2097 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2099 /* If we are going to expand we need to read in the whole the value even
2100 * if the passed buffer was too small as the expanded string might be
2101 * smaller than the unexpanded one and could fit into cbData bytes. */
2102 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2103 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2106 HeapFree(GetProcessHeap(), 0, pvBuf
);
2108 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2111 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2115 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2116 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2117 &dwType
, pvBuf
, &cbData
);
2120 /* Even if cbData was large enough we have to copy the
2121 * string since ExpandEnvironmentStrings can't handle
2122 * overlapping buffers. */
2123 CopyMemory(pvBuf
, pvData
, cbData
);
2126 /* Both the type or the value itself could have been modified in
2127 * between so we have to keep retrying until the buffer is large
2128 * enough or we no longer have to expand the value. */
2129 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2131 if (ret
== ERROR_SUCCESS
)
2133 /* Recheck dwType in case it changed since the first call */
2134 if (dwType
== REG_EXPAND_SZ
)
2136 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2137 pcbData
? *pcbData
: 0);
2139 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2140 ret
= ERROR_MORE_DATA
;
2143 CopyMemory(pvData
, pvBuf
, *pcbData
);
2146 HeapFree(GetProcessHeap(), 0, pvBuf
);
2149 if (pszSubKey
&& pszSubKey
[0])
2152 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2154 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2155 ZeroMemory(pvData
, *pcbData
);
2157 if (pdwType
) *pdwType
= dwType
;
2158 if (pcbData
) *pcbData
= cbData
;
2164 /************************************************************************
2170 RegSetKeyValueW(IN HKEY hKey
,
2171 IN LPCWSTR lpSubKey OPTIONAL
,
2172 IN LPCWSTR lpValueName OPTIONAL
,
2174 IN LPCVOID lpData OPTIONAL
,
2177 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2181 Status
= MapDefaultKey(&KeyHandle
,
2183 if (!NT_SUCCESS(Status
))
2185 return RtlNtStatusToDosError(Status
);
2188 if (lpSubKey
!= NULL
)
2190 OBJECT_ATTRIBUTES ObjectAttributes
;
2191 UNICODE_STRING SubKeyName
;
2193 RtlInitUnicodeString(&SubKeyName
,
2196 InitializeObjectAttributes(&ObjectAttributes
,
2198 OBJ_CASE_INSENSITIVE
,
2202 Status
= NtOpenKey(&SubKeyHandle
,
2205 if (!NT_SUCCESS(Status
))
2207 Ret
= RtlNtStatusToDosError(Status
);
2211 CurKey
= SubKeyHandle
;
2216 Ret
= RegSetValueExW(CurKey
,
2223 if (SubKeyHandle
!= NULL
)
2225 NtClose(SubKeyHandle
);
2229 ClosePredefKey(KeyHandle
);
2235 /************************************************************************
2241 RegSetKeyValueA(IN HKEY hKey
,
2242 IN LPCSTR lpSubKey OPTIONAL
,
2243 IN LPCSTR lpValueName OPTIONAL
,
2245 IN LPCVOID lpData OPTIONAL
,
2248 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2252 Status
= MapDefaultKey(&KeyHandle
,
2254 if (!NT_SUCCESS(Status
))
2256 return RtlNtStatusToDosError(Status
);
2259 if (lpSubKey
!= NULL
)
2261 OBJECT_ATTRIBUTES ObjectAttributes
;
2262 UNICODE_STRING SubKeyName
;
2264 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2267 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2271 InitializeObjectAttributes(&ObjectAttributes
,
2273 OBJ_CASE_INSENSITIVE
,
2277 Status
= NtOpenKey(&SubKeyHandle
,
2281 RtlFreeUnicodeString(&SubKeyName
);
2283 if (!NT_SUCCESS(Status
))
2285 Ret
= RtlNtStatusToDosError(Status
);
2289 CurKey
= SubKeyHandle
;
2294 Ret
= RegSetValueExA(CurKey
,
2301 if (SubKeyHandle
!= NULL
)
2303 NtClose(SubKeyHandle
);
2307 ClosePredefKey(KeyHandle
);
2313 /************************************************************************
2319 RegDeleteValueA(HKEY hKey
,
2322 UNICODE_STRING ValueName
;
2326 Status
= MapDefaultKey(&KeyHandle
,
2328 if (!NT_SUCCESS(Status
))
2330 return RtlNtStatusToDosError(Status
);
2333 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2334 (LPSTR
)lpValueName
);
2335 Status
= NtDeleteValueKey(KeyHandle
,
2337 RtlFreeUnicodeString (&ValueName
);
2339 ClosePredefKey(KeyHandle
);
2341 if (!NT_SUCCESS(Status
))
2343 return RtlNtStatusToDosError(Status
);
2346 return ERROR_SUCCESS
;
2350 /************************************************************************
2356 RegDeleteValueW(HKEY hKey
,
2357 LPCWSTR lpValueName
)
2359 UNICODE_STRING ValueName
;
2363 Status
= MapDefaultKey(&KeyHandle
,
2365 if (!NT_SUCCESS(Status
))
2367 return RtlNtStatusToDosError(Status
);
2370 RtlInitUnicodeString(&ValueName
,
2371 (LPWSTR
)lpValueName
);
2373 Status
= NtDeleteValueKey(KeyHandle
,
2376 ClosePredefKey(KeyHandle
);
2378 if (!NT_SUCCESS(Status
))
2380 return RtlNtStatusToDosError(Status
);
2383 return ERROR_SUCCESS
;
2387 /************************************************************************
2393 RegEnumKeyA(HKEY hKey
,
2401 return RegEnumKeyExA(hKey
,
2412 /************************************************************************
2418 RegEnumKeyW(HKEY hKey
,
2426 return RegEnumKeyExW(hKey
,
2437 /************************************************************************
2443 RegEnumKeyExA(HKEY hKey
,
2450 PFILETIME lpftLastWriteTime
)
2454 KEY_NODE_INFORMATION Node
;
2455 KEY_BASIC_INFORMATION Basic
;
2458 UNICODE_STRING StringU
;
2459 ANSI_STRING StringA
;
2460 LONG ErrorCode
= ERROR_SUCCESS
;
2462 DWORD ClassLength
= 0;
2468 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2469 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2471 if ((lpClass
) && (!lpcbClass
))
2473 return ERROR_INVALID_PARAMETER
;
2476 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2477 if (!NT_SUCCESS(Status
))
2479 return RtlNtStatusToDosError(Status
);
2484 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2495 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2502 /* The class name should start at a dword boundary */
2503 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2507 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2510 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2511 if (KeyInfo
== NULL
)
2513 ErrorCode
= ERROR_OUTOFMEMORY
;
2517 Status
= NtEnumerateKey(KeyHandle
,
2519 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2523 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2524 if (!NT_SUCCESS(Status
))
2526 ErrorCode
= RtlNtStatusToDosError (Status
);
2530 if (lpClass
== NULL
)
2532 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2534 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2538 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2539 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2540 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2545 if (KeyInfo
->Node
.NameLength
> NameLength
||
2546 KeyInfo
->Node
.ClassLength
> ClassLength
)
2548 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2552 StringA
.Buffer
= lpClass
;
2554 StringA
.MaximumLength
= *lpcbClass
;
2555 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2556 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2557 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2558 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2559 lpClass
[StringA
.Length
] = 0;
2560 *lpcbClass
= StringA
.Length
;
2561 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2562 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2563 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2567 if (ErrorCode
== ERROR_SUCCESS
)
2569 StringA
.Buffer
= lpName
;
2571 StringA
.MaximumLength
= *lpcbName
;
2572 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2573 lpName
[StringA
.Length
] = 0;
2574 *lpcbName
= StringA
.Length
;
2575 if (lpftLastWriteTime
!= NULL
)
2577 if (lpClass
== NULL
)
2579 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2580 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2584 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2585 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2591 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2592 TRACE("Key Name1 Length %d\n", NameLength
);
2593 TRACE("Key Name Length %d\n", *lpcbName
);
2594 TRACE("Key Name %s\n", lpName
);
2596 RtlFreeHeap(ProcessHeap
,
2601 ClosePredefKey(KeyHandle
);
2607 /************************************************************************
2613 RegEnumKeyExW(HKEY hKey
,
2620 PFILETIME lpftLastWriteTime
)
2624 KEY_NODE_INFORMATION Node
;
2625 KEY_BASIC_INFORMATION Basic
;
2631 ULONG ClassLength
= 0;
2633 LONG ErrorCode
= ERROR_SUCCESS
;
2636 Status
= MapDefaultKey(&KeyHandle
,
2638 if (!NT_SUCCESS(Status
))
2640 return RtlNtStatusToDosError(Status
);
2645 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2656 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2663 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2667 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2670 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2673 if (KeyInfo
== NULL
)
2675 ErrorCode
= ERROR_OUTOFMEMORY
;
2679 Status
= NtEnumerateKey(KeyHandle
,
2681 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2685 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2686 if (!NT_SUCCESS(Status
))
2688 ErrorCode
= RtlNtStatusToDosError (Status
);
2692 if (lpClass
== NULL
)
2694 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2696 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2700 RtlCopyMemory(lpName
,
2701 KeyInfo
->Basic
.Name
,
2702 KeyInfo
->Basic
.NameLength
);
2703 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2704 lpName
[*lpcbName
] = 0;
2709 if (KeyInfo
->Node
.NameLength
> NameLength
||
2710 KeyInfo
->Node
.ClassLength
> ClassLength
)
2712 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2716 RtlCopyMemory(lpName
,
2718 KeyInfo
->Node
.NameLength
);
2719 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2720 lpName
[*lpcbName
] = 0;
2721 RtlCopyMemory(lpClass
,
2722 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2723 KeyInfo
->Node
.ClassLength
);
2724 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2725 lpClass
[*lpcbClass
] = 0;
2729 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2731 if (lpClass
== NULL
)
2733 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2734 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2738 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2739 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2744 RtlFreeHeap(ProcessHeap
,
2749 ClosePredefKey(KeyHandle
);
2755 /************************************************************************
2761 RegEnumValueA(HKEY hKey
,
2773 char buffer
[256], *buf_ptr
= buffer
;
2774 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2775 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2777 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2778 // hkey, index, value, val_count, reserved, type, data, count );
2780 /* NT only checks count, not val_count */
2781 if ((data
&& !count
) || reserved
)
2782 return ERROR_INVALID_PARAMETER
;
2784 status
= MapDefaultKey(&KeyHandle
, hKey
);
2785 if (!NT_SUCCESS(status
))
2787 return RtlNtStatusToDosError(status
);
2790 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2791 if (data
) total_size
+= *count
;
2792 total_size
= min( sizeof(buffer
), total_size
);
2794 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2795 buffer
, total_size
, &total_size
);
2796 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2798 /* we need to fetch the contents for a string type even if not requested,
2799 * because we need to compute the length of the ASCII string. */
2800 if (value
|| data
|| is_string(info
->Type
))
2802 /* retry with a dynamically allocated buffer */
2803 while (status
== STATUS_BUFFER_OVERFLOW
)
2805 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2806 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2808 status
= STATUS_INSUFFICIENT_RESOURCES
;
2811 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2812 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2813 buf_ptr
, total_size
, &total_size
);
2816 if (status
) goto done
;
2818 if (is_string(info
->Type
))
2821 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2822 total_size
- info
->DataOffset
);
2825 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2828 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2829 total_size
- info
->DataOffset
);
2830 /* if the type is REG_SZ and data is not 0-terminated
2831 * and there is enough space in the buffer NT appends a \0 */
2832 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2835 info
->DataLength
= len
;
2839 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2840 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2843 if (value
&& !status
)
2847 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2848 if (len
>= *val_count
)
2850 status
= STATUS_BUFFER_OVERFLOW
;
2853 len
= *val_count
- 1;
2854 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2860 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2866 else status
= STATUS_SUCCESS
;
2868 if (type
) *type
= info
->Type
;
2869 if (count
) *count
= info
->DataLength
;
2872 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2873 ClosePredefKey(KeyHandle
);
2874 return RtlNtStatusToDosError(status
);
2878 /******************************************************************************
2879 * RegEnumValueW [ADVAPI32.@]
2883 * hkey [I] Handle to key to query
2884 * index [I] Index of value to query
2885 * value [O] Value string
2886 * val_count [I/O] Size of value buffer (in wchars)
2887 * reserved [I] Reserved
2888 * type [O] Type code
2889 * data [O] Value data
2890 * count [I/O] Size of data buffer (in bytes)
2893 * Success: ERROR_SUCCESS
2894 * Failure: nonzero error code from Winerror.h
2897 RegEnumValueW(HKEY hKey
,
2909 char buffer
[256], *buf_ptr
= buffer
;
2910 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2911 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2913 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2914 // hkey, index, value, val_count, reserved, type, data, count );
2916 /* NT only checks count, not val_count */
2917 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2919 status
= MapDefaultKey(&KeyHandle
, hKey
);
2920 if (!NT_SUCCESS(status
))
2922 return RtlNtStatusToDosError(status
);
2925 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2926 if (data
) total_size
+= *count
;
2927 total_size
= min( sizeof(buffer
), total_size
);
2929 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2930 buffer
, total_size
, &total_size
);
2931 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2935 /* retry with a dynamically allocated buffer */
2936 while (status
== STATUS_BUFFER_OVERFLOW
)
2938 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2939 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2941 status
= ERROR_NOT_ENOUGH_MEMORY
;
2944 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2945 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2946 buf_ptr
, total_size
, &total_size
);
2949 if (status
) goto done
;
2953 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2955 status
= STATUS_BUFFER_OVERFLOW
;
2958 memcpy( value
, info
->Name
, info
->NameLength
);
2959 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2960 value
[*val_count
] = 0;
2965 if (total_size
- info
->DataOffset
> *count
)
2967 status
= STATUS_BUFFER_OVERFLOW
;
2970 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2971 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2973 /* if the type is REG_SZ and data is not 0-terminated
2974 * and there is enough space in the buffer NT appends a \0 */
2975 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2976 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2980 else status
= STATUS_SUCCESS
;
2983 if (type
) *type
= info
->Type
;
2984 if (count
) *count
= info
->DataLength
;
2987 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2988 ClosePredefKey(KeyHandle
);
2989 return RtlNtStatusToDosError(status
);
2993 /************************************************************************
2999 RegFlushKey(HKEY hKey
)
3004 if (hKey
== HKEY_PERFORMANCE_DATA
)
3006 return ERROR_SUCCESS
;
3009 Status
= MapDefaultKey(&KeyHandle
,
3011 if (!NT_SUCCESS(Status
))
3013 return RtlNtStatusToDosError(Status
);
3016 Status
= NtFlushKey(KeyHandle
);
3018 ClosePredefKey(KeyHandle
);
3020 if (!NT_SUCCESS(Status
))
3022 return RtlNtStatusToDosError(Status
);
3025 return ERROR_SUCCESS
;
3029 /************************************************************************
3035 RegGetKeySecurity(HKEY hKey
,
3036 SECURITY_INFORMATION SecurityInformation
,
3037 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3038 LPDWORD lpcbSecurityDescriptor
)
3043 if (hKey
== HKEY_PERFORMANCE_DATA
)
3045 return ERROR_INVALID_HANDLE
;
3048 Status
= MapDefaultKey(&KeyHandle
,
3050 if (!NT_SUCCESS(Status
))
3052 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3053 return RtlNtStatusToDosError(Status
);
3057 Status
= NtQuerySecurityObject(KeyHandle
,
3058 SecurityInformation
,
3059 pSecurityDescriptor
,
3060 *lpcbSecurityDescriptor
,
3061 lpcbSecurityDescriptor
);
3064 ClosePredefKey(KeyHandle
);
3066 if (!NT_SUCCESS(Status
))
3068 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3069 return RtlNtStatusToDosError(Status
);
3072 return ERROR_SUCCESS
;
3076 /************************************************************************
3082 RegLoadKeyA(HKEY hKey
,
3086 UNICODE_STRING FileName
;
3087 UNICODE_STRING KeyName
;
3090 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3092 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3095 ErrorCode
= RegLoadKeyW(hKey
,
3099 RtlFreeUnicodeString(&FileName
);
3100 RtlFreeUnicodeString(&KeyName
);
3106 /************************************************************************
3112 RegLoadKeyW(HKEY hKey
,
3116 OBJECT_ATTRIBUTES FileObjectAttributes
;
3117 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3118 UNICODE_STRING FileName
;
3119 UNICODE_STRING KeyName
;
3122 LONG ErrorCode
= ERROR_SUCCESS
;
3124 if (hKey
== HKEY_PERFORMANCE_DATA
)
3126 return ERROR_INVALID_HANDLE
;
3129 Status
= MapDefaultKey(&KeyHandle
,
3131 if (!NT_SUCCESS(Status
))
3133 return RtlNtStatusToDosError(Status
);
3136 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3141 ErrorCode
= ERROR_BAD_PATHNAME
;
3145 InitializeObjectAttributes(&FileObjectAttributes
,
3147 OBJ_CASE_INSENSITIVE
,
3151 RtlInitUnicodeString(&KeyName
,
3154 InitializeObjectAttributes(&KeyObjectAttributes
,
3156 OBJ_CASE_INSENSITIVE
,
3160 Status
= NtLoadKey(&KeyObjectAttributes
,
3161 &FileObjectAttributes
);
3163 RtlFreeHeap(RtlGetProcessHeap(),
3167 if (!NT_SUCCESS(Status
))
3169 ErrorCode
= RtlNtStatusToDosError(Status
);
3174 ClosePredefKey(KeyHandle
);
3180 /************************************************************************
3181 * RegNotifyChangeKeyValue
3186 RegNotifyChangeKeyValue(HKEY hKey
,
3188 DWORD dwNotifyFilter
,
3192 IO_STATUS_BLOCK IoStatusBlock
;
3195 LONG ErrorCode
= ERROR_SUCCESS
;
3197 if (hKey
== HKEY_PERFORMANCE_DATA
)
3199 return ERROR_INVALID_HANDLE
;
3202 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3204 return ERROR_INVALID_PARAMETER
;
3207 Status
= MapDefaultKey(&KeyHandle
,
3209 if (!NT_SUCCESS(Status
))
3211 return RtlNtStatusToDosError(Status
);
3214 /* FIXME: Remote key handles must fail */
3216 Status
= NtNotifyChangeKey(KeyHandle
,
3226 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3228 ErrorCode
= RtlNtStatusToDosError(Status
);
3231 ClosePredefKey(KeyHandle
);
3237 /************************************************************************
3238 * RegOpenCurrentUser
3243 RegOpenCurrentUser(IN REGSAM samDesired
,
3244 OUT PHKEY phkResult
)
3248 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3249 (PHANDLE
)phkResult
);
3250 if (!NT_SUCCESS(Status
))
3252 /* NOTE - don't set the last error code! just return the error! */
3253 return RtlNtStatusToDosError(Status
);
3256 return ERROR_SUCCESS
;
3260 /************************************************************************
3263 * 20050503 Fireball - imported from WINE
3268 RegOpenKeyA(HKEY hKey
,
3272 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3273 hKey
, lpSubKey
, phkResult
);
3276 return ERROR_INVALID_PARAMETER
;
3278 if (!hKey
&& lpSubKey
&& phkResult
)
3280 return ERROR_INVALID_HANDLE
;
3283 if (!lpSubKey
|| !*lpSubKey
)
3286 return ERROR_SUCCESS
;
3289 return RegOpenKeyExA(hKey
,
3297 /************************************************************************
3302 * 20050503 Fireball - imported from WINE
3307 RegOpenKeyW(HKEY hKey
,
3311 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3312 hKey
, lpSubKey
, phkResult
);
3315 return ERROR_INVALID_PARAMETER
;
3317 if (!hKey
&& lpSubKey
&& phkResult
)
3319 return ERROR_INVALID_HANDLE
;
3322 if (!lpSubKey
|| !*lpSubKey
)
3325 return ERROR_SUCCESS
;
3328 return RegOpenKeyExW(hKey
,
3336 /************************************************************************
3342 RegOpenKeyExA(HKEY hKey
,
3348 OBJECT_ATTRIBUTES ObjectAttributes
;
3349 UNICODE_STRING SubKeyString
;
3352 LONG ErrorCode
= ERROR_SUCCESS
;
3354 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3355 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3358 return ERROR_INVALID_PARAMETER
;
3361 Status
= MapDefaultKey(&KeyHandle
,
3363 if (!NT_SUCCESS(Status
))
3365 return RtlNtStatusToDosError(Status
);
3368 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3370 InitializeObjectAttributes(&ObjectAttributes
,
3372 OBJ_CASE_INSENSITIVE
,
3376 Status
= NtOpenKey((PHANDLE
)phkResult
,
3379 RtlFreeUnicodeString(&SubKeyString
);
3380 if (!NT_SUCCESS(Status
))
3382 ErrorCode
= RtlNtStatusToDosError(Status
);
3385 ClosePredefKey(KeyHandle
);
3391 /************************************************************************
3397 RegOpenKeyExW(HKEY hKey
,
3403 OBJECT_ATTRIBUTES ObjectAttributes
;
3404 UNICODE_STRING SubKeyString
;
3407 LONG ErrorCode
= ERROR_SUCCESS
;
3409 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3410 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3413 return ERROR_INVALID_PARAMETER
;
3416 Status
= MapDefaultKey(&KeyHandle
, hKey
);
3417 if (!NT_SUCCESS(Status
))
3419 return RtlNtStatusToDosError(Status
);
3422 if (lpSubKey
!= NULL
)
3423 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)lpSubKey
);
3425 RtlInitUnicodeString(&SubKeyString
, (LPWSTR
)L
"");
3427 InitializeObjectAttributes(&ObjectAttributes
,
3429 OBJ_CASE_INSENSITIVE
,
3433 Status
= NtOpenKey((PHANDLE
)phkResult
,
3436 if (!NT_SUCCESS(Status
))
3438 ErrorCode
= RtlNtStatusToDosError(Status
);
3441 ClosePredefKey(KeyHandle
);
3447 /************************************************************************
3448 * RegOpenUserClassesRoot
3453 RegOpenUserClassesRoot(IN HANDLE hToken
,
3455 IN REGSAM samDesired
,
3456 OUT PHKEY phkResult
)
3458 const WCHAR UserClassesKeyPrefix
[] = L
"\\Registry\\User\\";
3459 const WCHAR UserClassesKeySuffix
[] = L
"_Classes";
3460 PTOKEN_USER TokenUserData
;
3461 ULONG RequiredLength
;
3462 UNICODE_STRING UserSidString
, UserClassesKeyRoot
;
3463 OBJECT_ATTRIBUTES ObjectAttributes
;
3466 /* check parameters */
3467 if (hToken
== NULL
|| dwOptions
!= 0 || phkResult
== NULL
)
3469 return ERROR_INVALID_PARAMETER
;
3473 * Get the user sid from the token
3477 /* determine how much memory we need */
3478 Status
= NtQueryInformationToken(hToken
,
3483 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
3485 /* NOTE - as opposed to all other registry functions windows does indeed
3486 change the last error code in case the caller supplied a invalid
3487 handle for example! */
3488 return RtlNtStatusToDosError(Status
);
3490 RegInitialize(); /* HACK until delay-loading is implemented */
3491 TokenUserData
= RtlAllocateHeap(ProcessHeap
,
3494 if (TokenUserData
== NULL
)
3496 return ERROR_NOT_ENOUGH_MEMORY
;
3499 /* attempt to read the information */
3500 Status
= NtQueryInformationToken(hToken
,
3505 if (!NT_SUCCESS(Status
))
3507 RtlFreeHeap(ProcessHeap
,
3510 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3512 /* the information appears to have changed?! try again */
3516 /* NOTE - as opposed to all other registry functions windows does indeed
3517 change the last error code in case the caller supplied a invalid
3518 handle for example! */
3519 return RtlNtStatusToDosError(Status
);
3523 * Build the absolute path for the user's registry in the form
3524 * "\Registry\User\<SID>_Classes"
3526 Status
= RtlConvertSidToUnicodeString(&UserSidString
,
3527 TokenUserData
->User
.Sid
,
3530 /* we don't need the user data anymore, free it */
3531 RtlFreeHeap(ProcessHeap
,
3535 if (!NT_SUCCESS(Status
))
3537 return RtlNtStatusToDosError(Status
);
3540 /* allocate enough memory for the entire key string */
3541 UserClassesKeyRoot
.Length
= 0;
3542 UserClassesKeyRoot
.MaximumLength
= UserSidString
.Length
+
3543 sizeof(UserClassesKeyPrefix
) +
3544 sizeof(UserClassesKeySuffix
);
3545 UserClassesKeyRoot
.Buffer
= RtlAllocateHeap(ProcessHeap
,
3547 UserClassesKeyRoot
.MaximumLength
);
3548 if (UserClassesKeyRoot
.Buffer
== NULL
)
3550 RtlFreeUnicodeString(&UserSidString
);
3551 return RtlNtStatusToDosError(Status
);
3554 /* build the string */
3555 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3556 UserClassesKeyPrefix
);
3557 RtlAppendUnicodeStringToString(&UserClassesKeyRoot
,
3559 RtlAppendUnicodeToString(&UserClassesKeyRoot
,
3560 UserClassesKeySuffix
);
3562 TRACE("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot
);
3567 InitializeObjectAttributes(&ObjectAttributes
,
3568 &UserClassesKeyRoot
,
3569 OBJ_CASE_INSENSITIVE
,
3573 Status
= NtOpenKey((PHANDLE
)phkResult
,
3577 RtlFreeUnicodeString(&UserSidString
);
3578 RtlFreeUnicodeString(&UserClassesKeyRoot
);
3580 if (!NT_SUCCESS(Status
))
3582 return RtlNtStatusToDosError(Status
);
3585 return ERROR_SUCCESS
;
3589 /************************************************************************
3595 RegQueryInfoKeyA(HKEY hKey
,
3600 LPDWORD lpcbMaxSubKeyLen
,
3601 LPDWORD lpcbMaxClassLen
,
3603 LPDWORD lpcbMaxValueNameLen
,
3604 LPDWORD lpcbMaxValueLen
,
3605 LPDWORD lpcbSecurityDescriptor
,
3606 PFILETIME lpftLastWriteTime
)
3608 WCHAR ClassName
[MAX_PATH
];
3609 UNICODE_STRING UnicodeString
;
3610 ANSI_STRING AnsiString
;
3613 RtlInitUnicodeString(&UnicodeString
,
3615 if (lpClass
!= NULL
)
3617 UnicodeString
.Buffer
= &ClassName
[0];
3618 UnicodeString
.MaximumLength
= sizeof(ClassName
);
3619 AnsiString
.MaximumLength
= *lpcbClass
;
3622 ErrorCode
= RegQueryInfoKeyW(hKey
,
3623 UnicodeString
.Buffer
,
3630 lpcbMaxValueNameLen
,
3632 lpcbSecurityDescriptor
,
3634 if ((ErrorCode
== ERROR_SUCCESS
) && (lpClass
!= NULL
))
3636 AnsiString
.Buffer
= lpClass
;
3637 AnsiString
.Length
= 0;
3638 UnicodeString
.Length
= *lpcbClass
* sizeof(WCHAR
);
3639 RtlUnicodeStringToAnsiString(&AnsiString
,
3642 *lpcbClass
= AnsiString
.Length
;
3643 lpClass
[AnsiString
.Length
] = 0;
3650 /************************************************************************
3656 RegQueryInfoKeyW(HKEY hKey
,
3661 LPDWORD lpcbMaxSubKeyLen
,
3662 LPDWORD lpcbMaxClassLen
,
3664 LPDWORD lpcbMaxValueNameLen
,
3665 LPDWORD lpcbMaxValueLen
,
3666 LPDWORD lpcbSecurityDescriptor
,
3667 PFILETIME lpftLastWriteTime
)
3669 KEY_FULL_INFORMATION FullInfoBuffer
;
3670 PKEY_FULL_INFORMATION FullInfo
;
3672 ULONG ClassLength
= 0;
3676 LONG ErrorCode
= ERROR_SUCCESS
;
3678 if ((lpClass
) && (!lpcbClass
))
3680 return ERROR_INVALID_PARAMETER
;
3683 Status
= MapDefaultKey(&KeyHandle
,
3685 if (!NT_SUCCESS(Status
))
3687 return RtlNtStatusToDosError(Status
);
3690 if (lpClass
!= NULL
)
3694 ClassLength
= min(*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
3701 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
) + ((ClassLength
+ 3) & ~3);
3702 FullInfo
= RtlAllocateHeap(ProcessHeap
,
3705 if (FullInfo
== NULL
)
3707 ErrorCode
= ERROR_OUTOFMEMORY
;
3711 FullInfo
->ClassLength
= ClassLength
;
3715 FullInfoSize
= sizeof(KEY_FULL_INFORMATION
);
3716 FullInfo
= &FullInfoBuffer
;
3717 FullInfo
->ClassLength
= 0;
3719 FullInfo
->ClassOffset
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
3721 Status
= NtQueryKey(KeyHandle
,
3726 TRACE("NtQueryKey() returned status 0x%X\n", Status
);
3727 if (!NT_SUCCESS(Status
))
3729 if (lpClass
!= NULL
)
3731 RtlFreeHeap(ProcessHeap
,
3736 ErrorCode
= RtlNtStatusToDosError(Status
);
3740 TRACE("SubKeys %d\n", FullInfo
->SubKeys
);
3741 if (lpcSubKeys
!= NULL
)
3743 *lpcSubKeys
= FullInfo
->SubKeys
;
3746 TRACE("MaxNameLen %lu\n", FullInfo
->MaxNameLen
);
3747 if (lpcbMaxSubKeyLen
!= NULL
)
3749 *lpcbMaxSubKeyLen
= FullInfo
->MaxNameLen
/ sizeof(WCHAR
) + 1;
3752 TRACE("MaxClassLen %lu\n", FullInfo
->MaxClassLen
);
3753 if (lpcbMaxClassLen
!= NULL
)
3755 *lpcbMaxClassLen
= FullInfo
->MaxClassLen
/ sizeof(WCHAR
) + 1;
3758 TRACE("Values %lu\n", FullInfo
->Values
);
3759 if (lpcValues
!= NULL
)
3761 *lpcValues
= FullInfo
->Values
;
3764 TRACE("MaxValueNameLen %lu\n", FullInfo
->MaxValueNameLen
);
3765 if (lpcbMaxValueNameLen
!= NULL
)
3767 *lpcbMaxValueNameLen
= FullInfo
->MaxValueNameLen
/ sizeof(WCHAR
) + 1;
3770 TRACE("MaxValueDataLen %lu\n", FullInfo
->MaxValueDataLen
);
3771 if (lpcbMaxValueLen
!= NULL
)
3773 *lpcbMaxValueLen
= FullInfo
->MaxValueDataLen
;
3777 if (lpcbSecurityDescriptor
!= NULL
)
3779 Status
= NtQuerySecurityObject(KeyHandle
,
3780 OWNER_SECURITY_INFORMATION
|
3781 GROUP_SECURITY_INFORMATION
|
3782 DACL_SECURITY_INFORMATION
,
3785 lpcbSecurityDescriptor
);
3786 if (!NT_SUCCESS(Status
))
3788 if (lpClass
!= NULL
)
3790 RtlFreeHeap(ProcessHeap
,
3795 ErrorCode
= RtlNtStatusToDosError(Status
);
3801 if (lpftLastWriteTime
!= NULL
)
3803 lpftLastWriteTime
->dwLowDateTime
= FullInfo
->LastWriteTime
.u
.LowPart
;
3804 lpftLastWriteTime
->dwHighDateTime
= FullInfo
->LastWriteTime
.u
.HighPart
;
3807 if (lpClass
!= NULL
)
3809 if (FullInfo
->ClassLength
> ClassLength
)
3811 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
3815 RtlCopyMemory(lpClass
,
3817 FullInfo
->ClassLength
);
3818 *lpcbClass
= FullInfo
->ClassLength
/ sizeof(WCHAR
);
3819 lpClass
[*lpcbClass
] = 0;
3822 RtlFreeHeap(ProcessHeap
,
3828 ClosePredefKey(KeyHandle
);
3834 /************************************************************************
3835 * RegQueryMultipleValuesA
3840 RegQueryMultipleValuesA(HKEY hKey
,
3847 DWORD maxBytes
= *ldwTotsize
;
3848 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3851 if (maxBytes
>= (1024*1024))
3852 return ERROR_TRANSFER_TOO_LONG
;
3856 TRACE("RegQueryMultipleValuesA(%p,%p,%ld,%p,%p=%ld)\n",
3857 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3859 for (i
= 0; i
< num_vals
; i
++)
3861 val_list
[i
].ve_valuelen
= 0;
3862 ErrorCode
= RegQueryValueExA(hKey
,
3863 val_list
[i
].ve_valuename
,
3867 &val_list
[i
].ve_valuelen
);
3868 if (ErrorCode
!= ERROR_SUCCESS
)
3873 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3875 ErrorCode
= RegQueryValueExA(hKey
,
3876 val_list
[i
].ve_valuename
,
3878 &val_list
[i
].ve_type
,
3880 &val_list
[i
].ve_valuelen
);
3881 if (ErrorCode
!= ERROR_SUCCESS
)
3886 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3888 bufptr
+= val_list
[i
].ve_valuelen
;
3891 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3894 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3898 /************************************************************************
3899 * RegQueryMultipleValuesW
3904 RegQueryMultipleValuesW(HKEY hKey
,
3911 DWORD maxBytes
= *ldwTotsize
;
3912 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
3915 if (maxBytes
>= (1024*1024))
3916 return ERROR_TRANSFER_TOO_LONG
;
3920 TRACE("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
3921 hKey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
3923 for (i
= 0; i
< num_vals
; i
++)
3925 val_list
[i
].ve_valuelen
= 0;
3926 ErrorCode
= RegQueryValueExW(hKey
,
3927 val_list
[i
].ve_valuename
,
3931 &val_list
[i
].ve_valuelen
);
3932 if (ErrorCode
!= ERROR_SUCCESS
)
3937 if (lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
3939 ErrorCode
= RegQueryValueExW(hKey
,
3940 val_list
[i
].ve_valuename
,
3942 &val_list
[i
].ve_type
,
3944 &val_list
[i
].ve_valuelen
);
3945 if (ErrorCode
!= ERROR_SUCCESS
)
3950 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
3952 bufptr
+= val_list
[i
].ve_valuelen
;
3955 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
3958 return (lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
) ? ERROR_SUCCESS
: ERROR_MORE_DATA
;
3962 /************************************************************************
3963 * RegQueryReflectionKey
3968 RegQueryReflectionKey(IN HKEY hBase
,
3969 OUT BOOL
* bIsReflectionDisabled
)
3971 FIXME("RegQueryReflectionKey(0x%p, 0x%p) UNIMPLEMENTED!\n",
3972 hBase
, bIsReflectionDisabled
);
3973 return ERROR_CALL_NOT_IMPLEMENTED
;
3977 /************************************************************************
3983 RegQueryValueExA(HKEY hKey
,
3990 UNICODE_STRING ValueName
;
3991 UNICODE_STRING ValueData
;
3998 TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
3999 hKey
, lpValueName
, lpData
, lpcbData
? *lpcbData
: 0);
4001 if (lpData
!= NULL
&& lpcbData
== NULL
)
4003 return ERROR_INVALID_PARAMETER
;
4008 ValueData
.Length
= 0;
4009 ValueData
.MaximumLength
= (*lpcbData
+ 1) * sizeof(WCHAR
);
4010 ValueData
.Buffer
= RtlAllocateHeap(ProcessHeap
,
4012 ValueData
.MaximumLength
);
4013 if (!ValueData
.Buffer
)
4015 return ERROR_OUTOFMEMORY
;
4020 ValueData
.Buffer
= NULL
;
4021 ValueData
.Length
= 0;
4022 ValueData
.MaximumLength
= 0;
4028 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4029 (LPSTR
)lpValueName
);
4031 Length
= (lpcbData
== NULL
) ? 0 : *lpcbData
* sizeof(WCHAR
);
4032 ErrorCode
= RegQueryValueExW(hKey
,
4036 (lpData
== NULL
) ? NULL
: (LPBYTE
)ValueData
.Buffer
,
4038 TRACE("ErrorCode %lu\n", ErrorCode
);
4039 RtlFreeUnicodeString(&ValueName
);
4041 if (ErrorCode
== ERROR_SUCCESS
||
4042 ErrorCode
== ERROR_MORE_DATA
)
4045 if (is_string(Type
))
4047 if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4049 Status
= RtlUnicodeToMultiByteN((PCHAR
)lpData
, *lpcbData
, &Index
, (PWCHAR
)ValueData
.Buffer
, Length
);
4050 if (NT_SUCCESS(Status
))
4052 PCHAR szData
= (PCHAR
)lpData
;
4053 if(&szData
[Index
] < (PCHAR
)(lpData
+ *lpcbData
))
4055 szData
[Index
] = '\0';
4060 ErrorCode
= RtlNtStatusToDosError(Status
);
4064 Length
= Length
/ sizeof(WCHAR
);
4066 else if (ErrorCode
== ERROR_SUCCESS
&& ValueData
.Buffer
!= NULL
)
4068 if (*lpcbData
< Length
)
4070 ErrorCode
= ERROR_MORE_DATA
;
4074 RtlMoveMemory(lpData
, ValueData
.Buffer
, Length
);
4078 if (lpcbData
!= NULL
)
4089 if (ValueData
.Buffer
!= NULL
)
4091 RtlFreeHeap(ProcessHeap
, 0, ValueData
.Buffer
);
4098 /************************************************************************
4105 RegQueryValueExW(HKEY hkeyorg
,
4114 UNICODE_STRING name_str
;
4116 char buffer
[256], *buf_ptr
= buffer
;
4117 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
4118 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
4120 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
4121 hkeyorg
, debugstr_w(name
), reserved
, type
, data
, count
,
4122 (count
&& data
) ? *count
: 0 );
4124 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
4126 status
= MapDefaultKey(&hkey
, hkeyorg
);
4127 if (!NT_SUCCESS(status
))
4129 return RtlNtStatusToDosError(status
);
4132 RtlInitUnicodeString( &name_str
, name
);
4134 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
4137 total_size
= info_size
;
4138 if (count
) *count
= 0;
4141 /* this matches Win9x behaviour - NT sets *type to a random value */
4142 if (type
) *type
= REG_NONE
;
4144 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4145 buffer
, total_size
, &total_size
);
4146 if (!NT_SUCCESS(status
) && status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4150 /* retry with a dynamically allocated buffer */
4151 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
4153 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4154 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
4156 ClosePredefKey(hkey
);
4157 return ERROR_NOT_ENOUGH_MEMORY
;
4159 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
4160 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
4161 buf_ptr
, total_size
, &total_size
);
4164 if (NT_SUCCESS(status
))
4166 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
4167 /* if the type is REG_SZ and data is not 0-terminated
4168 * and there is enough space in the buffer NT appends a \0 */
4169 if (is_string(info
->Type
) && total_size
- info_size
<= *count
-sizeof(WCHAR
))
4171 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
4172 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
4175 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
4177 else status
= STATUS_SUCCESS
;
4179 if (type
) *type
= info
->Type
;
4180 if (count
) *count
= total_size
- info_size
;
4183 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
4184 ClosePredefKey(hkey
);
4185 return RtlNtStatusToDosError(status
);
4189 /************************************************************************
4194 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
4199 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
4201 if (name
&& name
[0])
4203 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
4205 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4206 if (subkey
!= hkey
) RegCloseKey( subkey
);
4207 if (ret
== ERROR_FILE_NOT_FOUND
)
4209 /* return empty string if default value not found */
4210 if (data
) *data
= 0;
4211 if (count
) *count
= 1;
4212 ret
= ERROR_SUCCESS
;
4218 /************************************************************************
4223 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
4228 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
4231 return ERROR_INVALID_HANDLE
;
4233 if (name
&& name
[0])
4235 ret
= RegOpenKeyW( hkey
, name
, &subkey
);
4236 if (ret
!= ERROR_SUCCESS
)
4242 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
4246 RegCloseKey( subkey
);
4249 if (ret
== ERROR_FILE_NOT_FOUND
)
4251 /* return empty string if default value not found */
4255 *count
= sizeof(WCHAR
);
4256 ret
= ERROR_SUCCESS
;
4262 /************************************************************************
4268 RegReplaceKeyA(HKEY hKey
,
4273 UNICODE_STRING SubKey
;
4274 UNICODE_STRING NewFile
;
4275 UNICODE_STRING OldFile
;
4278 RtlCreateUnicodeStringFromAsciiz(&SubKey
,
4280 RtlCreateUnicodeStringFromAsciiz(&OldFile
,
4282 RtlCreateUnicodeStringFromAsciiz(&NewFile
,
4285 ErrorCode
= RegReplaceKeyW(hKey
,
4290 RtlFreeUnicodeString(&OldFile
);
4291 RtlFreeUnicodeString(&NewFile
);
4292 RtlFreeUnicodeString(&SubKey
);
4298 /************************************************************************
4304 RegReplaceKeyW(HKEY hKey
,
4309 OBJECT_ATTRIBUTES KeyObjectAttributes
;
4310 OBJECT_ATTRIBUTES NewObjectAttributes
;
4311 OBJECT_ATTRIBUTES OldObjectAttributes
;
4312 UNICODE_STRING SubKeyName
;
4313 UNICODE_STRING NewFileName
;
4314 UNICODE_STRING OldFileName
;
4315 BOOLEAN CloseRealKey
;
4316 HANDLE RealKeyHandle
;
4319 LONG ErrorCode
= ERROR_SUCCESS
;
4321 if (hKey
== HKEY_PERFORMANCE_DATA
)
4323 return ERROR_INVALID_HANDLE
;
4326 Status
= MapDefaultKey(&KeyHandle
,
4328 if (!NT_SUCCESS(Status
))
4330 return RtlNtStatusToDosError(Status
);
4333 /* Open the real key */
4334 if (lpSubKey
!= NULL
&& *lpSubKey
!= (WCHAR
)0)
4336 RtlInitUnicodeString(&SubKeyName
,
4338 InitializeObjectAttributes(&KeyObjectAttributes
,
4340 OBJ_CASE_INSENSITIVE
,
4343 Status
= NtOpenKey(&RealKeyHandle
,
4345 &KeyObjectAttributes
);
4346 if (!NT_SUCCESS(Status
))
4348 ErrorCode
= RtlNtStatusToDosError(Status
);
4352 CloseRealKey
= TRUE
;
4356 RealKeyHandle
= KeyHandle
;
4357 CloseRealKey
= FALSE
;
4360 /* Convert new file name */
4361 if (!RtlDosPathNameToNtPathName_U(lpNewFile
,
4368 NtClose(RealKeyHandle
);
4371 ErrorCode
= ERROR_INVALID_PARAMETER
;
4375 InitializeObjectAttributes(&NewObjectAttributes
,
4377 OBJ_CASE_INSENSITIVE
,
4381 /* Convert old file name */
4382 if (!RtlDosPathNameToNtPathName_U(lpOldFile
,
4387 RtlFreeHeap(RtlGetProcessHeap (),
4389 NewFileName
.Buffer
);
4392 NtClose(RealKeyHandle
);
4395 ErrorCode
= ERROR_INVALID_PARAMETER
;
4399 InitializeObjectAttributes(&OldObjectAttributes
,
4401 OBJ_CASE_INSENSITIVE
,
4405 Status
= NtReplaceKey(&NewObjectAttributes
,
4407 &OldObjectAttributes
);
4409 RtlFreeHeap(RtlGetProcessHeap(),
4411 OldFileName
.Buffer
);
4412 RtlFreeHeap(RtlGetProcessHeap(),
4414 NewFileName
.Buffer
);
4418 NtClose(RealKeyHandle
);
4421 if (!NT_SUCCESS(Status
))
4423 return RtlNtStatusToDosError(Status
);
4427 ClosePredefKey(KeyHandle
);
4433 /************************************************************************
4439 RegRestoreKeyA(HKEY hKey
,
4443 UNICODE_STRING FileName
;
4446 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4449 ErrorCode
= RegRestoreKeyW(hKey
,
4453 RtlFreeUnicodeString(&FileName
);
4459 /************************************************************************
4465 RegRestoreKeyW(HKEY hKey
,
4469 OBJECT_ATTRIBUTES ObjectAttributes
;
4470 IO_STATUS_BLOCK IoStatusBlock
;
4471 UNICODE_STRING FileName
;
4476 if (hKey
== HKEY_PERFORMANCE_DATA
)
4478 return ERROR_INVALID_HANDLE
;
4481 Status
= MapDefaultKey(&KeyHandle
,
4483 if (!NT_SUCCESS(Status
))
4485 return RtlNtStatusToDosError(Status
);
4488 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4493 Status
= STATUS_INVALID_PARAMETER
;
4497 InitializeObjectAttributes(&ObjectAttributes
,
4499 OBJ_CASE_INSENSITIVE
,
4503 Status
= NtOpenFile(&FileHandle
,
4508 FILE_SYNCHRONOUS_IO_NONALERT
);
4509 RtlFreeHeap(RtlGetProcessHeap(),
4512 if (!NT_SUCCESS(Status
))
4517 Status
= NtRestoreKey(KeyHandle
,
4520 NtClose (FileHandle
);
4523 ClosePredefKey(KeyHandle
);
4525 if (!NT_SUCCESS(Status
))
4527 return RtlNtStatusToDosError(Status
);
4530 return ERROR_SUCCESS
;
4534 /************************************************************************
4540 RegSaveKeyA(HKEY hKey
,
4542 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4544 UNICODE_STRING FileName
;
4547 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4549 ErrorCode
= RegSaveKeyW(hKey
,
4551 lpSecurityAttributes
);
4552 RtlFreeUnicodeString(&FileName
);
4558 /************************************************************************
4564 RegSaveKeyW(HKEY hKey
,
4566 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
4568 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
4569 OBJECT_ATTRIBUTES ObjectAttributes
;
4570 UNICODE_STRING FileName
;
4571 IO_STATUS_BLOCK IoStatusBlock
;
4576 Status
= MapDefaultKey(&KeyHandle
,
4578 if (!NT_SUCCESS(Status
))
4580 return RtlNtStatusToDosError(Status
);
4583 if (!RtlDosPathNameToNtPathName_U(lpFile
,
4588 Status
= STATUS_INVALID_PARAMETER
;
4592 if (lpSecurityAttributes
!= NULL
)
4594 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
4597 InitializeObjectAttributes(&ObjectAttributes
,
4599 OBJ_CASE_INSENSITIVE
,
4601 SecurityDescriptor
);
4602 Status
= NtCreateFile(&FileHandle
,
4603 GENERIC_WRITE
| SYNCHRONIZE
,
4607 FILE_ATTRIBUTE_NORMAL
,
4610 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_SYNCHRONOUS_IO_NONALERT
,
4613 RtlFreeHeap(RtlGetProcessHeap(),
4616 if (!NT_SUCCESS(Status
))
4621 Status
= NtSaveKey(KeyHandle
,
4623 NtClose (FileHandle
);
4626 ClosePredefKey(KeyHandle
);
4628 if (!NT_SUCCESS(Status
))
4630 return RtlNtStatusToDosError(Status
);
4633 return ERROR_SUCCESS
;
4637 /************************************************************************
4644 RegSaveKeyExA(HKEY hKey
,
4646 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4649 UNICODE_STRING FileName
;
4652 RtlCreateUnicodeStringFromAsciiz(&FileName
,
4654 ErrorCode
= RegSaveKeyExW(hKey
,
4656 lpSecurityAttributes
,
4658 RtlFreeUnicodeString(&FileName
);
4664 /************************************************************************
4671 RegSaveKeyExW(HKEY hKey
,
4673 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
4678 case REG_STANDARD_FORMAT
:
4679 case REG_LATEST_FORMAT
:
4680 case REG_NO_COMPRESSION
:
4683 return ERROR_INVALID_PARAMETER
;
4686 FIXME("RegSaveKeyExW(): Flags ignored!\n");
4688 return RegSaveKeyW(hKey
,
4690 lpSecurityAttributes
);
4694 /************************************************************************
4700 RegSetKeySecurity(HKEY hKey
,
4701 SECURITY_INFORMATION SecurityInformation
,
4702 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
4707 if (hKey
== HKEY_PERFORMANCE_DATA
)
4709 return ERROR_INVALID_HANDLE
;
4712 Status
= MapDefaultKey(&KeyHandle
,
4714 if (!NT_SUCCESS(Status
))
4716 return RtlNtStatusToDosError(Status
);
4719 Status
= NtSetSecurityObject(KeyHandle
,
4720 SecurityInformation
,
4721 pSecurityDescriptor
);
4723 ClosePredefKey(KeyHandle
);
4725 if (!NT_SUCCESS(Status
))
4727 return RtlNtStatusToDosError(Status
);
4730 return ERROR_SUCCESS
;
4734 /************************************************************************
4740 RegSetValueExA(HKEY hKey
,
4747 UNICODE_STRING ValueName
;
4749 ANSI_STRING AnsiString
;
4750 UNICODE_STRING Data
;
4756 /* Convert SubKey name to Unicode */
4757 if (lpValueName
!= NULL
&& lpValueName
[0] != '\0')
4760 bConverted
= RtlCreateUnicodeStringFromAsciiz(&ValueName
,
4763 return ERROR_NOT_ENOUGH_MEMORY
;
4767 ValueName
.Buffer
= NULL
;
4770 pValueName
= (LPWSTR
)ValueName
.Buffer
;
4773 if (is_string(dwType
) && (cbData
!= 0))
4775 /* Convert ANSI string Data to Unicode */
4776 /* If last character NOT zero then increment length */
4777 LONG bNoNulledStr
= ((lpData
[cbData
-1] != '\0') ? 1 : 0);
4778 AnsiString
.Buffer
= (PSTR
)lpData
;
4779 AnsiString
.Length
= cbData
+ bNoNulledStr
;
4780 AnsiString
.MaximumLength
= cbData
+ bNoNulledStr
;
4781 Status
= RtlAnsiStringToUnicodeString(&Data
,
4785 if (!NT_SUCCESS(Status
))
4787 if (pValueName
!= NULL
)
4788 RtlFreeUnicodeString(&ValueName
);
4790 return RtlNtStatusToDosError(Status
);
4792 pData
= (LPBYTE
)Data
.Buffer
;
4793 DataSize
= cbData
* sizeof(WCHAR
);
4798 pData
= (LPBYTE
)lpData
;
4802 ErrorCode
= RegSetValueExW(hKey
,
4809 if (pValueName
!= NULL
)
4810 RtlFreeUnicodeString(&ValueName
);
4812 if (Data
.Buffer
!= NULL
)
4813 RtlFreeUnicodeString(&Data
);
4819 /************************************************************************
4825 RegSetValueExW(HKEY hKey
,
4826 LPCWSTR lpValueName
,
4832 UNICODE_STRING ValueName
;
4833 PUNICODE_STRING pValueName
;
4837 Status
= MapDefaultKey(&KeyHandle
,
4839 if (!NT_SUCCESS(Status
))
4841 return RtlNtStatusToDosError(Status
);
4844 RtlInitUnicodeString(&ValueName
, lpValueName
);
4845 pValueName
= &ValueName
;
4847 if (is_string(dwType
) && (cbData
!= 0))
4849 PWSTR pwsData
= (PWSTR
)lpData
;
4851 if((pwsData
[cbData
/ sizeof(WCHAR
) - 1] != L
'\0') &&
4852 (pwsData
[cbData
/ sizeof(WCHAR
)] == L
'\0'))
4854 /* Increment length if last character is not zero and next is zero */
4855 cbData
+= sizeof(WCHAR
);
4859 Status
= NtSetValueKey(KeyHandle
,
4866 ClosePredefKey(KeyHandle
);
4868 if (!NT_SUCCESS(Status
))
4870 return RtlNtStatusToDosError(Status
);
4873 return ERROR_SUCCESS
;
4877 /************************************************************************
4883 RegSetValueA(HKEY hKeyOriginal
,
4894 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_a(lpSubKey
), dwType
, debugstr_a(lpData
), cbData
);
4896 if (dwType
!= REG_SZ
|| !lpData
) return ERROR_INVALID_PARAMETER
;
4898 Status
= MapDefaultKey(&hKey
, hKeyOriginal
);
4899 if (!NT_SUCCESS(Status
))
4901 return RtlNtStatusToDosError (Status
);
4905 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4907 ret
= RegCreateKeyA(hKey
, lpSubKey
, &subkey
);
4908 if (ret
!= ERROR_SUCCESS
)
4912 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
, strlen(lpData
)+1 );
4914 RegCloseKey(subkey
);
4917 ClosePredefKey(hKey
);
4923 /************************************************************************
4929 RegSetValueW(HKEY hKeyOriginal
,
4940 TRACE("(%p,%s,%d,%s,%d)\n", hKeyOriginal
, debugstr_w(lpSubKey
), dwType
, debugstr_w(lpData
), cbData
);
4942 if (dwType
!= REG_SZ
|| !lpData
)
4943 return ERROR_INVALID_PARAMETER
;
4945 Status
= MapDefaultKey(&hKey
,
4947 if (!NT_SUCCESS(Status
))
4949 return RtlNtStatusToDosError(Status
);
4953 if (lpSubKey
&& lpSubKey
[0]) /* need to create the subkey */
4955 ret
= RegCreateKeyW(hKey
, lpSubKey
, &subkey
);
4956 if (ret
!= ERROR_SUCCESS
)
4960 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)lpData
,
4961 (wcslen( lpData
) + 1) * sizeof(WCHAR
) );
4963 RegCloseKey(subkey
);
4966 ClosePredefKey(hKey
);
4972 /************************************************************************
4978 RegUnLoadKeyA(HKEY hKey
,
4981 UNICODE_STRING KeyName
;
4984 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
4987 ErrorCode
= RegUnLoadKeyW(hKey
,
4990 RtlFreeUnicodeString (&KeyName
);
4996 /************************************************************************
5002 RegUnLoadKeyW(HKEY hKey
,
5005 OBJECT_ATTRIBUTES ObjectAttributes
;
5006 UNICODE_STRING KeyName
;
5010 if (hKey
== HKEY_PERFORMANCE_DATA
)
5012 return ERROR_INVALID_HANDLE
;
5015 Status
= MapDefaultKey(&KeyHandle
, hKey
);
5016 if (!NT_SUCCESS(Status
))
5018 return RtlNtStatusToDosError(Status
);
5021 RtlInitUnicodeString(&KeyName
,
5024 InitializeObjectAttributes(&ObjectAttributes
,
5026 OBJ_CASE_INSENSITIVE
,
5030 Status
= NtUnloadKey(&ObjectAttributes
);
5032 ClosePredefKey(KeyHandle
);
5034 if (!NT_SUCCESS(Status
))
5036 return RtlNtStatusToDosError(Status
);
5039 return ERROR_SUCCESS
;
5043 /******************************************************************************
5044 * load_string [Internal]
5046 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
5047 * avoid importing user32, which is higher level than advapi32. Helper for
5050 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
5057 /* Negative values have to be inverted. */
5058 if (HIWORD(resId
) == 0xffff)
5059 resId
= (UINT
)(-((INT
)resId
));
5061 /* Load the resource into memory and get a pointer to it. */
5062 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
5063 if (!hResource
) return 0;
5064 hMemory
= LoadResource(hModule
, hResource
);
5065 if (!hMemory
) return 0;
5066 pString
= LockResource(hMemory
);
5068 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
5069 idxString
= resId
& 0xf;
5070 while (idxString
--) pString
+= *pString
+ 1;
5072 /* If no buffer is given, return length of the string. */
5073 if (!pwszBuffer
) return *pString
;
5075 /* Else copy over the string, respecting the buffer size. */
5076 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
5079 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
5080 pwszBuffer
[cMaxChars
] = L
'\0';
5087 /************************************************************************
5093 RegLoadMUIStringW(IN HKEY hKey
,
5094 IN LPCWSTR pszValue OPTIONAL
,
5095 OUT LPWSTR pszOutBuf
,
5097 OUT LPDWORD pcbData OPTIONAL
,
5099 IN LPCWSTR pszDirectory OPTIONAL
)
5101 DWORD dwValueType
, cbData
;
5102 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
5105 /* Parameter sanity checks. */
5106 if (!hKey
|| !pszOutBuf
)
5107 return ERROR_INVALID_PARAMETER
;
5109 if (pszDirectory
&& *pszDirectory
)
5111 FIXME("BaseDir parameter not yet supported!\n");
5112 return ERROR_INVALID_PARAMETER
;
5115 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
5116 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
5117 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5118 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
)
5120 result
= ERROR_FILE_NOT_FOUND
;
5123 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5124 if (!pwszTempBuffer
)
5126 result
= ERROR_NOT_ENOUGH_MEMORY
;
5129 result
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
5130 if (result
!= ERROR_SUCCESS
) goto cleanup
;
5132 /* Expand environment variables, if appropriate, or copy the original string over. */
5133 if (dwValueType
== REG_EXPAND_SZ
)
5135 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
5136 if (!cbData
) goto cleanup
;
5137 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5138 if (!pwszExpandedBuffer
)
5140 result
= ERROR_NOT_ENOUGH_MEMORY
;
5143 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
5147 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
5148 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
5151 /* If the value references a resource based string, parse the value and load the string.
5152 * Else just copy over the original value. */
5153 result
= ERROR_SUCCESS
;
5154 if (*pwszExpandedBuffer
!= L
'@') /* '@' is the prefix for resource based string entries. */
5156 lstrcpynW(pszOutBuf
, pwszExpandedBuffer
, cbOutBuf
/ sizeof(WCHAR
));
5160 WCHAR
*pComma
= wcsrchr(pwszExpandedBuffer
, L
',');
5164 /* Format of the expanded value is 'path_to_dll,-resId' */
5165 if (!pComma
|| pComma
[1] != L
'-')
5167 result
= ERROR_BADKEY
;
5171 uiStringId
= _wtoi(pComma
+2);
5174 hModule
= LoadLibraryExW(pwszExpandedBuffer
+ 1, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5175 if (!hModule
|| !load_string(hModule
, uiStringId
, pszOutBuf
, cbOutBuf
/ sizeof(WCHAR
)))
5176 result
= ERROR_BADKEY
;
5177 FreeLibrary(hModule
);
5181 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
5182 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
5187 /************************************************************************
5193 RegLoadMUIStringA(IN HKEY hKey
,
5194 IN LPCSTR pszValue OPTIONAL
,
5195 OUT LPSTR pszOutBuf
,
5197 OUT LPDWORD pcbData OPTIONAL
,
5199 IN LPCSTR pszDirectory OPTIONAL
)
5201 UNICODE_STRING valueW
, baseDirW
;
5203 DWORD cbData
= cbOutBuf
* sizeof(WCHAR
);
5206 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
5207 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
5208 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszDirectory
) ||
5209 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
5211 result
= ERROR_NOT_ENOUGH_MEMORY
;
5215 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, Flags
,
5218 if (result
== ERROR_SUCCESS
)
5220 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszOutBuf
, cbOutBuf
, NULL
, NULL
);
5226 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
5227 RtlFreeUnicodeString(&baseDirW
);
5228 RtlFreeUnicodeString(&valueW
);