2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Setup Library
4 * FILE: base/setup/lib/setuplib.c
5 * PURPOSE: Setup Library - Main initialization helpers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *****************************************************************/
23 /* GLOBALS ******************************************************************/
25 /* FUNCTIONS ****************************************************************/
29 IN OUT PUSETUP_DATA pSetupData
)
36 WCHAR UnattendInfPath
[MAX_PATH
];
38 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
39 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
41 DPRINT("UnattendInf path: '%S'\n", UnattendInfPath
);
43 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
45 DPRINT("Does not exist: %S\n", UnattendInfPath
);
49 /* Load 'unattend.inf' from installation media */
50 UnattendInf
= SetupOpenInfFileExW(UnattendInfPath
,
53 pSetupData
->LanguageId
,
56 if (UnattendInf
== INVALID_HANDLE_VALUE
)
58 DPRINT("SetupOpenInfFileExW() failed\n");
62 /* Open 'Unattend' section */
63 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
65 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
69 /* Get pointer 'Signature' key */
70 if (!INF_GetData(&Context
, NULL
, &Value
))
72 DPRINT("INF_GetData() failed for key 'Signature'\n");
76 /* Check 'Signature' string */
77 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
79 DPRINT("Signature not $ReactOS$\n");
86 /* Check if Unattend setup is enabled */
87 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
89 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
93 if (!INF_GetData(&Context
, NULL
, &Value
))
95 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
99 if (_wcsicmp(Value
, L
"yes") != 0)
101 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
108 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
109 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
111 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
115 if (!SetupGetIntField(&Context
, 1, &IntValue
))
117 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
121 pSetupData
->DestinationDiskNumber
= (LONG
)IntValue
;
123 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
124 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
126 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
130 if (!SetupGetIntField(&Context
, 1, &IntValue
))
132 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
136 pSetupData
->DestinationPartitionNumber
= (LONG
)IntValue
;
138 /* Search for 'InstallationDirectory' in the 'Unattend' section (optional) */
139 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
141 /* Get pointer 'InstallationDirectory' key */
142 if (!INF_GetData(&Context
, NULL
, &Value
))
144 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
148 RtlStringCchCopyW(pSetupData
->InstallationDirectory
,
149 ARRAYSIZE(pSetupData
->InstallationDirectory
),
155 IsUnattendedSetup
= TRUE
;
156 DPRINT("Running unattended setup\n");
158 /* Search for 'MBRInstallType' in the 'Unattend' section */
159 pSetupData
->MBRInstallType
= -1;
160 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
162 if (SetupGetIntField(&Context
, 1, &IntValue
))
164 pSetupData
->MBRInstallType
= IntValue
;
168 /* Search for 'FormatPartition' in the 'Unattend' section */
169 pSetupData
->FormatPartition
= 0;
170 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
172 if (SetupGetIntField(&Context
, 1, &IntValue
))
174 pSetupData
->FormatPartition
= IntValue
;
178 pSetupData
->AutoPartition
= 0;
179 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
181 if (SetupGetIntField(&Context
, 1, &IntValue
))
183 pSetupData
->AutoPartition
= IntValue
;
187 /* Search for LocaleID in the 'Unattend' section */
188 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
190 if (INF_GetData(&Context
, NULL
, &Value
))
192 LONG Id
= wcstol(Value
, NULL
, 16);
193 RtlStringCchPrintfW(pSetupData
->LocaleID
,
194 ARRAYSIZE(pSetupData
->LocaleID
),
201 SetupCloseInfFile(UnattendInf
);
206 IN OUT PUSETUP_DATA pSetupData
)
212 PINICACHE UnattendCache
;
213 PINICACHEITERATOR Iterator
;
215 // WCHAR CrLf[] = {L'\r', L'\n'};
216 CHAR CrLf
[] = {'\r', '\n'};
217 HANDLE FileHandle
, UnattendFileHandle
, SectionHandle
;
218 FILE_STANDARD_INFORMATION FileInfo
;
221 UNICODE_STRING FileName
;
222 OBJECT_ATTRIBUTES ObjectAttributes
;
223 IO_STATUS_BLOCK IoStatusBlock
;
226 PINICACHESECTION IniSection
;
227 WCHAR PathBuffer
[MAX_PATH
];
228 WCHAR UnattendInfPath
[MAX_PATH
];
230 /* Create a $winnt$.inf file with default entries */
231 IniCache
= IniCacheCreate();
235 IniSection
= IniCacheAppendSection(IniCache
, L
"SetupParams");
238 /* Key "skipmissingfiles" */
239 // RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
240 // L"\"%s\"", L"WinNt5.2");
241 // IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
242 // L"Version", PathBuffer);
245 IniSection
= IniCacheAppendSection(IniCache
, L
"Data");
248 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
249 L
"\"%s\"", IsUnattendedSetup
? L
"yes" : L
"no");
250 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
251 L
"UnattendedInstall", PathBuffer
);
253 // "floppylessbootpath" (yes/no)
255 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
256 L
"\"%s\"", L
"winnt");
257 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
258 L
"ProductType", PathBuffer
);
260 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
261 L
"\"%s\\\"", pSetupData
->SourceRootPath
.Buffer
);
262 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
263 L
"SourcePath", PathBuffer
);
265 // "floppyless" ("0")
270 /* TODO: Append the standard unattend.inf file */
271 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
272 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
273 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
275 DPRINT("Does not exist: %S\n", UnattendInfPath
);
279 Status
= IniCacheLoad(&UnattendCache
, UnattendInfPath
, FALSE
);
280 if (!NT_SUCCESS(Status
))
282 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath
);
286 IniCacheDestroy(UnattendCache
);
289 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
290 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
291 IniCacheSave(IniCache
, PathBuffer
);
292 IniCacheDestroy(IniCache
);
296 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
297 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
298 IniCacheSave(IniCache
, PathBuffer
);
299 IniCacheDestroy(IniCache
);
301 /* TODO: Append the standard unattend.inf file */
302 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
303 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
304 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
306 DPRINT("Does not exist: %S\n", UnattendInfPath
);
310 RtlInitUnicodeString(&FileName
, PathBuffer
);
311 InitializeObjectAttributes(&ObjectAttributes
,
313 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
316 Status
= NtOpenFile(&FileHandle
,
317 FILE_APPEND_DATA
| SYNCHRONIZE
,
321 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
322 if (!NT_SUCCESS(Status
))
324 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer
);
328 /* Query the file size */
329 Status
= NtQueryInformationFile(FileHandle
,
333 FileStandardInformation
);
334 if (!NT_SUCCESS(Status
))
336 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
337 FileInfo
.EndOfFile
.QuadPart
= 0ULL;
340 Status
= OpenAndMapFile(NULL
,
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("Cannot load %S !\n", UnattendInfPath
);
354 /* Write to the INI file */
357 Status
= NtWriteFile(FileHandle
,
367 Status
= NtWriteFile(FileHandle
,
376 if (!NT_SUCCESS(Status
))
378 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
381 /* Finally, unmap and close the file */
382 UnMapAndCloseFile(UnattendFileHandle
, SectionHandle
, ViewBase
);
390 OUT PUNICODE_STRING SourcePath
,
391 OUT PUNICODE_STRING SourceRootPath
,
392 OUT PUNICODE_STRING SourceRootDir
)
396 OBJECT_ATTRIBUTES ObjectAttributes
;
397 UCHAR ImageFileBuffer
[sizeof(UNICODE_STRING
) + MAX_PATH
* sizeof(WCHAR
)];
398 PUNICODE_STRING InstallSourcePath
= (PUNICODE_STRING
)&ImageFileBuffer
;
399 WCHAR SystemRootBuffer
[MAX_PATH
] = L
"";
400 UNICODE_STRING SystemRootPath
= RTL_CONSTANT_STRING(L
"\\SystemRoot");
404 /* Determine the installation source path via the full path of the installer */
405 RtlInitEmptyUnicodeString(InstallSourcePath
,
406 (PWSTR
)((ULONG_PTR
)ImageFileBuffer
+ sizeof(UNICODE_STRING
)),
407 sizeof(ImageFileBuffer
) - sizeof(UNICODE_STRING
)
408 /* Reserve space for a NULL terminator */ - sizeof(UNICODE_NULL
));
409 BufferSize
= sizeof(ImageFileBuffer
);
410 Status
= NtQueryInformationProcess(NtCurrentProcess(),
411 ProcessImageFileName
,
415 // STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ?
416 if (!NT_SUCCESS(Status
))
419 /* Manually NULL-terminate */
420 InstallSourcePath
->Buffer
[InstallSourcePath
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
422 /* Strip the trailing file name */
423 Ptr
= wcsrchr(InstallSourcePath
->Buffer
, OBJ_NAME_PATH_SEPARATOR
);
426 InstallSourcePath
->Length
= wcslen(InstallSourcePath
->Buffer
) * sizeof(WCHAR
);
430 * Now resolve the full path to \SystemRoot. In case it prefixes
431 * the installation source path determined from the full path of
432 * the installer, we use instead the resolved \SystemRoot as the
433 * installation source path.
434 * Otherwise, we use instead the path from the full installer path.
437 InitializeObjectAttributes(&ObjectAttributes
,
439 OBJ_CASE_INSENSITIVE
,
443 Status
= NtOpenSymbolicLinkObject(&Handle
,
446 if (!NT_SUCCESS(Status
))
449 * We failed at opening the \SystemRoot link (usually due to wrong
450 * access rights). Do not consider this as a fatal error, but use
451 * instead the image file path as the installation source path.
453 DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed with Status 0x%08lx\n",
454 &SystemRootPath
, Status
);
458 RtlInitEmptyUnicodeString(&SystemRootPath
,
460 sizeof(SystemRootBuffer
));
462 Status
= NtQuerySymbolicLinkObject(Handle
,
467 if (!NT_SUCCESS(Status
))
468 return Status
; // Unexpected error
470 /* Check whether the resolved \SystemRoot is a prefix of the image file path */
471 if (RtlPrefixUnicodeString(&SystemRootPath
, InstallSourcePath
, TRUE
))
473 /* Yes it is, so we use instead SystemRoot as the installation source path */
474 InstallSourcePath
= &SystemRootPath
;
480 * Retrieve the different source path components
482 RtlCreateUnicodeString(SourcePath
, InstallSourcePath
->Buffer
);
484 /* Strip trailing directory */
485 Ptr
= wcsrchr(InstallSourcePath
->Buffer
, OBJ_NAME_PATH_SEPARATOR
);
488 RtlCreateUnicodeString(SourceRootDir
, Ptr
);
493 RtlCreateUnicodeString(SourceRootDir
, L
"");
496 RtlCreateUnicodeString(SourceRootPath
, InstallSourcePath
->Buffer
);
498 return STATUS_SUCCESS
;
503 IN OUT PUSETUP_DATA pSetupData
)
509 WCHAR FileNameBuffer
[MAX_PATH
];
511 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
512 pSetupData
->SourcePath
.Buffer
, L
"txtsetup.sif");
514 DPRINT("SetupInf path: '%S'\n", FileNameBuffer
);
516 pSetupData
->SetupInf
=
517 SetupOpenInfFileExW(FileNameBuffer
,
519 /* INF_STYLE_WIN4 | */ INF_STYLE_OLDNT
,
520 pSetupData
->LanguageId
,
523 if (pSetupData
->SetupInf
== INVALID_HANDLE_VALUE
)
524 return ERROR_LOAD_TXTSETUPSIF
;
526 /* Open 'Version' section */
527 if (!SetupFindFirstLineW(pSetupData
->SetupInf
, L
"Version", L
"Signature", &Context
))
528 return ERROR_CORRUPT_TXTSETUPSIF
;
530 /* Get pointer 'Signature' key */
531 if (!INF_GetData(&Context
, NULL
, &Value
))
532 return ERROR_CORRUPT_TXTSETUPSIF
;
534 /* Check 'Signature' string */
535 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
538 return ERROR_SIGNATURE_TXTSETUPSIF
;
543 /* Open 'DiskSpaceRequirements' section */
544 if (!SetupFindFirstLineW(pSetupData
->SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
545 return ERROR_CORRUPT_TXTSETUPSIF
;
547 pSetupData
->RequiredPartitionDiskSpace
= ~0;
549 /* Get the 'FreeSysPartDiskSpace' value */
550 if (!SetupGetIntField(&Context
, 1, &IntValue
))
551 return ERROR_CORRUPT_TXTSETUPSIF
;
553 pSetupData
->RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
556 // Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
558 // Support for that should also be added in setupldr.
561 /* Update the Setup Source paths */
562 if (SetupFindFirstLineW(pSetupData
->SetupInf
, L
"SetupData", L
"SetupSourceDevice", &Context
))
565 * Get optional pointer 'SetupSourceDevice' key, its presence
566 * will dictate whether we also need 'SetupSourcePath'.
568 if (INF_GetData(&Context
, NULL
, &Value
))
570 /* Free the old source root path string and create the new one */
571 RtlFreeUnicodeString(&pSetupData
->SourceRootPath
);
572 RtlCreateUnicodeString(&pSetupData
->SourceRootPath
, Value
);
575 if (!SetupFindFirstLineW(pSetupData
->SetupInf
, L
"SetupData", L
"SetupSourcePath", &Context
))
577 /* The 'SetupSourcePath' value is mandatory! */
578 return ERROR_CORRUPT_TXTSETUPSIF
;
581 /* Get pointer 'SetupSourcePath' key */
582 if (!INF_GetData(&Context
, NULL
, &Value
))
584 /* The 'SetupSourcePath' value is mandatory! */
585 return ERROR_CORRUPT_TXTSETUPSIF
;
588 /* Free the old source path string and create the new one */
589 RtlFreeUnicodeString(&pSetupData
->SourceRootDir
);
590 RtlCreateUnicodeString(&pSetupData
->SourceRootDir
, Value
);
595 /* Search for 'DefaultPath' in the 'SetupData' section */
596 pSetupData
->InstallationDirectory
[0] = 0;
597 if (SetupFindFirstLineW(pSetupData
->SetupInf
, L
"SetupData", L
"DefaultPath", &Context
))
599 /* Get pointer 'DefaultPath' key */
600 if (!INF_GetData(&Context
, NULL
, &Value
))
601 return ERROR_CORRUPT_TXTSETUPSIF
;
603 RtlStringCchCopyW(pSetupData
->InstallationDirectory
,
604 ARRAYSIZE(pSetupData
->InstallationDirectory
),
610 return ERROR_SUCCESS
;
614 InitDestinationPaths(
615 IN OUT PUSETUP_DATA pSetupData
,
616 IN PCWSTR InstallationDir
,
617 IN PDISKENTRY DiskEntry
, // FIXME: HACK!
618 IN PPARTENTRY PartEntry
) // FIXME: HACK!
620 WCHAR PathBuffer
[MAX_PATH
];
623 // TODO: Check return status values of the functions!
626 /* Create 'pSetupData->DestinationRootPath' string */
627 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
628 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
629 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
630 DiskEntry
->DiskNumber
,
631 PartEntry
->PartitionNumber
);
632 RtlCreateUnicodeString(&pSetupData
->DestinationRootPath
, PathBuffer
);
633 DPRINT("DestinationRootPath: %wZ\n", &pSetupData
->DestinationRootPath
);
635 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
636 /* Create 'pSetupData->DestinationArcPath' */
637 RtlFreeUnicodeString(&pSetupData
->DestinationArcPath
);
638 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
639 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
640 DiskEntry
->BiosDiskNumber
,
641 PartEntry
->PartitionNumber
);
642 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallationDir
);
643 RtlCreateUnicodeString(&pSetupData
->DestinationArcPath
, PathBuffer
);
645 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
646 /* Create 'pSetupData->DestinationPath' string */
647 RtlFreeUnicodeString(&pSetupData
->DestinationPath
);
648 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
649 pSetupData
->DestinationRootPath
.Buffer
, InstallationDir
);
650 RtlCreateUnicodeString(&pSetupData
->DestinationPath
, PathBuffer
);
652 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
653 // FIXME: This is only temporary!! Must be removed later!
654 /***/RtlCreateUnicodeString(&pSetupData
->InstallPath
, InstallationDir
);/***/
656 return STATUS_SUCCESS
;
662 IN OUT PUSETUP_DATA pSetupData
,
667 RtlZeroMemory(pSetupData
, sizeof(*pSetupData
));
669 // pSetupData->ComputerList = NULL;
670 // pSetupData->DisplayList = NULL;
671 // pSetupData->KeyboardList = NULL;
672 // pSetupData->LayoutList = NULL;
673 // pSetupData->LanguageList = NULL;
675 /* Initialize global unicode strings */
676 RtlInitUnicodeString(&pSetupData
->SourcePath
, NULL
);
677 RtlInitUnicodeString(&pSetupData
->SourceRootPath
, NULL
);
678 RtlInitUnicodeString(&pSetupData
->SourceRootDir
, NULL
);
679 RtlInitUnicodeString(&pSetupData
->DestinationArcPath
, NULL
);
680 RtlInitUnicodeString(&pSetupData
->DestinationPath
, NULL
);
681 RtlInitUnicodeString(&pSetupData
->DestinationRootPath
, NULL
);
682 RtlInitUnicodeString(&pSetupData
->SystemRootPath
, NULL
);
684 // FIXME: This is only temporary!! Must be removed later!
685 /***/RtlInitUnicodeString(&pSetupData
->InstallPath
, NULL
);/***/
688 // TODO: Load and start SetupDD, and ask it for the information
691 return ERROR_SUCCESS
;
699 /* Get the source path and source root path */
701 // NOTE: Sometimes the source path may not be in SystemRoot !!
702 // (and this is the case when using the 1st-stage GUI setup!)
704 Status
= GetSourcePaths(&pSetupData
->SourcePath
,
705 &pSetupData
->SourceRootPath
,
706 &pSetupData
->SourceRootDir
);
707 if (!NT_SUCCESS(Status
))
709 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)", Status
);
710 return ERROR_NO_SOURCE_DRIVE
;
714 * SourcePath: '\Device\CdRom0\I386'
715 * SourceRootPath: '\Device\CdRom0'
716 * SourceRootDir: '\I386'
718 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData
->SourcePath
);
719 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData
->SourceRootPath
);
720 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData
->SourceRootDir
);
722 /* Load 'txtsetup.sif' from the installation media */
723 Error
= LoadSetupInf(pSetupData
);
724 if (Error
!= ERROR_SUCCESS
)
726 DPRINT1("LoadSetupInf() failed (Error 0x%lx)", Error
);
729 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData
->SourcePath
);
730 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData
->SourceRootPath
);
731 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData
->SourceRootDir
);
733 return ERROR_SUCCESS
;
736 return ERROR_SUCCESS
;
741 IN OUT PUSETUP_DATA pSetupData
)
743 /* Destroy the computer settings list */
744 if (pSetupData
->ComputerList
!= NULL
)
746 DestroyGenericList(pSetupData
->ComputerList
, TRUE
);
747 pSetupData
->ComputerList
= NULL
;
750 /* Destroy the display settings list */
751 if (pSetupData
->DisplayList
!= NULL
)
753 DestroyGenericList(pSetupData
->DisplayList
, TRUE
);
754 pSetupData
->DisplayList
= NULL
;
757 /* Destroy the keyboard settings list */
758 if (pSetupData
->KeyboardList
!= NULL
)
760 DestroyGenericList(pSetupData
->KeyboardList
, TRUE
);
761 pSetupData
->KeyboardList
= NULL
;
764 /* Destroy the keyboard layout list */
765 if (pSetupData
->LayoutList
!= NULL
)
767 DestroyGenericList(pSetupData
->LayoutList
, TRUE
);
768 pSetupData
->LayoutList
= NULL
;
771 /* Destroy the languages list */
772 if (pSetupData
->LanguageList
!= NULL
)
774 DestroyGenericList(pSetupData
->LanguageList
, FALSE
);
775 pSetupData
->LanguageList
= NULL
;
778 /* Close the Setup INF */
779 SetupCloseInfFile(pSetupData
->SetupInf
);
784 * Calls RegInitializeRegistry
785 * Calls ImportRegistryFile
786 * Calls SetDefaultPagefile
787 * Calls SetMountedDeviceValues
792 IN OUT PUSETUP_DATA pSetupData
,
793 /**/IN BOOLEAN RepairUpdateFlag
, /* HACK HACK! */
794 /**/IN PPARTLIST PartitionList
, /* HACK HACK! */
795 /**/IN WCHAR DestinationDriveLetter
, /* HACK HACK! */
796 /**/IN PCWSTR SelectedLanguageId
, /* HACK HACK! */
797 IN PGENERIC_LIST DisplayList
,
798 IN PGENERIC_LIST LayoutList
,
799 IN PGENERIC_LIST LanguageList
,
800 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL
)
802 ERROR_NUMBER ErrorNumber
;
804 INFCONTEXT InfContext
;
809 BOOLEAN ShouldRepairRegistry
= FALSE
;
812 if (RepairUpdateFlag
)
814 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
816 /* Verify the registry hives and check whether we need to update or repair any of them */
817 Status
= VerifyRegistryHives(&pSetupData
->DestinationPath
, &ShouldRepairRegistry
);
818 if (!NT_SUCCESS(Status
))
820 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status
);
821 ShouldRepairRegistry
= FALSE
;
823 if (!ShouldRepairRegistry
)
824 DPRINT1("No need to repair the registry\n");
828 ErrorNumber
= ERROR_SUCCESS
;
830 /* Update the registry */
831 if (StatusRoutine
) StatusRoutine(RegHiveUpdate
);
833 /* Initialize the registry and setup the registry hives */
834 Status
= RegInitializeRegistry(&pSetupData
->DestinationPath
);
835 if (!NT_SUCCESS(Status
))
837 DPRINT1("RegInitializeRegistry() failed\n");
838 /********** HACK!!!!!!!!!!! **********/
839 if (Status
== STATUS_NOT_IMPLEMENTED
)
841 /* The hack was called, return its corresponding error */
842 return ERROR_INITIALIZE_REGISTRY
;
845 /*************************************/
847 /* Something else failed */
848 return ERROR_CREATE_HIVE
;
852 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
855 * We fully setup the hives, in case we are doing a fresh installation
856 * (RepairUpdateFlag == FALSE), or in case we are doing an update
857 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
858 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
861 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Fresh", NULL
, &InfContext
); // Windows-compatible
863 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
); // ReactOS-specific
867 DPRINT1("SetupFindFirstLine() failed\n");
868 ErrorNumber
= ERROR_FIND_REGISTRY
;
872 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
875 * In case we are doing an update (RepairUpdateFlag == TRUE) and
876 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
877 * we only update the hives.
880 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Upgrade", NULL
, &InfContext
);
883 /* Nothing to do for update! */
884 DPRINT1("No update needed for the registry!\n");
891 INF_GetDataField(&InfContext
, 0, &Action
);
892 INF_GetDataField(&InfContext
, 1, &File
);
893 INF_GetDataField(&InfContext
, 2, &Section
);
895 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
899 INF_FreeData(Action
);
901 INF_FreeData(Section
);
905 if (!_wcsicmp(Action
, L
"AddReg"))
907 else if (!_wcsicmp(Action
, L
"DelReg"))
911 DPRINT1("Unrecognized registry INF action '%S'\n", Action
);
912 INF_FreeData(Action
);
914 INF_FreeData(Section
);
918 INF_FreeData(Action
);
920 if (StatusRoutine
) StatusRoutine(ImportRegHive
, File
);
922 if (!ImportRegistryFile(pSetupData
->SourcePath
.Buffer
,
924 pSetupData
->LanguageId
, Delete
))
926 DPRINT1("Importing %S failed\n", File
);
928 INF_FreeData(Section
);
929 ErrorNumber
= ERROR_IMPORT_HIVE
;
932 } while (SetupFindNextLine(&InfContext
, &InfContext
));
934 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
936 /* See the explanation for this test above */
938 /* Update display registry settings */
939 if (StatusRoutine
) StatusRoutine(DisplaySettingsUpdate
);
940 if (!ProcessDisplayRegistry(SetupInf
, DisplayList
))
942 ErrorNumber
= ERROR_UPDATE_DISPLAY_SETTINGS
;
947 if (StatusRoutine
) StatusRoutine(LocaleSettingsUpdate
);
948 if (!ProcessLocaleRegistry(LanguageList
))
950 ErrorNumber
= ERROR_UPDATE_LOCALESETTINGS
;
954 /* Add keyboard layouts */
955 if (StatusRoutine
) StatusRoutine(KeybLayouts
);
956 if (!AddKeyboardLayouts(SelectedLanguageId
))
958 ErrorNumber
= ERROR_ADDING_KBLAYOUTS
;
963 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId
)))
965 ErrorNumber
= ERROR_UPDATE_GEOID
;
969 if (!IsUnattendedSetup
)
971 /* Update keyboard layout settings */
972 if (StatusRoutine
) StatusRoutine(KeybSettingsUpdate
);
973 if (!ProcessKeyboardLayoutRegistry(LayoutList
, SelectedLanguageId
))
975 ErrorNumber
= ERROR_UPDATE_KBSETTINGS
;
980 /* Add codepage information to registry */
981 if (StatusRoutine
) StatusRoutine(CodePageInfoUpdate
);
982 if (!AddCodePage(SelectedLanguageId
))
984 ErrorNumber
= ERROR_ADDING_CODEPAGE
;
988 /* Set the default pagefile entry */
989 SetDefaultPagefile(DestinationDriveLetter
);
991 /* Update the mounted devices list */
992 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
993 SetMountedDeviceValues(PartitionList
);
998 // TODO: Unload all the registry stuff, perform cleanup,
999 // and copy the created hive files into .sav files.
1001 RegCleanupRegistry(&pSetupData
->DestinationPath
);
1004 * Check whether we were in update/repair mode but we were actually
1005 * repairing the registry hives. If so, we have finished repairing them,
1006 * and we now reset the flag and run the proper registry update.
1007 * Otherwise we have finished the registry update!
1009 if (RepairUpdateFlag
&& ShouldRepairRegistry
)
1011 ShouldRepairRegistry
= FALSE
;