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 *****************************************************************/
35 #define FLG_ADDREG_BINVALUETYPE 0x00000001
36 #define FLG_ADDREG_NOCLOBBER 0x00000002
37 #define FLG_ADDREG_DELVAL 0x00000004
38 #define FLG_ADDREG_APPEND 0x00000008
39 #define FLG_ADDREG_KEYONLY 0x00000010
40 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
41 #define FLG_ADDREG_TYPE_SZ 0x00000000
42 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
43 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
44 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
45 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
46 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
47 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
52 typedef struct _REG_DISK_MOUNT_INFO
55 LARGE_INTEGER StartingOffset
;
56 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
60 /* FUNCTIONS ****************************************************************/
63 GetRootKey (PWCHAR Name
)
65 if (!_wcsicmp (Name
, L
"HKCR"))
67 wcscpy (Name
, L
"\\Registry\\Machine\\SOFTWARE\\Classes\\");
71 if (!_wcsicmp (Name
, L
"HKCU"))
73 wcscpy (Name
, L
"\\Registry\\User\\.DEFAULT\\");
77 if (!_wcsicmp (Name
, L
"HKLM"))
79 wcscpy (Name
, L
"\\Registry\\Machine\\");
83 if (!_wcsicmp (Name
, L
"HKU"))
85 wcscpy (Name
, L
"\\Registry\\User\\");
90 if (!_wcsicmp (Name
, L
"HKR"))
98 /***********************************************************************
99 * append_multi_sz_value
101 * Append a multisz string to a multisz registry value.
105 append_multi_sz_value (HANDLE hkey
,
107 const WCHAR
*strings
,
110 DWORD size
, type
, total
;
113 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
114 if (type
!= REG_MULTI_SZ
) return;
116 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
117 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
119 /* compare each string against all the existing ones */
123 int len
= strlenW(strings
) + 1;
125 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
126 if (!strcmpiW( p
, strings
)) break;
128 if (!*p
) /* not found, need to append it */
130 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
138 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
139 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
142 HeapFree( GetProcessHeap(), 0, buffer
);
146 /***********************************************************************
147 * delete_multi_sz_value
149 * Remove a string from a multisz registry value.
152 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
155 WCHAR
*buffer
, *src
, *dst
;
157 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
158 if (type
!= REG_MULTI_SZ
) return;
159 /* allocate double the size, one for value before and one for after */
160 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
161 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
166 int len
= strlenW(src
) + 1;
167 if (strcmpiW( src
, string
))
169 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
175 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
177 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
178 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
179 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
182 HeapFree( GetProcessHeap(), 0, buffer
);
186 /***********************************************************************
189 * Perform an add/delete registry operation depending on the flags.
192 do_reg_operation(HANDLE KeyHandle
,
193 PUNICODE_STRING ValueName
,
197 WCHAR EmptyStr
= (WCHAR
)0;
201 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
206 RegDeleteValueW( KeyHandle
, ValueName
);
210 RegDeleteKeyW( KeyHandle
, NULL
);
216 if (Flags
& FLG_ADDREG_KEYONLY
)
220 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
222 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
223 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
225 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
230 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
232 case FLG_ADDREG_TYPE_SZ
:
236 case FLG_ADDREG_TYPE_MULTI_SZ
:
240 case FLG_ADDREG_TYPE_EXPAND_SZ
:
241 Type
= REG_EXPAND_SZ
;
244 case FLG_ADDREG_TYPE_BINARY
:
248 case FLG_ADDREG_TYPE_DWORD
:
252 case FLG_ADDREG_TYPE_NONE
:
261 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
262 (Type
== REG_DWORD
&& SetupGetFieldCount (Context
) == 5))
266 if (Type
== REG_MULTI_SZ
)
268 if (!SetupGetMultiSzFieldW (Context
, 5, NULL
, 0, &Size
))
273 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
277 SetupGetMultiSzFieldW (Context
, 5, Str
, Size
, NULL
);
280 if (Flags
& FLG_ADDREG_APPEND
)
285 // append_multi_sz_value( hkey, value, str, size );
287 RtlFreeHeap (ProcessHeap
, 0, Str
);
290 /* else fall through to normal string handling */
294 if (!SetupGetStringFieldW (Context
, 5, NULL
, 0, &Size
))
299 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
303 SetupGetStringFieldW (Context
, 5, Str
, Size
, NULL
);
307 if (Type
== REG_DWORD
)
309 ULONG dw
= Str
? wcstol (Str
, NULL
, 0) : 0;
311 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
314 NtSetValueKey (KeyHandle
,
321 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)&dw
, sizeof(ULONG
));
326 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
331 NtSetValueKey (KeyHandle
,
336 Size
* sizeof(WCHAR
));
338 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)Str
, Size
* sizeof(WCHAR
));
344 NtSetValueKey (KeyHandle
,
351 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)&EmptyStr
, sizeof(WCHAR
));
355 RtlFreeHeap (ProcessHeap
, 0, Str
);
357 else /* get the binary data */
361 if (!SetupGetBinaryField (Context
, 5, NULL
, 0, &Size
))
366 Data
= (unsigned char*) RtlAllocateHeap (ProcessHeap
, 0, Size
);
370 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
371 SetupGetBinaryField (Context
, 5, Data
, Size
, NULL
);
375 NtSetValueKey (KeyHandle
,
382 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)Data
, Size
);
385 RtlFreeHeap (ProcessHeap
, 0, Data
);
393 CreateNestedKey (PHANDLE KeyHandle
,
394 ACCESS_MASK DesiredAccess
,
395 POBJECT_ATTRIBUTES ObjectAttributes
)
397 OBJECT_ATTRIBUTES LocalObjectAttributes
;
398 UNICODE_STRING LocalKeyName
;
401 ULONG FullNameLength
;
404 HANDLE LocalKeyHandle
;
406 Status
= NtCreateKey (KeyHandle
,
413 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
414 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
417 /* Copy object attributes */
418 RtlCopyMemory (&LocalObjectAttributes
,
420 sizeof(OBJECT_ATTRIBUTES
));
421 RtlCreateUnicodeString (&LocalKeyName
,
422 ObjectAttributes
->ObjectName
->Buffer
);
423 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
424 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
426 /* Remove the last part of the key name and try to create the key again. */
427 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
429 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
430 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
432 Status
= STATUS_UNSUCCESSFUL
;
436 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
438 Status
= NtCreateKey (&LocalKeyHandle
,
440 &LocalObjectAttributes
,
445 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
448 if (!NT_SUCCESS(Status
))
450 RtlFreeUnicodeString (&LocalKeyName
);
454 /* Add removed parts of the key name and create them too. */
455 Length
= wcslen (LocalKeyName
.Buffer
);
458 if (Length
== FullNameLength
)
460 Status
= STATUS_SUCCESS
;
461 *KeyHandle
= LocalKeyHandle
;
464 NtClose (LocalKeyHandle
);
466 LocalKeyName
.Buffer
[Length
] = L
'\\';
467 Length
= wcslen (LocalKeyName
.Buffer
);
468 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
470 Status
= NtCreateKey (&LocalKeyHandle
,
472 &LocalObjectAttributes
,
477 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
478 if (!NT_SUCCESS(Status
))
482 RtlFreeUnicodeString (&LocalKeyName
);
488 /***********************************************************************
491 * Called once for each AddReg and DelReg entry in a given section.
494 registry_callback (HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
496 OBJECT_ATTRIBUTES ObjectAttributes
;
497 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
499 UNICODE_STRING Value
;
500 PUNICODE_STRING ValuePtr
;
510 Ok
= SetupFindFirstLineW (hInf
, Section
, NULL
, &Context
);
514 for (;Ok
; Ok
= SetupFindNextLine (&Context
, &Context
))
517 if (!SetupGetStringFieldW (&Context
, 1, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
519 if (!GetRootKey (Buffer
))
523 Length
= wcslen (Buffer
);
524 if (!SetupGetStringFieldW (&Context
, 2, Buffer
+ Length
, MAX_INF_STRING_LENGTH
- Length
, NULL
))
527 DPRINT("KeyName: <%S>\n", Buffer
);
530 if (!SetupGetIntField (&Context
, 4, (PINT
)&Flags
))
533 DPRINT("Flags: %lx\n", Flags
);
536 RtlInitUnicodeString (&Name
,
539 InitializeObjectAttributes (&ObjectAttributes
,
541 OBJ_CASE_INSENSITIVE
,
545 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
547 Status
= NtOpenKey (&KeyHandle
,
550 if (!NT_SUCCESS(Status
))
552 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
553 continue; /* ignore if it doesn't exist */
558 Status
= CreateNestedKey (&KeyHandle
,
561 if (!NT_SUCCESS(Status
))
563 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
568 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
570 LONG rc
= RegOpenKeyW(NULL
, Buffer
, &KeyHandle
);
571 if (rc
!= ERROR_SUCCESS
)
573 DPRINT("RegOpenKeyW(%S) failed (error %lu)\n", Buffer
, rc
);
574 continue; /* ignore if it doesn't exist */
579 LONG rc
= RegCreateKeyW(NULL
, Buffer
, &KeyHandle
);
580 if (rc
!= ERROR_SUCCESS
)
582 DPRINT("RegCreateKeyW(%S) failed (error %lu)\n", Buffer
, rc
);
589 if (SetupGetStringFieldW (&Context
, 3, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
591 RtlInitUnicodeString (&Value
,
601 if (!do_reg_operation (KeyHandle
, ValuePtr
, &Context
, Flags
))
618 ImportRegistryFile(PWSTR Filename
,
622 WCHAR FileNameBuffer
[MAX_PATH
];
626 /* Load inf file from install media. */
627 wcscpy(FileNameBuffer
, SourcePath
.Buffer
);
628 wcscat(FileNameBuffer
, L
"\\");
629 wcscat(FileNameBuffer
, Filename
);
631 hInf
= SetupOpenInfFileW(
636 if (hInf
== INVALID_HANDLE_VALUE
)
638 DPRINT1("SetupOpenInfFile() failed\n");
642 if (!registry_callback (hInf
, L
"AddReg", FALSE
))
644 DPRINT1("registry_callback() failed\n");
647 SetupCloseInfFile (hInf
);
654 SetInstallPathValue(PUNICODE_STRING InstallPath
)
656 OBJECT_ATTRIBUTES ObjectAttributes
;
657 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
658 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
662 /* Create the 'secret' InstallPath key */
663 InitializeObjectAttributes (&ObjectAttributes
,
665 OBJ_CASE_INSENSITIVE
,
668 Status
= NtOpenKey (&KeyHandle
,
671 if (!NT_SUCCESS(Status
))
673 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status
);
677 Status
= NtSetValueKey (KeyHandle
,
681 (PVOID
)InstallPath
->Buffer
,
682 InstallPath
->Length
);
684 if (!NT_SUCCESS(Status
))
686 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
694 SetMountedDeviceValue(CHAR Letter
, ULONG Signature
, LARGE_INTEGER StartingOffset
)
696 OBJECT_ATTRIBUTES ObjectAttributes
;
697 WCHAR ValueNameBuffer
[16];
698 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
699 UNICODE_STRING ValueName
;
700 REG_DISK_MOUNT_INFO MountInfo
;
704 swprintf(ValueNameBuffer
, L
"\\DosDevices\\%C:", Letter
);
705 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
707 InitializeObjectAttributes (&ObjectAttributes
,
709 OBJ_CASE_INSENSITIVE
,
712 Status
= NtOpenKey (&KeyHandle
,
715 if (!NT_SUCCESS(Status
))
717 Status
= NtCreateKey(&KeyHandle
,
722 REG_OPTION_NON_VOLATILE
,
726 if (!NT_SUCCESS(Status
))
728 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
732 MountInfo
.Signature
= Signature
;
733 MountInfo
.StartingOffset
= StartingOffset
;
734 Status
= NtSetValueKey (KeyHandle
,
741 if (!NT_SUCCESS(Status
))
743 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);