2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/advapi32/reg/reg.c
5 * PURPOSE: Registry functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Thomas Weidenmueller <w3seek@reactos.com>
11 * 20050502 Fireball imported some stuff from WINE
14 /* INCLUDES *****************************************************************/
17 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
19 /* DEFINES ******************************************************************/
21 #define MAX_DEFAULT_HANDLES 6
22 #define REG_MAX_NAME_SIZE 256
23 #define REG_MAX_DATA_SIZE 2048
25 /* GLOBALS ******************************************************************/
27 static RTL_CRITICAL_SECTION HandleTableCS
;
28 static HANDLE DefaultHandleTable
[MAX_DEFAULT_HANDLES
];
29 static HANDLE ProcessHeap
;
30 static BOOLEAN DefaultHandlesDisabled
= FALSE
;
31 static BOOLEAN DefaultHandleHKUDisabled
= FALSE
;
32 static BOOLEAN DllInitialized
= FALSE
; /* HACK */
34 /* PROTOTYPES ***************************************************************/
36 static NTSTATUS
MapDefaultKey (PHANDLE ParentKey
, HKEY Key
);
37 static VOID
CloseDefaultKeys(VOID
);
38 #define ClosePredefKey(Handle) \
39 if ((ULONG_PTR)Handle & 0x1) { \
42 #define IsPredefKey(HKey) \
43 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
44 #define GetPredefKeyIndex(HKey) \
45 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
47 static NTSTATUS
OpenClassesRootKey(PHANDLE KeyHandle
);
48 static NTSTATUS
OpenLocalMachineKey (PHANDLE KeyHandle
);
49 static NTSTATUS
OpenUsersKey (PHANDLE KeyHandle
);
50 static NTSTATUS
OpenCurrentConfigKey(PHANDLE KeyHandle
);
53 /* FUNCTIONS ****************************************************************/
54 /* check if value type needs string conversion (Ansi<->Unicode) */
55 __inline
static int is_string( DWORD type
)
57 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
60 /************************************************************************
61 * RegInitDefaultHandles
66 TRACE("RegInitialize()\n");
71 ProcessHeap
= RtlGetProcessHeap();
72 RtlZeroMemory(DefaultHandleTable
,
73 MAX_DEFAULT_HANDLES
* sizeof(HANDLE
));
74 RtlInitializeCriticalSection(&HandleTableCS
);
76 DllInitialized
= TRUE
;
83 /************************************************************************
89 TRACE("RegCleanup()\n");
92 RtlDeleteCriticalSection(&HandleTableCS
);
99 OpenPredefinedKey(IN ULONG Index
,
106 case 0: /* HKEY_CLASSES_ROOT */
107 Status
= OpenClassesRootKey (Handle
);
110 case 1: /* HKEY_CURRENT_USER */
111 Status
= RtlOpenCurrentUser (MAXIMUM_ALLOWED
,
115 case 2: /* HKEY_LOCAL_MACHINE */
116 Status
= OpenLocalMachineKey (Handle
);
119 case 3: /* HKEY_USERS */
120 Status
= OpenUsersKey (Handle
);
123 case 4: /* HKEY_PERFORMANCE_DATA */
124 Status
= OpenPerformanceDataKey (Handle
);
128 case 5: /* HKEY_CURRENT_CONFIG */
129 Status
= OpenCurrentConfigKey (Handle
);
132 case 6: /* HKEY_DYN_DATA */
133 Status
= STATUS_NOT_IMPLEMENTED
;
137 WARN("MapDefaultHandle() no handle creator\n");
138 Status
= STATUS_INVALID_PARAMETER
;
147 MapDefaultKey(OUT PHANDLE RealKey
,
152 BOOLEAN DoOpen
, DefDisabled
;
153 NTSTATUS Status
= STATUS_SUCCESS
;
155 TRACE("MapDefaultKey (Key %x)\n", Key
);
157 if (!IsPredefKey(Key
))
159 *RealKey
= (HANDLE
)((ULONG_PTR
)Key
& ~0x1);
160 return STATUS_SUCCESS
;
163 /* Handle special cases here */
164 Index
= GetPredefKeyIndex(Key
);
165 if (Index
>= MAX_DEFAULT_HANDLES
)
167 return STATUS_INVALID_PARAMETER
;
169 RegInitialize(); /* HACK until delay-loading is implemented */
170 RtlEnterCriticalSection (&HandleTableCS
);
172 if (Key
== HKEY_CURRENT_USER
)
173 DefDisabled
= DefaultHandleHKUDisabled
;
175 DefDisabled
= DefaultHandlesDisabled
;
179 Handle
= &DefaultHandleTable
[Index
];
180 DoOpen
= (*Handle
== NULL
);
190 /* create/open the default handle */
191 Status
= OpenPredefinedKey(Index
,
195 if (NT_SUCCESS(Status
))
200 *(PULONG_PTR
)Handle
|= 0x1;
203 RtlLeaveCriticalSection (&HandleTableCS
);
210 CloseDefaultKeys(VOID
)
213 RegInitialize(); /* HACK until delay-loading is implemented */
214 RtlEnterCriticalSection(&HandleTableCS
);
216 for (i
= 0; i
< MAX_DEFAULT_HANDLES
; i
++)
218 if (DefaultHandleTable
[i
] != NULL
)
220 NtClose(DefaultHandleTable
[i
]);
221 DefaultHandleTable
[i
] = NULL
;
225 RtlLeaveCriticalSection(&HandleTableCS
);
230 OpenClassesRootKey(PHANDLE KeyHandle
)
232 OBJECT_ATTRIBUTES Attributes
;
233 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\CLASSES");
235 TRACE("OpenClassesRootKey()\n");
237 InitializeObjectAttributes(&Attributes
,
239 OBJ_CASE_INSENSITIVE
,
242 return NtOpenKey(KeyHandle
,
249 OpenLocalMachineKey(PHANDLE KeyHandle
)
251 OBJECT_ATTRIBUTES Attributes
;
252 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine");
255 TRACE("OpenLocalMachineKey()\n");
257 InitializeObjectAttributes(&Attributes
,
259 OBJ_CASE_INSENSITIVE
,
262 Status
= NtOpenKey(KeyHandle
,
266 TRACE("NtOpenKey(%wZ) => %08x\n", &KeyName
, Status
);
273 OpenUsersKey(PHANDLE KeyHandle
)
275 OBJECT_ATTRIBUTES Attributes
;
276 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\User");
278 TRACE("OpenUsersKey()\n");
280 InitializeObjectAttributes(&Attributes
,
282 OBJ_CASE_INSENSITIVE
,
285 return NtOpenKey(KeyHandle
,
292 OpenCurrentConfigKey (PHANDLE KeyHandle
)
294 OBJECT_ATTRIBUTES Attributes
;
295 UNICODE_STRING KeyName
=
296 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
298 TRACE("OpenCurrentConfigKey()\n");
300 InitializeObjectAttributes(&Attributes
,
302 OBJ_CASE_INSENSITIVE
,
305 return NtOpenKey(KeyHandle
,
311 /************************************************************************
312 * RegDisablePredefinedCache
317 RegDisablePredefinedCache(VOID
)
319 RegInitialize(); /* HACK until delay-loading is implemented */
320 RtlEnterCriticalSection(&HandleTableCS
);
321 DefaultHandleHKUDisabled
= TRUE
;
322 RtlLeaveCriticalSection(&HandleTableCS
);
323 return ERROR_SUCCESS
;
327 /************************************************************************
328 * RegDisablePredefinedCacheEx
333 RegDisablePredefinedCacheEx(VOID
)
335 RegInitialize(); /* HACK until delay-loading is implemented */
336 RtlEnterCriticalSection(&HandleTableCS
);
337 DefaultHandlesDisabled
= TRUE
;
338 DefaultHandleHKUDisabled
= TRUE
;
339 RtlLeaveCriticalSection(&HandleTableCS
);
340 return ERROR_SUCCESS
;
344 /************************************************************************
345 * RegOverridePredefKey
350 RegOverridePredefKey(IN HKEY hKey
,
351 IN HKEY hNewHKey OPTIONAL
)
353 LONG ErrorCode
= ERROR_SUCCESS
;
355 if ((hKey
== HKEY_CLASSES_ROOT
||
356 hKey
== HKEY_CURRENT_CONFIG
||
357 hKey
== HKEY_CURRENT_USER
||
358 hKey
== HKEY_LOCAL_MACHINE
||
359 hKey
== HKEY_PERFORMANCE_DATA
||
360 hKey
== HKEY_USERS
) &&
361 !IsPredefKey(hNewHKey
))
366 Index
= GetPredefKeyIndex(hKey
);
367 Handle
= &DefaultHandleTable
[Index
];
369 if (hNewHKey
== NULL
)
371 /* restore the default mapping */
372 NTSTATUS Status
= OpenPredefinedKey(Index
,
374 if (!NT_SUCCESS(Status
))
376 return RtlNtStatusToDosError(Status
);
379 ASSERT(hNewHKey
!= NULL
);
381 RegInitialize(); /* HACK until delay-loading is implemented */
382 RtlEnterCriticalSection(&HandleTableCS
);
384 /* close the currently mapped handle if existing */
390 /* update the mapping */
393 RtlLeaveCriticalSection(&HandleTableCS
);
396 ErrorCode
= ERROR_INVALID_HANDLE
;
402 /************************************************************************
408 RegCloseKey(HKEY hKey
)
412 /* don't close null handle or a pseudo handle */
413 if ((!hKey
) || (((ULONG_PTR
)hKey
& 0xF0000000) == 0x80000000))
415 return ERROR_INVALID_HANDLE
;
418 Status
= NtClose(hKey
);
419 if (!NT_SUCCESS(Status
))
421 return RtlNtStatusToDosError(Status
);
424 return ERROR_SUCCESS
;
429 RegpCopyTree(IN HKEY hKeySrc
,
434 LIST_ENTRY ListEntry
;
437 } REGP_COPY_KEYS
, *PREGP_COPY_KEYS
;
439 LIST_ENTRY copyQueueHead
;
440 PREGP_COPY_KEYS copyKeys
, newCopyKeys
;
443 KEY_VALUE_FULL_INFORMATION
*KeyValue
;
444 KEY_NODE_INFORMATION
*KeyNode
;
447 ULONG Index
, BufferSizeRequired
, BufferSize
= 0x200;
448 NTSTATUS Status
= STATUS_SUCCESS
;
449 NTSTATUS Status2
= STATUS_SUCCESS
;
451 InitializeListHead(©QueueHead
);
453 Info
.Buffer
= RtlAllocateHeap(ProcessHeap
,
456 if (Info
.Buffer
== NULL
)
458 return STATUS_INSUFFICIENT_RESOURCES
;
461 copyKeys
= RtlAllocateHeap(ProcessHeap
,
463 sizeof(REGP_COPY_KEYS
));
464 if (copyKeys
!= NULL
)
466 copyKeys
->hKeySrc
= hKeySrc
;
467 copyKeys
->hKeyDest
= hKeyDest
;
468 InsertHeadList(©QueueHead
,
469 ©Keys
->ListEntry
);
471 /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
475 copyKeys
= CONTAINING_RECORD(copyQueueHead
.Flink
,
479 /* enumerate all values and copy them */
483 Status2
= NtEnumerateValueKey(copyKeys
->hKeySrc
,
485 KeyValueFullInformation
,
488 &BufferSizeRequired
);
489 if (NT_SUCCESS(Status2
))
491 UNICODE_STRING ValueName
;
494 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
495 ValueName
.Length
= Info
.KeyValue
->NameLength
;
496 ValueName
.MaximumLength
= ValueName
.Length
;
497 ValueName
.Buffer
= Info
.KeyValue
->Name
;
499 Data
= (PVOID
)((ULONG_PTR
)Info
.KeyValue
+ Info
.KeyValue
->DataOffset
);
501 Status2
= NtSetValueKey(copyKeys
->hKeyDest
,
503 Info
.KeyValue
->TitleIndex
,
506 Info
.KeyValue
->DataLength
);
508 /* don't break, let's try to copy as many values as possible */
509 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
516 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
520 ASSERT(BufferSize
< BufferSizeRequired
);
522 Buffer
= RtlReAllocateHeap(ProcessHeap
,
528 Info
.Buffer
= Buffer
;
533 /* don't break, let's try to copy as many values as possible */
534 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
537 if (NT_SUCCESS(Status
))
545 /* break to avoid an infinite loop in case of denied access or
547 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
556 /* enumerate all subkeys and open and enqueue them */
560 Status2
= NtEnumerateKey(copyKeys
->hKeySrc
,
565 &BufferSizeRequired
);
566 if (NT_SUCCESS(Status2
))
568 HANDLE KeyHandle
, NewKeyHandle
;
569 OBJECT_ATTRIBUTES ObjectAttributes
;
570 UNICODE_STRING SubKeyName
, ClassName
;
572 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
573 SubKeyName
.Length
= Info
.KeyNode
->NameLength
;
574 SubKeyName
.MaximumLength
= SubKeyName
.Length
;
575 SubKeyName
.Buffer
= Info
.KeyNode
->Name
;
576 ClassName
.Length
= Info
.KeyNode
->ClassLength
;
577 ClassName
.MaximumLength
= ClassName
.Length
;
578 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)Info
.KeyNode
+ Info
.KeyNode
->ClassOffset
);
580 /* open the subkey with sufficient rights */
582 InitializeObjectAttributes(&ObjectAttributes
,
584 OBJ_CASE_INSENSITIVE
,
588 Status2
= NtOpenKey(&KeyHandle
,
589 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
591 if (NT_SUCCESS(Status2
))
593 /* FIXME - attempt to query the security information */
595 InitializeObjectAttributes(&ObjectAttributes
,
597 OBJ_CASE_INSENSITIVE
,
601 Status2
= NtCreateKey(&NewKeyHandle
,
604 Info
.KeyNode
->TitleIndex
,
608 if (NT_SUCCESS(Status2
))
610 newCopyKeys
= RtlAllocateHeap(ProcessHeap
,
612 sizeof(REGP_COPY_KEYS
));
613 if (newCopyKeys
!= NULL
)
615 /* save the handles and enqueue the subkey */
616 newCopyKeys
->hKeySrc
= KeyHandle
;
617 newCopyKeys
->hKeyDest
= NewKeyHandle
;
618 InsertTailList(©QueueHead
,
619 &newCopyKeys
->ListEntry
);
624 NtClose(NewKeyHandle
);
626 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
635 if (!NT_SUCCESS(Status2
) && NT_SUCCESS(Status
))
642 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
646 ASSERT(BufferSize
< BufferSizeRequired
);
648 Buffer
= RtlReAllocateHeap(ProcessHeap
,
654 Info
.Buffer
= Buffer
;
659 /* don't break, let's try to copy as many keys as possible */
660 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
663 if (NT_SUCCESS(Status
))
671 /* break to avoid an infinite loop in case of denied access or
673 if (Status2
!= STATUS_NO_MORE_ENTRIES
&& NT_SUCCESS(Status
))
682 /* close the handles and remove the entry from the list */
683 if (copyKeys
->hKeySrc
!= hKeySrc
)
685 NtClose(copyKeys
->hKeySrc
);
687 if (copyKeys
->hKeyDest
!= hKeyDest
)
689 NtClose(copyKeys
->hKeyDest
);
692 RemoveEntryList(©Keys
->ListEntry
);
694 RtlFreeHeap(ProcessHeap
,
697 } while (!IsListEmpty(©QueueHead
));
700 Status
= STATUS_INSUFFICIENT_RESOURCES
;
702 RtlFreeHeap(ProcessHeap
,
710 /************************************************************************
716 RegCopyTreeW(IN HKEY hKeySrc
,
717 IN LPCWSTR lpSubKey OPTIONAL
,
720 HANDLE DestKeyHandle
, KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
723 Status
= MapDefaultKey(&KeyHandle
,
725 if (!NT_SUCCESS(Status
))
727 return RtlNtStatusToDosError(Status
);
730 Status
= MapDefaultKey(&DestKeyHandle
,
732 if (!NT_SUCCESS(Status
))
737 if (lpSubKey
!= NULL
)
739 OBJECT_ATTRIBUTES ObjectAttributes
;
740 UNICODE_STRING SubKeyName
;
742 RtlInitUnicodeString(&SubKeyName
,
745 InitializeObjectAttributes(&ObjectAttributes
,
747 OBJ_CASE_INSENSITIVE
,
751 Status
= NtOpenKey(&SubKeyHandle
,
752 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
754 if (!NT_SUCCESS(Status
))
759 CurKey
= SubKeyHandle
;
764 Status
= RegpCopyTree(CurKey
,
767 if (SubKeyHandle
!= NULL
)
769 NtClose(SubKeyHandle
);
773 ClosePredefKey(DestKeyHandle
);
775 ClosePredefKey(KeyHandle
);
777 if (!NT_SUCCESS(Status
))
779 return RtlNtStatusToDosError(Status
);
782 return ERROR_SUCCESS
;
786 /************************************************************************
792 RegCopyTreeA(IN HKEY hKeySrc
,
793 IN LPCSTR lpSubKey OPTIONAL
,
796 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
799 if (lpSubKey
!= NULL
&&
800 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
803 return ERROR_NOT_ENOUGH_MEMORY
;
806 Ret
= RegCopyTreeW(hKeySrc
,
810 RtlFreeUnicodeString(&SubKeyName
);
816 /************************************************************************
817 * RegConnectRegistryA
822 RegConnectRegistryA(IN LPCSTR lpMachineName
,
826 UNICODE_STRING MachineName
= { 0, 0, NULL
};
829 if (lpMachineName
!= NULL
&&
830 !RtlCreateUnicodeStringFromAsciiz(&MachineName
,
831 (LPSTR
)lpMachineName
))
833 return ERROR_NOT_ENOUGH_MEMORY
;
836 Ret
= RegConnectRegistryW(MachineName
.Buffer
,
840 RtlFreeUnicodeString(&MachineName
);
846 /************************************************************************
847 * RegConnectRegistryW
852 RegConnectRegistryW(LPCWSTR lpMachineName
,
858 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
860 if (!lpMachineName
|| !*lpMachineName
)
862 /* Use the local machine name */
863 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
867 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
868 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
870 /* MSDN says lpMachineName must start with \\ : not so */
871 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
874 if (GetComputerNameW(compName
, &len
))
876 if (!_wcsicmp(lpMachineName
, compName
))
877 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
880 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
881 ret
= ERROR_BAD_NETPATH
;
885 ret
= GetLastError();
892 /************************************************************************
895 * Create key and all necessary intermediate keys
898 CreateNestedKey(PHKEY KeyHandle
,
899 POBJECT_ATTRIBUTES ObjectAttributes
,
900 PUNICODE_STRING ClassString
,
903 DWORD
*lpdwDisposition
)
905 OBJECT_ATTRIBUTES LocalObjectAttributes
;
906 UNICODE_STRING LocalKeyName
;
909 ULONG FullNameLength
;
912 HANDLE LocalKeyHandle
;
914 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
920 (PULONG
)lpdwDisposition
);
921 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
922 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
925 /* Copy object attributes */
926 RtlCopyMemory(&LocalObjectAttributes
,
928 sizeof(OBJECT_ATTRIBUTES
));
929 RtlCreateUnicodeString(&LocalKeyName
,
930 ObjectAttributes
->ObjectName
->Buffer
);
931 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
932 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
934 LocalKeyHandle
= NULL
;
936 /* Remove the last part of the key name and try to create the key again. */
937 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
939 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
940 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
942 Status
= STATUS_UNSUCCESSFUL
;
947 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
949 Status
= NtCreateKey(&LocalKeyHandle
,
951 &LocalObjectAttributes
,
956 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
959 if (!NT_SUCCESS(Status
))
961 RtlFreeUnicodeString(&LocalKeyName
);
965 /* Add removed parts of the key name and create them too. */
966 Length
= wcslen(LocalKeyName
.Buffer
);
970 NtClose (LocalKeyHandle
);
972 LocalKeyName
.Buffer
[Length
] = L
'\\';
973 Length
= wcslen (LocalKeyName
.Buffer
);
974 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
976 if (Length
== FullNameLength
)
978 Status
= NtCreateKey((PHANDLE
) KeyHandle
,
984 (PULONG
)lpdwDisposition
);
988 Status
= NtCreateKey(&LocalKeyHandle
,
990 &LocalObjectAttributes
,
995 TRACE("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
996 if (!NT_SUCCESS(Status
))
1000 RtlFreeUnicodeString(&LocalKeyName
);
1006 /************************************************************************
1012 RegCreateKeyExA(HKEY hKey
,
1018 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1020 LPDWORD lpdwDisposition
)
1022 UNICODE_STRING SubKeyString
;
1023 UNICODE_STRING ClassString
;
1024 OBJECT_ATTRIBUTES ObjectAttributes
;
1026 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1029 TRACE("RegCreateKeyExA() called\n");
1031 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1032 return ERROR_INVALID_USER_BUFFER
;
1034 /* get the real parent key */
1035 Status
= MapDefaultKey(&ParentKey
,
1037 if (!NT_SUCCESS(Status
))
1039 return RtlNtStatusToDosError(Status
);
1042 TRACE("ParentKey %p\n", ParentKey
);
1044 if (lpClass
!= NULL
)
1046 RtlCreateUnicodeStringFromAsciiz(&ClassString
,
1050 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1051 Attributes
|= OBJ_OPENLINK
;
1053 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
1055 InitializeObjectAttributes(&ObjectAttributes
,
1059 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1060 Status
= CreateNestedKey(phkResult
,
1062 (lpClass
== NULL
)? NULL
: &ClassString
,
1066 RtlFreeUnicodeString(&SubKeyString
);
1067 if (lpClass
!= NULL
)
1069 RtlFreeUnicodeString(&ClassString
);
1072 ClosePredefKey(ParentKey
);
1074 TRACE("Status %x\n", Status
);
1075 if (!NT_SUCCESS(Status
))
1077 return RtlNtStatusToDosError(Status
);
1080 return ERROR_SUCCESS
;
1084 /************************************************************************
1090 RegCreateKeyExW(HKEY hKey
,
1096 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
1098 LPDWORD lpdwDisposition
)
1100 UNICODE_STRING SubKeyString
;
1101 UNICODE_STRING ClassString
;
1102 OBJECT_ATTRIBUTES ObjectAttributes
;
1104 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
1107 TRACE("RegCreateKeyExW() called\n");
1109 if (lpSecurityAttributes
&& lpSecurityAttributes
->nLength
!= sizeof(SECURITY_ATTRIBUTES
))
1110 return ERROR_INVALID_USER_BUFFER
;
1112 /* get the real parent key */
1113 Status
= MapDefaultKey(&ParentKey
,
1115 if (!NT_SUCCESS(Status
))
1117 return RtlNtStatusToDosError(Status
);
1120 TRACE("ParentKey %p\n", ParentKey
);
1122 if (dwOptions
& REG_OPTION_OPEN_LINK
)
1123 Attributes
|= OBJ_OPENLINK
;
1125 RtlInitUnicodeString(&ClassString
,
1127 RtlInitUnicodeString(&SubKeyString
,
1129 InitializeObjectAttributes(&ObjectAttributes
,
1133 lpSecurityAttributes
? (PSECURITY_DESCRIPTOR
)lpSecurityAttributes
->lpSecurityDescriptor
: NULL
);
1134 Status
= CreateNestedKey(phkResult
,
1136 (lpClass
== NULL
)? NULL
: &ClassString
,
1141 ClosePredefKey(ParentKey
);
1143 TRACE("Status %x\n", Status
);
1144 if (!NT_SUCCESS(Status
))
1146 return RtlNtStatusToDosError(Status
);
1149 return ERROR_SUCCESS
;
1153 /************************************************************************
1159 RegCreateKeyA(HKEY hKey
,
1163 return RegCreateKeyExA(hKey
,
1175 /************************************************************************
1181 RegCreateKeyW(HKEY hKey
,
1185 return RegCreateKeyExW(hKey
,
1197 /************************************************************************
1203 RegDeleteKeyA(HKEY hKey
,
1206 OBJECT_ATTRIBUTES ObjectAttributes
;
1207 UNICODE_STRING SubKeyName
;
1212 /* Make sure we got a subkey */
1216 return ERROR_INVALID_PARAMETER
;
1219 Status
= MapDefaultKey(&ParentKey
,
1221 if (!NT_SUCCESS(Status
))
1223 return RtlNtStatusToDosError(Status
);
1226 RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1228 InitializeObjectAttributes(&ObjectAttributes
,
1230 OBJ_CASE_INSENSITIVE
,
1234 Status
= NtOpenKey(&TargetKey
,
1237 RtlFreeUnicodeString(&SubKeyName
);
1238 if (!NT_SUCCESS(Status
))
1243 Status
= NtDeleteKey(TargetKey
);
1244 NtClose (TargetKey
);
1247 ClosePredefKey(ParentKey
);
1249 if (!NT_SUCCESS(Status
))
1251 return RtlNtStatusToDosError(Status
);
1254 return ERROR_SUCCESS
;
1258 /************************************************************************
1264 RegDeleteKeyW(HKEY hKey
,
1267 OBJECT_ATTRIBUTES ObjectAttributes
;
1268 UNICODE_STRING SubKeyName
;
1273 /* Make sure we got a subkey */
1277 return ERROR_INVALID_PARAMETER
;
1280 Status
= MapDefaultKey(&ParentKey
,
1282 if (!NT_SUCCESS(Status
))
1284 return RtlNtStatusToDosError(Status
);
1287 RtlInitUnicodeString(&SubKeyName
,
1289 InitializeObjectAttributes(&ObjectAttributes
,
1291 OBJ_CASE_INSENSITIVE
,
1294 Status
= NtOpenKey(&TargetKey
,
1297 if (!NT_SUCCESS(Status
))
1302 Status
= NtDeleteKey(TargetKey
);
1306 ClosePredefKey(ParentKey
);
1308 if (!NT_SUCCESS(Status
))
1310 return RtlNtStatusToDosError(Status
);
1313 return ERROR_SUCCESS
;
1317 /************************************************************************
1324 RegDeleteKeyExA(HKEY hKey
,
1329 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1330 return ERROR_CALL_NOT_IMPLEMENTED
;
1334 /************************************************************************
1341 RegDeleteKeyExW(HKEY hKey
,
1346 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1347 return ERROR_CALL_NOT_IMPLEMENTED
;
1351 /************************************************************************
1352 * RegDeleteKeyValueW
1357 RegDeleteKeyValueW(IN HKEY hKey
,
1358 IN LPCWSTR lpSubKey OPTIONAL
,
1359 IN LPCWSTR lpValueName OPTIONAL
)
1361 UNICODE_STRING ValueName
;
1362 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1365 Status
= MapDefaultKey(&KeyHandle
,
1367 if (!NT_SUCCESS(Status
))
1369 return RtlNtStatusToDosError(Status
);
1372 if (lpSubKey
!= NULL
)
1374 OBJECT_ATTRIBUTES ObjectAttributes
;
1375 UNICODE_STRING SubKeyName
;
1377 RtlInitUnicodeString(&SubKeyName
,
1380 InitializeObjectAttributes(&ObjectAttributes
,
1382 OBJ_CASE_INSENSITIVE
,
1386 Status
= NtOpenKey(&SubKeyHandle
,
1389 if (!NT_SUCCESS(Status
))
1394 CurKey
= SubKeyHandle
;
1399 RtlInitUnicodeString(&ValueName
,
1400 (LPWSTR
)lpValueName
);
1402 Status
= NtDeleteValueKey(CurKey
,
1405 if (SubKeyHandle
!= NULL
)
1407 NtClose(SubKeyHandle
);
1411 ClosePredefKey(KeyHandle
);
1413 if (!NT_SUCCESS(Status
))
1415 return RtlNtStatusToDosError(Status
);
1418 return ERROR_SUCCESS
;
1422 /************************************************************************
1423 * RegDeleteKeyValueA
1428 RegDeleteKeyValueA(IN HKEY hKey
,
1429 IN LPCSTR lpSubKey OPTIONAL
,
1430 IN LPCSTR lpValueName OPTIONAL
)
1432 UNICODE_STRING SubKey
= { 0, 0, NULL
}, ValueName
= { 0, 0, NULL
};
1435 if (lpSubKey
!= NULL
&&
1436 !RtlCreateUnicodeStringFromAsciiz(&SubKey
,
1439 return ERROR_NOT_ENOUGH_MEMORY
;
1442 if (lpValueName
!= NULL
&&
1443 !RtlCreateUnicodeStringFromAsciiz(&ValueName
,
1444 (LPSTR
)lpValueName
))
1446 RtlFreeUnicodeString(&SubKey
);
1447 return ERROR_NOT_ENOUGH_MEMORY
;
1450 Ret
= RegDeleteKeyValueW(hKey
,
1454 RtlFreeUnicodeString(&SubKey
);
1455 RtlFreeUnicodeString(&ValueName
);
1461 // Non-recursive RegDeleteTreeW implementation by Thomas, however it needs bugfixing
1463 RegpDeleteTree(IN HKEY hKey
)
1467 LIST_ENTRY ListEntry
;
1469 } REGP_DEL_KEYS
, *PREG_DEL_KEYS
;
1471 LIST_ENTRY delQueueHead
;
1472 PREG_DEL_KEYS delKeys
, newDelKeys
;
1475 PKEY_BASIC_INFORMATION BasicInfo
;
1476 PREG_DEL_KEYS KeyDelRoot
;
1477 NTSTATUS Status
= STATUS_SUCCESS
;
1478 NTSTATUS Status2
= STATUS_SUCCESS
;
1480 InitializeListHead(&delQueueHead
);
1482 ProcessHeap
= RtlGetProcessHeap();
1484 /* NOTE: no need to allocate enough memory for an additional KEY_BASIC_INFORMATION
1485 structure for the root key, we only do that for subkeys as we need to
1486 allocate REGP_DEL_KEYS structures anyway! */
1487 KeyDelRoot
= RtlAllocateHeap(ProcessHeap
,
1489 sizeof(REGP_DEL_KEYS
));
1490 if (KeyDelRoot
!= NULL
)
1492 KeyDelRoot
->KeyHandle
= hKey
;
1493 InsertTailList(&delQueueHead
,
1494 &KeyDelRoot
->ListEntry
);
1498 delKeys
= CONTAINING_RECORD(delQueueHead
.Flink
,
1507 /* check if this key contains subkeys and delete them first by queuing
1508 them at the head of the list */
1509 Status2
= NtEnumerateKey(delKeys
->KeyHandle
,
1511 KeyBasicInformation
,
1516 if (NT_SUCCESS(Status2
))
1518 OBJECT_ATTRIBUTES ObjectAttributes
;
1519 UNICODE_STRING SubKeyName
;
1521 ASSERT(newDelKeys
!= NULL
);
1522 ASSERT(BasicInfo
!= NULL
);
1524 /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
1525 SubKeyName
.Length
= BasicInfo
->NameLength
;
1526 SubKeyName
.MaximumLength
= BasicInfo
->NameLength
;
1527 SubKeyName
.Buffer
= BasicInfo
->Name
;
1529 InitializeObjectAttributes(&ObjectAttributes
,
1531 OBJ_CASE_INSENSITIVE
,
1535 /* open the subkey */
1536 Status2
= NtOpenKey(&newDelKeys
->KeyHandle
,
1537 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1539 if (!NT_SUCCESS(Status2
))
1544 /* enqueue this key to the head of the deletion queue */
1545 InsertHeadList(&delQueueHead
,
1546 &newDelKeys
->ListEntry
);
1548 /* try again from the head of the list */
1553 if (Status2
== STATUS_BUFFER_TOO_SMALL
)
1555 newDelKeys
= RtlAllocateHeap(ProcessHeap
,
1557 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1558 if (newDelKeys
!= NULL
)
1560 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1563 goto ReadFirstSubKey
;
1567 /* don't break, let's try to delete as many keys as possible */
1568 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1569 goto SubKeyFailureNoFree
;
1572 else if (Status2
== STATUS_BUFFER_OVERFLOW
)
1574 PREG_DEL_KEYS newDelKeys2
;
1576 ASSERT(newDelKeys
!= NULL
);
1578 /* we need more memory to query the key name */
1579 newDelKeys2
= RtlReAllocateHeap(ProcessHeap
,
1582 BufferSize
+ sizeof(REGP_DEL_KEYS
));
1583 if (newDelKeys2
!= NULL
)
1585 newDelKeys
= newDelKeys2
;
1586 BasicInfo
= (PKEY_BASIC_INFORMATION
)(newDelKeys
+ 1);
1589 goto ReadFirstSubKey
;
1593 /* don't break, let's try to delete as many keys as possible */
1594 Status2
= STATUS_INSUFFICIENT_RESOURCES
;
1597 else if (Status2
== STATUS_NO_MORE_ENTRIES
)
1599 /* in some race conditions where another thread would delete
1600 the same tree at the same time, newDelKeys could actually
1602 if (newDelKeys
!= NULL
)
1604 RtlFreeHeap(ProcessHeap
,
1612 /* newDelKeys can be NULL here when NtEnumerateKey returned an
1613 error other than STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW! */
1614 if (newDelKeys
!= NULL
)
1616 RtlFreeHeap(ProcessHeap
,
1621 SubKeyFailureNoFree
:
1622 /* don't break, let's try to delete as many keys as possible */
1623 if (NT_SUCCESS(Status
))
1629 Status2
= NtDeleteKey(delKeys
->KeyHandle
);
1631 /* NOTE: do NOT close the handle anymore, it's invalid already! */
1633 if (!NT_SUCCESS(Status2
))
1635 /* close the key handle so we don't leak handles for keys we were
1636 unable to delete. But only do this for handles not supplied
1639 if (delKeys
->KeyHandle
!= hKey
)
1641 NtClose(delKeys
->KeyHandle
);
1644 if (NT_SUCCESS(Status
))
1646 /* don't break, let's try to delete as many keys as possible */
1651 /* remove the entry from the list */
1652 RemoveEntryList(&delKeys
->ListEntry
);
1654 RtlFreeHeap(ProcessHeap
,
1657 } while (!IsListEmpty(&delQueueHead
));
1660 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1666 /************************************************************************
1672 RegDeleteTreeW(IN HKEY hKey
,
1673 IN LPCWSTR lpSubKey OPTIONAL
)
1675 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
1678 Status
= MapDefaultKey(&KeyHandle
,
1680 if (!NT_SUCCESS(Status
))
1682 return RtlNtStatusToDosError(Status
);
1685 if (lpSubKey
!= NULL
)
1687 OBJECT_ATTRIBUTES ObjectAttributes
;
1688 UNICODE_STRING SubKeyName
;
1690 RtlInitUnicodeString(&SubKeyName
,
1693 InitializeObjectAttributes(&ObjectAttributes
,
1695 OBJ_CASE_INSENSITIVE
,
1699 Status
= NtOpenKey(&SubKeyHandle
,
1700 DELETE
| KEY_ENUMERATE_SUB_KEYS
,
1702 if (!NT_SUCCESS(Status
))
1707 CurKey
= SubKeyHandle
;
1712 Status
= RegpDeleteTree(CurKey
);
1714 if (NT_SUCCESS(Status
))
1716 /* make sure we only close hKey (KeyHandle) when the caller specified a
1717 subkey, because the handle would be invalid already! */
1718 if (CurKey
!= KeyHandle
)
1720 ClosePredefKey(KeyHandle
);
1723 return ERROR_SUCCESS
;
1727 /* make sure we close all handles we created! */
1728 if (SubKeyHandle
!= NULL
)
1730 NtClose(SubKeyHandle
);
1734 ClosePredefKey(KeyHandle
);
1736 return RtlNtStatusToDosError(Status
);
1742 /************************************************************************
1749 RegDeleteTreeW(HKEY hKey
,
1753 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
1754 DWORD dwMaxLen
, dwSize
;
1758 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1760 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
1762 Status
= MapDefaultKey(&KeyHandle
,
1764 if (!NT_SUCCESS(Status
))
1766 return RtlNtStatusToDosError(Status
);
1769 hSubKey
= KeyHandle
;
1773 ret
= RegOpenKeyExW(KeyHandle
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1776 ClosePredefKey(KeyHandle
);
1781 /* Get highest length for keys, values */
1782 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
1783 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
1784 if (ret
) goto cleanup
;
1788 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
1789 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1791 /* Name too big: alloc a buffer for it */
1792 if (!(lpszName
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
1794 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1800 /* Recursively delete all the subkeys */
1804 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
1805 NULL
, NULL
, NULL
)) break;
1807 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
1808 if (ret
) goto cleanup
;
1812 ret
= RegDeleteKeyW(KeyHandle
, lpszSubKey
);
1817 if (RegEnumValueW(KeyHandle
, 0, lpszName
, &dwSize
,
1818 NULL
, NULL
, NULL
, NULL
)) break;
1820 ret
= RegDeleteValueW(KeyHandle
, lpszName
);
1821 if (ret
) goto cleanup
;
1825 /* Free buffer if allocated */
1826 if (lpszName
!= szNameBuf
)
1827 RtlFreeHeap( RtlGetProcessHeap(), 0, lpszName
);
1829 RegCloseKey(hSubKey
);
1831 ClosePredefKey(KeyHandle
);
1837 /************************************************************************
1843 RegDeleteTreeA(IN HKEY hKey
,
1844 IN LPCSTR lpSubKey OPTIONAL
)
1846 UNICODE_STRING SubKeyName
= { 0, 0, NULL
};
1849 if (lpSubKey
!= NULL
&&
1850 !RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
1853 return ERROR_NOT_ENOUGH_MEMORY
;
1856 Ret
= RegDeleteTreeW(hKey
,
1859 RtlFreeUnicodeString(&SubKeyName
);
1865 /************************************************************************
1866 * RegDisableReflectionKey
1871 RegDisableReflectionKey(IN HKEY hBase
)
1873 FIXME("RegDisableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1874 return ERROR_CALL_NOT_IMPLEMENTED
;
1878 /************************************************************************
1879 * RegEnableReflectionKey
1884 RegEnableReflectionKey(IN HKEY hBase
)
1886 FIXME("RegEnableReflectionKey(0x%p) UNIMPLEMENTED!\n", hBase
);
1887 return ERROR_CALL_NOT_IMPLEMENTED
;
1891 /******************************************************************************
1892 * RegpApplyRestrictions [internal]
1894 * Helper function for RegGetValueA/W.
1897 RegpApplyRestrictions(DWORD dwFlags
,
1902 /* Check if the type is restricted by the passed flags */
1903 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1909 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1910 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1911 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1912 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1913 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1914 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1915 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1918 if (dwFlags
& dwMask
)
1920 /* Type is not restricted, check for size mismatch */
1921 if (dwType
== REG_BINARY
)
1925 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1927 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1930 if (cbExpect
&& cbData
!= cbExpect
)
1931 *ret
= ERROR_DATATYPE_MISMATCH
;
1934 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1939 /******************************************************************************
1940 * RegGetValueW [ADVAPI32.@]
1942 * Retrieves the type and data for a value name associated with a key,
1943 * optionally expanding its content and restricting its type.
1946 * hKey [I] Handle to an open key.
1947 * pszSubKey [I] Name of the subkey of hKey.
1948 * pszValue [I] Name of value under hKey/szSubKey to query.
1949 * dwFlags [I] Flags restricting the value type to retrieve.
1950 * pdwType [O] Destination for the values type, may be NULL.
1951 * pvData [O] Destination for the values content, may be NULL.
1952 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1953 * retrieve the whole content, including the trailing '\0'
1957 * Success: ERROR_SUCCESS
1958 * Failure: nonzero error code from Winerror.h
1961 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1962 * expanded and pdwType is set to REG_SZ instead.
1963 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1964 * without RRF_NOEXPAND is thus not allowed.
1965 * An exception is the case where RRF_RT_ANY is specified, because then
1966 * RRF_NOEXPAND is allowed.
1969 RegGetValueW(HKEY hKey
,
1977 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1981 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1982 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1983 pvData
, pcbData
, cbData
);
1985 if (pvData
&& !pcbData
)
1986 return ERROR_INVALID_PARAMETER
;
1987 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1988 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1989 return ERROR_INVALID_PARAMETER
;
1991 if (pszSubKey
&& pszSubKey
[0])
1993 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1994 if (ret
!= ERROR_SUCCESS
) return ret
;
1997 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1999 /* If we are going to expand we need to read in the whole the value even
2000 * if the passed buffer was too small as the expanded string might be
2001 * smaller than the unexpanded one and could fit into cbData bytes. */
2002 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2003 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2007 HeapFree(GetProcessHeap(), 0, pvBuf
);
2009 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2012 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2016 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2017 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2018 &dwType
, pvBuf
, &cbData
);
2021 /* Even if cbData was large enough we have to copy the
2022 * string since ExpandEnvironmentStrings can't handle
2023 * overlapping buffers. */
2024 CopyMemory(pvBuf
, pvData
, cbData
);
2027 /* Both the type or the value itself could have been modified in
2028 * between so we have to keep retrying until the buffer is large
2029 * enough or we no longer have to expand the value. */
2031 while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2033 if (ret
== ERROR_SUCCESS
)
2035 /* Recheck dwType in case it changed since the first call */
2036 if (dwType
== REG_EXPAND_SZ
)
2038 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2039 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2041 if (pvData
&& pcbData
&& cbData
> *pcbData
)
2042 ret
= ERROR_MORE_DATA
;
2045 CopyMemory(pvData
, pvBuf
, *pcbData
);
2048 HeapFree(GetProcessHeap(), 0, pvBuf
);
2051 if (pszSubKey
&& pszSubKey
[0])
2054 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2056 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2057 ZeroMemory(pvData
, *pcbData
);
2069 /******************************************************************************
2070 * RegGetValueA [ADVAPI32.@]
2075 RegGetValueA(HKEY hKey
,
2083 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2087 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
2088 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
2091 if (pvData
&& !pcbData
)
2092 return ERROR_INVALID_PARAMETER
;
2093 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2094 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2095 return ERROR_INVALID_PARAMETER
;
2097 if (pszSubKey
&& pszSubKey
[0])
2099 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2100 if (ret
!= ERROR_SUCCESS
) return ret
;
2103 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2105 /* If we are going to expand we need to read in the whole the value even
2106 * if the passed buffer was too small as the expanded string might be
2107 * smaller than the unexpanded one and could fit into cbData bytes. */
2108 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2109 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
2112 HeapFree(GetProcessHeap(), 0, pvBuf
);
2114 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2117 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2121 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2122 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2123 &dwType
, pvBuf
, &cbData
);
2126 /* Even if cbData was large enough we have to copy the
2127 * string since ExpandEnvironmentStrings can't handle
2128 * overlapping buffers. */
2129 CopyMemory(pvBuf
, pvData
, cbData
);
2132 /* Both the type or the value itself could have been modified in
2133 * between so we have to keep retrying until the buffer is large
2134 * enough or we no longer have to expand the value. */
2135 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2137 if (ret
== ERROR_SUCCESS
)
2139 /* Recheck dwType in case it changed since the first call */
2140 if (dwType
== REG_EXPAND_SZ
)
2142 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2143 pcbData
? *pcbData
: 0);
2145 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2146 ret
= ERROR_MORE_DATA
;
2149 CopyMemory(pvData
, pvBuf
, *pcbData
);
2152 HeapFree(GetProcessHeap(), 0, pvBuf
);
2155 if (pszSubKey
&& pszSubKey
[0])
2158 RegpApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2160 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2161 ZeroMemory(pvData
, *pcbData
);
2163 if (pdwType
) *pdwType
= dwType
;
2164 if (pcbData
) *pcbData
= cbData
;
2170 /************************************************************************
2176 RegSetKeyValueW(IN HKEY hKey
,
2177 IN LPCWSTR lpSubKey OPTIONAL
,
2178 IN LPCWSTR lpValueName OPTIONAL
,
2180 IN LPCVOID lpData OPTIONAL
,
2183 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2187 Status
= MapDefaultKey(&KeyHandle
,
2189 if (!NT_SUCCESS(Status
))
2191 return RtlNtStatusToDosError(Status
);
2194 if (lpSubKey
!= NULL
)
2196 OBJECT_ATTRIBUTES ObjectAttributes
;
2197 UNICODE_STRING SubKeyName
;
2199 RtlInitUnicodeString(&SubKeyName
,
2202 InitializeObjectAttributes(&ObjectAttributes
,
2204 OBJ_CASE_INSENSITIVE
,
2208 Status
= NtOpenKey(&SubKeyHandle
,
2211 if (!NT_SUCCESS(Status
))
2213 Ret
= RtlNtStatusToDosError(Status
);
2217 CurKey
= SubKeyHandle
;
2222 Ret
= RegSetValueExW(CurKey
,
2229 if (SubKeyHandle
!= NULL
)
2231 NtClose(SubKeyHandle
);
2235 ClosePredefKey(KeyHandle
);
2241 /************************************************************************
2247 RegSetKeyValueA(IN HKEY hKey
,
2248 IN LPCSTR lpSubKey OPTIONAL
,
2249 IN LPCSTR lpValueName OPTIONAL
,
2251 IN LPCVOID lpData OPTIONAL
,
2254 HANDLE KeyHandle
, CurKey
, SubKeyHandle
= NULL
;
2258 Status
= MapDefaultKey(&KeyHandle
,
2260 if (!NT_SUCCESS(Status
))
2262 return RtlNtStatusToDosError(Status
);
2265 if (lpSubKey
!= NULL
)
2267 OBJECT_ATTRIBUTES ObjectAttributes
;
2268 UNICODE_STRING SubKeyName
;
2270 if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName
,
2273 Ret
= ERROR_NOT_ENOUGH_MEMORY
;
2277 InitializeObjectAttributes(&ObjectAttributes
,
2279 OBJ_CASE_INSENSITIVE
,
2283 Status
= NtOpenKey(&SubKeyHandle
,
2287 RtlFreeUnicodeString(&SubKeyName
);
2289 if (!NT_SUCCESS(Status
))
2291 Ret
= RtlNtStatusToDosError(Status
);
2295 CurKey
= SubKeyHandle
;
2300 Ret
= RegSetValueExA(CurKey
,
2307 if (SubKeyHandle
!= NULL
)
2309 NtClose(SubKeyHandle
);
2313 ClosePredefKey(KeyHandle
);
2319 /************************************************************************
2325 RegDeleteValueA(HKEY hKey
,
2328 UNICODE_STRING ValueName
;
2332 Status
= MapDefaultKey(&KeyHandle
,
2334 if (!NT_SUCCESS(Status
))
2336 return RtlNtStatusToDosError(Status
);
2339 RtlCreateUnicodeStringFromAsciiz(&ValueName
,
2340 (LPSTR
)lpValueName
);
2341 Status
= NtDeleteValueKey(KeyHandle
,
2343 RtlFreeUnicodeString (&ValueName
);
2345 ClosePredefKey(KeyHandle
);
2347 if (!NT_SUCCESS(Status
))
2349 return RtlNtStatusToDosError(Status
);
2352 return ERROR_SUCCESS
;
2356 /************************************************************************
2362 RegDeleteValueW(HKEY hKey
,
2363 LPCWSTR lpValueName
)
2365 UNICODE_STRING ValueName
;
2369 Status
= MapDefaultKey(&KeyHandle
,
2371 if (!NT_SUCCESS(Status
))
2373 return RtlNtStatusToDosError(Status
);
2376 RtlInitUnicodeString(&ValueName
,
2377 (LPWSTR
)lpValueName
);
2379 Status
= NtDeleteValueKey(KeyHandle
,
2382 ClosePredefKey(KeyHandle
);
2384 if (!NT_SUCCESS(Status
))
2386 return RtlNtStatusToDosError(Status
);
2389 return ERROR_SUCCESS
;
2393 /************************************************************************
2399 RegEnumKeyA(HKEY hKey
,
2407 return RegEnumKeyExA(hKey
,
2418 /************************************************************************
2424 RegEnumKeyW(HKEY hKey
,
2432 return RegEnumKeyExW(hKey
,
2443 /************************************************************************
2449 RegEnumKeyExA(HKEY hKey
,
2456 PFILETIME lpftLastWriteTime
)
2460 KEY_NODE_INFORMATION Node
;
2461 KEY_BASIC_INFORMATION Basic
;
2464 UNICODE_STRING StringU
;
2465 ANSI_STRING StringA
;
2466 LONG ErrorCode
= ERROR_SUCCESS
;
2468 DWORD ClassLength
= 0;
2474 TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
2475 hKey
, dwIndex
, lpName
, *lpcbName
, lpClass
, lpcbClass
? *lpcbClass
: 0);
2477 if ((lpClass
) && (!lpcbClass
))
2479 return ERROR_INVALID_PARAMETER
;
2482 Status
= MapDefaultKey(&KeyHandle
, hKey
);
2483 if (!NT_SUCCESS(Status
))
2485 return RtlNtStatusToDosError(Status
);
2490 NameLength
= min (*lpcbName
- 1 , REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2501 ClassLength
= min (*lpcbClass
-1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2508 /* The class name should start at a dword boundary */
2509 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2513 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2516 KeyInfo
= RtlAllocateHeap (ProcessHeap
, 0, BufferSize
);
2517 if (KeyInfo
== NULL
)
2519 ErrorCode
= ERROR_OUTOFMEMORY
;
2523 Status
= NtEnumerateKey(KeyHandle
,
2525 lpClass
== NULL
? KeyBasicInformation
: KeyNodeInformation
,
2529 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2530 if (!NT_SUCCESS(Status
))
2532 ErrorCode
= RtlNtStatusToDosError (Status
);
2536 if (lpClass
== NULL
)
2538 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2540 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2544 StringU
.Buffer
= KeyInfo
->Basic
.Name
;
2545 StringU
.Length
= KeyInfo
->Basic
.NameLength
;
2546 StringU
.MaximumLength
= KeyInfo
->Basic
.NameLength
;
2551 if (KeyInfo
->Node
.NameLength
> NameLength
||
2552 KeyInfo
->Node
.ClassLength
> ClassLength
)
2554 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2558 StringA
.Buffer
= lpClass
;
2560 StringA
.MaximumLength
= *lpcbClass
;
2561 StringU
.Buffer
= (PWCHAR
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
);
2562 StringU
.Length
= KeyInfo
->Node
.ClassLength
;
2563 StringU
.MaximumLength
= KeyInfo
->Node
.ClassLength
;
2564 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2565 lpClass
[StringA
.Length
] = 0;
2566 *lpcbClass
= StringA
.Length
;
2567 StringU
.Buffer
= KeyInfo
->Node
.Name
;
2568 StringU
.Length
= KeyInfo
->Node
.NameLength
;
2569 StringU
.MaximumLength
= KeyInfo
->Node
.NameLength
;
2573 if (ErrorCode
== ERROR_SUCCESS
)
2575 StringA
.Buffer
= lpName
;
2577 StringA
.MaximumLength
= *lpcbName
;
2578 RtlUnicodeStringToAnsiString (&StringA
, &StringU
, FALSE
);
2579 lpName
[StringA
.Length
] = 0;
2580 *lpcbName
= StringA
.Length
;
2581 if (lpftLastWriteTime
!= NULL
)
2583 if (lpClass
== NULL
)
2585 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2586 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2590 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2591 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2597 /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
2598 TRACE("Key Name1 Length %d\n", NameLength
);
2599 TRACE("Key Name Length %d\n", *lpcbName
);
2600 TRACE("Key Name %s\n", lpName
);
2602 RtlFreeHeap(ProcessHeap
,
2607 ClosePredefKey(KeyHandle
);
2613 /************************************************************************
2619 RegEnumKeyExW(HKEY hKey
,
2626 PFILETIME lpftLastWriteTime
)
2630 KEY_NODE_INFORMATION Node
;
2631 KEY_BASIC_INFORMATION Basic
;
2637 ULONG ClassLength
= 0;
2639 LONG ErrorCode
= ERROR_SUCCESS
;
2642 Status
= MapDefaultKey(&KeyHandle
,
2644 if (!NT_SUCCESS(Status
))
2646 return RtlNtStatusToDosError(Status
);
2651 NameLength
= min (*lpcbName
- 1, REG_MAX_NAME_SIZE
) * sizeof (WCHAR
);
2662 ClassLength
= min (*lpcbClass
- 1, REG_MAX_NAME_SIZE
) * sizeof(WCHAR
);
2669 BufferSize
= ((sizeof(KEY_NODE_INFORMATION
) + NameLength
+ 3) & ~3) + ClassLength
;
2673 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + NameLength
;
2676 KeyInfo
= RtlAllocateHeap(ProcessHeap
,
2679 if (KeyInfo
== NULL
)
2681 ErrorCode
= ERROR_OUTOFMEMORY
;
2685 Status
= NtEnumerateKey(KeyHandle
,
2687 lpClass
? KeyNodeInformation
: KeyBasicInformation
,
2691 TRACE("NtEnumerateKey() returned status 0x%X\n", Status
);
2692 if (!NT_SUCCESS(Status
))
2694 ErrorCode
= RtlNtStatusToDosError (Status
);
2698 if (lpClass
== NULL
)
2700 if (KeyInfo
->Basic
.NameLength
> NameLength
)
2702 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2706 RtlCopyMemory(lpName
,
2707 KeyInfo
->Basic
.Name
,
2708 KeyInfo
->Basic
.NameLength
);
2709 *lpcbName
= (DWORD
)(KeyInfo
->Basic
.NameLength
/ sizeof(WCHAR
));
2710 lpName
[*lpcbName
] = 0;
2715 if (KeyInfo
->Node
.NameLength
> NameLength
||
2716 KeyInfo
->Node
.ClassLength
> ClassLength
)
2718 ErrorCode
= ERROR_BUFFER_OVERFLOW
;
2722 RtlCopyMemory(lpName
,
2724 KeyInfo
->Node
.NameLength
);
2725 *lpcbName
= KeyInfo
->Node
.NameLength
/ sizeof(WCHAR
);
2726 lpName
[*lpcbName
] = 0;
2727 RtlCopyMemory(lpClass
,
2728 (PVOID
)((ULONG_PTR
)KeyInfo
->Node
.Name
+ KeyInfo
->Node
.ClassOffset
),
2729 KeyInfo
->Node
.ClassLength
);
2730 *lpcbClass
= (DWORD
)(KeyInfo
->Node
.ClassLength
/ sizeof(WCHAR
));
2731 lpClass
[*lpcbClass
] = 0;
2735 if (ErrorCode
== ERROR_SUCCESS
&& lpftLastWriteTime
!= NULL
)
2737 if (lpClass
== NULL
)
2739 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.LowPart
;
2740 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Basic
.LastWriteTime
.u
.HighPart
;
2744 lpftLastWriteTime
->dwLowDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.LowPart
;
2745 lpftLastWriteTime
->dwHighDateTime
= KeyInfo
->Node
.LastWriteTime
.u
.HighPart
;
2750 RtlFreeHeap(ProcessHeap
,
2755 ClosePredefKey(KeyHandle
);
2761 /************************************************************************
2767 RegEnumValueA(HKEY hKey
,
2779 char buffer
[256], *buf_ptr
= buffer
;
2780 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2781 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2783 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2784 // hkey, index, value, val_count, reserved, type, data, count );
2786 /* NT only checks count, not val_count */
2787 if ((data
&& !count
) || reserved
)
2788 return ERROR_INVALID_PARAMETER
;
2790 status
= MapDefaultKey(&KeyHandle
, hKey
);
2791 if (!NT_SUCCESS(status
))
2793 return RtlNtStatusToDosError(status
);
2796 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2797 if (data
) total_size
+= *count
;
2798 total_size
= min( sizeof(buffer
), total_size
);
2800 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2801 buffer
, total_size
, &total_size
);
2802 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2804 /* we need to fetch the contents for a string type even if not requested,
2805 * because we need to compute the length of the ASCII string. */
2806 if (value
|| data
|| is_string(info
->Type
))
2808 /* retry with a dynamically allocated buffer */
2809 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2811 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2812 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2814 status
= STATUS_INSUFFICIENT_RESOURCES
;
2817 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2818 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2819 buf_ptr
, total_size
, &total_size
);
2822 if (status
) goto done
;
2824 if (is_string(info
->Type
))
2827 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2831 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2834 RtlUnicodeToMultiByteN( (PCHAR
)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2836 /* if the type is REG_SZ and data is not 0-terminated
2837 * and there is enough space in the buffer NT appends a \0 */
2838 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2841 info
->DataLength
= len
;
2845 if (info
->DataLength
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2846 else memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2849 if (value
&& !status
)
2853 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2854 if (len
>= *val_count
)
2856 status
= STATUS_BUFFER_OVERFLOW
;
2859 len
= *val_count
- 1;
2860 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2866 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2872 else status
= STATUS_SUCCESS
;
2874 if (type
) *type
= info
->Type
;
2875 if (count
) *count
= info
->DataLength
;
2878 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2879 ClosePredefKey(KeyHandle
);
2880 return RtlNtStatusToDosError(status
);
2884 /******************************************************************************
2885 * RegEnumValueW [ADVAPI32.@]
2889 * hkey [I] Handle to key to query
2890 * index [I] Index of value to query
2891 * value [O] Value string
2892 * val_count [I/O] Size of value buffer (in wchars)
2893 * reserved [I] Reserved
2894 * type [O] Type code
2895 * data [O] Value data
2896 * count [I/O] Size of data buffer (in bytes)
2899 * Success: ERROR_SUCCESS
2900 * Failure: nonzero error code from Winerror.h
2903 RegEnumValueW(HKEY hKey
,
2915 char buffer
[256], *buf_ptr
= buffer
;
2916 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2917 static const int info_size
= FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION
, Name
);
2919 //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
2920 // hkey, index, value, val_count, reserved, type, data, count );
2922 /* NT only checks count, not val_count */
2923 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2925 status
= MapDefaultKey(&KeyHandle
, hKey
);
2926 if (!NT_SUCCESS(status
))
2928 return RtlNtStatusToDosError(status
);
2931 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2932 if (data
) total_size
+= *count
;
2933 total_size
= min( sizeof(buffer
), total_size
);
2935 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2936 buffer
, total_size
, &total_size
);
2937 if (status
&& (status
!= STATUS_BUFFER_OVERFLOW
) && (status
!= STATUS_BUFFER_TOO_SMALL
)) goto done
;
2941 /* retry with a dynamically allocated buffer */
2942 while ((status
== STATUS_BUFFER_OVERFLOW
) || (status
== STATUS_BUFFER_TOO_SMALL
))
2944 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2945 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
2947 status
= ERROR_NOT_ENOUGH_MEMORY
;
2950 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2951 status
= NtEnumerateValueKey( KeyHandle
, index
, KeyValueFullInformation
,
2952 buf_ptr
, total_size
, &total_size
);
2955 if (status
) goto done
;
2959 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2961 status
= STATUS_BUFFER_OVERFLOW
;
2964 memcpy( value
, info
->Name
, info
->NameLength
);
2965 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2966 value
[*val_count
] = 0;
2971 if (info
->DataLength
> *count
)
2973 status
= STATUS_BUFFER_OVERFLOW
;
2976 memcpy( data
, buf_ptr
+ info
->DataOffset
, info
->DataLength
);
2977 if (is_string(info
->Type
) && info
->DataLength
<= *count
- sizeof(WCHAR
))
2979 /* if the type is REG_SZ and data is not 0-terminated
2980 * and there is enough space in the buffer NT appends a \0 */
2981 WCHAR
*ptr
= (WCHAR
*)(data
+ info
->DataLength
);
2982 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2986 else status
= STATUS_SUCCESS
;
2989 if (type
) *type
= info
->Type
;
2990 if (count
) *count
= info
->DataLength
;
2993 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2994 ClosePredefKey(KeyHandle
);
2995 return RtlNtStatusToDosError(status
);
2999 /************************************************************************
3005 RegFlushKey(HKEY hKey
)
3010 if (hKey
== HKEY_PERFORMANCE_DATA
)
3012 return ERROR_SUCCESS
;
3015 Status
= MapDefaultKey(&KeyHandle
,
3017 if (!NT_SUCCESS(Status
))
3019 return RtlNtStatusToDosError(Status
);
3022 Status
= NtFlushKey(KeyHandle
);
3024 ClosePredefKey(KeyHandle
);
3026 if (!NT_SUCCESS(Status
))
3028 return RtlNtStatusToDosError(Status
);
3031 return ERROR_SUCCESS
;
3035 /************************************************************************
3041 RegGetKeySecurity(HKEY hKey
,
3042 SECURITY_INFORMATION SecurityInformation
,
3043 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3044 LPDWORD lpcbSecurityDescriptor
)
3049 if (hKey
== HKEY_PERFORMANCE_DATA
)
3051 return ERROR_INVALID_HANDLE
;
3054 Status
= MapDefaultKey(&KeyHandle
,
3056 if (!NT_SUCCESS(Status
))
3058 TRACE("MapDefaultKey() failed (Status %lx)\n", Status
);
3059 return RtlNtStatusToDosError(Status
);
3063 Status
= NtQuerySecurityObject(KeyHandle
,
3064 SecurityInformation
,
3065 pSecurityDescriptor
,
3066 *lpcbSecurityDescriptor
,
3067 lpcbSecurityDescriptor
);
3070 ClosePredefKey(KeyHandle
);
3072 if (!NT_SUCCESS(Status
))
3074 WARN("NtQuerySecurityObject() failed (Status %lx)\n", Status
);
3075 return RtlNtStatusToDosError(Status
);
3078 return ERROR_SUCCESS
;
3082 /************************************************************************
3088 RegLoadKeyA(HKEY hKey
,
3092 UNICODE_STRING FileName
;
3093 UNICODE_STRING KeyName
;
3096 RtlCreateUnicodeStringFromAsciiz(&KeyName
,
3098 RtlCreateUnicodeStringFromAsciiz(&FileName
,
3101 ErrorCode
= RegLoadKeyW(hKey
,
3105 RtlFreeUnicodeString(&FileName
);
3106 RtlFreeUnicodeString(&KeyName
);
3112 /************************************************************************
3118 RegLoadKeyW(HKEY hKey
,
3122 OBJECT_ATTRIBUTES FileObjectAttributes
;
3123 OBJECT_ATTRIBUTES KeyObjectAttributes
;
3124 UNICODE_STRING FileName
;
3125 UNICODE_STRING KeyName
;
3128 LONG ErrorCode
= ERROR_SUCCESS
;
3130 if (hKey
== HKEY_PERFORMANCE_DATA
)
3132 return ERROR_INVALID_HANDLE
;
3135 Status
= MapDefaultKey(&KeyHandle
,
3137 if (!NT_SUCCESS(Status
))
3139 return RtlNtStatusToDosError(Status
);
3142 if (!RtlDosPathNameToNtPathName_U(lpFile
,
3147 ErrorCode
= ERROR_BAD_PATHNAME
;
3151 InitializeObjectAttributes(&FileObjectAttributes
,
3153 OBJ_CASE_INSENSITIVE
,
3157 RtlInitUnicodeString(&KeyName
,
3160 InitializeObjectAttributes(&KeyObjectAttributes
,
3162 OBJ_CASE_INSENSITIVE
,
3166 Status
= NtLoadKey(&KeyObjectAttributes
,
3167 &FileObjectAttributes
);
3169 RtlFreeHeap(RtlGetProcessHeap(),
3173 if (!NT_SUCCESS(Status
))
3175 ErrorCode
= RtlNtStatusToDosError(Status
);
3180 ClosePredefKey(KeyHandle
);
3186 /************************************************************************
3187 * RegNotifyChangeKeyValue
3192 RegNotifyChangeKeyValue(HKEY hKey
,
3194 DWORD dwNotifyFilter
,
3198 IO_STATUS_BLOCK IoStatusBlock
;
3201 LONG ErrorCode
= ERROR_SUCCESS
;
3203 if (hKey
== HKEY_PERFORMANCE_DATA
)
3205 return ERROR_INVALID_HANDLE
;
3208 if (fAsynchronous
== TRUE
&& hEvent
== NULL
)
3210 return ERROR_INVALID_PARAMETER
;
3213 Status
= MapDefaultKey(&KeyHandle
,
3215 if (!NT_SUCCESS(Status
))
3217 return RtlNtStatusToDosError(Status
);
3220 /* FIXME: Remote key handles must fail */
3222 Status
= NtNotifyChangeKey(KeyHandle
,
3232 if (!NT_SUCCESS(Status
) && Status
!= STATUS_TIMEOUT
)
3234 ErrorCode
= RtlNtStatusToDosError(Status
);
3237 ClosePredefKey(KeyHandle
);
3243 /************************************************************************
3244 * RegOpenCurrentUser
3249 RegOpenCurrentUser(IN REGSAM samDesired
,
3250 OUT PHKEY phkResult
)
3254 Status
= RtlOpenCurrentUser((ACCESS_MASK
)samDesired
,
3255 (PHANDLE
)phkResult
);
3256 if (!NT_SUCCESS(Status
))
3258 /* NOTE - don't set the last error code! just return the error! */
3259 return RtlNtStatusToDosError(Status
);
3262 return ERROR_SUCCESS
;
3266 /************************************************************************
3269 * 20050503 Fireball - imported from WINE
3274 RegOpenKeyA(HKEY hKey
,
3278 TRACE("RegOpenKeyA hKey 0x%x lpSubKey %s phkResult %p\n",
3279 hKey
, lpSubKey
, phkResult
);
3282 return ERROR_INVALID_PARAMETER
;
3284 if (!hKey
&& lpSubKey
&& phkResult
)
3286 return ERROR_INVALID_HANDLE
;
3289 if (!lpSubKey
|| !*lpSubKey
)
3292 return ERROR_SUCCESS
;
3295 return RegOpenKeyExA(hKey
,
3303 /************************************************************************
3308 * 20050503 Fireball - imported from WINE
3313 RegOpenKeyW(HKEY hKey
,
3317 TRACE("RegOpenKeyW hKey 0x%x lpSubKey %S phkResult %p\n",
3318 hKey
, lpSubKey
, phkResult
);
3321 return ERROR_INVALID_PARAMETER
;
3323 if (!hKey
&& lpSubKey
&& phkResult
)
3325 return ERROR_INVALID_HANDLE
;
3328 if (!lpSubKey
|| !*lpSubKey
)
3331 return ERROR_SUCCESS
;
3334 return RegOpenKeyExW(hKey
,
3342 /************************************************************************
3348 RegOpenKeyExA(HKEY hKey
,
3354 OBJECT_ATTRIBUTES ObjectAttributes
;
3355 UNICODE_STRING SubKeyString
;
3358 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3359 LONG ErrorCode
= ERROR_SUCCESS
;
3361 TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3362 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);
3365 return ERROR_INVALID_PARAMETER
;
3368 Status
= MapDefaultKey(&KeyHandle
,
3370 if (!NT_SUCCESS(Status
))
3372 return RtlNtStatusToDosError(Status
);
3375 if (ulOptions
& REG_OPTION_OPEN_LINK
)
3376 Attributes
|= OBJ_OPENLINK
;
3378 RtlCreateUnicodeStringFromAsciiz(&SubKeyString
,
3380 InitializeObjectAttributes(&ObjectAttributes
,
3386 Status
= NtOpenKey((PHANDLE
)phkResult
,
3389 RtlFreeUnicodeString(&SubKeyString
);
3390 if (!NT_SUCCESS(Status
))
3392 ErrorCode
= RtlNtStatusToDosError(Status
);
3395 ClosePredefKey(KeyHandle
);
3401 /************************************************************************
3407 RegOpenKeyExW(HKEY hKey
,
3413 OBJECT_ATTRIBUTES ObjectAttributes
;
3414 UNICODE_STRING SubKeyString
;
3417 ULONG Attributes
= OBJ_CASE_INSENSITIVE
;
3418 LONG ErrorCode
= ERROR_SUCCESS
;
3420 TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
3421 hKey
, lpSubKey
, ulOptions
, samDesired
, phkResult
);