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_DELREG_BIT 0x00008000
39 #define FLG_ADDREG_BINVALUETYPE 0x00000001
40 #define FLG_ADDREG_NOCLOBBER 0x00000002
41 #define FLG_ADDREG_DELVAL 0x00000004
42 #define FLG_ADDREG_APPEND 0x00000008
43 #define FLG_ADDREG_KEYONLY 0x00000010
44 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
45 #define FLG_ADDREG_64BITKEY 0x00001000
46 #define FLG_ADDREG_KEYONLY_COMMON 0x00002000
47 #define FLG_ADDREG_32BITKEY 0x00004000
48 #define FLG_ADDREG_TYPE_SZ 0x00000000
49 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
50 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
51 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
52 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
53 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
54 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
56 #define FLG_DELREG_VALUE (0x00000000)
57 #define FLG_DELREG_TYPE_MASK FLG_ADDREG_TYPE_MASK
58 #define FLG_DELREG_TYPE_SZ FLG_ADDREG_TYPE_SZ
59 #define FLG_DELREG_TYPE_MULTI_SZ FLG_ADDREG_TYPE_MULTI_SZ
60 #define FLG_DELREG_TYPE_EXPAND_SZ FLG_ADDREG_TYPE_EXPAND_SZ
61 #define FLG_DELREG_TYPE_BINARY FLG_ADDREG_TYPE_BINARY
62 #define FLG_DELREG_TYPE_DWORD FLG_ADDREG_TYPE_DWORD
63 #define FLG_DELREG_TYPE_NONE FLG_ADDREG_TYPE_NONE
64 #define FLG_DELREG_64BITKEY FLG_ADDREG_64BITKEY
65 #define FLG_DELREG_KEYONLY_COMMON FLG_ADDREG_KEYONLY_COMMON
66 #define FLG_DELREG_32BITKEY FLG_ADDREG_32BITKEY
67 #define FLG_DELREG_OPERATION_MASK (0x000000FE)
68 #define FLG_DELREG_MULTI_SZ_DELSTRING (FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT | 0x00000002)
71 /* FUNCTIONS ****************************************************************/
75 GetRootKey (PWCHAR Name
)
77 if (!_wcsicmp (Name
, L
"HKCR"))
79 wcscpy (Name
, L
"\\Registry\\Machine\\SOFTWARE\\Classes\\");
83 if (!_wcsicmp (Name
, L
"HKCU"))
85 wcscpy (Name
, L
"\\Registry\\User\\.DEFAULT\\");
89 if (!_wcsicmp (Name
, L
"HKLM"))
91 wcscpy (Name
, L
"\\Registry\\Machine\\");
95 if (!_wcsicmp (Name
, L
"HKU"))
97 wcscpy (Name
, L
"\\Registry\\User\\");
102 if (!_wcsicmp (Name
, L
"HKR"))
110 /***********************************************************************
111 * append_multi_sz_value
113 * Append a multisz string to a multisz registry value.
117 append_multi_sz_value (HANDLE hkey
,
119 const WCHAR
*strings
,
122 DWORD size
, type
, total
;
125 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
126 if (type
!= REG_MULTI_SZ
) return;
128 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
129 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
131 /* compare each string against all the existing ones */
135 int len
= strlenW(strings
) + 1;
137 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
138 if (!strcmpiW( p
, strings
)) break;
140 if (!*p
) /* not found, need to append it */
142 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
150 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
151 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
154 HeapFree( GetProcessHeap(), 0, buffer
);
158 /***********************************************************************
159 * delete_multi_sz_value
161 * Remove a string from a multisz registry value.
164 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
167 WCHAR
*buffer
, *src
, *dst
;
169 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
170 if (type
!= REG_MULTI_SZ
) return;
171 /* allocate double the size, one for value before and one for after */
172 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
173 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
178 int len
= strlenW(src
) + 1;
179 if (strcmpiW( src
, string
))
181 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
187 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
189 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
190 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
191 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
194 HeapFree( GetProcessHeap(), 0, buffer
);
198 /***********************************************************************
201 * Perform an add/delete registry operation depending on the flags.
204 do_reg_operation(HANDLE KeyHandle
,
205 PUNICODE_STRING ValueName
,
209 WCHAR EmptyStr
= (WCHAR
)0;
213 if (Flags
& (FLG_ADDREG_DELREG_BIT
| FLG_ADDREG_DELVAL
)) /* deletion */
216 if (ValueName
&& !(flags
& FLG_DELREG_KEYONLY_COMMON
))
218 if ((Flags
& FLG_DELREG_MULTI_SZ_DELSTRING
) == FLG_DELREG_MULTI_SZ_DELSTRING
)
222 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
) || !size
) return TRUE
;
223 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
224 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
225 delete_multi_sz_value( hkey
, value
, str
);
226 HeapFree( GetProcessHeap(), 0, str
);
230 RegDeleteValueW( hkey
, value
);
235 RegDeleteKeyW( hkey
, NULL
);
241 if (Flags
& (FLG_ADDREG_KEYONLY
| FLG_ADDREG_KEYONLY_COMMON
))
245 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
247 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
248 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
250 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
255 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
257 case FLG_ADDREG_TYPE_SZ
:
261 case FLG_ADDREG_TYPE_MULTI_SZ
:
265 case FLG_ADDREG_TYPE_EXPAND_SZ
:
266 Type
= REG_EXPAND_SZ
;
269 case FLG_ADDREG_TYPE_BINARY
:
273 case FLG_ADDREG_TYPE_DWORD
:
277 case FLG_ADDREG_TYPE_NONE
:
286 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
287 (Type
== REG_DWORD
&& InfGetFieldCount (Context
) == 5))
291 if (Type
== REG_MULTI_SZ
)
293 if (!InfGetMultiSzField (Context
, 5, NULL
, 0, &Size
))
298 Str
= RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
302 InfGetMultiSzField (Context
, 5, Str
, Size
, NULL
);
305 if (Flags
& FLG_ADDREG_APPEND
)
310 // append_multi_sz_value( hkey, value, str, size );
312 RtlFreeHeap (ProcessHeap
, 0, Str
);
315 /* else fall through to normal string handling */
319 if (!InfGetStringField (Context
, 5, NULL
, 0, &Size
))
324 Str
= RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
328 InfGetStringField (Context
, 5, Str
, Size
, NULL
);
332 if (Type
== REG_DWORD
)
334 ULONG dw
= Str
? wcstol (Str
, NULL
, 16) : 0;
336 DPRINT1("setting dword %wZ to %lx\n", &ValueName
, dw
);
338 NtSetValueKey (KeyHandle
,
347 DPRINT1("setting value %wZ to %S\n", ValueName
, Str
);
350 NtSetValueKey (KeyHandle
,
355 Size
* sizeof(WCHAR
));
359 NtSetValueKey (KeyHandle
,
367 RtlFreeHeap (ProcessHeap
, 0, Str
);
369 else /* get the binary data */
373 if (!InfGetBinaryField (Context
, 5, NULL
, 0, &Size
))
378 Data
= RtlAllocateHeap (ProcessHeap
, 0, Size
);
382 DPRINT1("setting binary data %wZ len %lu\n", ValueName
, Size
);
383 InfGetBinaryField (Context
, 5, Data
, Size
, NULL
);
386 NtSetValueKey (KeyHandle
,
393 RtlFreeHeap (ProcessHeap
, 0, Data
);
403 CreateNestedKey (PHANDLE KeyHandle
,
404 ACCESS_MASK DesiredAccess
,
405 POBJECT_ATTRIBUTES ObjectAttributes
)
407 OBJECT_ATTRIBUTES LocalObjectAttributes
;
408 UNICODE_STRING LocalKeyName
;
411 ULONG FullNameLength
;
414 HANDLE LocalKeyHandle
;
416 Status
= NtCreateKey (KeyHandle
,
423 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
424 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
427 /* Copy object attributes */
428 RtlCopyMemory (&LocalObjectAttributes
,
430 sizeof(OBJECT_ATTRIBUTES
));
431 RtlCreateUnicodeString (&LocalKeyName
,
432 ObjectAttributes
->ObjectName
->Buffer
);
433 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
434 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
436 /* Remove the last part of the key name and try to create the key again. */
437 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
439 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
440 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
442 Status
= STATUS_UNSUCCESSFUL
;
446 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
448 Status
= NtCreateKey (&LocalKeyHandle
,
450 &LocalObjectAttributes
,
455 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
458 if (!NT_SUCCESS(Status
))
460 RtlFreeUnicodeString (&LocalKeyName
);
464 /* Add removed parts of the key name and create them too. */
465 Length
= wcslen (LocalKeyName
.Buffer
);
468 if (Length
== FullNameLength
)
470 Status
== STATUS_SUCCESS
;
471 *KeyHandle
= LocalKeyHandle
;
474 NtClose (LocalKeyHandle
);
476 LocalKeyName
.Buffer
[Length
] = L
'\\';
477 Length
= wcslen (LocalKeyName
.Buffer
);
478 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
480 Status
= NtCreateKey (&LocalKeyHandle
,
482 &LocalObjectAttributes
,
487 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
488 if (!NT_SUCCESS(Status
))
492 RtlFreeUnicodeString (&LocalKeyName
);
498 /***********************************************************************
501 * Called once for each AddReg and DelReg entry in a given section.
504 registry_callback (HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
506 OBJECT_ATTRIBUTES ObjectAttributes
;
507 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
509 UNICODE_STRING Value
;
510 PUNICODE_STRING ValuePtr
;
520 Ok
= InfFindFirstLine (hInf
, Section
, NULL
, &Context
);
522 for (;Ok
; Ok
= InfFindNextLine (&Context
, &Context
))
525 if (!InfGetStringField (&Context
, 1, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
527 if (!GetRootKey (Buffer
))
531 Length
= wcslen (Buffer
);
532 if (!InfGetStringField (&Context
, 2, Buffer
+ Length
, MAX_INF_STRING_LENGTH
- Length
, NULL
))
535 DPRINT1("KeyName: <%S>\n", Buffer
);
538 if (!InfGetIntField (&Context
, 4, (PLONG
)&Flags
))
541 DPRINT1("Flags: %lx\n", Flags
);
545 if (Flags
& FLG_ADDREG_DELREG_BIT
)
546 continue; /* ignore this entry */
551 Flags
= FLG_ADDREG_DELREG_BIT
;
552 else if (!(Flags
& FLG_ADDREG_DELREG_BIT
))
553 continue; /* ignore this entry */
556 RtlInitUnicodeString (&Name
,
559 InitializeObjectAttributes (&ObjectAttributes
,
561 OBJ_CASE_INSENSITIVE
,
565 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
567 Status
= NtOpenKey (&KeyHandle
,
570 if (!NT_SUCCESS(Status
))
572 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
573 continue; /* ignore if it doesn't exist */
578 Status
= CreateNestedKey (&KeyHandle
,
581 if (!NT_SUCCESS(Status
))
583 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
589 if (InfGetStringField (&Context
, 3, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
591 RtlInitUnicodeString (&Value
,
601 if (!do_reg_operation (KeyHandle
, ValuePtr
, &Context
, Flags
))
615 ImportRegistryData(PWSTR Filename
)
617 WCHAR FileNameBuffer
[MAX_PATH
];
618 UNICODE_STRING FileName
;
623 /* Load inf file from install media. */
624 wcscpy(FileNameBuffer
, SourceRootPath
.Buffer
);
625 wcscat(FileNameBuffer
, L
"\\install\\");
626 wcscat(FileNameBuffer
, Filename
);
628 RtlInitUnicodeString(&FileName
,
631 Status
= InfOpenFile(&hInf
,
634 if (!NT_SUCCESS(Status
))
636 DPRINT1("InfOpenFile() failed (Status %lx)\n", Status
);
640 if (!registry_callback (hInf
, L
"AddReg", FALSE
))
642 DPRINT1("registry_callback() failed\n");
652 SetupUpdateRegistry(VOID
)
654 OBJECT_ATTRIBUTES ObjectAttributes
;
655 UNICODE_STRING KeyName
;
656 UNICODE_STRING ValueName
;
660 RtlInitUnicodeStringFromLiteral(&KeyName
,
661 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control");
662 InitializeObjectAttributes(&ObjectAttributes
,
664 OBJ_CASE_INSENSITIVE
,
667 Status
= NtCreateKey(&KeyHandle
,
672 REG_OPTION_NON_VOLATILE
,
674 if (!NT_SUCCESS(Status
))
676 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
683 /* Create '\Registry\Machine\System\Setup' key */
684 RtlInitUnicodeStringFromLiteral(&KeyName
,
685 L
"\\Registry\\Machine\\SYSTEM\\Setup");
686 InitializeObjectAttributes(&ObjectAttributes
,
688 OBJ_CASE_INSENSITIVE
,
691 Status
= NtCreateKey(&KeyHandle
,
696 REG_OPTION_NON_VOLATILE
,
698 if (!NT_SUCCESS(Status
))
700 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
703 /* FIXME: Create value 'SetupType' */
705 /* FIXME: Create value 'SystemSetupInProgress' */
711 SetStatusText(" Importing hivesys.inf...");
713 if (!ImportRegistryData (L
"hivesys.inf"))
715 DPRINT1("ImportRegistryData (\"hivesys.inf\") failed\n");
718 SetStatusText(" Done...");
720 return STATUS_SUCCESS
;