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 ***************************************************************/
37 RtlCheckRegistryKey(IN ULONG RelativeTo,
43 Status = RtlpGetRegistryHandle(RelativeTo,
47 if (!NT_SUCCESS(Status))
52 return(STATUS_SUCCESS);
60 RtlCreateRegistryKey(IN ULONG RelativeTo,
66 Status = RtlpGetRegistryHandle(RelativeTo,
70 if (!NT_SUCCESS(Status))
75 return(STATUS_SUCCESS);
83 RtlDeleteRegistryValue(IN ULONG RelativeTo,
91 Status = RtlpGetRegistryHandle(RelativeTo,
95 if (!NT_SUCCESS(Status))
98 RtlInitUnicodeString(&Name,
101 Status = NtDeleteValueKey(KeyHandle,
114 RtlFormatCurrentUserKeyPath(PUNICODE_STRING KeyPath)
118 RtlCreateUnicodeString(KeyPath,
119 L"\\Registry\\User\\.Default");
121 return(STATUS_SUCCESS);
129 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
130 OUT PHANDLE KeyHandle)
132 OBJECT_ATTRIBUTES ObjectAttributes;
134 UNICODE_STRING KeyPath = UNICODE_STRING_INITIALIZER(L"\\Registry\\User\\.Default");
136 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
137 if (NT_SUCCESS(Status))
139 InitializeObjectAttributes(&ObjectAttributes,
141 OBJ_CASE_INSENSITIVE,
144 Status = NtOpenKey(KeyHandle,
147 if (NT_SUCCESS(Status)) {
148 RtlFreeUnicodeString(&KeyPath);
149 return(STATUS_SUCCESS);
152 InitializeObjectAttributes(&ObjectAttributes,
154 OBJ_CASE_INSENSITIVE,
157 Status = NtOpenKey(KeyHandle,
160 RtlFreeUnicodeString(&KeyPath);
169 RtlQueryRegistryValues(IN ULONG RelativeTo,
171 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
173 IN PVOID Environment)
176 HANDLE BaseKeyHandle;
177 HANDLE CurrentKeyHandle;
178 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
179 OBJECT_ATTRIBUTES ObjectAttributes;
180 UNICODE_STRING KeyName;
181 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
182 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
191 UNICODE_STRING EnvValue;
192 UNICODE_STRING EnvExpandedValue;
194 DPRINT("RtlQueryRegistryValues() called\n");
196 Status = RtlpGetRegistryHandle(RelativeTo,
200 if (!NT_SUCCESS(Status))
202 DPRINT("RtlpGetRegistryHandle() failed (Status %lx)\n", Status);
206 CurrentKeyHandle = BaseKeyHandle;
207 QueryEntry = QueryTable;
208 while ((QueryEntry->QueryRoutine != NULL) ||
209 (QueryEntry->Name != NULL))
211 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
212 (BaseKeyHandle != CurrentKeyHandle))
214 NtClose(CurrentKeyHandle);
215 CurrentKeyHandle = BaseKeyHandle;
218 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
220 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
222 RtlInitUnicodeString(&KeyName,
224 InitializeObjectAttributes(&ObjectAttributes,
226 OBJ_CASE_INSENSITIVE,
229 Status = NtOpenKey(&CurrentKeyHandle,
232 if (!NT_SUCCESS(Status))
235 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
237 DPRINT("Query value directly: %S\n", QueryEntry->Name);
239 RtlInitUnicodeString(&KeyName,
242 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
243 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
246 if (ValueInfo == NULL)
248 Status = STATUS_NO_MEMORY;
252 Status = NtQueryValueKey(CurrentKeyHandle,
254 KeyValuePartialInformation,
258 if (!NT_SUCCESS(Status))
260 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
262 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
263 Status = STATUS_OBJECT_NAME_NOT_FOUND;
267 if (QueryEntry->DefaultType == REG_SZ)
269 PUNICODE_STRING ValueString;
270 PUNICODE_STRING SourceString;
272 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
273 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
274 if (ValueString->Buffer == NULL)
276 ValueString->Length = SourceString->Length;
277 ValueString->MaximumLength = SourceString->MaximumLength;
278 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
280 ValueString->MaximumLength);
281 if (!ValueString->Buffer)
283 ValueString->Buffer[0] = 0;
284 memcpy(ValueString->Buffer,
285 SourceString->Buffer,
286 SourceString->MaximumLength);
290 ValueString->Length = min(SourceString->Length,
291 ValueString->MaximumLength - sizeof(WCHAR));
292 memcpy(ValueString->Buffer,
293 SourceString->Buffer,
294 ValueString->Length);
295 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
300 memcpy(QueryEntry->EntryContext,
301 QueryEntry->DefaultData,
302 QueryEntry->DefaultLength);
304 Status = STATUS_SUCCESS;
308 if ((ValueInfo->Type == REG_SZ) ||
309 (ValueInfo->Type == REG_MULTI_SZ) ||
310 (ValueInfo->Type == REG_EXPAND_SZ && (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
312 PUNICODE_STRING ValueString;
314 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
315 if (ValueString->Buffer == NULL)
317 ValueString->MaximumLength = ValueInfo->DataLength;
318 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
320 ValueString->MaximumLength);
321 if (ValueString->Buffer == NULL)
323 Status = STATUS_INSUFFICIENT_RESOURCES;
326 ValueString->Buffer[0] = 0;
328 ValueString->Length = min(ValueInfo->DataLength,
329 ValueString->MaximumLength) - sizeof(WCHAR);
330 memcpy(ValueString->Buffer,
332 ValueString->Length);
333 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
335 else if (ValueInfo->Type == REG_EXPAND_SZ)
337 PUNICODE_STRING ValueString;
339 DPRINT("Expand REG_EXPAND_SZ type\n");
341 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
343 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
345 ValueInfo->DataLength * 2);
346 if (ExpandBuffer == NULL)
348 Status = STATUS_NO_MEMORY;
352 RtlInitUnicodeString(&EnvValue,
353 (PWSTR)ValueInfo->Data);
354 EnvExpandedValue.Length = 0;
355 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2;
356 EnvExpandedValue.Buffer = ExpandBuffer;
359 RtlExpandEnvironmentStrings_U(Environment,
364 if (ValueString->Buffer == NULL)
366 ValueString->MaximumLength = EnvExpandedValue.Length + sizeof(WCHAR);
367 ValueString->Length = EnvExpandedValue.Length;
368 ValueString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
370 ValueString->MaximumLength);
371 if (ValueString->Buffer == NULL)
373 Status = STATUS_INSUFFICIENT_RESOURCES;
379 ValueString->Length = min(EnvExpandedValue.Length,
380 ValueString->MaximumLength - sizeof(WCHAR));
383 memcpy(ValueString->Buffer,
384 EnvExpandedValue.Buffer,
385 ValueString->Length);
386 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
388 RtlFreeHeap(RtlGetProcessHeap(),
394 memcpy(QueryEntry->EntryContext,
396 ValueInfo->DataLength);
400 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
402 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
406 RtlFreeHeap(RtlGetProcessHeap(),
412 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
413 if (QueryEntry->Name != NULL)
415 RtlInitUnicodeString(&KeyName,
418 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
419 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
422 if (ValueInfo == NULL)
424 Status = STATUS_NO_MEMORY;
428 Status = NtQueryValueKey(CurrentKeyHandle,
430 KeyValuePartialInformation,
434 if (!NT_SUCCESS(Status))
436 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
437 QueryEntry->DefaultType,
438 QueryEntry->DefaultData,
439 QueryEntry->DefaultLength,
441 QueryEntry->EntryContext);
443 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
444 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
446 DPRINT("Expand REG_MULTI_SZ type\n");
447 StringPtr = (PWSTR)ValueInfo->Data;
448 while (*StringPtr != 0)
450 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
451 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
456 QueryEntry->EntryContext);
457 if(!NT_SUCCESS(Status))
459 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
462 else if ((ValueInfo->Type == REG_EXPAND_SZ) &&
463 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
465 DPRINT("Expand REG_EXPAND_SZ type\n");
467 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
469 ValueInfo->DataLength * 2);
470 if (ExpandBuffer == NULL)
472 Status = STATUS_NO_MEMORY;
476 RtlInitUnicodeString(&EnvValue,
477 (PWSTR)ValueInfo->Data);
478 EnvExpandedValue.Length = 0;
479 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
480 EnvExpandedValue.Buffer = ExpandBuffer;
483 RtlExpandEnvironmentStrings_U(Environment,
488 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
489 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
494 QueryEntry->EntryContext);
496 RtlFreeHeap(RtlGetProcessHeap(),
502 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
505 ValueInfo->DataLength,
507 QueryEntry->EntryContext);
510 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
512 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
516 RtlFreeHeap(RtlGetProcessHeap(),
519 if (!NT_SUCCESS(Status))
522 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
524 DPRINT("Simple callback\n");
525 Status = QueryEntry->QueryRoutine(NULL,
530 QueryEntry->EntryContext);
531 if (!NT_SUCCESS(Status))
536 DPRINT("Enumerate values\n");
538 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
539 FullValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
542 if (FullValueInfo == NULL)
544 Status = STATUS_NO_MEMORY;
547 ValueNameSize = 256 * sizeof(WCHAR);
548 ValueName = RtlAllocateHeap(RtlGetProcessHeap(),
551 if (ValueName == NULL)
553 Status = STATUS_NO_MEMORY;
559 Status = NtEnumerateValueKey(CurrentKeyHandle,
561 KeyValueFullInformation,
565 if (!NT_SUCCESS(Status))
567 if ((Status == STATUS_NO_MORE_ENTRIES) &&
569 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
571 Status = STATUS_OBJECT_NAME_NOT_FOUND;
573 else if (Status == STATUS_NO_MORE_ENTRIES)
575 Status = STATUS_SUCCESS;
580 if (FullValueInfo->NameLength > ValueNameSize - sizeof(WCHAR))
582 /* Should not happen, because the name length is limited to 255 characters */
583 RtlFreeHeap(RtlGetProcessHeap(),
586 ValueNameSize = FullValueInfo->NameLength + sizeof(WCHAR);
587 ValueName = RtlAllocateHeap(RtlGetProcessHeap(),
590 if (ValueName == NULL)
592 Status = STATUS_NO_MEMORY;
599 FullValueInfo->NameLength);
600 ValueName[FullValueInfo->NameLength / sizeof(WCHAR)] = 0;
602 DPRINT("FullValueInfo->Type: %lu\n", FullValueInfo->Type);
603 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
604 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
606 DPRINT("Expand REG_MULTI_SZ type\n");
607 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
608 while (*StringPtr != 0)
610 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
611 Status = QueryEntry->QueryRoutine(ValueName,
616 QueryEntry->EntryContext);
617 if(!NT_SUCCESS(Status))
619 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
622 else if ((FullValueInfo->Type == REG_EXPAND_SZ) &&
623 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
625 DPRINT("Expand REG_EXPAND_SZ type\n");
627 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
628 ExpandBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
630 FullValueInfo->DataLength * 2);
631 if (ExpandBuffer == NULL)
633 Status = STATUS_NO_MEMORY;
637 RtlInitUnicodeString(&EnvValue,
639 EnvExpandedValue.Length = 0;
640 EnvExpandedValue.MaximumLength = FullValueInfo->DataLength * 2;
641 EnvExpandedValue.Buffer = ExpandBuffer;
644 RtlExpandEnvironmentStrings_U(Environment,
649 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
650 Status = QueryEntry->QueryRoutine(ValueName,
655 QueryEntry->EntryContext);
657 RtlFreeHeap(RtlGetProcessHeap(),
663 Status = QueryEntry->QueryRoutine(ValueName,
665 (PVOID)FullValueInfo + FullValueInfo->DataOffset,
666 FullValueInfo->DataLength,
668 QueryEntry->EntryContext);
671 if (!NT_SUCCESS(Status))
674 /* FIXME: How will these be deleted? */
679 RtlFreeHeap(RtlGetProcessHeap(),
682 RtlFreeHeap(RtlGetProcessHeap(),
685 if (!NT_SUCCESS(Status))
693 if (CurrentKeyHandle != BaseKeyHandle)
694 NtClose(CurrentKeyHandle);
696 NtClose(BaseKeyHandle);
706 RtlWriteRegistryValue(IN ULONG RelativeTo,
711 IN ULONG ValueLength)
717 Status = RtlpGetRegistryHandle(RelativeTo,
721 if (!NT_SUCCESS(Status))
724 RtlInitUnicodeString(&Name,
727 Status = NtSetValueKey(KeyHandle,
733 if (NT_SUCCESS(Status))
744 RtlpNtCreateKey(OUT HANDLE KeyHandle,
745 IN ACCESS_MASK DesiredAccess,
746 IN POBJECT_ATTRIBUTES ObjectAttributes,
748 OUT PULONG Disposition,
751 if (ObjectAttributes != NULL)
752 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
754 return(NtCreateKey(KeyHandle,
768 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
769 OUT PUNICODE_STRING SubKeyName,
773 PKEY_BASIC_INFORMATION KeyInfo = NULL;
774 ULONG BufferLength = 0;
775 ULONG ReturnedLength;
778 if (SubKeyName->MaximumLength != 0)
780 BufferLength = SubKeyName->MaximumLength +
781 sizeof(KEY_BASIC_INFORMATION);
782 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(),
786 return(STATUS_NO_MEMORY);
789 Status = NtEnumerateKey(KeyHandle,
795 if (NT_SUCCESS(Status))
797 if (KeyInfo->NameLength + sizeof(WCHAR) <= SubKeyName->MaximumLength)
799 memmove(SubKeyName->Buffer,
801 KeyInfo->NameLength);
802 SubKeyName->Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
803 SubKeyName->Length = KeyInfo->NameLength;
807 Status = STATUS_BUFFER_OVERFLOW;
813 RtlFreeHeap(RtlGetProcessHeap(),
826 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
828 return(NtDeleteKey(KeyHandle));
836 RtlpNtOpenKey(OUT HANDLE KeyHandle,
837 IN ACCESS_MASK DesiredAccess,
838 IN POBJECT_ATTRIBUTES ObjectAttributes,
841 if (ObjectAttributes != NULL)
842 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
844 return(NtOpenKey(KeyHandle,
854 RtlpNtQueryValueKey(IN HANDLE KeyHandle,
855 OUT PULONG Type OPTIONAL,
856 OUT PVOID Data OPTIONAL,
857 IN OUT PULONG DataLength OPTIONAL,
860 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
861 UNICODE_STRING ValueName;
863 ULONG ReturnedLength;
866 RtlInitUnicodeString(&ValueName,
869 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
870 if (DataLength != NULL)
871 BufferLength = *DataLength;
873 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
876 if (ValueInfo == NULL)
877 return(STATUS_NO_MEMORY);
879 Status = NtQueryValueKey(KeyHandle,
881 KeyValuePartialInformation,
885 if (NT_SUCCESS(Status))
887 if (DataLength != NULL)
888 *DataLength = ValueInfo->DataLength;
891 *Type = ValueInfo->Type;
897 ValueInfo->DataLength);
901 RtlFreeHeap(RtlGetProcessHeap(),
913 RtlpNtSetValueKey(IN HANDLE KeyHandle,
918 UNICODE_STRING ValueName;
920 RtlInitUnicodeString(&ValueName,
922 return(NtSetValueKey(KeyHandle,
931 /* INTERNAL FUNCTIONS ******************************************************/
934 RtlpGetRegistryHandle(ULONG RelativeTo,
939 UNICODE_STRING KeyName;
940 WCHAR KeyBuffer[MAX_PATH];
941 OBJECT_ATTRIBUTES ObjectAttributes;
944 DPRINT("RtlpGetRegistryHandle()\n");
946 if (RelativeTo & RTL_REGISTRY_HANDLE)
948 Status = NtDuplicateObject(NtCurrentProcess(),
954 DUPLICATE_SAME_ACCESS);
958 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
959 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
961 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
962 return(STATUS_INVALID_PARAMETER);
965 KeyName.MaximumLength = MAX_PATH;
966 KeyName.Buffer = KeyBuffer;
971 case RTL_REGISTRY_ABSOLUTE:
972 RtlAppendUnicodeToString(&KeyName,
976 case RTL_REGISTRY_SERVICES:
977 RtlAppendUnicodeToString(&KeyName,
978 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
981 case RTL_REGISTRY_CONTROL:
982 RtlAppendUnicodeToString(&KeyName,
983 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
986 case RTL_REGISTRY_WINDOWS_NT:
987 RtlAppendUnicodeToString(&KeyName,
988 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
991 case RTL_REGISTRY_DEVICEMAP:
992 RtlAppendUnicodeToString(&KeyName,
993 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
996 case RTL_REGISTRY_USER:
997 Status = RtlFormatCurrentUserKeyPath(&KeyName);
998 if (!NT_SUCCESS(Status))
1002 /* ReactOS specific */
1003 case RTL_REGISTRY_ENUM:
1004 RtlAppendUnicodeToString(&KeyName,
1005 L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1009 DPRINT("KeyName %wZ\n", &KeyName);
1011 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
1015 RtlAppendUnicodeToString(&KeyName,
1018 DPRINT("KeyName %wZ\n", &KeyName);
1020 InitializeObjectAttributes(&ObjectAttributes,
1022 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1028 Status = NtCreateKey(KeyHandle,
1038 Status = NtOpenKey(KeyHandle,