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: base/setup/usetup/registry.c
23 * PURPOSE: Registry creation functions
27 /* INCLUDES *****************************************************************/
34 #define FLG_ADDREG_BINVALUETYPE 0x00000001
35 #define FLG_ADDREG_NOCLOBBER 0x00000002
36 #define FLG_ADDREG_DELVAL 0x00000004
37 #define FLG_ADDREG_APPEND 0x00000008
38 #define FLG_ADDREG_KEYONLY 0x00000010
39 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
40 #define FLG_ADDREG_TYPE_SZ 0x00000000
41 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
42 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
43 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
44 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
45 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
46 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
49 #define Architecture L"x86"
50 #elif defined(_M_AMD64)
51 #define Architecture L"amd64"
52 #elif defined(_M_IA64)
53 #define Architecture L"ia64"
55 #define Architecture L"arm"
57 #define Architecture L"ppc"
60 /* FUNCTIONS ****************************************************************/
67 if (!_wcsicmp (Name
, L
"HKCR"))
69 wcscpy (Name
, L
"\\Registry\\Machine\\SOFTWARE\\Classes\\");
73 if (!_wcsicmp (Name
, L
"HKCU"))
75 wcscpy (Name
, L
"\\Registry\\User\\.DEFAULT\\");
79 if (!_wcsicmp (Name
, L
"HKLM"))
81 wcscpy (Name
, L
"\\Registry\\Machine\\");
85 if (!_wcsicmp (Name
, L
"HKU"))
87 wcscpy (Name
, L
"\\Registry\\User\\");
92 if (!_wcsicmp (Name
, L
"HKR"))
100 /***********************************************************************
101 * append_multi_sz_value
103 * Append a multisz string to a multisz registry value.
107 append_multi_sz_value (HANDLE hkey
,
109 const WCHAR
*strings
,
112 DWORD size
, type
, total
;
115 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
116 if (type
!= REG_MULTI_SZ
) return;
118 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
119 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
121 /* compare each string against all the existing ones */
125 int len
= strlenW(strings
) + 1;
127 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
128 if (!strcmpiW( p
, strings
)) break;
130 if (!*p
) /* not found, need to append it */
132 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
140 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
141 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
144 HeapFree( GetProcessHeap(), 0, buffer
);
148 /***********************************************************************
149 * delete_multi_sz_value
151 * Remove a string from a multisz registry value.
154 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
157 WCHAR
*buffer
, *src
, *dst
;
159 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
160 if (type
!= REG_MULTI_SZ
) return;
161 /* allocate double the size, one for value before and one for after */
162 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
163 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
168 int len
= strlenW(src
) + 1;
169 if (strcmpiW( src
, string
))
171 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
177 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
179 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
180 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
181 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
184 HeapFree( GetProcessHeap(), 0, buffer
);
188 /***********************************************************************
191 * Perform an add/delete registry operation depending on the flags.
194 do_reg_operation(HANDLE KeyHandle
,
195 PUNICODE_STRING ValueName
,
199 WCHAR EmptyStr
= (WCHAR
)0;
203 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
208 RegDeleteValueW( KeyHandle
, ValueName
);
212 RegDeleteKeyW( KeyHandle
, NULL
);
218 if (Flags
& FLG_ADDREG_KEYONLY
)
222 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
224 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
225 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
227 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
232 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
234 case FLG_ADDREG_TYPE_SZ
:
238 case FLG_ADDREG_TYPE_MULTI_SZ
:
242 case FLG_ADDREG_TYPE_EXPAND_SZ
:
243 Type
= REG_EXPAND_SZ
;
246 case FLG_ADDREG_TYPE_BINARY
:
250 case FLG_ADDREG_TYPE_DWORD
:
254 case FLG_ADDREG_TYPE_NONE
:
263 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
264 (Type
== REG_DWORD
&& SetupGetFieldCount (Context
) == 5))
268 if (Type
== REG_MULTI_SZ
)
270 if (!SetupGetMultiSzFieldW (Context
, 5, NULL
, 0, &Size
))
275 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
279 SetupGetMultiSzFieldW (Context
, 5, Str
, Size
, NULL
);
282 if (Flags
& FLG_ADDREG_APPEND
)
287 // append_multi_sz_value( hkey, value, str, size );
289 RtlFreeHeap (ProcessHeap
, 0, Str
);
292 /* else fall through to normal string handling */
296 if (!SetupGetStringFieldW (Context
, 5, NULL
, 0, &Size
))
301 Str
= (WCHAR
*) RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
305 SetupGetStringFieldW (Context
, 5, Str
, Size
, NULL
);
309 if (Type
== REG_DWORD
)
311 ULONG dw
= Str
? wcstoul (Str
, NULL
, 0) : 0;
313 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
315 NtSetValueKey (KeyHandle
,
324 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
328 NtSetValueKey (KeyHandle
,
333 Size
* sizeof(WCHAR
));
337 NtSetValueKey (KeyHandle
,
345 RtlFreeHeap (ProcessHeap
, 0, Str
);
347 else /* get the binary data */
351 if (!SetupGetBinaryField (Context
, 5, NULL
, 0, &Size
))
356 Data
= (unsigned char*) RtlAllocateHeap (ProcessHeap
, 0, Size
);
360 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
361 SetupGetBinaryField (Context
, 5, Data
, Size
, NULL
);
364 NtSetValueKey (KeyHandle
,
371 RtlFreeHeap (ProcessHeap
, 0, Data
);
378 CreateNestedKey (PHANDLE KeyHandle
,
379 ACCESS_MASK DesiredAccess
,
380 POBJECT_ATTRIBUTES ObjectAttributes
)
382 OBJECT_ATTRIBUTES LocalObjectAttributes
;
383 UNICODE_STRING LocalKeyName
;
386 USHORT FullNameLength
;
388 HANDLE LocalKeyHandle
;
390 Status
= NtCreateKey (KeyHandle
,
397 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
398 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
401 /* Copy object attributes */
402 RtlCopyMemory (&LocalObjectAttributes
,
404 sizeof(OBJECT_ATTRIBUTES
));
405 RtlCreateUnicodeString (&LocalKeyName
,
406 ObjectAttributes
->ObjectName
->Buffer
);
407 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
408 FullNameLength
= LocalKeyName
.Length
;
410 /* Remove the last part of the key name and try to create the key again. */
411 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
413 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
414 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
416 Status
= STATUS_UNSUCCESSFUL
;
420 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
422 Status
= NtCreateKey (&LocalKeyHandle
,
424 &LocalObjectAttributes
,
429 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
432 if (!NT_SUCCESS(Status
))
434 RtlFreeUnicodeString (&LocalKeyName
);
438 /* Add removed parts of the key name and create them too. */
441 if (LocalKeyName
.Length
== FullNameLength
)
443 Status
= STATUS_SUCCESS
;
444 *KeyHandle
= LocalKeyHandle
;
447 NtClose (LocalKeyHandle
);
449 LocalKeyName
.Buffer
[LocalKeyName
.Length
/ sizeof(WCHAR
)] = L
'\\';
450 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
452 Status
= NtCreateKey (&LocalKeyHandle
,
454 &LocalObjectAttributes
,
459 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
460 if (!NT_SUCCESS(Status
))
464 RtlFreeUnicodeString (&LocalKeyName
);
469 /***********************************************************************
472 * Called once for each AddReg and DelReg entry in a given section.
475 registry_callback(HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
477 OBJECT_ATTRIBUTES ObjectAttributes
;
478 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
480 UNICODE_STRING Value
;
481 PUNICODE_STRING ValuePtr
;
491 Ok
= SetupFindFirstLineW (hInf
, Section
, NULL
, &Context
);
495 for (;Ok
; Ok
= SetupFindNextLine (&Context
, &Context
))
498 if (!SetupGetStringFieldW (&Context
, 1, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
500 if (!GetRootKey (Buffer
))
504 Length
= wcslen (Buffer
);
505 if (!SetupGetStringFieldW (&Context
, 2, Buffer
+ Length
, MAX_INF_STRING_LENGTH
- Length
, NULL
))
508 DPRINT("KeyName: <%S>\n", Buffer
);
511 if (!SetupGetIntField (&Context
, 4, (PINT
)&Flags
))
514 DPRINT("Flags: %lx\n", Flags
);
516 RtlInitUnicodeString (&Name
,
519 InitializeObjectAttributes (&ObjectAttributes
,
521 OBJ_CASE_INSENSITIVE
,
525 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
527 Status
= NtOpenKey (&KeyHandle
,
530 if (!NT_SUCCESS(Status
))
532 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
533 continue; /* ignore if it doesn't exist */
538 Status
= CreateNestedKey (&KeyHandle
,
541 if (!NT_SUCCESS(Status
))
543 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
549 if (SetupGetStringFieldW (&Context
, 3, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
551 RtlInitUnicodeString (&Value
,
561 if (!do_reg_operation (KeyHandle
, ValuePtr
, &Context
, Flags
))
582 WCHAR FileNameBuffer
[MAX_PATH
];
586 /* Load inf file from install media. */
587 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
588 SourcePath
.Buffer
, Filename
);
590 hInf
= SetupOpenInfFileW(FileNameBuffer
,
595 if (hInf
== INVALID_HANDLE_VALUE
)
597 DPRINT1("SetupOpenInfFile() failed\n");
601 if (!registry_callback(hInf
, L
"AddReg", FALSE
))
603 DPRINT1("registry_callback() failed\n");
606 if (!registry_callback(hInf
, L
"AddReg.NT" Architecture
, FALSE
))
608 DPRINT1("registry_callback() failed\n");
619 PUNICODE_STRING InstallPath
)
621 OBJECT_ATTRIBUTES ObjectAttributes
;
622 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
623 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
627 /* Create the 'secret' InstallPath key */
628 InitializeObjectAttributes(&ObjectAttributes
,
630 OBJ_CASE_INSENSITIVE
,
633 Status
= NtOpenKey(&KeyHandle
,
636 if (!NT_SUCCESS(Status
))
638 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status
);
642 Status
= NtSetValueKey(KeyHandle
,
646 (PVOID
)InstallPath
->Buffer
,
647 InstallPath
->Length
+ sizeof(WCHAR
));
649 if (!NT_SUCCESS(Status
))
651 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
663 OBJECT_ATTRIBUTES ObjectAttributes
;
664 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
665 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"PagingFiles");
666 WCHAR ValueBuffer
[] = L
"?:\\pagefile.sys 0 0\0";
670 InitializeObjectAttributes(&ObjectAttributes
,
672 OBJ_CASE_INSENSITIVE
,
675 Status
= NtOpenKey(&KeyHandle
,
678 if (!NT_SUCCESS(Status
))
681 ValueBuffer
[0] = Drive
;
683 NtSetValueKey(KeyHandle
,
688 sizeof(ValueBuffer
));