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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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)
51 #define Architecture L"x86"
52 #elif defined(_M_AMD64)
53 #define Architecture L"amd64"
54 #elif defined(_M_IA64)
55 #define Architecture L"ia64"
57 #define Architecture L"arm"
59 #define Architecture L"ppc"
64 typedef struct _REG_DISK_MOUNT_INFO
67 LARGE_INTEGER StartingOffset
;
68 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
72 /* FUNCTIONS ****************************************************************/
79 if (!_wcsicmp (Name
, L
"HKCR"))
81 wcscpy (Name
, L
"\\Registry\\Machine\\SOFTWARE\\Classes\\");
85 if (!_wcsicmp (Name
, L
"HKCU"))
87 wcscpy (Name
, L
"\\Registry\\User\\.DEFAULT\\");
91 if (!_wcsicmp (Name
, L
"HKLM"))
93 wcscpy (Name
, L
"\\Registry\\Machine\\");
97 if (!_wcsicmp (Name
, L
"HKU"))
99 wcscpy (Name
, L
"\\Registry\\User\\");
104 if (!_wcsicmp (Name
, L
"HKR"))
112 /***********************************************************************
113 * append_multi_sz_value
115 * Append a multisz string to a multisz registry value.
119 append_multi_sz_value (HANDLE hkey
,
121 const WCHAR
*strings
,
124 DWORD size
, type
, total
;
127 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
128 if (type
!= REG_MULTI_SZ
) return;
130 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
131 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
133 /* compare each string against all the existing ones */
137 int len
= strlenW(strings
) + 1;
139 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
140 if (!strcmpiW( p
, strings
)) break;
142 if (!*p
) /* not found, need to append it */
144 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
152 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
153 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
156 HeapFree( GetProcessHeap(), 0, buffer
);
160 /***********************************************************************
161 * delete_multi_sz_value
163 * Remove a string from a multisz registry value.
166 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
169 WCHAR
*buffer
, *src
, *dst
;
171 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
172 if (type
!= REG_MULTI_SZ
) return;
173 /* allocate double the size, one for value before and one for after */
174 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
175 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
180 int len
= strlenW(src
) + 1;
181 if (strcmpiW( src
, string
))
183 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
189 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
191 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
192 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
193 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
196 HeapFree( GetProcessHeap(), 0, buffer
);
200 /***********************************************************************
203 * Perform an add/delete registry operation depending on the flags.
206 do_reg_operation(HANDLE KeyHandle
,
207 PUNICODE_STRING ValueName
,
211 WCHAR EmptyStr
= (WCHAR
)0;
215 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
220 RegDeleteValueW( KeyHandle
, ValueName
);
224 RegDeleteKeyW( KeyHandle
, NULL
);
230 if (Flags
& FLG_ADDREG_KEYONLY
)
234 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
236 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
237 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
239 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
244 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
246 case FLG_ADDREG_TYPE_SZ
:
250 case FLG_ADDREG_TYPE_MULTI_SZ
:
254 case FLG_ADDREG_TYPE_EXPAND_SZ
:
255 Type
= REG_EXPAND_SZ
;
258 case FLG_ADDREG_TYPE_BINARY
:
262 case FLG_ADDREG_TYPE_DWORD
:
266 case FLG_ADDREG_TYPE_NONE
:
275 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
276 (Type
== REG_DWORD
&& SetupGetFieldCount (Context
) == 5))
280 if (Type
== REG_MULTI_SZ
)
282 if (!SetupGetMultiSzFieldW (Context
, 5, NULL
, 0, &Size
))
287 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
291 SetupGetMultiSzFieldW (Context
, 5, Str
, Size
, NULL
);
294 if (Flags
& FLG_ADDREG_APPEND
)
299 // append_multi_sz_value( hkey, value, str, size );
301 RtlFreeHeap (ProcessHeap
, 0, Str
);
304 /* else fall through to normal string handling */
308 if (!SetupGetStringFieldW (Context
, 5, NULL
, 0, &Size
))
313 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
317 SetupGetStringFieldW (Context
, 5, Str
, Size
, NULL
);
321 if (Type
== REG_DWORD
)
323 ULONG dw
= Str
? wcstoul (Str
, NULL
, 0) : 0;
325 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
328 NtSetValueKey (KeyHandle
,
335 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)&dw
, sizeof(ULONG
));
340 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
345 NtSetValueKey (KeyHandle
,
350 Size
* sizeof(WCHAR
));
352 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)Str
, Size
* sizeof(WCHAR
));
358 NtSetValueKey (KeyHandle
,
365 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)&EmptyStr
, sizeof(WCHAR
));
369 RtlFreeHeap (ProcessHeap
, 0, Str
);
371 else /* get the binary data */
375 if (!SetupGetBinaryField (Context
, 5, NULL
, 0, &Size
))
380 Data
= (unsigned char*) RtlAllocateHeap (ProcessHeap
, 0, Size
);
384 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
385 SetupGetBinaryField (Context
, 5, Data
, Size
, NULL
);
389 NtSetValueKey (KeyHandle
,
396 RegSetValueExW(KeyHandle
, ValueName
, 0, Type
, (const UCHAR
*)Data
, Size
);
399 RtlFreeHeap (ProcessHeap
, 0, Data
);
407 CreateNestedKey (PHANDLE KeyHandle
,
408 ACCESS_MASK DesiredAccess
,
409 POBJECT_ATTRIBUTES ObjectAttributes
)
411 OBJECT_ATTRIBUTES LocalObjectAttributes
;
412 UNICODE_STRING LocalKeyName
;
415 USHORT FullNameLength
;
417 HANDLE LocalKeyHandle
;
419 Status
= NtCreateKey (KeyHandle
,
426 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
427 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
430 /* Copy object attributes */
431 RtlCopyMemory (&LocalObjectAttributes
,
433 sizeof(OBJECT_ATTRIBUTES
));
434 RtlCreateUnicodeString (&LocalKeyName
,
435 ObjectAttributes
->ObjectName
->Buffer
);
436 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
437 FullNameLength
= LocalKeyName
.Length
;
439 /* Remove the last part of the key name and try to create the key again. */
440 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
442 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
443 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
445 Status
= STATUS_UNSUCCESSFUL
;
449 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
451 Status
= NtCreateKey (&LocalKeyHandle
,
453 &LocalObjectAttributes
,
458 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
461 if (!NT_SUCCESS(Status
))
463 RtlFreeUnicodeString (&LocalKeyName
);
467 /* Add removed parts of the key name and create them too. */
470 if (LocalKeyName
.Length
== FullNameLength
)
472 Status
= STATUS_SUCCESS
;
473 *KeyHandle
= LocalKeyHandle
;
476 NtClose (LocalKeyHandle
);
478 LocalKeyName
.Buffer
[LocalKeyName
.Length
/ sizeof(WCHAR
)] = L
'\\';
479 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
481 Status
= NtCreateKey (&LocalKeyHandle
,
483 &LocalObjectAttributes
,
488 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
489 if (!NT_SUCCESS(Status
))
493 RtlFreeUnicodeString (&LocalKeyName
);
499 /***********************************************************************
502 * Called once for each AddReg and DelReg entry in a given section.
505 registry_callback(HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
507 OBJECT_ATTRIBUTES ObjectAttributes
;
508 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
510 UNICODE_STRING Value
;
511 PUNICODE_STRING ValuePtr
;
521 Ok
= SetupFindFirstLineW (hInf
, Section
, NULL
, &Context
);
525 for (;Ok
; Ok
= SetupFindNextLine (&Context
, &Context
))
528 if (!SetupGetStringFieldW (&Context
, 1, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
530 if (!GetRootKey (Buffer
))
534 Length
= wcslen (Buffer
);
535 if (!SetupGetStringFieldW (&Context
, 2, Buffer
+ Length
, MAX_INF_STRING_LENGTH
- Length
, NULL
))
538 DPRINT("KeyName: <%S>\n", Buffer
);
541 if (!SetupGetIntField (&Context
, 4, (PINT
)&Flags
))
544 DPRINT("Flags: %lx\n", Flags
);
547 RtlInitUnicodeString (&Name
,
550 InitializeObjectAttributes (&ObjectAttributes
,
552 OBJ_CASE_INSENSITIVE
,
556 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
558 Status
= NtOpenKey (&KeyHandle
,
561 if (!NT_SUCCESS(Status
))
563 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
564 continue; /* ignore if it doesn't exist */
569 Status
= CreateNestedKey (&KeyHandle
,
572 if (!NT_SUCCESS(Status
))
574 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
579 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
581 LONG rc
= RegOpenKeyW(NULL
, Buffer
, &KeyHandle
);
582 if (rc
!= ERROR_SUCCESS
)
584 DPRINT("RegOpenKeyW(%S) failed (error %lu)\n", Buffer
, rc
);
585 continue; /* ignore if it doesn't exist */
590 LONG rc
= RegCreateKeyW(NULL
, Buffer
, &KeyHandle
);
591 if (rc
!= ERROR_SUCCESS
)
593 DPRINT("RegCreateKeyW(%S) failed (error %lu)\n", Buffer
, rc
);
600 if (SetupGetStringFieldW (&Context
, 3, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
602 RtlInitUnicodeString (&Value
,
612 if (!do_reg_operation (KeyHandle
, ValuePtr
, &Context
, Flags
))
635 WCHAR FileNameBuffer
[MAX_PATH
];
639 /* Load inf file from install media. */
640 wcscpy(FileNameBuffer
, SourcePath
.Buffer
);
641 wcscat(FileNameBuffer
, L
"\\");
642 wcscat(FileNameBuffer
, Filename
);
644 hInf
= SetupOpenInfFileW(FileNameBuffer
,
649 if (hInf
== INVALID_HANDLE_VALUE
)
651 DPRINT1("SetupOpenInfFile() failed\n");
655 if (!registry_callback(hInf
, L
"AddReg", FALSE
))
657 DPRINT1("registry_callback() failed\n");
660 if (!registry_callback(hInf
, L
"AddReg.NT" Architecture
, FALSE
))
662 DPRINT1("registry_callback() failed\n");
673 PUNICODE_STRING InstallPath
)
675 OBJECT_ATTRIBUTES ObjectAttributes
;
676 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
677 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
681 /* Create the 'secret' InstallPath key */
682 InitializeObjectAttributes(&ObjectAttributes
,
684 OBJ_CASE_INSENSITIVE
,
687 Status
= NtOpenKey(&KeyHandle
,
690 if (!NT_SUCCESS(Status
))
692 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status
);
696 Status
= NtSetValueKey(KeyHandle
,
700 (PVOID
)InstallPath
->Buffer
,
701 InstallPath
->Length
+ sizeof(WCHAR
));
703 if (!NT_SUCCESS(Status
))
705 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
714 SetMountedDeviceValue(
717 LARGE_INTEGER StartingOffset
)
719 OBJECT_ATTRIBUTES ObjectAttributes
;
720 WCHAR ValueNameBuffer
[16];
721 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
722 UNICODE_STRING ValueName
;
723 REG_DISK_MOUNT_INFO MountInfo
;
727 swprintf(ValueNameBuffer
, L
"\\DosDevices\\%C:", Letter
);
728 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
730 InitializeObjectAttributes(&ObjectAttributes
,
732 OBJ_CASE_INSENSITIVE
,
735 Status
= NtOpenKey(&KeyHandle
,
738 if (!NT_SUCCESS(Status
))
740 Status
= NtCreateKey(&KeyHandle
,
745 REG_OPTION_NON_VOLATILE
,
749 if (!NT_SUCCESS(Status
))
751 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
755 MountInfo
.Signature
= Signature
;
756 MountInfo
.StartingOffset
= StartingOffset
;
757 Status
= NtSetValueKey(KeyHandle
,
764 if (!NT_SUCCESS(Status
))
766 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
778 OBJECT_ATTRIBUTES ObjectAttributes
;
779 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
780 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"PagingFiles");
781 WCHAR ValueBuffer
[] = L
"?:\\pagefile.sys 0 0\0";
785 InitializeObjectAttributes(&ObjectAttributes
,
787 OBJ_CASE_INSENSITIVE
,
790 Status
= NtOpenKey(&KeyHandle
,
793 if (!NT_SUCCESS(Status
))
796 ValueBuffer
[0] = Drive
;
798 NtSetValueKey(KeyHandle
,
803 sizeof(ValueBuffer
));