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 *****************************************************************/
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 /* FUNCTIONS ****************************************************************/
52 GetRootKey (PWCHAR Name
)
54 if (!_wcsicmp (Name
, L
"HKCR"))
56 wcscpy (Name
, L
"\\Registry\\Machine\\SOFTWARE\\Classes\\");
60 if (!_wcsicmp (Name
, L
"HKCU"))
62 wcscpy (Name
, L
"\\Registry\\User\\.DEFAULT\\");
66 if (!_wcsicmp (Name
, L
"HKLM"))
68 wcscpy (Name
, L
"\\Registry\\Machine\\");
72 if (!_wcsicmp (Name
, L
"HKU"))
74 wcscpy (Name
, L
"\\Registry\\User\\");
79 if (!_wcsicmp (Name
, L
"HKR"))
87 /***********************************************************************
88 * append_multi_sz_value
90 * Append a multisz string to a multisz registry value.
94 append_multi_sz_value (HANDLE hkey
,
99 DWORD size
, type
, total
;
102 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
103 if (type
!= REG_MULTI_SZ
) return;
105 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
106 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
108 /* compare each string against all the existing ones */
112 int len
= strlenW(strings
) + 1;
114 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
115 if (!strcmpiW( p
, strings
)) break;
117 if (!*p
) /* not found, need to append it */
119 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
127 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
128 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
131 HeapFree( GetProcessHeap(), 0, buffer
);
135 /***********************************************************************
136 * delete_multi_sz_value
138 * Remove a string from a multisz registry value.
141 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
144 WCHAR
*buffer
, *src
, *dst
;
146 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
147 if (type
!= REG_MULTI_SZ
) return;
148 /* allocate double the size, one for value before and one for after */
149 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
150 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
155 int len
= strlenW(src
) + 1;
156 if (strcmpiW( src
, string
))
158 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
164 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
166 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
167 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
168 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
171 HeapFree( GetProcessHeap(), 0, buffer
);
175 /***********************************************************************
178 * Perform an add/delete registry operation depending on the flags.
181 do_reg_operation(HANDLE KeyHandle
,
182 PUNICODE_STRING ValueName
,
186 WCHAR EmptyStr
= (WCHAR
)0;
190 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
195 RegDeleteValueW( hkey
, value
);
199 RegDeleteKeyW( hkey
, NULL
);
205 if (Flags
& FLG_ADDREG_KEYONLY
)
209 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
211 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
212 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
214 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
219 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
221 case FLG_ADDREG_TYPE_SZ
:
225 case FLG_ADDREG_TYPE_MULTI_SZ
:
229 case FLG_ADDREG_TYPE_EXPAND_SZ
:
230 Type
= REG_EXPAND_SZ
;
233 case FLG_ADDREG_TYPE_BINARY
:
237 case FLG_ADDREG_TYPE_DWORD
:
241 case FLG_ADDREG_TYPE_NONE
:
250 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
251 (Type
== REG_DWORD
&& InfGetFieldCount (Context
) == 5))
255 if (Type
== REG_MULTI_SZ
)
257 if (!InfGetMultiSzField (Context
, 5, NULL
, 0, &Size
))
262 Str
= RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
266 InfGetMultiSzField (Context
, 5, Str
, Size
, NULL
);
269 if (Flags
& FLG_ADDREG_APPEND
)
274 // append_multi_sz_value( hkey, value, str, size );
276 RtlFreeHeap (ProcessHeap
, 0, Str
);
279 /* else fall through to normal string handling */
283 if (!InfGetStringField (Context
, 5, NULL
, 0, &Size
))
288 Str
= RtlAllocateHeap (ProcessHeap
, 0, Size
* sizeof(WCHAR
));
292 InfGetStringField (Context
, 5, Str
, Size
, NULL
);
296 if (Type
== REG_DWORD
)
298 ULONG dw
= Str
? wcstol (Str
, NULL
, 0) : 0;
300 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
302 NtSetValueKey (KeyHandle
,
311 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
315 NtSetValueKey (KeyHandle
,
320 Size
* sizeof(WCHAR
));
324 NtSetValueKey (KeyHandle
,
332 RtlFreeHeap (ProcessHeap
, 0, Str
);
334 else /* get the binary data */
338 if (!InfGetBinaryField (Context
, 5, NULL
, 0, &Size
))
343 Data
= RtlAllocateHeap (ProcessHeap
, 0, Size
);
347 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
348 InfGetBinaryField (Context
, 5, Data
, Size
, NULL
);
351 NtSetValueKey (KeyHandle
,
358 RtlFreeHeap (ProcessHeap
, 0, Data
);
366 CreateNestedKey (PHANDLE KeyHandle
,
367 ACCESS_MASK DesiredAccess
,
368 POBJECT_ATTRIBUTES ObjectAttributes
)
370 OBJECT_ATTRIBUTES LocalObjectAttributes
;
371 UNICODE_STRING LocalKeyName
;
374 ULONG FullNameLength
;
377 HANDLE LocalKeyHandle
;
379 Status
= NtCreateKey (KeyHandle
,
386 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
387 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
390 /* Copy object attributes */
391 RtlCopyMemory (&LocalObjectAttributes
,
393 sizeof(OBJECT_ATTRIBUTES
));
394 RtlCreateUnicodeString (&LocalKeyName
,
395 ObjectAttributes
->ObjectName
->Buffer
);
396 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
397 FullNameLength
= LocalKeyName
.Length
/ sizeof(WCHAR
);
399 /* Remove the last part of the key name and try to create the key again. */
400 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
402 Ptr
= wcsrchr (LocalKeyName
.Buffer
, '\\');
403 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
405 Status
= STATUS_UNSUCCESSFUL
;
409 LocalKeyName
.Length
= wcslen (LocalKeyName
.Buffer
) * sizeof(WCHAR
);
411 Status
= NtCreateKey (&LocalKeyHandle
,
413 &LocalObjectAttributes
,
418 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
421 if (!NT_SUCCESS(Status
))
423 RtlFreeUnicodeString (&LocalKeyName
);
427 /* Add removed parts of the key name and create them too. */
428 Length
= wcslen (LocalKeyName
.Buffer
);
431 if (Length
== FullNameLength
)
433 Status
= STATUS_SUCCESS
;
434 *KeyHandle
= LocalKeyHandle
;
437 NtClose (LocalKeyHandle
);
439 LocalKeyName
.Buffer
[Length
] = L
'\\';
440 Length
= wcslen (LocalKeyName
.Buffer
);
441 LocalKeyName
.Length
= Length
* sizeof(WCHAR
);
443 Status
= NtCreateKey (&LocalKeyHandle
,
445 &LocalObjectAttributes
,
450 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
451 if (!NT_SUCCESS(Status
))
455 RtlFreeUnicodeString (&LocalKeyName
);
461 /***********************************************************************
464 * Called once for each AddReg and DelReg entry in a given section.
467 registry_callback (HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
469 OBJECT_ATTRIBUTES ObjectAttributes
;
470 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
472 UNICODE_STRING Value
;
473 PUNICODE_STRING ValuePtr
;
483 Ok
= InfFindFirstLine (hInf
, Section
, NULL
, &Context
);
485 for (;Ok
; Ok
= InfFindNextLine (&Context
, &Context
))
488 if (!InfGetStringField (&Context
, 1, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
490 if (!GetRootKey (Buffer
))
494 Length
= wcslen (Buffer
);
495 if (!InfGetStringField (&Context
, 2, Buffer
+ Length
, MAX_INF_STRING_LENGTH
- Length
, NULL
))
498 DPRINT("KeyName: <%S>\n", Buffer
);
501 if (!InfGetIntField (&Context
, 4, (PLONG
)&Flags
))
504 DPRINT("Flags: %lx\n", Flags
);
506 RtlInitUnicodeString (&Name
,
509 InitializeObjectAttributes (&ObjectAttributes
,
511 OBJ_CASE_INSENSITIVE
,
515 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
517 Status
= NtOpenKey (&KeyHandle
,
520 if (!NT_SUCCESS(Status
))
522 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
523 continue; /* ignore if it doesn't exist */
528 Status
= CreateNestedKey (&KeyHandle
,
531 if (!NT_SUCCESS(Status
))
533 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
539 if (InfGetStringField (&Context
, 3, Buffer
, MAX_INF_STRING_LENGTH
, NULL
))
541 RtlInitUnicodeString (&Value
,
551 if (!do_reg_operation (KeyHandle
, ValuePtr
, &Context
, Flags
))
565 ImportRegistryFile(PWSTR Filename
,
569 WCHAR FileNameBuffer
[MAX_PATH
];
570 UNICODE_STRING FileName
;
575 /* Load inf file from install media. */
576 wcscpy(FileNameBuffer
, SourceRootPath
.Buffer
);
577 wcscat(FileNameBuffer
, L
"\\reactos\\");
578 wcscat(FileNameBuffer
, Filename
);
580 RtlInitUnicodeString(&FileName
,
583 Status
= InfOpenFile(&hInf
,
586 if (!NT_SUCCESS(Status
))
588 DPRINT1("InfOpenFile() failed (Status %lx)\n", Status
);
592 if (!registry_callback (hInf
, L
"AddReg", FALSE
))
594 DPRINT1("registry_callback() failed\n");
604 SetInstallPathValue(PUNICODE_STRING InstallPath
)
606 OBJECT_ATTRIBUTES ObjectAttributes
;
607 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
608 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
612 /* Create the 'secret' InstallPath key */
613 InitializeObjectAttributes (&ObjectAttributes
,
615 OBJ_CASE_INSENSITIVE
,
618 Status
= NtOpenKey (&KeyHandle
,
621 if (!NT_SUCCESS(Status
))
623 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status
);
627 Status
= NtSetValueKey (KeyHandle
,
631 (PVOID
)InstallPath
->Buffer
,
632 InstallPath
->Length
);
634 if (!NT_SUCCESS(Status
))
636 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);