3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Rtl registry functions
6 * FILE: lib/ntdll/rtl/registry.c
14 * - finish RtlQueryRegistryValues()
15 * - support RTL_QUERY_REGISTRY_DELETE
17 * - finish RtlFormatCurrentUserKeyPath()
20 /* INCLUDES ****************************************************************/
22 #include <ddk/ntddk.h>
23 #include <ntdll/rtl.h>
24 #include <ntdll/registry.h>
25 #include <ntos/minmax.h>
28 #include <ntdll/ntdll.h>
31 /* FUNCTIONS ***************************************************************/
34 RtlCheckRegistryKey(IN ULONG RelativeTo,
40 Status = RtlpGetRegistryHandle(RelativeTo,
44 if (!NT_SUCCESS(Status))
49 return(STATUS_SUCCESS);
54 RtlCreateRegistryKey(IN ULONG RelativeTo,
60 Status = RtlpGetRegistryHandle(RelativeTo,
64 if (!NT_SUCCESS(Status))
69 return(STATUS_SUCCESS);
74 RtlDeleteRegistryValue(IN ULONG RelativeTo,
82 Status = RtlpGetRegistryHandle(RelativeTo,
86 if (!NT_SUCCESS(Status))
89 RtlInitUnicodeString(&Name,
92 Status = NtDeleteValueKey(KeyHandle,
102 RtlFormatCurrentUserKeyPath(PUNICODE_STRING KeyPath)
106 RtlCreateUnicodeString(KeyPath,
107 L"\\Registry\\User\\.Default");
109 return(STATUS_SUCCESS);
114 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
115 OUT PHANDLE KeyHandle)
117 OBJECT_ATTRIBUTES ObjectAttributes;
119 UNICODE_STRING KeyPath = UNICODE_STRING_INITIALIZER(L"\\Registry\\User\\.Default");
121 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
122 if (NT_SUCCESS(Status))
124 InitializeObjectAttributes(&ObjectAttributes,
126 OBJ_CASE_INSENSITIVE,
129 Status = NtOpenKey(KeyHandle,
132 if (NT_SUCCESS(Status)) {
133 RtlFreeUnicodeString(&KeyPath);
134 return(STATUS_SUCCESS);
137 InitializeObjectAttributes(&ObjectAttributes,
139 OBJ_CASE_INSENSITIVE,
142 Status = NtOpenKey(KeyHandle,
145 RtlFreeUnicodeString(&KeyPath);
151 RtlQueryRegistryValues(IN ULONG RelativeTo,
153 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
155 IN PVOID Environment)
158 HANDLE BaseKeyHandle;
159 HANDLE CurrentKeyHandle;
160 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
161 OBJECT_ATTRIBUTES ObjectAttributes;
162 UNICODE_STRING KeyName;
163 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
164 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
171 UNICODE_STRING EnvValue;
172 UNICODE_STRING EnvExpandedValue;
174 DPRINT("RtlQueryRegistryValues() called\n");
176 Status = RtlpGetRegistryHandle(RelativeTo,
180 if (!NT_SUCCESS(Status))
182 DPRINT("RtlpGetRegistryHandle() failed (Status %lx)\n", Status);
186 CurrentKeyHandle = BaseKeyHandle;
187 QueryEntry = QueryTable;
188 while ((QueryEntry->QueryRoutine != NULL) ||
189 (QueryEntry->Name != NULL))
191 if ((QueryEntry->QueryRoutine == NULL) &&
192 ((QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY) != 0))
194 Status = STATUS_INVALID_PARAMETER;
198 DPRINT("Name: %S\n", QueryEntry->Name);
200 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
201 (BaseKeyHandle != CurrentKeyHandle))
203 NtClose(CurrentKeyHandle);
204 CurrentKeyHandle = BaseKeyHandle;
207 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
209 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
211 RtlInitUnicodeString(&KeyName,
213 InitializeObjectAttributes(&ObjectAttributes,
215 OBJ_CASE_INSENSITIVE,
218 Status = NtOpenKey(&CurrentKeyHandle,
221 if (!NT_SUCCESS(Status))
224 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
226 DPRINT("Query value directly: %S\n", QueryEntry->Name);
228 RtlInitUnicodeString(&KeyName,
231 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
232 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
235 if (ValueInfo == NULL)
237 Status = STATUS_NO_MEMORY;
241 Status = NtQueryValueKey(CurrentKeyHandle,
243 KeyValuePartialInformation,
247 if (!NT_SUCCESS(Status))
249 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
251 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
252 Status = STATUS_OBJECT_NAME_NOT_FOUND;
256 if (QueryEntry->DefaultType == REG_SZ)
258 PUNICODE_STRING ValueString;
259 PUNICODE_STRING SourceString;
261 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
262 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
263 if (ValueString->Buffer == 0)
265 ValueString->Length = SourceString->Length;
266 ValueString->MaximumLength = SourceString->MaximumLength;
267 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
269 ValueString->MaximumLength);
270 if (!ValueString->Buffer)
272 ValueString->Buffer[0] = 0;
273 memcpy(ValueString->Buffer,
274 SourceString->Buffer,
275 SourceString->MaximumLength);
279 ValueString->Length = min(SourceString->Length,
280 ValueString->MaximumLength - sizeof(WCHAR));
281 memcpy(ValueString->Buffer,
282 SourceString->Buffer,
283 ValueString->Length);
284 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
289 memcpy(QueryEntry->EntryContext,
290 QueryEntry->DefaultData,
291 QueryEntry->DefaultLength);
293 Status = STATUS_SUCCESS;
297 if ((ValueInfo->Type == REG_SZ) ||
298 (ValueInfo->Type == REG_MULTI_SZ) ||
299 (ValueInfo->Type == REG_EXPAND_SZ && (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
301 PUNICODE_STRING ValueString;
303 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
304 if (ValueString->Buffer == NULL)
306 ValueString->MaximumLength = ValueInfo->DataLength + sizeof(WCHAR);
307 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
309 ValueString->MaximumLength);
310 if (ValueString->Buffer == NULL)
312 Status = STATUS_INSUFFICIENT_RESOURCES;
315 ValueString->Buffer[0] = 0;
317 ValueString->Length = min(ValueInfo->DataLength,
318 ValueString->MaximumLength - sizeof(WCHAR));
319 memcpy(ValueString->Buffer,
321 ValueString->Length);
322 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
324 else if (ValueInfo->Type == REG_EXPAND_SZ)
326 PUNICODE_STRING ValueString;
328 DPRINT("Expand REG_EXPAND_SZ type\n");
330 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
332 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
334 ValueInfo->DataLength * 2);
335 if (ExpandBuffer == NULL)
337 Status = STATUS_NO_MEMORY;
341 RtlInitUnicodeString(&EnvValue,
342 (PWSTR)ValueInfo->Data);
343 EnvExpandedValue.Length = 0;
344 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
345 EnvExpandedValue.Buffer = ExpandBuffer;
348 RtlExpandEnvironmentStrings_U(Environment,
353 if (ValueString->Buffer == NULL)
355 ValueString->MaximumLength = EnvExpandedValue.Length + sizeof(WCHAR);
356 ValueString->Length = EnvExpandedValue.Length;
357 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
359 ValueString->MaximumLength);
360 if (ValueString->Buffer == NULL)
362 Status = STATUS_INSUFFICIENT_RESOURCES;
368 ValueString->Length = min(EnvExpandedValue.Length,
369 ValueString->MaximumLength - sizeof(WCHAR));
372 memcpy(ValueString->Buffer,
373 EnvExpandedValue.Buffer,
374 ValueString->Length);
375 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
377 RtlFreeHeap(RtlGetProcessHeap(),
383 memcpy(QueryEntry->EntryContext,
385 ValueInfo->DataLength);
389 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
391 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
395 RtlFreeHeap(RtlGetProcessHeap(),
401 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
402 if (QueryEntry->Name != NULL)
404 RtlInitUnicodeString(&KeyName,
407 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
408 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
411 if (ValueInfo == NULL)
413 Status = STATUS_NO_MEMORY;
417 Status = NtQueryValueKey(CurrentKeyHandle,
419 KeyValuePartialInformation,
423 if (!NT_SUCCESS(Status))
425 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
426 QueryEntry->DefaultType,
427 QueryEntry->DefaultData,
428 QueryEntry->DefaultLength,
430 QueryEntry->EntryContext);
432 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
433 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
435 DPRINT("Expand REG_MULTI_SZ type\n");
436 StringPtr = (PWSTR)ValueInfo->Data;
437 while (*StringPtr != 0)
439 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
440 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
445 QueryEntry->EntryContext);
446 if(!NT_SUCCESS(Status))
448 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
451 else if ((ValueInfo->Type == REG_EXPAND_SZ) &&
452 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
454 DPRINT("Expand REG_EXPAND_SZ type\n");
456 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
458 ValueInfo->DataLength * 2);
459 if (ExpandBuffer == NULL)
461 Status = STATUS_NO_MEMORY;
465 RtlInitUnicodeString(&EnvValue,
466 (PWSTR)ValueInfo->Data);
467 EnvExpandedValue.Length = 0;
468 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
469 EnvExpandedValue.Buffer = ExpandBuffer;
472 RtlExpandEnvironmentStrings_U(Environment,
477 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
478 Status = QueryEntry->QueryRoutine(FullValueInfo->Name,
483 QueryEntry->EntryContext);
485 RtlFreeHeap(RtlGetProcessHeap(),
491 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
494 ValueInfo->DataLength,
496 QueryEntry->EntryContext);
499 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
501 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
505 RtlFreeHeap(RtlGetProcessHeap(),
508 if (!NT_SUCCESS(Status))
511 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
513 DPRINT("Simple callback\n");
514 Status = QueryEntry->QueryRoutine(NULL,
519 QueryEntry->EntryContext);
520 if (!NT_SUCCESS(Status))
525 DPRINT("Enumerate values\n");
527 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
528 FullValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
531 if (FullValueInfo == NULL)
533 Status = STATUS_NO_MEMORY;
540 Status = NtEnumerateValueKey(CurrentKeyHandle,
542 KeyValueFullInformation,
546 if (!NT_SUCCESS(Status))
548 if ((Status == STATUS_NO_MORE_ENTRIES) &&
550 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
552 Status = STATUS_OBJECT_NAME_NOT_FOUND;
554 else if (Status == STATUS_NO_MORE_ENTRIES)
556 Status = STATUS_SUCCESS;
561 DPRINT("FullValueInfo->Type: %lu\n", FullValueInfo->Type);
562 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
563 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
565 DPRINT("Expand REG_MULTI_SZ type\n");
566 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
567 while (*StringPtr != 0)
569 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
570 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
575 QueryEntry->EntryContext);
576 if(!NT_SUCCESS(Status))
578 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
581 else if ((FullValueInfo->Type == REG_EXPAND_SZ) &&
582 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
584 DPRINT("Expand REG_EXPAND_SZ type\n");
586 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
587 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
589 FullValueInfo->DataLength * 2);
590 if (ExpandBuffer == NULL)
592 Status = STATUS_NO_MEMORY;
596 RtlInitUnicodeString(&EnvValue,
598 EnvExpandedValue.Length = 0;
599 EnvExpandedValue.MaximumLength = FullValueInfo->DataLength * 2 * sizeof(WCHAR);
600 EnvExpandedValue.Buffer = ExpandBuffer;
603 RtlExpandEnvironmentStrings_U(Environment,
608 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
609 Status = QueryEntry->QueryRoutine(FullValueInfo->Name,
614 QueryEntry->EntryContext);
616 RtlFreeHeap(RtlGetProcessHeap(),
622 Status = QueryEntry->QueryRoutine(FullValueInfo->Name,
624 (PVOID)FullValueInfo + FullValueInfo->DataOffset,
625 FullValueInfo->DataLength,
627 QueryEntry->EntryContext);
630 if (!NT_SUCCESS(Status))
633 /* FIXME: How will these be deleted? */
638 RtlFreeHeap(RtlGetProcessHeap(),
642 if (!NT_SUCCESS(Status))
650 if (CurrentKeyHandle != BaseKeyHandle)
651 NtClose(CurrentKeyHandle);
653 NtClose(BaseKeyHandle);
660 RtlWriteRegistryValue(IN ULONG RelativeTo,
665 IN ULONG ValueLength)
671 Status = RtlpGetRegistryHandle(RelativeTo,
675 if (!NT_SUCCESS(Status))
678 RtlInitUnicodeString(&Name,
681 Status = NtSetValueKey(KeyHandle,
687 if (NT_SUCCESS(Status))
695 RtlpNtCreateKey(OUT HANDLE KeyHandle,
696 IN ACCESS_MASK DesiredAccess,
697 IN POBJECT_ATTRIBUTES ObjectAttributes,
699 OUT PULONG Disposition,
702 if (ObjectAttributes != NULL)
703 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
705 return(NtCreateKey(KeyHandle,
716 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
717 OUT PUNICODE_STRING SubKeyName,
721 PKEY_BASIC_INFORMATION KeyInfo = NULL;
722 ULONG BufferLength = 0;
723 ULONG ReturnedLength;
726 if (SubKeyName->MaximumLength != 0)
728 BufferLength = SubKeyName->MaximumLength +
729 sizeof(KEY_BASIC_INFORMATION);
730 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(),
734 return(STATUS_NO_MEMORY);
737 Status = NtEnumerateKey(KeyHandle,
743 if (NT_SUCCESS(Status))
745 if (KeyInfo->NameLength + sizeof(WCHAR) <= SubKeyName->MaximumLength)
747 memmove(SubKeyName->Buffer,
749 KeyInfo->NameLength);
750 SubKeyName->Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
751 SubKeyName->Length = KeyInfo->NameLength;
755 Status = STATUS_BUFFER_OVERFLOW;
761 RtlFreeHeap(RtlGetProcessHeap(),
771 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
773 return(NtDeleteKey(KeyHandle));
778 RtlpNtOpenKey(OUT HANDLE KeyHandle,
779 IN ACCESS_MASK DesiredAccess,
780 IN POBJECT_ATTRIBUTES ObjectAttributes,
783 if (ObjectAttributes != NULL)
784 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
786 return(NtOpenKey(KeyHandle,
793 RtlpNtQueryValueKey(IN HANDLE KeyHandle,
794 OUT PULONG Type OPTIONAL,
795 OUT PVOID Data OPTIONAL,
796 IN OUT PULONG DataLength OPTIONAL,
799 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
800 UNICODE_STRING ValueName;
802 ULONG ReturnedLength;
805 RtlInitUnicodeString(&ValueName,
808 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
809 if (DataLength != NULL)
810 BufferLength = *DataLength;
812 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
815 if (ValueInfo == NULL)
816 return(STATUS_NO_MEMORY);
818 Status = NtQueryValueKey(KeyHandle,
820 KeyValuePartialInformation,
824 if (NT_SUCCESS(Status))
826 if (DataLength != NULL)
827 *DataLength = ValueInfo->DataLength;
830 *Type = ValueInfo->Type;
836 ValueInfo->DataLength);
840 RtlFreeHeap(RtlGetProcessHeap(),
849 RtlpNtSetValueKey(IN HANDLE KeyHandle,
854 UNICODE_STRING ValueName;
856 RtlInitUnicodeString(&ValueName,
858 return(NtSetValueKey(KeyHandle,
867 /* INTERNAL FUNCTIONS ******************************************************/
870 RtlpGetRegistryHandle(ULONG RelativeTo,
875 UNICODE_STRING KeyName;
876 WCHAR KeyBuffer[MAX_PATH];
877 OBJECT_ATTRIBUTES ObjectAttributes;
880 DPRINT("RtlpGetRegistryHandle()\n");
882 if (RelativeTo & RTL_REGISTRY_HANDLE)
884 Status = NtDuplicateObject(NtCurrentProcess(),
890 DUPLICATE_SAME_ACCESS);
894 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
895 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
897 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
898 return(STATUS_INVALID_PARAMETER);
901 KeyName.MaximumLength = MAX_PATH;
902 KeyName.Buffer = KeyBuffer;
907 case RTL_REGISTRY_ABSOLUTE:
908 RtlAppendUnicodeToString(&KeyName,
912 case RTL_REGISTRY_SERVICES:
913 RtlAppendUnicodeToString(&KeyName,
914 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
917 case RTL_REGISTRY_CONTROL:
918 RtlAppendUnicodeToString(&KeyName,
919 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
922 case RTL_REGISTRY_WINDOWS_NT:
923 RtlAppendUnicodeToString(&KeyName,
924 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
927 case RTL_REGISTRY_DEVICEMAP:
928 RtlAppendUnicodeToString(&KeyName,
929 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
932 case RTL_REGISTRY_USER:
933 Status = RtlFormatCurrentUserKeyPath(&KeyName);
934 if (!NT_SUCCESS(Status))
938 /* ReactOS specific */
939 case RTL_REGISTRY_ENUM:
940 RtlAppendUnicodeToString(&KeyName,
941 L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
945 DPRINT("KeyName %wZ\n", &KeyName);
947 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
951 RtlAppendUnicodeToString(&KeyName,
954 DPRINT("KeyName %wZ\n", &KeyName);
956 InitializeObjectAttributes(&ObjectAttributes,
958 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
964 Status = NtCreateKey(KeyHandle,
974 Status = NtOpenKey(KeyHandle,