3 * Copyright (C) 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/registry.c
23 * PURPOSE: Registry creation functions
24 * PROGRAMMER: Eric Kohl
27 /* INCLUDES *****************************************************************/
29 #include <ddk/ntddk.h>
30 #include <ntdll/rtl.h>
38 #define FLG_ADDREG_BINVALUETYPE 0x00000001
39 #define FLG_ADDREG_NOCLOBBER 0x00000002
40 #define FLG_ADDREG_DELVAL 0x00000004
41 #define FLG_ADDREG_APPEND 0x00000008
42 #define FLG_ADDREG_KEYONLY 0x00000010
43 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
44 #define FLG_ADDREG_TYPE_SZ 0x00000000
45 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
46 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
47 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
48 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
49 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
50 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
53 /* FUNCTIONS ****************************************************************/
56 GetRootKey (PWCHAR Name)
58 if (!_wcsicmp (Name, L"HKCR"))
60 wcscpy (Name, L"\\Registry\\Machine\\SOFTWARE\\Classes\\");
64 if (!_wcsicmp (Name, L"HKCU"))
66 wcscpy (Name, L"\\Registry\\User\\.DEFAULT\\");
70 if (!_wcsicmp (Name, L"HKLM"))
72 wcscpy (Name, L"\\Registry\\Machine\\");
76 if (!_wcsicmp (Name, L"HKU"))
78 wcscpy (Name, L"\\Registry\\User\\");
83 if (!_wcsicmp (Name, L"HKR"))
91 /***********************************************************************
92 * append_multi_sz_value
94 * Append a multisz string to a multisz registry value.
98 append_multi_sz_value (HANDLE hkey,
100 const WCHAR *strings,
103 DWORD size, type, total;
106 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
107 if (type != REG_MULTI_SZ) return;
109 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
110 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
112 /* compare each string against all the existing ones */
116 int len = strlenW(strings) + 1;
118 for (p = buffer; *p; p += strlenW(p) + 1)
119 if (!strcmpiW( p, strings )) break;
121 if (!*p) /* not found, need to append it */
123 memcpy( p, strings, len * sizeof(WCHAR) );
131 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
132 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
135 HeapFree( GetProcessHeap(), 0, buffer );
139 /***********************************************************************
140 * delete_multi_sz_value
142 * Remove a string from a multisz registry value.
145 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
148 WCHAR *buffer, *src, *dst;
150 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
151 if (type != REG_MULTI_SZ) return;
152 /* allocate double the size, one for value before and one for after */
153 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
154 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
159 int len = strlenW(src) + 1;
160 if (strcmpiW( src, string ))
162 memcpy( dst, src, len * sizeof(WCHAR) );
168 if (dst != buffer + 2*size) /* did we remove something? */
170 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
171 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
172 (BYTE *)(buffer + size), dst - (buffer + size) );
175 HeapFree( GetProcessHeap(), 0, buffer );
179 /***********************************************************************
182 * Perform an add/delete registry operation depending on the flags.
185 do_reg_operation(HANDLE KeyHandle,
186 PUNICODE_STRING ValueName,
190 WCHAR EmptyStr = (WCHAR)0;
195 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
200 RegDeleteValueW( hkey, value );
204 RegDeleteKeyW( hkey, NULL );
210 if (Flags & FLG_ADDREG_KEYONLY)
214 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
216 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
217 if (exists && (flags & FLG_ADDREG_NOCLOBBER))
219 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
224 switch (Flags & FLG_ADDREG_TYPE_MASK)
226 case FLG_ADDREG_TYPE_SZ:
230 case FLG_ADDREG_TYPE_MULTI_SZ:
234 case FLG_ADDREG_TYPE_EXPAND_SZ:
235 Type = REG_EXPAND_SZ;
238 case FLG_ADDREG_TYPE_BINARY:
242 case FLG_ADDREG_TYPE_DWORD:
246 case FLG_ADDREG_TYPE_NONE:
255 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
256 (Type == REG_DWORD && InfGetFieldCount (Context) == 5))
260 if (Type == REG_MULTI_SZ)
262 if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size))
267 Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
271 InfGetMultiSzField (Context, 5, Str, Size, NULL);
274 if (Flags & FLG_ADDREG_APPEND)
279 // append_multi_sz_value( hkey, value, str, size );
281 RtlFreeHeap (ProcessHeap, 0, Str);
284 /* else fall through to normal string handling */
288 if (!InfGetStringField (Context, 5, NULL, 0, &Size))
293 Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
297 InfGetStringField (Context, 5, Str, Size, NULL);
301 if (Type == REG_DWORD)
303 ULONG dw = Str ? wcstol (Str, NULL, 0) : 0;
305 DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
307 NtSetValueKey (KeyHandle,
316 DPRINT("setting value %wZ to %S\n", ValueName, Str);
320 NtSetValueKey (KeyHandle,
325 Size * sizeof(WCHAR));
329 NtSetValueKey (KeyHandle,
337 RtlFreeHeap (ProcessHeap, 0, Str);
339 else /* get the binary data */
343 if (!InfGetBinaryField (Context, 5, NULL, 0, &Size))
348 Data = RtlAllocateHeap (ProcessHeap, 0, Size);
352 DPRINT("setting binary data %wZ len %lu\n", ValueName, Size);
353 InfGetBinaryField (Context, 5, Data, Size, NULL);
356 NtSetValueKey (KeyHandle,
363 RtlFreeHeap (ProcessHeap, 0, Data);
371 CreateNestedKey (PHANDLE KeyHandle,
372 ACCESS_MASK DesiredAccess,
373 POBJECT_ATTRIBUTES ObjectAttributes)
375 OBJECT_ATTRIBUTES LocalObjectAttributes;
376 UNICODE_STRING LocalKeyName;
379 ULONG FullNameLength;
382 HANDLE LocalKeyHandle;
384 Status = NtCreateKey (KeyHandle,
391 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
392 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
395 /* Copy object attributes */
396 RtlCopyMemory (&LocalObjectAttributes,
398 sizeof(OBJECT_ATTRIBUTES));
399 RtlCreateUnicodeString (&LocalKeyName,
400 ObjectAttributes->ObjectName->Buffer);
401 LocalObjectAttributes.ObjectName = &LocalKeyName;
402 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
404 /* Remove the last part of the key name and try to create the key again. */
405 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
407 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
408 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
410 Status = STATUS_UNSUCCESSFUL;
414 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
416 Status = NtCreateKey (&LocalKeyHandle,
418 &LocalObjectAttributes,
423 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
426 if (!NT_SUCCESS(Status))
428 RtlFreeUnicodeString (&LocalKeyName);
432 /* Add removed parts of the key name and create them too. */
433 Length = wcslen (LocalKeyName.Buffer);
436 if (Length == FullNameLength)
438 Status == STATUS_SUCCESS;
439 *KeyHandle = LocalKeyHandle;
442 NtClose (LocalKeyHandle);
444 LocalKeyName.Buffer[Length] = L'\\';
445 Length = wcslen (LocalKeyName.Buffer);
446 LocalKeyName.Length = Length * sizeof(WCHAR);
448 Status = NtCreateKey (&LocalKeyHandle,
450 &LocalObjectAttributes,
455 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
456 if (!NT_SUCCESS(Status))
460 RtlFreeUnicodeString (&LocalKeyName);
466 /***********************************************************************
469 * Called once for each AddReg and DelReg entry in a given section.
472 registry_callback (HINF hInf, PCWSTR Section, BOOLEAN Delete)
474 OBJECT_ATTRIBUTES ObjectAttributes;
475 WCHAR Buffer[MAX_INF_STRING_LENGTH];
477 UNICODE_STRING Value;
478 PUNICODE_STRING ValuePtr;
488 Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
490 for (;Ok; Ok = InfFindNextLine (&Context, &Context))
493 if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
495 if (!GetRootKey (Buffer))
499 Length = wcslen (Buffer);
500 if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
503 DPRINT("KeyName: <%S>\n", Buffer);
506 if (!InfGetIntField (&Context, 4, (PLONG)&Flags))
509 DPRINT("Flags: %lx\n", Flags);
511 RtlInitUnicodeString (&Name,
514 InitializeObjectAttributes (&ObjectAttributes,
516 OBJ_CASE_INSENSITIVE,
520 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
522 Status = NtOpenKey (&KeyHandle,
525 if (!NT_SUCCESS(Status))
527 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
528 continue; /* ignore if it doesn't exist */
533 Status = CreateNestedKey (&KeyHandle,
536 if (!NT_SUCCESS(Status))
538 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
544 if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
546 RtlInitUnicodeString (&Value,
556 if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
570 ImportRegistryFile(PWSTR Filename,
574 WCHAR FileNameBuffer[MAX_PATH];
575 UNICODE_STRING FileName;
580 /* Load inf file from install media. */
581 wcscpy(FileNameBuffer, SourceRootPath.Buffer);
582 wcscat(FileNameBuffer, L"\\reactos\\");
583 wcscat(FileNameBuffer, Filename);
585 RtlInitUnicodeString(&FileName,
588 Status = InfOpenFile(&hInf,
591 if (!NT_SUCCESS(Status))
593 DPRINT1("InfOpenFile() failed (Status %lx)\n", Status);
597 if (!registry_callback (hInf, L"AddReg", FALSE))
599 DPRINT1("registry_callback() failed\n");
609 SetInstallPathValue(PUNICODE_STRING InstallPath)
611 OBJECT_ATTRIBUTES ObjectAttributes;
612 UNICODE_STRING KeyName;
613 UNICODE_STRING ValueName;
617 /* Create the 'secret' InstallPath key */
618 RtlInitUnicodeStringFromLiteral (&KeyName,
619 L"\\Registry\\Machine\\HARDWARE");
620 InitializeObjectAttributes (&ObjectAttributes,
622 OBJ_CASE_INSENSITIVE,
625 Status = NtOpenKey (&KeyHandle,
628 if (!NT_SUCCESS(Status))
630 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
634 RtlInitUnicodeStringFromLiteral (&ValueName,
636 Status = NtSetValueKey (KeyHandle,
640 (PVOID)InstallPath->Buffer,
641 InstallPath->Length);
643 if (!NT_SUCCESS(Status))
645 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);