3 * Copyright (C) 2002, 2003, 2004 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/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
41 /* GLOBALS & LOCALS *********************************************************/
44 BOOLEAN IsUnattendedSetup
= FALSE
;
46 static USETUP_DATA USetupData
;
48 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
49 static WCHAR DestinationDriveLetter
;
54 PCWSTR SelectedLanguageId
;
55 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
56 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
58 static BOOLEAN RepairUpdateFlag
= FALSE
;
60 /* Global partition list on the system */
61 static PPARTLIST PartitionList
= NULL
;
63 /* List of currently supported file systems for the partition to be formatted */
64 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
66 /* Machine state for the formatter */
67 static PPARTENTRY TempPartition
= NULL
;
68 static FORMATMACHINESTATE FormatState
= Start
;
70 /*****************************************************/
72 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
73 static PGENERIC_LIST NtOsInstallsList
= NULL
;
76 /* FUNCTIONS ****************************************************************/
79 PrintString(char* fmt
,...)
83 UNICODE_STRING UnicodeString
;
84 ANSI_STRING AnsiString
;
87 vsprintf(buffer
, fmt
, ap
);
90 RtlInitAnsiString(&AnsiString
, buffer
);
91 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
92 NtDisplayString(&UnicodeString
);
93 RtlFreeUnicodeString(&UnicodeString
);
98 DrawBox(IN SHORT xLeft
,
106 /* Draw upper left corner */
109 FillConsoleOutputCharacterA(StdOutput
,
115 /* Draw upper edge */
118 FillConsoleOutputCharacterA(StdOutput
,
124 /* Draw upper right corner */
125 coPos
.X
= xLeft
+ Width
- 1;
127 FillConsoleOutputCharacterA(StdOutput
,
133 /* Draw right edge, inner space and left edge */
134 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
137 FillConsoleOutputCharacterA(StdOutput
,
144 FillConsoleOutputCharacterA(StdOutput
,
150 coPos
.X
= xLeft
+ Width
- 1;
151 FillConsoleOutputCharacterA(StdOutput
,
158 /* Draw lower left corner */
160 coPos
.Y
= yTop
+ Height
- 1;
161 FillConsoleOutputCharacterA(StdOutput
,
167 /* Draw lower edge */
169 coPos
.Y
= yTop
+ Height
- 1;
170 FillConsoleOutputCharacterA(StdOutput
,
176 /* Draw lower right corner */
177 coPos
.X
= xLeft
+ Width
- 1;
178 coPos
.Y
= yTop
+ Height
- 1;
179 FillConsoleOutputCharacterA(StdOutput
,
188 PopupError(PCCH Text
,
206 /* Count text lines and longest line */
213 p
= strchr(pnext
, '\n');
217 Length
= strlen(pnext
);
222 Length
= (ULONG
)(p
- pnext
);
228 if (Length
> MaxLength
)
237 /* Check length of status line */
240 Length
= strlen(Status
);
242 if (Length
> MaxLength
)
246 Width
= MaxLength
+ 4;
252 yTop
= (yScreen
- Height
) / 2;
253 xLeft
= (xScreen
- Width
) / 2;
256 /* Set screen attributes */
258 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
260 FillConsoleOutputAttribute(StdOutput
,
261 FOREGROUND_RED
| BACKGROUND_WHITE
,
267 DrawBox(xLeft
, yTop
, Width
, Height
);
269 /* Print message text */
274 p
= strchr(pnext
, '\n');
278 Length
= strlen(pnext
);
283 Length
= (ULONG
)(p
- pnext
);
290 WriteConsoleOutputCharacterA(StdOutput
,
304 /* Print separator line and status text */
307 coPos
.Y
= yTop
+ Height
- 3;
309 FillConsoleOutputCharacterA(StdOutput
,
316 FillConsoleOutputCharacterA(StdOutput
,
322 coPos
.X
= xLeft
+ Width
- 1;
323 FillConsoleOutputCharacterA(StdOutput
,
331 WriteConsoleOutputCharacterA(StdOutput
,
333 min(strlen(Status
), (SIZE_T
)Width
- 4),
338 if (WaitEvent
== POPUP_WAIT_NONE
)
343 CONSOLE_ConInKey(Ir
);
345 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
346 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
358 * FALSE: Don't quit setup.
361 ConfirmQuit(PINPUT_RECORD Ir
)
364 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
368 CONSOLE_ConInKey(Ir
);
370 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
371 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
376 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
390 PGENERIC_LIST_ENTRY ListEntry
;
393 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
395 if (USetupData
.LayoutList
== NULL
)
397 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
398 if (USetupData
.LayoutList
== NULL
)
400 /* FIXME: Handle error! */
405 /* Search for default layout (if provided) */
406 if (pszNewLayout
!= NULL
)
408 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
409 ListEntry
= GetNextListEntry(ListEntry
))
411 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
413 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
423 GetSettingDescription(
424 IN PGENERIC_LIST_ENTRY Entry
,
426 IN SIZE_T cchBufferSize
)
428 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
429 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
434 GetNTOSInstallationName(
435 IN PGENERIC_LIST_ENTRY Entry
,
437 IN SIZE_T cchBufferSize
)
439 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
440 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
442 if (PartEntry
&& PartEntry
->DriveLetter
)
444 /* We have retrieved a partition that is mounted */
445 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
447 PartEntry
->DriveLetter
,
448 NtOsInstall
->PathComponent
,
449 NtOsInstall
->InstallationName
);
453 /* We failed somewhere, just show the NT path */
454 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
456 &NtOsInstall
->SystemNtPath
,
457 NtOsInstall
->InstallationName
);
463 * Displays the LanguagePage.
465 * Next pages: WelcomePage, QuitPage
468 * Init SelectedLanguageId
469 * Init USetupData.LanguageId
472 * Number of the next page.
475 LanguagePage(PINPUT_RECORD Ir
)
477 GENERIC_LIST_UI ListUi
;
478 PCWSTR NewLanguageId
;
479 BOOL RefreshPage
= FALSE
;
481 /* Initialize the computer settings list */
482 if (USetupData
.LanguageList
== NULL
)
484 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
485 if (USetupData
.LanguageList
== NULL
)
487 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
492 SelectedLanguageId
= DefaultLanguage
;
493 USetupData
.LanguageId
= 0;
496 SetConsoleCodePage();
500 * If there is no language or just a single one in the list,
501 * skip the language selection process altogether.
503 if (GetNumberOfListEntries(USetupData
.LanguageList
) <= 1)
505 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
509 InitGenericListUi(&ListUi
, USetupData
.LanguageList
, GetSettingDescription
);
510 DrawGenericList(&ListUi
,
515 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
517 MUIDisplayPage(LANGUAGE_PAGE
);
521 CONSOLE_ConInKey(Ir
);
523 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
524 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
526 ScrollDownGenericList(&ListUi
);
529 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
530 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
532 ScrollUpGenericList(&ListUi
);
535 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
536 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
538 ScrollPageDownGenericList(&ListUi
);
541 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
542 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
544 ScrollPageUpGenericList(&ListUi
);
547 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
548 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
553 RedrawGenericList(&ListUi
);
555 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
557 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
560 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
562 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
564 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
570 SetConsoleCodePage();
574 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
577 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
583 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
586 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
588 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
590 /* Clear the language page */
591 MUIClearPage(LANGUAGE_PAGE
);
593 SelectedLanguageId
= NewLanguageId
;
596 SetConsoleCodePage();
598 /* Redraw language selection page in native language */
599 MUIDisplayPage(LANGUAGE_PAGE
);
614 * LanguagePage (at once, default)
615 * InstallIntroPage (at once, if unattended)
620 * Init USetupData.SourcePath
621 * Init USetupData.SourceRootPath
622 * Init USetupData.SourceRootDir
623 * Init USetupData.SetupInf
624 * Init USetupData.RequiredPartitionDiskSpace
625 * Init IsUnattendedSetup
626 * If unattended, init *List and sets the Codepage
627 * If unattended, init SelectedLanguageId
628 * If unattended, init USetupData.LanguageId
631 * Number of the next page.
634 SetupStartPage(PINPUT_RECORD Ir
)
637 PGENERIC_LIST_ENTRY ListEntry
;
640 MUIDisplayPage(SETUP_INIT_PAGE
);
642 /* Initialize Setup, phase 1 */
643 Error
= InitializeSetup(&USetupData
, 1);
644 if (Error
!= ERROR_SUCCESS
)
646 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
650 /* Initialize the user-mode PnP manager */
651 if (!EnableUserModePnpManager())
652 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
654 /* Wait for any immediate pending installations to finish */
655 if (WaitNoPendingInstallEvents(NULL
) != STATUS_WAIT_0
)
656 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
658 CheckUnattendedSetup(&USetupData
);
660 if (IsUnattendedSetup
)
662 // TODO: Read options from inf
663 /* Load the hardware, language and keyboard layout lists */
665 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
666 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
667 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
669 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
672 SelectedLanguageId
= DefaultLanguage
;
673 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
674 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
676 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
678 /* first we hack LanguageList */
679 for (ListEntry
= GetFirstListEntry(USetupData
.LanguageList
); ListEntry
;
680 ListEntry
= GetNextListEntry(ListEntry
))
682 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
683 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
685 DPRINT("found %S in LanguageList\n", LocaleId
);
686 SetCurrentListEntry(USetupData
.LanguageList
, ListEntry
);
692 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
693 ListEntry
= GetNextListEntry(ListEntry
))
695 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
696 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
698 DPRINT("found %S in LayoutList\n", LocaleId
);
699 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
704 SetConsoleCodePage();
706 return INSTALL_INTRO_PAGE
;
709 return LANGUAGE_PAGE
;
714 * Displays the WelcomePage.
717 * InstallIntroPage (default)
724 * Number of the next page.
727 WelcomePage(PINPUT_RECORD Ir
)
729 MUIDisplayPage(WELCOME_PAGE
);
733 CONSOLE_ConInKey(Ir
);
735 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
736 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
743 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
745 return INSTALL_INTRO_PAGE
;
747 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
749 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
751 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
762 * Displays the License page.
765 * WelcomePage (default)
768 * Number of the next page.
771 LicensePage(PINPUT_RECORD Ir
)
773 MUIDisplayPage(LICENSE_PAGE
);
777 CONSOLE_ConInKey(Ir
);
779 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
790 * Displays the RepairIntroPage.
793 * RebootPage (default)
799 * Number of the next page.
802 RepairIntroPage(PINPUT_RECORD Ir
)
804 MUIDisplayPage(REPAIR_INTRO_PAGE
);
808 CONSOLE_ConInKey(Ir
);
810 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
814 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
816 RepairUpdateFlag
= TRUE
;
817 return INSTALL_INTRO_PAGE
;
819 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
821 return RECOVERY_PAGE
;
823 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
824 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
830 return REPAIR_INTRO_PAGE
;
834 * Displays the UpgradeRepairPage.
837 * RebootPage (default)
843 * Number of the next page.
846 UpgradeRepairPage(PINPUT_RECORD Ir
)
848 GENERIC_LIST_UI ListUi
;
851 if (PartitionList
== NULL
)
853 PartitionList
= CreatePartitionList();
854 if (PartitionList
== NULL
)
856 /* FIXME: show an error dialog */
857 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
860 else if (IsListEmpty(&PartitionList
->DiskListHead
))
862 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
866 /* Reset the formatter machine state */
867 TempPartition
= NULL
;
872 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
873 if (!NtOsInstallsList
)
874 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
877 * If there is no available installation (or just a single one??) that can
878 * be updated in the list, just continue with the regular installation.
880 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
882 RepairUpdateFlag
= FALSE
;
884 // return INSTALL_INTRO_PAGE;
885 return DEVICE_SETTINGS_PAGE
;
886 // return SCSI_CONTROLLER_PAGE;
889 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
891 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
892 DrawGenericList(&ListUi
,
897 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
900 CONSOLE_ConInKey(Ir
);
902 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
904 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
906 case VK_DOWN
: /* DOWN */
907 ScrollDownGenericList(&ListUi
);
910 ScrollUpGenericList(&ListUi
);
912 case VK_NEXT
: /* PAGE DOWN */
913 ScrollPageDownGenericList(&ListUi
);
915 case VK_PRIOR
: /* PAGE UP */
916 ScrollPageUpGenericList(&ListUi
);
923 RedrawGenericList(&ListUi
);
926 case VK_ESCAPE
: /* ESC */
928 RestoreGenericListUiState(&ListUi
);
929 // return nextPage; // prevPage;
931 // return INSTALL_INTRO_PAGE;
932 return DEVICE_SETTINGS_PAGE
;
933 // return SCSI_CONTROLLER_PAGE;
939 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
940 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
941 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
943 /* Retrieve the current installation */
944 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
946 CurrentInstallation
=
947 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
949 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
950 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
952 RepairUpdateFlag
= TRUE
;
955 /***/return INSTALL_INTRO_PAGE
;/***/
957 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
958 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
960 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
965 return UPGRADE_REPAIR_PAGE
;
970 * Displays the InstallIntroPage.
973 * DeviceSettingsPage (At once if repair or update is selected)
974 * SelectPartitionPage (At once if unattended setup)
975 * DeviceSettingsPage (default)
979 * Number of the next page.
982 InstallIntroPage(PINPUT_RECORD Ir
)
984 if (RepairUpdateFlag
)
986 #if 1 /* Old code that looks good */
988 // return SELECT_PARTITION_PAGE;
989 return DEVICE_SETTINGS_PAGE
;
991 #else /* Possible new code? */
993 return DEVICE_SETTINGS_PAGE
;
994 // return SCSI_CONTROLLER_PAGE;
999 if (IsUnattendedSetup
)
1000 return SELECT_PARTITION_PAGE
;
1002 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1006 CONSOLE_ConInKey(Ir
);
1008 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1009 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1011 if (ConfirmQuit(Ir
))
1016 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1018 return UPGRADE_REPAIR_PAGE
;
1022 return INSTALL_INTRO_PAGE
;
1028 ScsiControllerPage(PINPUT_RECORD Ir
)
1030 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1032 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1034 /* FIXME: print loaded mass storage driver descriptions */
1036 CONSOLE_SetTextXY(8, 10, "TEST device");
1039 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1043 CONSOLE_ConInKey(Ir
);
1045 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1046 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1048 if (ConfirmQuit(Ir
))
1053 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1055 return DEVICE_SETTINGS_PAGE
;
1059 return SCSI_CONTROLLER_PAGE
;
1063 OemDriverPage(PINPUT_RECORD Ir
)
1065 // MUIDisplayPage(OEM_DRIVER_PAGE);
1067 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1069 /* FIXME: Implement!! */
1071 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1075 CONSOLE_ConInKey(Ir
);
1077 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1078 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1080 if (ConfirmQuit(Ir
))
1085 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1087 return DEVICE_SETTINGS_PAGE
;
1091 return OEM_DRIVER_PAGE
;
1097 * Displays the DeviceSettingsPage.
1100 * SelectPartitionPage (At once if repair or update is selected)
1101 * ComputerSettingsPage
1102 * DisplaySettingsPage
1103 * KeyboardSettingsPage
1104 * LayoutsettingsPage
1105 * SelectPartitionPage
1109 * Init USetupData.ComputerList
1110 * Init USetupData.DisplayList
1111 * Init USetupData.KeyboardList
1112 * Init USetupData.LayoutList
1115 * Number of the next page.
1118 DeviceSettingsPage(PINPUT_RECORD Ir
)
1120 static ULONG Line
= 16;
1122 /* Initialize the computer settings list */
1123 if (USetupData
.ComputerList
== NULL
)
1125 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
1126 if (USetupData
.ComputerList
== NULL
)
1128 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1133 /* Initialize the display settings list */
1134 if (USetupData
.DisplayList
== NULL
)
1136 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
1137 if (USetupData
.DisplayList
== NULL
)
1139 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1144 /* Initialize the keyboard settings list */
1145 if (USetupData
.KeyboardList
== NULL
)
1147 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
1148 if (USetupData
.KeyboardList
== NULL
)
1150 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1155 /* Initialize the keyboard layout list */
1156 if (USetupData
.LayoutList
== NULL
)
1158 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1159 if (USetupData
.LayoutList
== NULL
)
1161 /* FIXME: report error */
1162 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1167 if (RepairUpdateFlag
)
1168 return SELECT_PARTITION_PAGE
;
1170 // if (IsUnattendedSetup)
1171 // return SELECT_PARTITION_PAGE;
1173 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1175 DrawGenericListCurrentItem(USetupData
.ComputerList
, GetSettingDescription
, 25, 11);
1176 DrawGenericListCurrentItem(USetupData
.DisplayList
, GetSettingDescription
, 25, 12);
1177 DrawGenericListCurrentItem(USetupData
.KeyboardList
, GetSettingDescription
, 25, 13);
1178 DrawGenericListCurrentItem(USetupData
.LayoutList
, GetSettingDescription
, 25, 14);
1180 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1184 CONSOLE_ConInKey(Ir
);
1186 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1187 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1189 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1193 else if (Line
== 16)
1198 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1200 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1201 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1203 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1207 else if (Line
== 16)
1212 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1214 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1215 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1217 if (ConfirmQuit(Ir
))
1222 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1225 return COMPUTER_SETTINGS_PAGE
;
1226 else if (Line
== 12)
1227 return DISPLAY_SETTINGS_PAGE
;
1228 else if (Line
== 13)
1229 return KEYBOARD_SETTINGS_PAGE
;
1230 else if (Line
== 14)
1231 return LAYOUT_SETTINGS_PAGE
;
1232 else if (Line
== 16)
1233 return SELECT_PARTITION_PAGE
;
1237 return DEVICE_SETTINGS_PAGE
;
1242 * Handles generic selection lists.
1245 * GenericList: The list to handle.
1246 * nextPage: The page it needs to jump to after this page.
1247 * Ir: The PINPUT_RECORD
1250 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1251 PAGE_NUMBER nextPage
,
1256 CONSOLE_ConInKey(Ir
);
1258 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1259 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1261 ScrollDownGenericList(ListUi
);
1263 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1264 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1266 ScrollUpGenericList(ListUi
);
1268 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1269 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1271 ScrollPageDownGenericList(ListUi
);
1273 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1274 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1276 ScrollPageUpGenericList(ListUi
);
1278 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1279 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1281 if (ConfirmQuit(Ir
))
1284 RedrawGenericList(ListUi
);
1286 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1287 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1289 RestoreGenericListUiState(ListUi
);
1290 return nextPage
; // Use some "prevPage;" instead?
1292 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1296 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1299 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1306 * Displays the ComputerSettingsPage.
1309 * DeviceSettingsPage
1313 * Number of the next page.
1316 ComputerSettingsPage(PINPUT_RECORD Ir
)
1318 GENERIC_LIST_UI ListUi
;
1319 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1321 InitGenericListUi(&ListUi
, USetupData
.ComputerList
, GetSettingDescription
);
1322 DrawGenericList(&ListUi
,
1327 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1332 * Displays the DisplaySettingsPage.
1335 * DeviceSettingsPage
1339 * Number of the next page.
1342 DisplaySettingsPage(PINPUT_RECORD Ir
)
1344 GENERIC_LIST_UI ListUi
;
1345 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1347 InitGenericListUi(&ListUi
, USetupData
.DisplayList
, GetSettingDescription
);
1348 DrawGenericList(&ListUi
,
1353 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1358 * Displays the KeyboardSettingsPage.
1361 * DeviceSettingsPage
1365 * Number of the next page.
1368 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1370 GENERIC_LIST_UI ListUi
;
1371 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1373 InitGenericListUi(&ListUi
, USetupData
.KeyboardList
, GetSettingDescription
);
1374 DrawGenericList(&ListUi
,
1379 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1384 * Displays the LayoutSettingsPage.
1387 * DeviceSettingsPage
1391 * Number of the next page.
1394 LayoutSettingsPage(PINPUT_RECORD Ir
)
1396 GENERIC_LIST_UI ListUi
;
1397 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1399 InitGenericListUi(&ListUi
, USetupData
.LayoutList
, GetSettingDescription
);
1400 DrawGenericList(&ListUi
,
1405 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1410 IsDiskSizeValid(PPARTENTRY PartEntry
)
1414 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1415 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1417 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1419 /* Partition is too small so ask for another one */
1420 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1431 * Displays the SelectPartitionPage.
1434 * SelectFileSystemPage (At once if unattended)
1435 * SelectFileSystemPage (Default if free space is selected)
1436 * CreatePrimaryPartitionPage
1437 * CreateExtendedPartitionPage
1438 * CreateLogicalPartitionPage
1439 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1440 * DeletePartitionPage
1444 * Set InstallShortcut (only if not unattended + free space is selected)
1447 * Number of the next page.
1450 SelectPartitionPage(PINPUT_RECORD Ir
)
1455 if (PartitionList
== NULL
)
1457 PartitionList
= CreatePartitionList();
1458 if (PartitionList
== NULL
)
1460 /* FIXME: show an error dialog */
1461 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1464 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1466 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1470 /* Reset the formatter machine state */
1471 TempPartition
= NULL
;
1472 FormatState
= Start
;
1475 if (RepairUpdateFlag
)
1477 /* Determine the selected installation disk & partition */
1478 if (!SelectPartition(PartitionList
,
1479 CurrentInstallation
->DiskNumber
,
1480 CurrentInstallation
->PartitionNumber
))
1482 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1486 return SELECT_FILE_SYSTEM_PAGE
;
1489 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1491 InitPartitionListUi(&ListUi
, PartitionList
,
1496 DrawPartitionList(&ListUi
);
1498 if (IsUnattendedSetup
)
1500 if (!SelectPartition(PartitionList
,
1501 USetupData
.DestinationDiskNumber
,
1502 USetupData
.DestinationPartitionNumber
))
1504 if (USetupData
.AutoPartition
)
1506 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1508 CreateLogicalPartition(PartitionList
,
1509 PartitionList
->CurrentPartition
,
1510 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1515 CreatePrimaryPartition(PartitionList
,
1516 PartitionList
->CurrentPartition
,
1517 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1521 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1522 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1524 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1525 USetupData
.RequiredPartitionDiskSpace
);
1526 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1529 return SELECT_FILE_SYSTEM_PAGE
;
1534 DrawPartitionList(&ListUi
);
1536 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1537 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1539 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1540 USetupData
.RequiredPartitionDiskSpace
);
1541 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1544 return SELECT_FILE_SYSTEM_PAGE
;
1550 /* Update status text */
1551 if (PartitionList
->CurrentPartition
== NULL
)
1553 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1555 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1557 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1559 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1563 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1568 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1570 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1572 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1576 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1581 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1585 CONSOLE_ConInKey(Ir
);
1587 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1588 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1590 if (ConfirmQuit(Ir
))
1592 DestroyPartitionList(PartitionList
);
1593 PartitionList
= NULL
;
1599 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1600 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1602 ScrollDownPartitionList(&ListUi
);
1604 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1605 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1607 ScrollUpPartitionList(&ListUi
);
1609 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1611 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1612 continue; // return SELECT_PARTITION_PAGE;
1614 if (PartitionList
->CurrentPartition
== NULL
||
1615 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1617 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1619 Error
= LogicalPartitionCreationChecks(PartitionList
->CurrentPartition
);
1620 if (Error
!= NOT_AN_ERROR
)
1622 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1623 return SELECT_PARTITION_PAGE
;
1626 CreateLogicalPartition(PartitionList
,
1627 PartitionList
->CurrentPartition
,
1633 Error
= PrimaryPartitionCreationChecks(PartitionList
->CurrentPartition
);
1634 if (Error
!= NOT_AN_ERROR
)
1636 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1637 return SELECT_PARTITION_PAGE
;
1640 CreatePrimaryPartition(PartitionList
,
1641 PartitionList
->CurrentPartition
,
1647 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1649 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1650 USetupData
.RequiredPartitionDiskSpace
);
1651 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1654 return SELECT_FILE_SYSTEM_PAGE
;
1656 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1658 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1660 Error
= PrimaryPartitionCreationChecks(PartitionList
->CurrentPartition
);
1661 if (Error
!= NOT_AN_ERROR
)
1663 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1664 return SELECT_PARTITION_PAGE
;
1667 return CREATE_PRIMARY_PARTITION_PAGE
;
1670 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1672 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1674 Error
= ExtendedPartitionCreationChecks(PartitionList
->CurrentPartition
);
1675 if (Error
!= NOT_AN_ERROR
)
1677 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1678 return SELECT_PARTITION_PAGE
;
1681 return CREATE_EXTENDED_PARTITION_PAGE
;
1684 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1686 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1688 Error
= LogicalPartitionCreationChecks(PartitionList
->CurrentPartition
);
1689 if (Error
!= NOT_AN_ERROR
)
1691 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1692 return SELECT_PARTITION_PAGE
;
1695 return CREATE_LOGICAL_PARTITION_PAGE
;
1698 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1700 UNICODE_STRING CurrentPartition
;
1701 WCHAR PathBuffer
[MAX_PATH
];
1703 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1705 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1706 return SELECT_PARTITION_PAGE
;
1709 // TODO: Do something similar before trying to format the partition?
1710 if (!PartitionList
->CurrentPartition
->New
&&
1711 PartitionList
->CurrentPartition
->FormatState
!= Unformatted
)
1713 ASSERT(PartitionList
->CurrentPartition
->PartitionNumber
!= 0);
1715 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1716 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1717 PartitionList
->CurrentDisk
->DiskNumber
,
1718 PartitionList
->CurrentPartition
->PartitionNumber
);
1719 RtlInitUnicodeString(&CurrentPartition
, PathBuffer
);
1722 * Check whether the user attempts to delete the partition on which
1723 * the installation source is present. If so, fail with an error.
1725 // &USetupData.SourceRootPath
1726 if (RtlPrefixUnicodeString(&CurrentPartition
, &USetupData
.SourcePath
, TRUE
))
1728 PopupError("You cannot delete the partition containing the installation source!",
1729 MUIGetString(STRING_CONTINUE
),
1730 Ir
, POPUP_WAIT_ENTER
);
1731 return SELECT_PARTITION_PAGE
;
1735 if (PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
||
1736 PartitionList
->CurrentPartition
->BootIndicator
)
1738 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1741 return DELETE_PARTITION_PAGE
;
1745 return SELECT_PARTITION_PAGE
;
1749 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1750 /* Restriction for MaxSize */
1751 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1754 ShowPartitionSizeInputBox(SHORT Left
,
1778 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1783 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1784 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1787 WriteConsoleOutputCharacterA(StdOutput
,
1793 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1794 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1796 WriteConsoleOutputCharacterA(StdOutput
,
1802 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1803 Length
= wcslen(InputBuffer
);
1805 CONSOLE_SetInputTextXY(iLeft
,
1807 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1809 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1810 CONSOLE_SetCursorType(TRUE
, TRUE
);
1814 CONSOLE_ConInKey(&Ir
);
1816 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1817 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1822 InputBuffer
[0] = UNICODE_NULL
;
1823 CONSOLE_SetCursorType(TRUE
, FALSE
);
1826 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1828 CONSOLE_SetCursorType(TRUE
, FALSE
);
1831 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1836 InputBuffer
[0] = UNICODE_NULL
;
1837 CONSOLE_SetCursorType(TRUE
, FALSE
);
1840 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1841 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1844 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1846 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1847 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1850 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1852 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1853 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1858 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1861 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1862 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1867 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1870 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1871 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1875 memmove(&InputBuffer
[Pos
],
1876 &InputBuffer
[Pos
+ 1],
1877 (Length
- Pos
- 1) * sizeof(WCHAR
));
1878 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1881 CONSOLE_SetInputTextXY(iLeft
,
1883 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1885 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1888 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1893 memmove(&InputBuffer
[Pos
- 1],
1895 (Length
- Pos
) * sizeof(WCHAR
));
1896 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1900 CONSOLE_SetInputTextXY(iLeft
,
1902 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1904 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1907 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1909 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1911 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1913 if ((ch
>= L
'0') && (ch
<= L
'9'))
1916 memmove(&InputBuffer
[Pos
+ 1],
1918 (Length
- Pos
) * sizeof(WCHAR
));
1919 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1920 InputBuffer
[Pos
] = ch
;
1924 CONSOLE_SetInputTextXY(iLeft
,
1926 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1928 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1937 * Displays the CreatePrimaryPartitionPage.
1940 * SelectPartitionPage
1941 * SelectFileSystemPage (default)
1945 * Number of the next page.
1948 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1950 PDISKENTRY DiskEntry
;
1951 PPARTENTRY PartEntry
;
1954 WCHAR InputBuffer
[50];
1958 ULONGLONG SectorCount
;
1961 if (PartitionList
== NULL
||
1962 PartitionList
->CurrentDisk
== NULL
||
1963 PartitionList
->CurrentPartition
== NULL
)
1965 /* FIXME: show an error dialog */
1969 DiskEntry
= PartitionList
->CurrentDisk
;
1970 PartEntry
= PartitionList
->CurrentPartition
;
1972 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1974 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1976 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1978 if (DiskSize
>= 10 * GB
) /* 10 GB */
1980 DiskSize
= DiskSize
/ GB
;
1981 Unit
= MUIGetString(STRING_GB
);
1986 DiskSize
= DiskSize
/ MB
;
1990 Unit
= MUIGetString(STRING_MB
);
1993 if (DiskEntry
->DriverName
.Length
> 0)
1995 CONSOLE_PrintTextXY(6, 10,
1996 MUIGetString(STRING_HDINFOPARTCREATE_1
),
1999 DiskEntry
->DiskNumber
,
2003 &DiskEntry
->DriverName
,
2004 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2005 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2010 CONSOLE_PrintTextXY(6, 10,
2011 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2014 DiskEntry
->DiskNumber
,
2018 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2019 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2023 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2026 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2027 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2030 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2032 PartEntry
= PartitionList
->CurrentPartition
;
2035 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2037 if (MaxSize
> PARTITION_MAXSIZE
)
2038 MaxSize
= PARTITION_MAXSIZE
;
2040 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2041 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2045 if (ConfirmQuit(Ir
))
2052 return SELECT_PARTITION_PAGE
;
2056 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2064 if (PartSize
> MaxSize
)
2070 /* Convert to bytes */
2071 if (PartSize
== MaxSize
)
2073 /* Use all of the unpartitioned disk space */
2074 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2078 /* Calculate the sector count from the size in MB */
2079 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2081 /* But never get larger than the unpartitioned disk space */
2082 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2083 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2086 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2088 CreatePrimaryPartition(PartitionList
,
2089 PartitionList
->CurrentPartition
,
2093 return SELECT_PARTITION_PAGE
;
2097 return CREATE_PRIMARY_PARTITION_PAGE
;
2102 * Displays the CreateExtendedPartitionPage.
2105 * SelectPartitionPage (default)
2109 * Number of the next page.
2112 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2114 PDISKENTRY DiskEntry
;
2115 PPARTENTRY PartEntry
;
2118 WCHAR InputBuffer
[50];
2122 ULONGLONG SectorCount
;
2125 if (PartitionList
== NULL
||
2126 PartitionList
->CurrentDisk
== NULL
||
2127 PartitionList
->CurrentPartition
== NULL
)
2129 /* FIXME: show an error dialog */
2133 DiskEntry
= PartitionList
->CurrentDisk
;
2134 PartEntry
= PartitionList
->CurrentPartition
;
2136 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2138 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2140 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2142 if (DiskSize
>= 10 * GB
) /* 10 GB */
2144 DiskSize
= DiskSize
/ GB
;
2145 Unit
= MUIGetString(STRING_GB
);
2150 DiskSize
= DiskSize
/ MB
;
2154 Unit
= MUIGetString(STRING_MB
);
2157 if (DiskEntry
->DriverName
.Length
> 0)
2159 CONSOLE_PrintTextXY(6, 10,
2160 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2163 DiskEntry
->DiskNumber
,
2167 &DiskEntry
->DriverName
,
2168 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2169 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2174 CONSOLE_PrintTextXY(6, 10,
2175 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2178 DiskEntry
->DiskNumber
,
2182 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2183 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2187 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2190 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2191 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2194 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2196 PartEntry
= PartitionList
->CurrentPartition
;
2199 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2201 if (MaxSize
> PARTITION_MAXSIZE
)
2202 MaxSize
= PARTITION_MAXSIZE
;
2204 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2205 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2209 if (ConfirmQuit(Ir
))
2216 return SELECT_PARTITION_PAGE
;
2220 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2228 if (PartSize
> MaxSize
)
2234 /* Convert to bytes */
2235 if (PartSize
== MaxSize
)
2237 /* Use all of the unpartitioned disk space */
2238 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2242 /* Calculate the sector count from the size in MB */
2243 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2245 /* But never get larger than the unpartitioned disk space */
2246 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2247 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2250 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2252 CreateExtendedPartition(PartitionList
,
2253 PartitionList
->CurrentPartition
,
2256 return SELECT_PARTITION_PAGE
;
2260 return CREATE_EXTENDED_PARTITION_PAGE
;
2265 * Displays the CreateLogicalPartitionPage.
2268 * SelectFileSystemPage (default)
2272 * Number of the next page.
2275 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2277 PDISKENTRY DiskEntry
;
2278 PPARTENTRY PartEntry
;
2281 WCHAR InputBuffer
[50];
2285 ULONGLONG SectorCount
;
2288 if (PartitionList
== NULL
||
2289 PartitionList
->CurrentDisk
== NULL
||
2290 PartitionList
->CurrentPartition
== NULL
)
2292 /* FIXME: show an error dialog */
2296 DiskEntry
= PartitionList
->CurrentDisk
;
2297 PartEntry
= PartitionList
->CurrentPartition
;
2299 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2301 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2303 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2305 if (DiskSize
>= 10 * GB
) /* 10 GB */
2307 DiskSize
= DiskSize
/ GB
;
2308 Unit
= MUIGetString(STRING_GB
);
2313 DiskSize
= DiskSize
/ MB
;
2317 Unit
= MUIGetString(STRING_MB
);
2320 if (DiskEntry
->DriverName
.Length
> 0)
2322 CONSOLE_PrintTextXY(6, 10,
2323 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2326 DiskEntry
->DiskNumber
,
2330 &DiskEntry
->DriverName
,
2331 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2332 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2337 CONSOLE_PrintTextXY(6, 10,
2338 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2341 DiskEntry
->DiskNumber
,
2345 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2346 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2350 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2353 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2354 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2357 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2359 PartEntry
= PartitionList
->CurrentPartition
;
2362 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2364 if (MaxSize
> PARTITION_MAXSIZE
)
2365 MaxSize
= PARTITION_MAXSIZE
;
2367 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2368 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2372 if (ConfirmQuit(Ir
))
2379 return SELECT_PARTITION_PAGE
;
2383 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2391 if (PartSize
> MaxSize
)
2397 /* Convert to bytes */
2398 if (PartSize
== MaxSize
)
2400 /* Use all of the unpartitioned disk space */
2401 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2405 /* Calculate the sector count from the size in MB */
2406 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2408 /* But never get larger than the unpartitioned disk space */
2409 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2410 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2413 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2415 CreateLogicalPartition(PartitionList
,
2416 PartitionList
->CurrentPartition
,
2420 return SELECT_PARTITION_PAGE
;
2424 return CREATE_LOGICAL_PARTITION_PAGE
;
2429 * Displays the ConfirmDeleteSystemPartitionPage.
2432 * DeletePartitionPage (default)
2433 * SelectPartitionPage
2436 * Number of the next page.
2439 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2441 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2445 CONSOLE_ConInKey(Ir
);
2447 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2448 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2450 if (ConfirmQuit(Ir
))
2455 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2457 return DELETE_PARTITION_PAGE
;
2459 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2461 return SELECT_PARTITION_PAGE
;
2465 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2470 * Displays the DeletePartitionPage.
2473 * SelectPartitionPage (default)
2477 * Number of the next page.
2480 DeletePartitionPage(PINPUT_RECORD Ir
)
2482 PDISKENTRY DiskEntry
;
2483 PPARTENTRY PartEntry
;
2487 CHAR PartTypeString
[32];
2489 if (PartitionList
== NULL
||
2490 PartitionList
->CurrentDisk
== NULL
||
2491 PartitionList
->CurrentPartition
== NULL
)
2493 /* FIXME: show an error dialog */
2497 DiskEntry
= PartitionList
->CurrentDisk
;
2498 PartEntry
= PartitionList
->CurrentPartition
;
2500 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2502 /* Adjust partition type */
2503 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2505 ARRAYSIZE(PartTypeString
));
2507 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2509 if (PartSize
>= 10 * GB
) /* 10 GB */
2511 PartSize
= PartSize
/ GB
;
2512 Unit
= MUIGetString(STRING_GB
);
2516 if (PartSize
>= 10 * MB
) /* 10 MB */
2518 PartSize
= PartSize
/ MB
;
2519 Unit
= MUIGetString(STRING_MB
);
2523 PartSize
= PartSize
/ KB
;
2524 Unit
= MUIGetString(STRING_KB
);
2527 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2529 CONSOLE_PrintTextXY(6, 10,
2530 MUIGetString(STRING_HDDINFOUNK2
),
2531 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2532 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2533 PartEntry
->PartitionType
,
2539 CONSOLE_PrintTextXY(6, 10,
2540 " %c%c %s %I64u %s",
2541 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2542 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2548 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2550 if (DiskSize
>= 10 * GB
) /* 10 GB */
2552 DiskSize
= DiskSize
/ GB
;
2553 Unit
= MUIGetString(STRING_GB
);
2558 DiskSize
= DiskSize
/ MB
;
2562 Unit
= MUIGetString(STRING_MB
);
2565 if (DiskEntry
->DriverName
.Length
> 0)
2567 CONSOLE_PrintTextXY(6, 12,
2568 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2571 DiskEntry
->DiskNumber
,
2575 &DiskEntry
->DriverName
,
2576 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2577 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2582 CONSOLE_PrintTextXY(6, 12,
2583 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2586 DiskEntry
->DiskNumber
,
2590 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2591 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2597 CONSOLE_ConInKey(Ir
);
2599 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2600 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2602 if (ConfirmQuit(Ir
))
2607 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2609 return SELECT_PARTITION_PAGE
;
2611 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2613 DeleteCurrentPartition(PartitionList
);
2614 return SELECT_PARTITION_PAGE
;
2618 return DELETE_PARTITION_PAGE
;
2623 ResetFileSystemList(VOID
)
2625 if (!FileSystemList
)
2628 DestroyFileSystemList(FileSystemList
);
2629 FileSystemList
= NULL
;
2633 * Displays the SelectFileSystemPage.
2636 * CheckFileSystemPage (At once if RepairUpdate is selected)
2637 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2638 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2639 * SelectPartitionPage (If the user aborts)
2640 * FormatPartitionPage (Default)
2644 * Calls UpdatePartitionType()
2645 * Calls CheckActiveSystemPartition()
2648 * Number of the next page.
2651 SelectFileSystemPage(PINPUT_RECORD Ir
)
2653 PDISKENTRY DiskEntry
;
2654 PPARTENTRY PartEntry
;
2659 CHAR PartTypeString
[32];
2660 FORMATMACHINESTATE PreviousFormatState
;
2663 DPRINT("SelectFileSystemPage()\n");
2665 if (PartitionList
== NULL
||
2666 PartitionList
->CurrentDisk
== NULL
||
2667 PartitionList
->CurrentPartition
== NULL
)
2669 /* FIXME: show an error dialog */
2673 /* Find or set the active system partition when starting formatting */
2674 if (FormatState
== Start
)
2676 /* Find or set the active system partition */
2677 CheckActiveSystemPartition(PartitionList
);
2678 if (PartitionList
->SystemPartition
== NULL
)
2680 /* FIXME: show an error dialog */
2682 // Error dialog should say that we cannot find a suitable
2683 // system partition and create one on the system. At this point,
2684 // it may be nice to ask the user whether he wants to continue,
2685 // or use an external drive as the system drive/partition
2686 // (e.g. floppy, USB drive, etc...)
2692 * If the system partition can be created in some
2693 * non-partitioned space, create it now.
2695 if (!PartitionList
->SystemPartition
->IsPartitioned
)
2697 // if (IsUnattendedSetup)
2699 CreatePrimaryPartition(PartitionList
,
2700 PartitionList
->SystemPartition
,
2701 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart,
2703 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2710 /* Commit all partition changes to all the disks */
2711 if (!WritePartitionsToDisk(PartitionList
))
2713 DPRINT("WritePartitionsToDisk() failed\n");
2714 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
2719 * In all cases, whether or not we are going to perform a formatting,
2720 * we must perform a filesystem check of both the system and the
2721 * installation partitions.
2723 PartitionList
->CurrentPartition
->NeedsCheck
= TRUE
;
2724 if (PartitionList
->SystemPartition
!= PartitionList
->CurrentPartition
)
2725 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2728 * In case we just repair an existing installation, or make
2729 * an unattended setup without formatting, just go to the
2730 * filesystem check step.
2732 if (RepairUpdateFlag
)
2733 return CHECK_FILE_SYSTEM_PAGE
;
2735 if (IsUnattendedSetup
&& !USetupData
.FormatPartition
)
2736 return CHECK_FILE_SYSTEM_PAGE
;
2739 // ASSERT(PartitionList->SystemPartition->IsPartitioned);
2741 /* Reset the filesystem list for each partition that is to be formatted */
2742 ResetFileSystemList();
2744 PreviousFormatState
= FormatState
;
2745 switch (FormatState
)
2750 * We start by formatting the system partition in case it is new
2751 * (it didn't exist before) and is not the same as the installation
2752 * partition. Otherwise we just require a filesystem check on it,
2753 * and start by formatting the installation partition instead.
2756 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2758 if ((PartitionList
->SystemPartition
!= PartitionList
->CurrentPartition
) &&
2759 (PartitionList
->SystemPartition
->FormatState
== Unformatted
))
2761 TempPartition
= PartitionList
->SystemPartition
;
2762 TempPartition
->NeedsCheck
= TRUE
;
2764 // TODO: Should we let the user using a custom file-system,
2765 // or should we always use FAT(32) for it?
2766 // For "compatibility", FAT(32) would be best indeed.
2768 FormatState
= FormatSystemPartition
;
2769 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2773 TempPartition
= PartitionList
->CurrentPartition
;
2774 TempPartition
->NeedsCheck
= TRUE
;
2776 if (PartitionList
->SystemPartition
!= PartitionList
->CurrentPartition
)
2778 /* The system partition is separate, so it had better be formatted! */
2779 ASSERT((PartitionList
->SystemPartition
->FormatState
== Preformatted
) ||
2780 (PartitionList
->SystemPartition
->FormatState
== Formatted
));
2782 /* Require a filesystem check on the system partition too */
2783 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2786 FormatState
= FormatInstallPartition
;
2787 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2792 case FormatSystemPartition
:
2794 TempPartition
= PartitionList
->CurrentPartition
;
2795 TempPartition
->NeedsCheck
= TRUE
;
2797 FormatState
= FormatInstallPartition
;
2798 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2802 case FormatInstallPartition
:
2803 case FormatOtherPartition
:
2805 if (GetNextUnformattedPartition(PartitionList
,
2809 FormatState
= FormatOtherPartition
;
2810 TempPartition
->NeedsCheck
= TRUE
;
2812 if (FormatState
== FormatInstallPartition
)
2813 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2815 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2819 FormatState
= FormatDone
;
2821 if (FormatState
== FormatInstallPartition
)
2822 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2824 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2826 return CHECK_FILE_SYSTEM_PAGE
;
2833 DPRINT1("FormatState: FormatDone\n");
2834 return CHECK_FILE_SYSTEM_PAGE
;
2839 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2840 /* FIXME: show an error dialog */
2845 PartEntry
= TempPartition
;
2846 DiskEntry
= PartEntry
->DiskEntry
;
2848 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
2850 /* Adjust disk size */
2851 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2852 if (DiskSize
>= 10 * GB
) /* 10 GB */
2854 DiskSize
= DiskSize
/ GB
;
2855 DiskUnit
= MUIGetString(STRING_GB
);
2859 DiskSize
= DiskSize
/ MB
;
2860 DiskUnit
= MUIGetString(STRING_MB
);
2863 /* Adjust partition size */
2864 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2865 if (PartSize
>= 10 * GB
) /* 10 GB */
2867 PartSize
= PartSize
/ GB
;
2868 PartUnit
= MUIGetString(STRING_GB
);
2872 PartSize
= PartSize
/ MB
;
2873 PartUnit
= MUIGetString(STRING_MB
);
2876 /* Adjust partition type */
2877 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2879 ARRAYSIZE(PartTypeString
));
2881 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2883 if (PartEntry
->AutoCreate
)
2885 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2888 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2889 PartEntry
->PartitionNumber
,
2895 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2896 DiskEntry
->DiskNumber
,
2902 &DiskEntry
->DriverName
,
2903 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2904 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2907 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2909 PartEntry
->AutoCreate
= FALSE
;
2911 else if (PartEntry
->New
)
2913 switch (FormatState
)
2915 case FormatSystemPartition
:
2916 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2919 case FormatInstallPartition
:
2920 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2923 case FormatOtherPartition
:
2924 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2931 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2935 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2937 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2939 CONSOLE_PrintTextXY(8, 10,
2940 MUIGetString(STRING_HDDINFOUNK4
),
2941 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2942 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2943 PartEntry
->PartitionType
,
2949 CONSOLE_PrintTextXY(8, 10,
2951 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2952 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2958 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2959 DiskEntry
->DiskNumber
,
2965 &DiskEntry
->DriverName
,
2966 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2967 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2971 ASSERT(FileSystemList
== NULL
);
2973 if (IsUnattendedSetup
)
2975 ASSERT(USetupData
.FormatPartition
);
2977 switch (USetupData
.FsType
)
2979 /* 1 is for BtrFS */
2981 DefaultFs
= L
"BTRFS";
2984 /* If we don't understand input, default to FAT */
2992 /* By default select the "FAT" file system */
2996 /* Create the file system list */
2997 // TODO: Display only the FSes compatible with the selected partition!
2998 FileSystemList
= CreateFileSystemList(6, 26,
3000 PartEntry
->FormatState
== Unformatted
,
3002 if (FileSystemList
== NULL
)
3004 /* FIXME: show an error dialog */
3008 if (IsUnattendedSetup
)
3010 ASSERT(USetupData
.FormatPartition
);
3011 return FORMAT_PARTITION_PAGE
;
3014 DrawFileSystemList(FileSystemList
);
3018 CONSOLE_ConInKey(Ir
);
3020 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3021 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3023 if (ConfirmQuit(Ir
))
3025 /* Reset the filesystem list */
3026 ResetFileSystemList();
3032 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3033 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
3035 /* Reset the formatter machine state */
3036 TempPartition
= NULL
;
3037 FormatState
= Start
;
3039 /* Reset the filesystem list */
3040 ResetFileSystemList();
3042 return SELECT_PARTITION_PAGE
;
3044 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3045 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
3047 ScrollDownFileSystemList(FileSystemList
);
3049 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3050 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
3052 ScrollUpFileSystemList(FileSystemList
);
3054 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
3056 if (!FileSystemList
->Selected
->FileSystem
)
3058 ASSERT(!TempPartition
->New
&& TempPartition
->FormatState
!= Unformatted
);
3061 * Skip formatting this partition. We will also ignore
3062 * filesystem checks on it, unless it is either the system
3063 * or the installation partition.
3065 if (TempPartition
!= PartitionList
->SystemPartition
&&
3066 TempPartition
!= PartitionList
->CurrentPartition
)
3068 PartEntry
->NeedsCheck
= FALSE
;
3071 return SELECT_FILE_SYSTEM_PAGE
;
3075 /* Format this partition */
3076 return FORMAT_PARTITION_PAGE
;
3081 FormatState
= PreviousFormatState
;
3083 return SELECT_FILE_SYSTEM_PAGE
;
3088 * Displays the FormatPartitionPage.
3091 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3092 * SelectPartitionPage (At once)
3096 * Sets PartitionList->CurrentPartition->FormatState
3097 * Sets USetupData.DestinationRootPath
3100 * Number of the next page.
3103 FormatPartitionPage(PINPUT_RECORD Ir
)
3106 PDISKENTRY DiskEntry
;
3107 PPARTENTRY PartEntry
;
3108 PFILE_SYSTEM_ITEM SelectedFileSystem
;
3109 UNICODE_STRING PartitionRootPath
;
3110 WCHAR PathBuffer
[MAX_PATH
];
3111 CHAR Buffer
[MAX_PATH
];
3116 PPARTITION_INFORMATION PartitionInfo
;
3119 DPRINT("FormatPartitionPage()\n");
3121 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
3123 if (PartitionList
== NULL
|| TempPartition
== NULL
)
3125 /* FIXME: show an error dialog */
3129 PartEntry
= TempPartition
;
3130 DiskEntry
= PartEntry
->DiskEntry
;
3132 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3134 SelectedFileSystem
= FileSystemList
->Selected
;
3135 ASSERT(SelectedFileSystem
&& SelectedFileSystem
->FileSystem
);
3139 if (!IsUnattendedSetup
)
3140 CONSOLE_ConInKey(Ir
);
3142 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3143 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3145 if (ConfirmQuit(Ir
))
3147 /* Reset the filesystem list */
3148 ResetFileSystemList();
3154 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3156 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3158 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3160 /* FIXME: show an error dialog */
3162 /* Reset the filesystem list */
3163 ResetFileSystemList();
3169 CONSOLE_PrintTextXY(6, 12,
3170 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3171 DiskEntry
->Cylinders
,
3172 DiskEntry
->TracksPerCylinder
,
3173 DiskEntry
->SectorsPerTrack
,
3174 DiskEntry
->BytesPerSector
,
3175 DiskEntry
->Dirty
? '*' : ' ');
3179 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3181 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3183 CONSOLE_PrintTextXY(6, Line
,
3184 "%2u: %2lu %c %12I64u %12I64u %02x",
3186 PartitionInfo
->PartitionNumber
,
3187 PartitionInfo
->BootIndicator
? 'A' : '-',
3188 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3189 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3190 PartitionInfo
->PartitionType
);
3195 /* Commit the partition changes to the disk */
3196 Status
= WritePartitions(DiskEntry
);
3197 if (!NT_SUCCESS(Status
))
3199 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
3200 DiskEntry
->DiskNumber
, Status
);
3202 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3204 /* Reset the filesystem list */
3205 ResetFileSystemList();
3210 /* Set PartitionRootPath */
3211 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3212 L
"\\Device\\Harddisk%lu\\Partition%lu",
3213 DiskEntry
->DiskNumber
,
3214 PartEntry
->PartitionNumber
);
3215 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3216 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3218 /* Format the partition */
3219 Status
= FormatPartition(&PartitionRootPath
,
3220 SelectedFileSystem
->FileSystem
,
3221 SelectedFileSystem
->QuickFormat
);
3222 if (Status
== STATUS_NOT_SUPPORTED
)
3225 "Setup is currently unable to format a partition in %S.\n"
3227 " \x07 Press ENTER to continue Setup.\n"
3228 " \x07 Press F3 to quit Setup.",
3229 SelectedFileSystem
->FileSystem
);
3232 MUIGetString(STRING_QUITCONTINUE
),
3233 NULL
, POPUP_WAIT_NONE
);
3237 CONSOLE_ConInKey(Ir
);
3239 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3240 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3242 if (ConfirmQuit(Ir
))
3244 /* Reset the filesystem list */
3245 ResetFileSystemList();
3250 return SELECT_FILE_SYSTEM_PAGE
;
3253 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3255 return SELECT_FILE_SYSTEM_PAGE
;
3259 else if (!NT_SUCCESS(Status
))
3261 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3262 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3264 /* Reset the filesystem list */
3265 ResetFileSystemList();
3271 // TODO: Here, call a partlist.c function that update the actual FS name
3272 // and the label fields of the volume.
3274 PartEntry
->FormatState
= Formatted
;
3275 // PartEntry->FileSystem = FileSystem;
3276 PartEntry
->New
= FALSE
;
3279 CONSOLE_SetStatusText(" Done. Press any key ...");
3280 CONSOLE_ConInKey(Ir
);
3283 return SELECT_FILE_SYSTEM_PAGE
;
3287 return FORMAT_PARTITION_PAGE
;
3292 * Displays the CheckFileSystemPage.
3295 * InstallDirectoryPage (At once)
3299 * Inits or reloads FileSystemList
3302 * Number of the next page.
3305 CheckFileSystemPage(PINPUT_RECORD Ir
)
3308 PDISKENTRY DiskEntry
;
3309 PPARTENTRY PartEntry
;
3310 UNICODE_STRING PartitionRootPath
;
3311 WCHAR PathBuffer
[MAX_PATH
];
3312 CHAR Buffer
[MAX_PATH
];
3314 if (PartitionList
== NULL
)
3316 /* FIXME: show an error dialog */
3320 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3322 return INSTALL_DIRECTORY_PAGE
;
3325 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3327 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3329 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3331 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3332 PartEntry
->PartitionType
, (*PartEntry
->FileSystem
? PartEntry
->FileSystem
: L
"n/a"));
3334 /* HACK: Do not try to check a partition with an unknown filesystem */
3335 if (!*PartEntry
->FileSystem
)
3337 PartEntry
->NeedsCheck
= FALSE
;
3338 return CHECK_FILE_SYSTEM_PAGE
;
3341 /* Set PartitionRootPath */
3342 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3343 L
"\\Device\\Harddisk%lu\\Partition%lu",
3344 DiskEntry
->DiskNumber
,
3345 PartEntry
->PartitionNumber
);
3346 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3347 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3349 /* Check the partition */
3350 Status
= ChkdskPartition(&PartitionRootPath
, PartEntry
->FileSystem
);
3351 if (Status
== STATUS_NOT_SUPPORTED
)
3354 * Partition checking is not supported with the current filesystem,
3355 * so disable FS checks on it.
3357 PartEntry
->NeedsCheck
= FALSE
;
3360 "Setup is currently unable to check a partition formatted in %S.\n"
3362 " \x07 Press ENTER to continue Setup.\n"
3363 " \x07 Press F3 to quit Setup.",
3364 PartEntry
->FileSystem
);
3367 MUIGetString(STRING_QUITCONTINUE
),
3368 NULL
, POPUP_WAIT_NONE
);
3372 CONSOLE_ConInKey(Ir
);
3374 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3375 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3377 if (ConfirmQuit(Ir
))
3380 return CHECK_FILE_SYSTEM_PAGE
;
3382 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3384 return CHECK_FILE_SYSTEM_PAGE
;
3388 else if (!NT_SUCCESS(Status
))
3390 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3391 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3392 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3393 "(Status 0x%08lx).\n", Status
);
3395 // MUIGetString(STRING_REBOOTCOMPUTER),
3396 MUIGetString(STRING_CONTINUE
),
3397 Ir
, POPUP_WAIT_ENTER
);
3399 // return QUIT_PAGE;
3402 PartEntry
->NeedsCheck
= FALSE
;
3403 return CHECK_FILE_SYSTEM_PAGE
;
3408 BuildInstallPaths(PWSTR InstallDir
,
3409 PDISKENTRY DiskEntry
,
3410 PPARTENTRY PartEntry
)
3414 Status
= InitDestinationPaths(&USetupData
, InstallDir
, DiskEntry
, PartEntry
);
3416 if (!NT_SUCCESS(Status
))
3418 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status
);
3422 /* Initialize DestinationDriveLetter */
3423 DestinationDriveLetter
= PartEntry
->DriveLetter
;
3425 return STATUS_SUCCESS
;
3431 IN PCWSTR InstallDir
)
3435 Length
= wcslen(InstallDir
);
3437 // TODO: Add check for 8.3 too.
3439 /* Path must be at least 2 characters long */
3443 /* Path must start with a backslash */
3444 // if (InstallDir[0] != L'\\')
3447 /* Path must not end with a backslash */
3448 if (InstallDir
[Length
- 1] == L
'\\')
3451 /* Path must not contain whitespace characters */
3452 for (i
= 0; i
< Length
; i
++)
3454 if (iswspace(InstallDir
[i
]))
3458 /* Path component must not end with a dot */
3459 for (i
= 0; i
< Length
; i
++)
3461 if (InstallDir
[i
] == L
'\\' && i
> 0)
3463 if (InstallDir
[i
- 1] == L
'.')
3468 if (InstallDir
[Length
- 1] == L
'.')
3476 * Displays the InstallDirectoryPage.
3483 * Number of the next page.
3486 InstallDirectoryPage(PINPUT_RECORD Ir
)
3488 PDISKENTRY DiskEntry
;
3489 PPARTENTRY PartEntry
;
3490 WCHAR InstallDir
[MAX_PATH
];
3495 /* We do not need the filesystem list anymore */
3496 ResetFileSystemList();
3498 if (PartitionList
== NULL
||
3499 PartitionList
->CurrentDisk
== NULL
||
3500 PartitionList
->CurrentPartition
== NULL
)
3502 /* FIXME: show an error dialog */
3506 DiskEntry
= PartitionList
->CurrentDisk
;
3507 PartEntry
= PartitionList
->CurrentPartition
;
3509 // if (IsUnattendedSetup)
3510 if (RepairUpdateFlag
)
3511 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3512 else if (USetupData
.InstallationDirectory
[0])
3513 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3515 wcscpy(InstallDir
, L
"\\ReactOS");
3518 * Check the validity of the predefined 'InstallDir'. If we are either
3519 * in unattended setup or in update/repair mode, and the installation path
3520 * is valid, just perform the installation. Otherwise (either in the case
3521 * of an invalid path, or we are in regular setup), display the UI and allow
3522 * the user to specify a new installation path.
3524 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3526 Status
= BuildInstallPaths(InstallDir
,
3529 if (!NT_SUCCESS(Status
))
3531 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3532 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3533 MUIGetString(STRING_CONTINUE
),
3534 Ir
, POPUP_WAIT_ENTER
);
3539 * Check whether the user attempts to install ReactOS within the
3540 * installation source directory, or in a subdirectory thereof.
3541 * If so, fail with an error.
3543 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3545 PopupError("You cannot install ReactOS within the installation source directory!",
3546 MUIGetString(STRING_CONTINUE
),
3547 Ir
, POPUP_WAIT_ENTER
);
3548 return INSTALL_DIRECTORY_PAGE
;
3551 return PREPARE_COPY_PAGE
;
3554 Length
= wcslen(InstallDir
);
3557 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3558 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3559 CONSOLE_SetCursorXY(8 + Pos
, 11);
3560 CONSOLE_SetCursorType(TRUE
, TRUE
);
3564 CONSOLE_ConInKey(Ir
);
3566 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3567 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3569 CONSOLE_SetCursorType(TRUE
, FALSE
);
3571 if (ConfirmQuit(Ir
))
3574 CONSOLE_SetCursorType(TRUE
, TRUE
);
3577 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3578 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3582 memmove(&InstallDir
[Pos
],
3583 &InstallDir
[Pos
+ 1],
3584 (Length
- Pos
- 1) * sizeof(WCHAR
));
3585 InstallDir
[Length
- 1] = UNICODE_NULL
;
3588 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3589 CONSOLE_SetCursorXY(8 + Pos
, 11);
3592 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3593 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3596 CONSOLE_SetCursorXY(8 + Pos
, 11);
3598 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3599 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3602 CONSOLE_SetCursorXY(8 + Pos
, 11);
3604 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3605 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3610 CONSOLE_SetCursorXY(8 + Pos
, 11);
3613 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3614 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3619 CONSOLE_SetCursorXY(8 + Pos
, 11);
3622 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3624 CONSOLE_SetCursorType(TRUE
, FALSE
);
3627 * Check for the validity of the installation directory and pop up
3628 * an error if it is not the case. Then the user can fix its input.
3630 if (!IsValidPath(InstallDir
))
3632 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3633 return INSTALL_DIRECTORY_PAGE
;
3636 Status
= BuildInstallPaths(InstallDir
,
3639 if (!NT_SUCCESS(Status
))
3641 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3642 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3643 MUIGetString(STRING_CONTINUE
),
3644 Ir
, POPUP_WAIT_ENTER
);
3649 * Check whether the user attempts to install ReactOS within the
3650 * installation source directory, or in a subdirectory thereof.
3651 * If so, fail with an error.
3653 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3655 PopupError("You cannot install ReactOS within the installation source directory!",
3656 MUIGetString(STRING_CONTINUE
),
3657 Ir
, POPUP_WAIT_ENTER
);
3658 return INSTALL_DIRECTORY_PAGE
;
3661 return PREPARE_COPY_PAGE
;
3663 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3668 memmove(&InstallDir
[Pos
- 1],
3670 (Length
- Pos
) * sizeof(WCHAR
));
3671 InstallDir
[Length
- 1] = UNICODE_NULL
;
3675 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3676 CONSOLE_SetCursorXY(8 + Pos
, 11);
3679 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3683 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3684 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3687 memmove(&InstallDir
[Pos
+ 1],
3689 (Length
- Pos
) * sizeof(WCHAR
));
3690 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3691 InstallDir
[Pos
] = c
;
3695 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3696 CONSOLE_SetCursorXY(8 + Pos
, 11);
3702 return INSTALL_DIRECTORY_PAGE
;
3706 // PSETUP_ERROR_ROUTINE
3710 IN PUSETUP_DATA pSetupData
,
3716 va_start(arg_ptr
, pSetupData
);
3718 if (pSetupData
->LastErrorNumber
>= ERROR_SUCCESS
&&
3719 pSetupData
->LastErrorNumber
< ERROR_LAST_ERROR_CODE
)
3721 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3722 MUIDisplayErrorV(pSetupData
->LastErrorNumber
, &Ir
, POPUP_WAIT_ENTER
, arg_ptr
);
3729 * Displays the PrepareCopyPage.
3732 * FileCopyPage(At once)
3736 * Calls PrepareFileCopy
3739 * Number of the next page.
3742 PrepareCopyPage(PINPUT_RECORD Ir
)
3744 // ERROR_NUMBER ErrorNumber;
3747 MUIDisplayPage(PREPARE_COPY_PAGE
);
3749 /* ErrorNumber = */ Success
= PrepareFileCopy(&USetupData
, NULL
);
3750 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success
)
3752 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3756 return FILE_COPY_PAGE
;
3759 typedef struct _COPYCONTEXT
3761 ULONG TotalOperations
;
3762 ULONG CompletedOperations
;
3763 PPROGRESSBAR ProgressBar
;
3764 PPROGRESSBAR MemoryBars
[4];
3765 } COPYCONTEXT
, *PCOPYCONTEXT
;
3768 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3771 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3773 /* Get the memory information from the system */
3774 NtQuerySystemInformation(SystemPerformanceInformation
,
3779 /* Check if this is initial setup */
3782 /* Set maximum limits to be total RAM pages */
3783 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3784 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3785 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3788 /* Set current values */
3789 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3790 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3791 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3796 FileCopyCallback(PVOID Context
,
3801 PCOPYCONTEXT CopyContext
= (PCOPYCONTEXT
)Context
;
3802 PFILEPATHS_W FilePathInfo
;
3803 PCWSTR SrcFileName
, DstFileName
;
3805 switch (Notification
)
3807 case SPFILENOTIFY_STARTSUBQUEUE
:
3809 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3810 CopyContext
->CompletedOperations
= 0;
3811 ProgressSetStepCount(CopyContext
->ProgressBar
,
3812 CopyContext
->TotalOperations
);
3813 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3817 case SPFILENOTIFY_STARTDELETE
:
3818 case SPFILENOTIFY_STARTRENAME
:
3819 case SPFILENOTIFY_STARTCOPY
:
3821 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3823 if (Notification
== SPFILENOTIFY_STARTDELETE
)
3825 /* Display delete message */
3826 ASSERT(Param2
== FILEOP_DELETE
);
3828 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3829 if (DstFileName
) ++DstFileName
;
3830 else DstFileName
= FilePathInfo
->Target
;
3832 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING
),
3835 else if (Notification
== SPFILENOTIFY_STARTRENAME
)
3837 /* Display move/rename message */
3838 ASSERT(Param2
== FILEOP_RENAME
);
3840 SrcFileName
= wcsrchr(FilePathInfo
->Source
, L
'\\');
3841 if (SrcFileName
) ++SrcFileName
;
3842 else SrcFileName
= FilePathInfo
->Source
;
3844 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3845 if (DstFileName
) ++DstFileName
;
3846 else DstFileName
= FilePathInfo
->Target
;
3848 if (!wcsicmp(SrcFileName
, DstFileName
))
3849 Param2
= STRING_MOVING
;
3851 Param2
= STRING_RENAMING
;
3853 CONSOLE_SetStatusText(MUIGetString(Param2
),
3854 SrcFileName
, DstFileName
);
3856 else if (Notification
== SPFILENOTIFY_STARTCOPY
)
3858 /* Display copy message */
3859 ASSERT(Param2
== FILEOP_COPY
);
3861 /* NOTE: When extracting from CABs the Source is the CAB name */
3862 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3863 if (DstFileName
) ++DstFileName
;
3864 else DstFileName
= FilePathInfo
->Target
;
3866 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
),
3870 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3874 case SPFILENOTIFY_COPYERROR
:
3876 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3878 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3879 FilePathInfo
->Target
, FilePathInfo
->Win32Error
);
3883 case SPFILENOTIFY_ENDDELETE
:
3884 case SPFILENOTIFY_ENDRENAME
:
3885 case SPFILENOTIFY_ENDCOPY
:
3887 CopyContext
->CompletedOperations
++;
3889 /* SYSREG checkpoint */
3890 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3891 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3893 ProgressNextStep(CopyContext
->ProgressBar
);
3894 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3904 * Displays the FileCopyPage.
3907 * RegistryPage(At once)
3913 * Number of the next page.
3916 FileCopyPage(PINPUT_RECORD Ir
)
3918 COPYCONTEXT CopyContext
;
3921 MUIDisplayPage(FILE_COPY_PAGE
);
3923 /* Create context for the copy process */
3924 CopyContext
.TotalOperations
= 0;
3925 CopyContext
.CompletedOperations
= 0;
3927 /* Create the progress bar as well */
3928 CopyContext
.ProgressBar
= CreateProgressBar(13,
3935 MUIGetString(STRING_SETUPCOPYINGFILES
));
3937 // fit memory bars to screen width, distribute them uniform
3938 MemBarWidth
= (xScreen
- 26) / 5;
3939 MemBarWidth
-= MemBarWidth
% 2; // make even
3940 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3941 /* Create the paged pool progress bar */
3942 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
3951 /* Create the non paged pool progress bar */
3952 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (MemBarWidth
/ 2),
3954 (xScreen
/ 2) + (MemBarWidth
/ 2),
3956 (xScreen
/ 2)- (MemBarWidth
/ 2),
3961 /* Create the global memory progress bar */
3962 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - MemBarWidth
,
3966 xScreen
- 13 - MemBarWidth
,
3971 /* Do the file copying */
3972 DoFileCopy(&USetupData
, FileCopyCallback
, &CopyContext
);
3974 /* If we get here, we're done, so cleanup the progress bar */
3975 DestroyProgressBar(CopyContext
.ProgressBar
);
3976 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
3977 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
3978 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
3980 /* Create the $winnt$.inf file */
3981 InstallSetupInfFile(&USetupData
);
3983 /* Go display the next page */
3984 return REGISTRY_PAGE
;
3990 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
3992 /* WARNING: Please keep this lookup table in sync with the resources! */
3993 static const UINT StringIDs
[] =
3995 STRING_DONE
, /* Success */
3996 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
3997 STRING_IMPORTFILE
, /* ImportRegHive */
3998 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
3999 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4000 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4001 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4002 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4007 if (RegStatus
< ARRAYSIZE(StringIDs
))
4009 va_start(args
, RegStatus
);
4010 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4015 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4020 * Displays the RegistryPage.
4023 * SuccessPage (if RepairUpdate)
4024 * BootLoaderPage (default)
4028 * Calls UpdateRegistry
4031 * Number of the next page.
4034 RegistryPage(PINPUT_RECORD Ir
)
4038 MUIDisplayPage(REGISTRY_PAGE
);
4040 Error
= UpdateRegistry(&USetupData
,
4043 DestinationDriveLetter
,
4046 if (Error
!= ERROR_SUCCESS
)
4048 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4053 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4054 return BOOT_LOADER_PAGE
;
4060 * Displays the BootLoaderPage.
4063 * SuccessPage (if RepairUpdate)
4064 * BootLoaderHarddiskMbrPage
4065 * BootLoaderHarddiskVbrPage
4066 * BootLoaderFloppyPage
4071 * Calls RegInitializeRegistry
4072 * Calls ImportRegistryFile
4073 * Calls SetDefaultPagefile
4074 * Calls SetMountedDeviceValues
4077 * Number of the next page.
4080 BootLoaderPage(PINPUT_RECORD Ir
)
4082 UCHAR PartitionType
;
4083 BOOLEAN InstallOnFloppy
;
4085 WCHAR PathBuffer
[MAX_PATH
];
4087 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4089 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
&& PartitionList
->SystemPartition
->PartitionNumber
!= 0);
4091 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4092 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4093 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4094 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4095 PartitionList
->SystemPartition
->PartitionNumber
);
4096 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4097 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4099 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4101 /* For unattended setup, skip MBR installation or install on floppy if needed */
4102 if (IsUnattendedSetup
)
4104 if ((USetupData
.MBRInstallType
== 0) ||
4105 (USetupData
.MBRInstallType
== 1))
4112 * We may install an MBR or VBR, but before that, check whether
4113 * we need to actually install the VBR on floppy.
4115 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4117 DPRINT("Error: system partition invalid (unused)\n");
4118 InstallOnFloppy
= TRUE
;
4120 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4122 /* OS/2 boot manager partition */
4123 DPRINT("Found OS/2 boot manager partition\n");
4124 InstallOnFloppy
= TRUE
;
4126 else if (PartitionType
== PARTITION_LINUX
)
4128 /* Linux partition */
4129 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
4130 InstallOnFloppy
= FALSE
;
4132 else if (PartitionType
== PARTITION_IFS
)
4134 /* NTFS partition */
4135 DPRINT("Found NTFS partition\n");
4137 // FIXME: Make it FALSE when we'll support NTFS installation!
4138 InstallOnFloppy
= TRUE
;
4140 else if ((PartitionType
== PARTITION_FAT_12
) ||
4141 (PartitionType
== PARTITION_FAT_16
) ||
4142 (PartitionType
== PARTITION_HUGE
) ||
4143 (PartitionType
== PARTITION_XINT13
) ||
4144 (PartitionType
== PARTITION_FAT32
) ||
4145 (PartitionType
== PARTITION_FAT32_XINT13
))
4147 DPRINT("Found FAT partition\n");
4148 InstallOnFloppy
= FALSE
;
4152 /* Unknown partition */
4153 DPRINT("Unknown partition found\n");
4154 InstallOnFloppy
= TRUE
;
4157 /* We should install on floppy */
4158 if (InstallOnFloppy
)
4160 USetupData
.MBRInstallType
= 1;
4164 /* Is it an unattended install on hdd? */
4165 if (IsUnattendedSetup
)
4167 if ((USetupData
.MBRInstallType
== 2) ||
4168 (USetupData
.MBRInstallType
== 3))
4174 MUIDisplayPage(BOOT_LOADER_PAGE
);
4175 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4179 CONSOLE_ConInKey(Ir
);
4181 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4182 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4184 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4193 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4195 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4196 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4198 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4207 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4209 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4210 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
4212 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4216 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4218 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4219 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
4221 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4225 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4227 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4228 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4230 if (ConfirmQuit(Ir
))
4235 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4239 /* Install on both MBR and VBR */
4240 USetupData
.MBRInstallType
= 2;
4243 else if (Line
== 13)
4245 /* Install on VBR only */
4246 USetupData
.MBRInstallType
= 3;
4249 else if (Line
== 14)
4251 /* Install on floppy */
4252 USetupData
.MBRInstallType
= 1;
4255 else if (Line
== 15)
4257 /* Skip MBR installation */
4258 USetupData
.MBRInstallType
= 0;
4262 return BOOT_LOADER_PAGE
;
4267 switch (USetupData
.MBRInstallType
)
4269 /* Skip MBR installation */
4271 return SUCCESS_PAGE
;
4273 /* Install on floppy */
4275 return BOOT_LOADER_FLOPPY_PAGE
;
4277 /* Install on both MBR and VBR */
4279 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4281 /* Install on VBR only */
4283 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4286 return BOOT_LOADER_PAGE
;
4291 * Displays the BootLoaderFloppyPage.
4294 * SuccessPage (At once)
4298 * Calls InstallFatBootcodeToFloppy()
4301 * Number of the next page.
4304 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4308 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4310 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4314 CONSOLE_ConInKey(Ir
);
4316 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4317 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4319 if (ConfirmQuit(Ir
))
4324 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4326 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4327 &USetupData
.DestinationArcPath
);
4328 if (!NT_SUCCESS(Status
))
4330 if (Status
== STATUS_DEVICE_NOT_READY
)
4331 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4333 /* TODO: Print error message */
4334 return BOOT_LOADER_FLOPPY_PAGE
;
4337 return SUCCESS_PAGE
;
4341 return BOOT_LOADER_FLOPPY_PAGE
;
4346 * Displays the BootLoaderHarddiskVbrPage.
4349 * SuccessPage (At once)
4353 * Calls InstallVBRToPartition()
4356 * Number of the next page.
4359 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4363 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4364 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4365 &USetupData
.SourceRootPath
,
4366 &USetupData
.DestinationArcPath
,
4367 PartitionList
->SystemPartition
->PartitionType
);
4368 if (!NT_SUCCESS(Status
))
4370 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4371 PartitionList
->SystemPartition
->FileSystem
);
4375 return SUCCESS_PAGE
;
4380 * Displays the BootLoaderHarddiskMbrPage.
4383 * SuccessPage (At once)
4387 * Calls InstallVBRToPartition()
4388 * Calls InstallMbrBootCodeToDisk()
4391 * Number of the next page.
4394 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4397 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4399 /* Step 1: Write the VBR */
4400 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4401 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4402 &USetupData
.SourceRootPath
,
4403 &USetupData
.DestinationArcPath
,
4404 PartitionList
->SystemPartition
->PartitionType
);
4405 if (!NT_SUCCESS(Status
))
4407 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4408 PartitionList
->SystemPartition
->FileSystem
);
4412 /* Step 2: Write the MBR */
4413 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4414 L
"\\Device\\Harddisk%d\\Partition0",
4415 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4416 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4417 &USetupData
.SourceRootPath
,
4418 DestinationDevicePathBuffer
);
4419 if (!NT_SUCCESS(Status
))
4421 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4422 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
, L
"MBR");
4426 return SUCCESS_PAGE
;
4431 * @name ProgressTimeOutStringHandler
4433 * Handles the generation (displaying) of the timeout
4434 * countdown to the screen dynamically.
4437 * A pointer to a progress bar.
4439 * @param AlwaysUpdate
4440 * Constantly update the progress bar (boolean type).
4443 * A pointer to a string buffer.
4445 * @param cchBufferSize
4446 * The buffer's size in number of characters.
4449 * TRUE or FALSE on function termination.
4454 ProgressTimeOutStringHandler(
4455 IN PPROGRESSBAR Bar
,
4456 IN BOOLEAN AlwaysUpdate
,
4458 IN SIZE_T cchBufferSize
)
4460 ULONG OldProgress
= Bar
->Progress
;
4462 if (Bar
->StepCount
== 0)
4468 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4471 /* Build the progress string if it has changed */
4472 if (Bar
->ProgressFormatText
&&
4473 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4475 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4476 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4485 * @name ProgressCountdown
4487 * Displays and draws a red-coloured progress bar with a countdown.
4488 * When the timeout is reached, the flush page is displayed for reboot.
4491 * A pointer to an input keyboard record.
4494 * Initial countdown value in seconds.
4502 IN PINPUT_RECORD Ir
,
4506 ULONG StartTime
, BarWidth
, TimerDiv
;
4508 LONG TimerValue
, OldTimerValue
;
4509 LARGE_INTEGER Timeout
;
4510 PPROGRESSBAR ProgressBar
;
4511 BOOLEAN RefreshProgress
= TRUE
;
4513 /* Bail out if the timeout is already zero */
4517 /* Create the timeout progress bar and set it up */
4518 ProgressBar
= CreateProgressBarEx(13,
4525 FOREGROUND_RED
| BACKGROUND_BLUE
,
4528 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4529 ProgressTimeOutStringHandler
);
4531 BarWidth
= max(1, ProgressBar
->Width
);
4532 TimerValue
= TimeOut
* BarWidth
;
4533 ProgressSetStepCount(ProgressBar
, TimerValue
);
4535 StartTime
= NtGetTickCount();
4538 TimerDiv
= 1000 / BarWidth
;
4539 TimerDiv
= max(1, TimerDiv
);
4540 OldTimerValue
= TimerValue
;
4543 /* Decrease the timer */
4546 * Compute how much time the previous operations took.
4547 * This allows us in particular to take account for any time
4548 * elapsed if something slowed down.
4550 TimeElapsed
= NtGetTickCount() - StartTime
;
4551 if (TimeElapsed
>= TimerDiv
)
4553 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4554 TimeElapsed
/= TimerDiv
;
4555 StartTime
+= (TimerDiv
* TimeElapsed
);
4557 if (TimeElapsed
<= TimerValue
)
4558 TimerValue
-= TimeElapsed
;
4562 RefreshProgress
= TRUE
;
4565 if (RefreshProgress
)
4567 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4568 RefreshProgress
= FALSE
;
4571 /* Stop when the timer reaches zero */
4572 if (TimerValue
<= 0)
4575 /* Check for user key presses */
4578 * If the timer is used, use a passive wait of maximum 1 second
4579 * while monitoring for incoming console input events, so that
4580 * we are still able to display the timing count.
4583 /* Wait a maximum of 1 second for input events */
4584 TimeElapsed
= NtGetTickCount() - StartTime
;
4585 if (TimeElapsed
< TimerDiv
)
4587 /* Convert the time to NT Format */
4588 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4589 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4593 Status
= STATUS_TIMEOUT
;
4596 /* Check whether the input event has been signaled, or a timeout happened */
4597 if (Status
== STATUS_TIMEOUT
)
4601 if (Status
!= STATUS_WAIT_0
)
4603 /* An error happened, bail out */
4604 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4608 /* Check for an ENTER key press */
4609 while (CONSOLE_ConInKeyPeek(Ir
))
4611 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4613 /* Found it, stop waiting */
4620 /* Destroy the progress bar and quit */
4621 DestroyProgressBar(ProgressBar
);
4626 * Displays the QuitPage.
4629 * FlushPage (At once)
4635 * Number of the next page.
4638 QuitPage(PINPUT_RECORD Ir
)
4640 MUIDisplayPage(QUIT_PAGE
);
4642 /* Destroy the NTOS installations list */
4643 if (NtOsInstallsList
!= NULL
)
4645 DestroyGenericList(NtOsInstallsList
, TRUE
);
4646 NtOsInstallsList
= NULL
;
4649 /* Destroy the partition list */
4650 if (PartitionList
!= NULL
)
4652 DestroyPartitionList(PartitionList
);
4653 PartitionList
= NULL
;
4656 /* Reset the formatter machine state */
4657 TempPartition
= NULL
;
4658 FormatState
= Start
;
4660 /* Destroy the filesystem list */
4661 ResetFileSystemList();
4663 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4665 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4666 ProgressCountdown(Ir
, 15);
4672 * Displays the SuccessPage.
4675 * FlushPage (At once)
4681 * Number of the next page.
4684 SuccessPage(PINPUT_RECORD Ir
)
4686 MUIDisplayPage(SUCCESS_PAGE
);
4688 if (IsUnattendedSetup
)
4691 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4692 ProgressCountdown(Ir
, 15);
4698 * Displays the FlushPage.
4701 * RebootPage (At once)
4704 * Number of the next page.
4707 FlushPage(PINPUT_RECORD Ir
)
4709 MUIDisplayPage(FLUSH_PAGE
);
4715 * The start routine and page management
4725 InfSetHeap(ProcessHeap
);
4727 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4728 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4729 if (!NT_SUCCESS(Status
))
4730 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4732 /* Initialize the user-mode PnP manager */
4733 Status
= InitializeUserModePnpManager(&USetupData
.SetupInf
);
4734 if (!NT_SUCCESS(Status
))
4737 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status
);
4740 if (!CONSOLE_Init())
4742 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4743 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4744 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4746 /* We failed to initialize the video, just quit the installer */
4747 return STATUS_APP_INIT_FAILURE
;
4750 /* Initialize Setup, phase 0 */
4751 InitializeSetup(&USetupData
, 0);
4752 USetupData
.ErrorRoutine
= USetupErrorRoutine
;
4754 /* Hide the cursor and clear the screen and keyboard buffer */
4755 CONSOLE_SetCursorType(TRUE
, FALSE
);
4756 CONSOLE_ClearScreen();
4759 /* Global Initialization page */
4760 Page
= SetupStartPage(&Ir
);
4762 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4764 CONSOLE_ClearScreen();
4767 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4774 Page
= LanguagePage(&Ir
);
4779 Page
= WelcomePage(&Ir
);
4784 Page
= LicensePage(&Ir
);
4788 case INSTALL_INTRO_PAGE
:
4789 Page
= InstallIntroPage(&Ir
);
4793 case SCSI_CONTROLLER_PAGE
:
4794 Page
= ScsiControllerPage(&Ir
);
4797 case OEM_DRIVER_PAGE
:
4798 Page
= OemDriverPage(&Ir
);
4802 case DEVICE_SETTINGS_PAGE
:
4803 Page
= DeviceSettingsPage(&Ir
);
4806 case COMPUTER_SETTINGS_PAGE
:
4807 Page
= ComputerSettingsPage(&Ir
);
4810 case DISPLAY_SETTINGS_PAGE
:
4811 Page
= DisplaySettingsPage(&Ir
);
4814 case KEYBOARD_SETTINGS_PAGE
:
4815 Page
= KeyboardSettingsPage(&Ir
);
4818 case LAYOUT_SETTINGS_PAGE
:
4819 Page
= LayoutSettingsPage(&Ir
);
4822 case SELECT_PARTITION_PAGE
:
4823 Page
= SelectPartitionPage(&Ir
);
4826 case CREATE_PRIMARY_PARTITION_PAGE
:
4827 Page
= CreatePrimaryPartitionPage(&Ir
);
4830 case CREATE_EXTENDED_PARTITION_PAGE
:
4831 Page
= CreateExtendedPartitionPage(&Ir
);
4834 case CREATE_LOGICAL_PARTITION_PAGE
:
4835 Page
= CreateLogicalPartitionPage(&Ir
);
4838 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4839 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4842 case DELETE_PARTITION_PAGE
:
4843 Page
= DeletePartitionPage(&Ir
);
4846 case SELECT_FILE_SYSTEM_PAGE
:
4847 Page
= SelectFileSystemPage(&Ir
);
4850 case FORMAT_PARTITION_PAGE
:
4851 Page
= FormatPartitionPage(&Ir
);
4854 case CHECK_FILE_SYSTEM_PAGE
:
4855 Page
= CheckFileSystemPage(&Ir
);
4858 case INSTALL_DIRECTORY_PAGE
:
4859 Page
= InstallDirectoryPage(&Ir
);
4862 case PREPARE_COPY_PAGE
:
4863 Page
= PrepareCopyPage(&Ir
);
4866 case FILE_COPY_PAGE
:
4867 Page
= FileCopyPage(&Ir
);
4871 Page
= RegistryPage(&Ir
);
4874 case BOOT_LOADER_PAGE
:
4875 Page
= BootLoaderPage(&Ir
);
4878 case BOOT_LOADER_FLOPPY_PAGE
:
4879 Page
= BootLoaderFloppyPage(&Ir
);
4882 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
4883 Page
= BootLoaderHarddiskMbrPage(&Ir
);
4886 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
4887 Page
= BootLoaderHarddiskVbrPage(&Ir
);
4891 case REPAIR_INTRO_PAGE
:
4892 Page
= RepairIntroPage(&Ir
);
4895 case UPGRADE_REPAIR_PAGE
:
4896 Page
= UpgradeRepairPage(&Ir
);
4900 Page
= SuccessPage(&Ir
);
4904 Page
= FlushPage(&Ir
);
4908 Page
= QuitPage(&Ir
);
4912 case SETUP_INIT_PAGE
:
4919 /* Terminate the user-mode PnP manager */
4920 TerminateUserModePnpManager();
4922 /* Setup has finished */
4923 FinishSetup(&USetupData
);
4925 if (Page
== RECOVERY_PAGE
)
4931 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
4932 NtShutdownSystem(ShutdownReboot
);
4933 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
4935 return STATUS_SUCCESS
;
4940 NtProcessStartup(PPEB Peb
)
4945 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
4947 ProcessHeap
= Peb
->ProcessHeap
;
4949 NtQuerySystemTime(&Time
);
4951 Status
= RunUSetup();
4953 if (NT_SUCCESS(Status
))
4956 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
4957 * a protective waiting.
4958 * This wait is needed because, since we are started as SMSS.EXE,
4959 * the NT kernel explicitly waits 5 seconds for the initial process
4960 * SMSS.EXE to initialize (as a protective measure), and otherwise
4961 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
4963 Time
.QuadPart
+= 50000000;
4964 NtDelayExecution(FALSE
, &Time
);
4968 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
4969 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
4970 0, 0, NULL
, 0, NULL
);
4973 NtTerminateProcess(NtCurrentProcess(), Status
);