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)
30 #include <ntstrsafe.h>
42 /* GLOBALS & LOCALS *********************************************************/
45 BOOLEAN IsUnattendedSetup
= FALSE
;
47 static USETUP_DATA USetupData
;
49 /* Partition where to perform the installation */
50 static PPARTENTRY InstallPartition
= NULL
;
51 // static PPARTENTRY SystemPartition = NULL; // The system partition we will actually use (can be different from PartitionList->SystemPartition in case we install on removable disk)
53 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
54 static WCHAR DestinationDriveLetter
;
59 PCWSTR SelectedLanguageId
;
60 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
61 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
63 static BOOLEAN RepairUpdateFlag
= FALSE
;
65 /* Global partition list on the system */
66 static PPARTLIST PartitionList
= NULL
;
68 /* Currently selected partition entry in the list */
69 static PPARTENTRY CurrentPartition
= NULL
;
71 /* List of supported file systems for the partition to be formatted */
72 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
74 /* Machine state for the formatter */
75 static PPARTENTRY TempPartition
= NULL
;
76 static FORMATMACHINESTATE FormatState
= Start
;
78 /*****************************************************/
80 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
81 static PGENERIC_LIST NtOsInstallsList
= NULL
;
84 /* FUNCTIONS ****************************************************************/
87 PrintString(char* fmt
,...)
91 UNICODE_STRING UnicodeString
;
92 ANSI_STRING AnsiString
;
95 vsprintf(buffer
, fmt
, ap
);
98 RtlInitAnsiString(&AnsiString
, buffer
);
99 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
100 NtDisplayString(&UnicodeString
);
101 RtlFreeUnicodeString(&UnicodeString
);
106 DrawBox(IN SHORT xLeft
,
114 /* Draw upper left corner */
117 FillConsoleOutputCharacterA(StdOutput
,
123 /* Draw upper edge */
126 FillConsoleOutputCharacterA(StdOutput
,
132 /* Draw upper right corner */
133 coPos
.X
= xLeft
+ Width
- 1;
135 FillConsoleOutputCharacterA(StdOutput
,
141 /* Draw right edge, inner space and left edge */
142 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
145 FillConsoleOutputCharacterA(StdOutput
,
152 FillConsoleOutputCharacterA(StdOutput
,
158 coPos
.X
= xLeft
+ Width
- 1;
159 FillConsoleOutputCharacterA(StdOutput
,
166 /* Draw lower left corner */
168 coPos
.Y
= yTop
+ Height
- 1;
169 FillConsoleOutputCharacterA(StdOutput
,
175 /* Draw lower edge */
177 coPos
.Y
= yTop
+ Height
- 1;
178 FillConsoleOutputCharacterA(StdOutput
,
184 /* Draw lower right corner */
185 coPos
.X
= xLeft
+ Width
- 1;
186 coPos
.Y
= yTop
+ Height
- 1;
187 FillConsoleOutputCharacterA(StdOutput
,
196 PopupError(PCCH Text
,
214 /* Count text lines and longest line */
221 p
= strchr(pnext
, '\n');
225 Length
= strlen(pnext
);
230 Length
= (ULONG
)(p
- pnext
);
236 if (Length
> MaxLength
)
245 /* Check length of status line */
248 Length
= strlen(Status
);
250 if (Length
> MaxLength
)
254 Width
= MaxLength
+ 4;
260 yTop
= (yScreen
- Height
) / 2;
261 xLeft
= (xScreen
- Width
) / 2;
264 /* Set screen attributes */
266 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
268 FillConsoleOutputAttribute(StdOutput
,
269 FOREGROUND_RED
| BACKGROUND_WHITE
,
275 DrawBox(xLeft
, yTop
, Width
, Height
);
277 /* Print message text */
282 p
= strchr(pnext
, '\n');
286 Length
= strlen(pnext
);
291 Length
= (ULONG
)(p
- pnext
);
298 WriteConsoleOutputCharacterA(StdOutput
,
312 /* Print separator line and status text */
315 coPos
.Y
= yTop
+ Height
- 3;
317 FillConsoleOutputCharacterA(StdOutput
,
324 FillConsoleOutputCharacterA(StdOutput
,
330 coPos
.X
= xLeft
+ Width
- 1;
331 FillConsoleOutputCharacterA(StdOutput
,
339 WriteConsoleOutputCharacterA(StdOutput
,
341 min(strlen(Status
), (SIZE_T
)Width
- 4),
346 if (WaitEvent
== POPUP_WAIT_NONE
)
351 CONSOLE_ConInKey(Ir
);
353 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
354 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
366 * FALSE: Don't quit setup.
369 ConfirmQuit(PINPUT_RECORD Ir
)
372 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
376 CONSOLE_ConInKey(Ir
);
378 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
379 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
384 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
398 PGENERIC_LIST_ENTRY ListEntry
;
401 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
403 if (USetupData
.LayoutList
== NULL
)
405 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
406 if (USetupData
.LayoutList
== NULL
)
408 /* FIXME: Handle error! */
413 /* Search for default layout (if provided) */
414 if (pszNewLayout
!= NULL
)
416 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
417 ListEntry
= GetNextListEntry(ListEntry
))
419 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
421 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
431 GetSettingDescription(
432 IN PGENERIC_LIST_ENTRY Entry
,
434 IN SIZE_T cchBufferSize
)
436 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
437 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
442 GetNTOSInstallationName(
443 IN PGENERIC_LIST_ENTRY Entry
,
445 IN SIZE_T cchBufferSize
)
447 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
448 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
450 if (PartEntry
&& PartEntry
->DriveLetter
)
452 /* We have retrieved a partition that is mounted */
453 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
455 PartEntry
->DriveLetter
,
456 NtOsInstall
->PathComponent
,
457 NtOsInstall
->InstallationName
);
461 /* We failed somewhere, just show the NT path */
462 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
464 &NtOsInstall
->SystemNtPath
,
465 NtOsInstall
->InstallationName
);
471 * Displays the LanguagePage.
473 * Next pages: WelcomePage, QuitPage
476 * Init SelectedLanguageId
477 * Init USetupData.LanguageId
480 * Number of the next page.
483 LanguagePage(PINPUT_RECORD Ir
)
485 GENERIC_LIST_UI ListUi
;
486 PCWSTR NewLanguageId
;
487 BOOL RefreshPage
= FALSE
;
489 /* Initialize the computer settings list */
490 if (USetupData
.LanguageList
== NULL
)
492 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
493 if (USetupData
.LanguageList
== NULL
)
495 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
500 SelectedLanguageId
= DefaultLanguage
;
501 USetupData
.LanguageId
= 0;
504 SetConsoleCodePage();
508 * If there is no language or just a single one in the list,
509 * skip the language selection process altogether.
511 if (GetNumberOfListEntries(USetupData
.LanguageList
) <= 1)
513 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
517 InitGenericListUi(&ListUi
, USetupData
.LanguageList
, GetSettingDescription
);
518 DrawGenericList(&ListUi
,
523 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
525 MUIDisplayPage(LANGUAGE_PAGE
);
529 CONSOLE_ConInKey(Ir
);
531 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
532 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
534 ScrollDownGenericList(&ListUi
);
537 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
538 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
540 ScrollUpGenericList(&ListUi
);
543 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
544 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
546 ScrollPageDownGenericList(&ListUi
);
549 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
550 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
552 ScrollPageUpGenericList(&ListUi
);
555 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
556 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
561 RedrawGenericList(&ListUi
);
563 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
565 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
568 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
570 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
572 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
578 SetConsoleCodePage();
582 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
585 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
591 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
594 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
596 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
598 /* Clear the language page */
599 MUIClearPage(LANGUAGE_PAGE
);
601 SelectedLanguageId
= NewLanguageId
;
604 SetConsoleCodePage();
606 /* Redraw language selection page in native language */
607 MUIDisplayPage(LANGUAGE_PAGE
);
622 * LanguagePage (at once, default)
623 * InstallIntroPage (at once, if unattended)
628 * Init USetupData.SourcePath
629 * Init USetupData.SourceRootPath
630 * Init USetupData.SourceRootDir
631 * Init USetupData.SetupInf
632 * Init USetupData.RequiredPartitionDiskSpace
633 * Init IsUnattendedSetup
634 * If unattended, init *List and sets the Codepage
635 * If unattended, init SelectedLanguageId
636 * If unattended, init USetupData.LanguageId
639 * Number of the next page.
642 SetupStartPage(PINPUT_RECORD Ir
)
645 PGENERIC_LIST_ENTRY ListEntry
;
648 MUIDisplayPage(SETUP_INIT_PAGE
);
650 /* Initialize Setup, phase 1 */
651 Error
= InitializeSetup(&USetupData
, 1);
652 if (Error
!= ERROR_SUCCESS
)
654 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
658 /* Initialize the user-mode PnP manager */
659 if (!EnableUserModePnpManager())
660 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
662 /* Wait for any immediate pending installations to finish */
663 if (WaitNoPendingInstallEvents(NULL
) != STATUS_WAIT_0
)
664 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
666 CheckUnattendedSetup(&USetupData
);
668 if (IsUnattendedSetup
)
670 // TODO: Read options from inf
671 /* Load the hardware, language and keyboard layout lists */
673 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
674 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
675 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
677 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
680 SelectedLanguageId
= DefaultLanguage
;
681 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
682 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
684 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
686 /* first we hack LanguageList */
687 for (ListEntry
= GetFirstListEntry(USetupData
.LanguageList
); ListEntry
;
688 ListEntry
= GetNextListEntry(ListEntry
))
690 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
691 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
693 DPRINT("found %S in LanguageList\n", LocaleId
);
694 SetCurrentListEntry(USetupData
.LanguageList
, ListEntry
);
700 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
701 ListEntry
= GetNextListEntry(ListEntry
))
703 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
704 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
706 DPRINT("found %S in LayoutList\n", LocaleId
);
707 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
712 SetConsoleCodePage();
714 return INSTALL_INTRO_PAGE
;
717 return LANGUAGE_PAGE
;
722 * Displays the WelcomePage.
725 * InstallIntroPage (default)
732 * Number of the next page.
735 WelcomePage(PINPUT_RECORD Ir
)
737 MUIDisplayPage(WELCOME_PAGE
);
741 CONSOLE_ConInKey(Ir
);
743 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
744 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
751 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
753 return INSTALL_INTRO_PAGE
;
755 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
757 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
759 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
770 * Displays the License page.
773 * WelcomePage (default)
776 * Number of the next page.
779 LicensePage(PINPUT_RECORD Ir
)
781 MUIDisplayPage(LICENSE_PAGE
);
785 CONSOLE_ConInKey(Ir
);
787 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
798 * Displays the RepairIntroPage.
801 * RebootPage (default)
807 * Number of the next page.
810 RepairIntroPage(PINPUT_RECORD Ir
)
812 MUIDisplayPage(REPAIR_INTRO_PAGE
);
816 CONSOLE_ConInKey(Ir
);
818 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
822 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
824 RepairUpdateFlag
= TRUE
;
825 return INSTALL_INTRO_PAGE
;
827 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
829 return RECOVERY_PAGE
;
831 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
832 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
838 return REPAIR_INTRO_PAGE
;
842 * Displays the UpgradeRepairPage.
845 * RebootPage (default)
851 * Number of the next page.
854 UpgradeRepairPage(PINPUT_RECORD Ir
)
856 GENERIC_LIST_UI ListUi
;
859 if (PartitionList
== NULL
)
861 PartitionList
= CreatePartitionList();
862 if (PartitionList
== NULL
)
864 /* FIXME: show an error dialog */
865 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
868 else if (IsListEmpty(&PartitionList
->DiskListHead
))
870 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
874 /* Reset the formatter machine state */
875 TempPartition
= NULL
;
880 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
881 if (!NtOsInstallsList
)
882 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
885 * If there is no available installation (or just a single one??) that can
886 * be updated in the list, just continue with the regular installation.
888 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
890 RepairUpdateFlag
= FALSE
;
892 // return INSTALL_INTRO_PAGE;
893 return DEVICE_SETTINGS_PAGE
;
894 // return SCSI_CONTROLLER_PAGE;
897 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
899 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
900 DrawGenericList(&ListUi
,
905 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
908 CONSOLE_ConInKey(Ir
);
910 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
912 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
914 case VK_DOWN
: /* DOWN */
915 ScrollDownGenericList(&ListUi
);
918 ScrollUpGenericList(&ListUi
);
920 case VK_NEXT
: /* PAGE DOWN */
921 ScrollPageDownGenericList(&ListUi
);
923 case VK_PRIOR
: /* PAGE UP */
924 ScrollPageUpGenericList(&ListUi
);
931 RedrawGenericList(&ListUi
);
934 case VK_ESCAPE
: /* ESC */
936 RestoreGenericListUiState(&ListUi
);
937 // return nextPage; // prevPage;
939 // return INSTALL_INTRO_PAGE;
940 return DEVICE_SETTINGS_PAGE
;
941 // return SCSI_CONTROLLER_PAGE;
947 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
948 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
949 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
951 /* Retrieve the current installation */
952 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
954 CurrentInstallation
=
955 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
957 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
958 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
960 RepairUpdateFlag
= TRUE
;
963 /***/return INSTALL_INTRO_PAGE
;/***/
965 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
966 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
968 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
973 return UPGRADE_REPAIR_PAGE
;
978 * Displays the InstallIntroPage.
981 * DeviceSettingsPage (At once if repair or update is selected)
982 * SelectPartitionPage (At once if unattended setup)
983 * DeviceSettingsPage (default)
987 * Number of the next page.
990 InstallIntroPage(PINPUT_RECORD Ir
)
992 if (RepairUpdateFlag
)
994 #if 1 /* Old code that looks good */
996 // return SELECT_PARTITION_PAGE;
997 return DEVICE_SETTINGS_PAGE
;
999 #else /* Possible new code? */
1001 return DEVICE_SETTINGS_PAGE
;
1002 // return SCSI_CONTROLLER_PAGE;
1007 if (IsUnattendedSetup
)
1008 return SELECT_PARTITION_PAGE
;
1010 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1014 CONSOLE_ConInKey(Ir
);
1016 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1017 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1019 if (ConfirmQuit(Ir
))
1024 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1026 return UPGRADE_REPAIR_PAGE
;
1030 return INSTALL_INTRO_PAGE
;
1036 ScsiControllerPage(PINPUT_RECORD Ir
)
1038 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1040 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1042 /* FIXME: print loaded mass storage driver descriptions */
1044 CONSOLE_SetTextXY(8, 10, "TEST device");
1047 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1051 CONSOLE_ConInKey(Ir
);
1053 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1054 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1056 if (ConfirmQuit(Ir
))
1061 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1063 return DEVICE_SETTINGS_PAGE
;
1067 return SCSI_CONTROLLER_PAGE
;
1071 OemDriverPage(PINPUT_RECORD Ir
)
1073 // MUIDisplayPage(OEM_DRIVER_PAGE);
1075 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1077 /* FIXME: Implement!! */
1079 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1083 CONSOLE_ConInKey(Ir
);
1085 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1086 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1088 if (ConfirmQuit(Ir
))
1093 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1095 return DEVICE_SETTINGS_PAGE
;
1099 return OEM_DRIVER_PAGE
;
1105 * Displays the DeviceSettingsPage.
1108 * SelectPartitionPage (At once if repair or update is selected)
1109 * ComputerSettingsPage
1110 * DisplaySettingsPage
1111 * KeyboardSettingsPage
1112 * LayoutsettingsPage
1113 * SelectPartitionPage
1117 * Init USetupData.ComputerList
1118 * Init USetupData.DisplayList
1119 * Init USetupData.KeyboardList
1120 * Init USetupData.LayoutList
1123 * Number of the next page.
1126 DeviceSettingsPage(PINPUT_RECORD Ir
)
1128 static ULONG Line
= 16;
1130 /* Initialize the computer settings list */
1131 if (USetupData
.ComputerList
== NULL
)
1133 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
1134 if (USetupData
.ComputerList
== NULL
)
1136 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1141 /* Initialize the display settings list */
1142 if (USetupData
.DisplayList
== NULL
)
1144 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
1145 if (USetupData
.DisplayList
== NULL
)
1147 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1152 /* Initialize the keyboard settings list */
1153 if (USetupData
.KeyboardList
== NULL
)
1155 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
1156 if (USetupData
.KeyboardList
== NULL
)
1158 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1163 /* Initialize the keyboard layout list */
1164 if (USetupData
.LayoutList
== NULL
)
1166 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1167 if (USetupData
.LayoutList
== NULL
)
1169 /* FIXME: report error */
1170 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1175 if (RepairUpdateFlag
)
1176 return SELECT_PARTITION_PAGE
;
1178 // if (IsUnattendedSetup)
1179 // return SELECT_PARTITION_PAGE;
1181 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1183 DrawGenericListCurrentItem(USetupData
.ComputerList
, GetSettingDescription
, 25, 11);
1184 DrawGenericListCurrentItem(USetupData
.DisplayList
, GetSettingDescription
, 25, 12);
1185 DrawGenericListCurrentItem(USetupData
.KeyboardList
, GetSettingDescription
, 25, 13);
1186 DrawGenericListCurrentItem(USetupData
.LayoutList
, GetSettingDescription
, 25, 14);
1188 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1192 CONSOLE_ConInKey(Ir
);
1194 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1195 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1197 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1201 else if (Line
== 16)
1206 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1208 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1209 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1211 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1215 else if (Line
== 16)
1220 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1222 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1223 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1225 if (ConfirmQuit(Ir
))
1230 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1233 return COMPUTER_SETTINGS_PAGE
;
1234 else if (Line
== 12)
1235 return DISPLAY_SETTINGS_PAGE
;
1236 else if (Line
== 13)
1237 return KEYBOARD_SETTINGS_PAGE
;
1238 else if (Line
== 14)
1239 return LAYOUT_SETTINGS_PAGE
;
1240 else if (Line
== 16)
1241 return SELECT_PARTITION_PAGE
;
1245 return DEVICE_SETTINGS_PAGE
;
1250 * Handles generic selection lists.
1253 * GenericList: The list to handle.
1254 * nextPage: The page it needs to jump to after this page.
1255 * Ir: The PINPUT_RECORD
1258 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1259 PAGE_NUMBER nextPage
,
1264 CONSOLE_ConInKey(Ir
);
1266 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1267 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1269 ScrollDownGenericList(ListUi
);
1271 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1272 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1274 ScrollUpGenericList(ListUi
);
1276 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1277 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1279 ScrollPageDownGenericList(ListUi
);
1281 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1282 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1284 ScrollPageUpGenericList(ListUi
);
1286 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1287 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1289 if (ConfirmQuit(Ir
))
1292 RedrawGenericList(ListUi
);
1294 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1295 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1297 RestoreGenericListUiState(ListUi
);
1298 return nextPage
; // Use some "prevPage;" instead?
1300 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1304 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1307 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1314 * Displays the ComputerSettingsPage.
1317 * DeviceSettingsPage
1321 * Number of the next page.
1324 ComputerSettingsPage(PINPUT_RECORD Ir
)
1326 GENERIC_LIST_UI ListUi
;
1327 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1329 InitGenericListUi(&ListUi
, USetupData
.ComputerList
, GetSettingDescription
);
1330 DrawGenericList(&ListUi
,
1335 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1340 * Displays the DisplaySettingsPage.
1343 * DeviceSettingsPage
1347 * Number of the next page.
1350 DisplaySettingsPage(PINPUT_RECORD Ir
)
1352 GENERIC_LIST_UI ListUi
;
1353 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1355 InitGenericListUi(&ListUi
, USetupData
.DisplayList
, GetSettingDescription
);
1356 DrawGenericList(&ListUi
,
1361 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1366 * Displays the KeyboardSettingsPage.
1369 * DeviceSettingsPage
1373 * Number of the next page.
1376 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1378 GENERIC_LIST_UI ListUi
;
1379 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1381 InitGenericListUi(&ListUi
, USetupData
.KeyboardList
, GetSettingDescription
);
1382 DrawGenericList(&ListUi
,
1387 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1392 * Displays the LayoutSettingsPage.
1395 * DeviceSettingsPage
1399 * Number of the next page.
1402 LayoutSettingsPage(PINPUT_RECORD Ir
)
1404 GENERIC_LIST_UI ListUi
;
1405 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1407 InitGenericListUi(&ListUi
, USetupData
.LayoutList
, GetSettingDescription
);
1408 DrawGenericList(&ListUi
,
1413 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1418 IsDiskSizeValid(PPARTENTRY PartEntry
)
1422 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1423 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1425 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1427 /* Partition is too small so ask for another one */
1428 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1439 * Displays the SelectPartitionPage.
1442 * SelectFileSystemPage (At once if unattended)
1443 * SelectFileSystemPage (Default if free space is selected)
1444 * CreatePrimaryPartitionPage
1445 * CreateExtendedPartitionPage
1446 * CreateLogicalPartitionPage
1447 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1448 * DeletePartitionPage
1452 * Set InstallShortcut (only if not unattended + free space is selected)
1455 * Number of the next page.
1458 SelectPartitionPage(PINPUT_RECORD Ir
)
1463 if (PartitionList
== NULL
)
1465 PartitionList
= CreatePartitionList();
1466 if (PartitionList
== NULL
)
1468 /* FIXME: show an error dialog */
1469 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1472 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1474 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1478 /* Reset the formatter machine state */
1479 TempPartition
= NULL
;
1480 FormatState
= Start
;
1483 if (RepairUpdateFlag
)
1485 ASSERT(CurrentInstallation
);
1487 /* Determine the selected installation disk & partition */
1488 InstallPartition
= SelectPartition(PartitionList
,
1489 CurrentInstallation
->DiskNumber
,
1490 CurrentInstallation
->PartitionNumber
);
1491 if (!InstallPartition
)
1493 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1496 ASSERT(!IsContainerPartition(InstallPartition
->PartitionType
));
1498 return SELECT_FILE_SYSTEM_PAGE
;
1501 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1503 InitPartitionListUi(&ListUi
, PartitionList
,
1508 DrawPartitionList(&ListUi
);
1510 if (IsUnattendedSetup
)
1512 /* Determine the selected installation disk & partition */
1513 InstallPartition
= SelectPartition(PartitionList
,
1514 USetupData
.DestinationDiskNumber
,
1515 USetupData
.DestinationPartitionNumber
);
1516 if (!InstallPartition
)
1518 CurrentPartition
= ListUi
.CurrentPartition
;
1520 if (USetupData
.AutoPartition
)
1522 ASSERT(CurrentPartition
!= NULL
);
1523 ASSERT(!IsContainerPartition(CurrentPartition
->PartitionType
));
1525 if (CurrentPartition
->LogicalPartition
)
1527 CreateLogicalPartition(PartitionList
,
1529 CurrentPartition
->SectorCount
.QuadPart
,
1534 CreatePrimaryPartition(PartitionList
,
1536 CurrentPartition
->SectorCount
.QuadPart
,
1540 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1541 if (!IsDiskSizeValid(CurrentPartition
))
1543 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1544 USetupData
.RequiredPartitionDiskSpace
);
1545 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1548 InstallPartition
= CurrentPartition
;
1549 return SELECT_FILE_SYSTEM_PAGE
;
1554 ASSERT(!IsContainerPartition(InstallPartition
->PartitionType
));
1556 DrawPartitionList(&ListUi
); // FIXME: Doesn't make much sense...
1558 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1559 if (!IsDiskSizeValid(InstallPartition
))
1561 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1562 USetupData
.RequiredPartitionDiskSpace
);
1563 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1566 return SELECT_FILE_SYSTEM_PAGE
;
1572 CurrentPartition
= ListUi
.CurrentPartition
;
1574 /* Update status text */
1575 if (CurrentPartition
== NULL
)
1577 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1579 else if (CurrentPartition
->LogicalPartition
)
1581 if (CurrentPartition
->IsPartitioned
)
1583 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1587 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1592 if (CurrentPartition
->IsPartitioned
)
1594 if (IsContainerPartition(CurrentPartition
->PartitionType
))
1596 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1600 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1605 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1609 CONSOLE_ConInKey(Ir
);
1611 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1612 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1614 if (ConfirmQuit(Ir
))
1616 DestroyPartitionList(PartitionList
);
1617 PartitionList
= NULL
;
1623 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1624 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1626 ScrollDownPartitionList(&ListUi
);
1628 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1629 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1631 ScrollUpPartitionList(&ListUi
);
1633 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1635 ASSERT(CurrentPartition
!= NULL
);
1637 if (IsContainerPartition(CurrentPartition
->PartitionType
))
1638 continue; // return SELECT_PARTITION_PAGE;
1641 * Check whether the user wants to install ReactOS on a disk that
1642 * is not recognized by the computer's firmware and if so, display
1643 * a warning since such disks may not be bootable.
1645 if (CurrentPartition
->DiskEntry
->MediaType
== FixedMedia
&&
1646 !CurrentPartition
->DiskEntry
->BiosFound
)
1648 PopupError("The disk you have selected for installing ReactOS\n"
1649 "is not visible by the firmware of your computer,\n"
1650 "and so may not be bootable.\n"
1651 "Press ENTER to continue nonetheless.",
1652 MUIGetString(STRING_CONTINUE
),
1653 Ir
, POPUP_WAIT_ENTER
);
1654 // return SELECT_PARTITION_PAGE;
1657 if (CurrentPartition
->IsPartitioned
== FALSE
)
1659 if (CurrentPartition
->LogicalPartition
)
1661 Error
= LogicalPartitionCreationChecks(CurrentPartition
);
1662 if (Error
!= NOT_AN_ERROR
)
1664 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1665 return SELECT_PARTITION_PAGE
;
1668 CreateLogicalPartition(PartitionList
,
1675 Error
= PrimaryPartitionCreationChecks(CurrentPartition
);
1676 if (Error
!= NOT_AN_ERROR
)
1678 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1679 return SELECT_PARTITION_PAGE
;
1682 CreatePrimaryPartition(PartitionList
,
1689 if (!IsDiskSizeValid(CurrentPartition
))
1691 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1692 USetupData
.RequiredPartitionDiskSpace
);
1693 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1696 InstallPartition
= CurrentPartition
;
1697 return SELECT_FILE_SYSTEM_PAGE
;
1699 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1701 ASSERT(CurrentPartition
!= NULL
);
1703 if (CurrentPartition
->LogicalPartition
== FALSE
)
1705 Error
= PrimaryPartitionCreationChecks(CurrentPartition
);
1706 if (Error
!= NOT_AN_ERROR
)
1708 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1709 return SELECT_PARTITION_PAGE
;
1712 return CREATE_PRIMARY_PARTITION_PAGE
;
1715 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1717 ASSERT(CurrentPartition
!= NULL
);
1719 if (CurrentPartition
->LogicalPartition
== FALSE
)
1721 Error
= ExtendedPartitionCreationChecks(CurrentPartition
);
1722 if (Error
!= NOT_AN_ERROR
)
1724 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1725 return SELECT_PARTITION_PAGE
;
1728 return CREATE_EXTENDED_PARTITION_PAGE
;
1731 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1733 ASSERT(CurrentPartition
!= NULL
);
1735 if (CurrentPartition
->LogicalPartition
)
1737 Error
= LogicalPartitionCreationChecks(CurrentPartition
);
1738 if (Error
!= NOT_AN_ERROR
)
1740 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1741 return SELECT_PARTITION_PAGE
;
1744 return CREATE_LOGICAL_PARTITION_PAGE
;
1747 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1749 UNICODE_STRING CurrentPartitionU
;
1750 WCHAR PathBuffer
[MAX_PATH
];
1752 ASSERT(CurrentPartition
!= NULL
);
1754 if (CurrentPartition
->IsPartitioned
== FALSE
)
1756 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1757 return SELECT_PARTITION_PAGE
;
1760 // TODO: Do something similar before trying to format the partition?
1761 if (!CurrentPartition
->New
&&
1762 !IsContainerPartition(CurrentPartition
->PartitionType
) &&
1763 CurrentPartition
->FormatState
!= Unformatted
)
1765 ASSERT(CurrentPartition
->PartitionNumber
!= 0);
1767 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1768 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1769 CurrentPartition
->DiskEntry
->DiskNumber
,
1770 CurrentPartition
->PartitionNumber
);
1771 RtlInitUnicodeString(&CurrentPartitionU
, PathBuffer
);
1774 * Check whether the user attempts to delete the partition on which
1775 * the installation source is present. If so, fail with an error.
1777 // &USetupData.SourceRootPath
1778 if (RtlPrefixUnicodeString(&CurrentPartitionU
, &USetupData
.SourcePath
, TRUE
))
1780 PopupError("You cannot delete the partition containing the installation source!",
1781 MUIGetString(STRING_CONTINUE
),
1782 Ir
, POPUP_WAIT_ENTER
);
1783 return SELECT_PARTITION_PAGE
;
1787 // FIXME TODO: PartitionList->SystemPartition is not yet initialized!!!!
1788 if (CurrentPartition
== PartitionList
->SystemPartition
||
1789 CurrentPartition
->BootIndicator
)
1791 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1794 return DELETE_PARTITION_PAGE
;
1798 return SELECT_PARTITION_PAGE
;
1802 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1803 /* Restriction for MaxSize */
1804 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1807 ShowPartitionSizeInputBox(SHORT Left
,
1831 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1836 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1837 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1840 WriteConsoleOutputCharacterA(StdOutput
,
1846 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1847 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1849 WriteConsoleOutputCharacterA(StdOutput
,
1855 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1856 Length
= wcslen(InputBuffer
);
1858 CONSOLE_SetInputTextXY(iLeft
,
1860 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1862 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1863 CONSOLE_SetCursorType(TRUE
, TRUE
);
1867 CONSOLE_ConInKey(&Ir
);
1869 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1870 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1875 InputBuffer
[0] = UNICODE_NULL
;
1876 CONSOLE_SetCursorType(TRUE
, FALSE
);
1879 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1881 CONSOLE_SetCursorType(TRUE
, FALSE
);
1884 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1889 InputBuffer
[0] = UNICODE_NULL
;
1890 CONSOLE_SetCursorType(TRUE
, FALSE
);
1893 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1894 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1897 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1899 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1900 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1903 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1905 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1906 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1911 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1914 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1915 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1920 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1923 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1924 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1928 memmove(&InputBuffer
[Pos
],
1929 &InputBuffer
[Pos
+ 1],
1930 (Length
- Pos
- 1) * sizeof(WCHAR
));
1931 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1934 CONSOLE_SetInputTextXY(iLeft
,
1936 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1938 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1941 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1946 memmove(&InputBuffer
[Pos
- 1],
1948 (Length
- Pos
) * sizeof(WCHAR
));
1949 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1953 CONSOLE_SetInputTextXY(iLeft
,
1955 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1957 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1960 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1962 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1964 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1966 if ((ch
>= L
'0') && (ch
<= L
'9'))
1969 memmove(&InputBuffer
[Pos
+ 1],
1971 (Length
- Pos
) * sizeof(WCHAR
));
1972 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1973 InputBuffer
[Pos
] = ch
;
1977 CONSOLE_SetInputTextXY(iLeft
,
1979 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1981 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1990 * Displays the CreatePrimaryPartitionPage.
1993 * SelectPartitionPage
1994 * SelectFileSystemPage (default)
1998 * Number of the next page.
2001 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
2003 PPARTENTRY PartEntry
;
2004 PDISKENTRY DiskEntry
;
2007 WCHAR InputBuffer
[50];
2011 ULONGLONG SectorCount
;
2014 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2016 /* FIXME: show an error dialog */
2020 PartEntry
= CurrentPartition
;
2021 DiskEntry
= CurrentPartition
->DiskEntry
;
2023 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2025 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
2027 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2029 if (DiskSize
>= 10 * GB
) /* 10 GB */
2031 DiskSize
= DiskSize
/ GB
;
2032 Unit
= MUIGetString(STRING_GB
);
2037 DiskSize
= DiskSize
/ MB
;
2041 Unit
= MUIGetString(STRING_MB
);
2044 if (DiskEntry
->DriverName
.Length
> 0)
2046 CONSOLE_PrintTextXY(6, 10,
2047 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2050 DiskEntry
->DiskNumber
,
2054 &DiskEntry
->DriverName
,
2055 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2056 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2061 CONSOLE_PrintTextXY(6, 10,
2062 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2065 DiskEntry
->DiskNumber
,
2069 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2070 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2074 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2077 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2078 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2081 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2083 PartEntry
= CurrentPartition
;
2086 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2088 if (MaxSize
> PARTITION_MAXSIZE
)
2089 MaxSize
= PARTITION_MAXSIZE
;
2091 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2092 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2096 if (ConfirmQuit(Ir
))
2103 return SELECT_PARTITION_PAGE
;
2107 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2115 if (PartSize
> MaxSize
)
2121 /* Convert to bytes */
2122 if (PartSize
== MaxSize
)
2124 /* Use all of the unpartitioned disk space */
2125 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2129 /* Calculate the sector count from the size in MB */
2130 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2132 /* But never get larger than the unpartitioned disk space */
2133 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2134 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2137 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2139 CreatePrimaryPartition(PartitionList
,
2144 return SELECT_PARTITION_PAGE
;
2148 return CREATE_PRIMARY_PARTITION_PAGE
;
2153 * Displays the CreateExtendedPartitionPage.
2156 * SelectPartitionPage (default)
2160 * Number of the next page.
2163 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2165 PPARTENTRY PartEntry
;
2166 PDISKENTRY DiskEntry
;
2169 WCHAR InputBuffer
[50];
2173 ULONGLONG SectorCount
;
2176 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2178 /* FIXME: show an error dialog */
2182 PartEntry
= CurrentPartition
;
2183 DiskEntry
= CurrentPartition
->DiskEntry
;
2185 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2187 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2189 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2191 if (DiskSize
>= 10 * GB
) /* 10 GB */
2193 DiskSize
= DiskSize
/ GB
;
2194 Unit
= MUIGetString(STRING_GB
);
2199 DiskSize
= DiskSize
/ MB
;
2203 Unit
= MUIGetString(STRING_MB
);
2206 if (DiskEntry
->DriverName
.Length
> 0)
2208 CONSOLE_PrintTextXY(6, 10,
2209 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2212 DiskEntry
->DiskNumber
,
2216 &DiskEntry
->DriverName
,
2217 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2218 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2223 CONSOLE_PrintTextXY(6, 10,
2224 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2227 DiskEntry
->DiskNumber
,
2231 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2232 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2236 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2239 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2240 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2243 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2245 PartEntry
= CurrentPartition
;
2248 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2250 if (MaxSize
> PARTITION_MAXSIZE
)
2251 MaxSize
= PARTITION_MAXSIZE
;
2253 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2254 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2258 if (ConfirmQuit(Ir
))
2265 return SELECT_PARTITION_PAGE
;
2269 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2277 if (PartSize
> MaxSize
)
2283 /* Convert to bytes */
2284 if (PartSize
== MaxSize
)
2286 /* Use all of the unpartitioned disk space */
2287 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2291 /* Calculate the sector count from the size in MB */
2292 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2294 /* But never get larger than the unpartitioned disk space */
2295 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2296 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2299 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2301 CreateExtendedPartition(PartitionList
,
2305 return SELECT_PARTITION_PAGE
;
2309 return CREATE_EXTENDED_PARTITION_PAGE
;
2314 * Displays the CreateLogicalPartitionPage.
2317 * SelectFileSystemPage (default)
2321 * Number of the next page.
2324 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2326 PPARTENTRY PartEntry
;
2327 PDISKENTRY DiskEntry
;
2330 WCHAR InputBuffer
[50];
2334 ULONGLONG SectorCount
;
2337 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2339 /* FIXME: show an error dialog */
2343 PartEntry
= CurrentPartition
;
2344 DiskEntry
= CurrentPartition
->DiskEntry
;
2346 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2348 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2350 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2352 if (DiskSize
>= 10 * GB
) /* 10 GB */
2354 DiskSize
= DiskSize
/ GB
;
2355 Unit
= MUIGetString(STRING_GB
);
2360 DiskSize
= DiskSize
/ MB
;
2364 Unit
= MUIGetString(STRING_MB
);
2367 if (DiskEntry
->DriverName
.Length
> 0)
2369 CONSOLE_PrintTextXY(6, 10,
2370 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2373 DiskEntry
->DiskNumber
,
2377 &DiskEntry
->DriverName
,
2378 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2379 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2384 CONSOLE_PrintTextXY(6, 10,
2385 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2388 DiskEntry
->DiskNumber
,
2392 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2393 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2397 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2400 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2401 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2404 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2406 PartEntry
= CurrentPartition
;
2409 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2411 if (MaxSize
> PARTITION_MAXSIZE
)
2412 MaxSize
= PARTITION_MAXSIZE
;
2414 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2415 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2419 if (ConfirmQuit(Ir
))
2426 return SELECT_PARTITION_PAGE
;
2430 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2438 if (PartSize
> MaxSize
)
2444 /* Convert to bytes */
2445 if (PartSize
== MaxSize
)
2447 /* Use all of the unpartitioned disk space */
2448 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2452 /* Calculate the sector count from the size in MB */
2453 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2455 /* But never get larger than the unpartitioned disk space */
2456 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2457 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2460 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2462 CreateLogicalPartition(PartitionList
,
2467 return SELECT_PARTITION_PAGE
;
2471 return CREATE_LOGICAL_PARTITION_PAGE
;
2476 * Displays the ConfirmDeleteSystemPartitionPage.
2479 * DeletePartitionPage (default)
2480 * SelectPartitionPage
2483 * Number of the next page.
2486 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2488 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2492 CONSOLE_ConInKey(Ir
);
2494 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2495 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2497 if (ConfirmQuit(Ir
))
2502 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2504 return DELETE_PARTITION_PAGE
;
2506 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2508 return SELECT_PARTITION_PAGE
;
2512 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2517 * Displays the DeletePartitionPage.
2520 * SelectPartitionPage (default)
2524 * Number of the next page.
2527 DeletePartitionPage(PINPUT_RECORD Ir
)
2529 PPARTENTRY PartEntry
;
2530 PDISKENTRY DiskEntry
;
2534 CHAR PartTypeString
[32];
2536 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2538 /* FIXME: show an error dialog */
2542 PartEntry
= CurrentPartition
;
2543 DiskEntry
= CurrentPartition
->DiskEntry
;
2545 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2547 /* Adjust partition type */
2548 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2550 ARRAYSIZE(PartTypeString
));
2552 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2554 if (PartSize
>= 10 * GB
) /* 10 GB */
2556 PartSize
= PartSize
/ GB
;
2557 Unit
= MUIGetString(STRING_GB
);
2561 if (PartSize
>= 10 * MB
) /* 10 MB */
2563 PartSize
= PartSize
/ MB
;
2564 Unit
= MUIGetString(STRING_MB
);
2568 PartSize
= PartSize
/ KB
;
2569 Unit
= MUIGetString(STRING_KB
);
2572 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2574 CONSOLE_PrintTextXY(6, 10,
2575 MUIGetString(STRING_HDDINFOUNK2
),
2576 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2577 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2578 PartEntry
->PartitionType
,
2584 CONSOLE_PrintTextXY(6, 10,
2585 " %c%c %s %I64u %s",
2586 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2587 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2593 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2595 if (DiskSize
>= 10 * GB
) /* 10 GB */
2597 DiskSize
= DiskSize
/ GB
;
2598 Unit
= MUIGetString(STRING_GB
);
2603 DiskSize
= DiskSize
/ MB
;
2607 Unit
= MUIGetString(STRING_MB
);
2610 if (DiskEntry
->DriverName
.Length
> 0)
2612 CONSOLE_PrintTextXY(6, 12,
2613 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2616 DiskEntry
->DiskNumber
,
2620 &DiskEntry
->DriverName
,
2621 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2622 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2627 CONSOLE_PrintTextXY(6, 12,
2628 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2631 DiskEntry
->DiskNumber
,
2635 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2636 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2642 CONSOLE_ConInKey(Ir
);
2644 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2645 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2647 if (ConfirmQuit(Ir
))
2652 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2654 return SELECT_PARTITION_PAGE
;
2656 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2658 DeletePartition(PartitionList
,
2661 return SELECT_PARTITION_PAGE
;
2665 return DELETE_PARTITION_PAGE
;
2670 ResetFileSystemList(VOID
)
2672 if (!FileSystemList
)
2675 DestroyFileSystemList(FileSystemList
);
2676 FileSystemList
= NULL
;
2680 * Displays the SelectFileSystemPage.
2683 * CheckFileSystemPage (At once if RepairUpdate is selected)
2684 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2685 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2686 * SelectPartitionPage (If the user aborts)
2687 * FormatPartitionPage (Default)
2691 * Calls UpdatePartitionType()
2692 * Calls CheckActiveSystemPartition()
2695 * Number of the next page.
2698 SelectFileSystemPage(PINPUT_RECORD Ir
)
2700 PPARTENTRY PartEntry
;
2701 PDISKENTRY DiskEntry
;
2706 CHAR PartTypeString
[32];
2707 FORMATMACHINESTATE PreviousFormatState
;
2710 DPRINT("SelectFileSystemPage()\n");
2712 if (PartitionList
== NULL
|| InstallPartition
== NULL
)
2714 /* FIXME: show an error dialog */
2718 /* Find or set the active system partition when starting formatting */
2719 if (FormatState
== Start
)
2721 /* Find or set the active system partition */
2722 CheckActiveSystemPartition(PartitionList
,
2724 InstallPartition
->DiskEntry
,
2726 if (PartitionList
->SystemPartition
== NULL
)
2728 /* FIXME: show an error dialog */
2730 // Error dialog should say that we cannot find a suitable
2731 // system partition and create one on the system. At this point,
2732 // it may be nice to ask the user whether he wants to continue,
2733 // or use an external drive as the system drive/partition
2734 // (e.g. floppy, USB drive, etc...)
2740 * If the system partition can be created in some
2741 * non-partitioned space, create it now.
2743 if (!PartitionList
->SystemPartition
->IsPartitioned
)
2745 // if (IsUnattendedSetup)
2747 CreatePrimaryPartition(PartitionList
,
2748 PartitionList
->SystemPartition
,
2749 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart,
2751 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2758 /* Commit all partition changes to all the disks */
2759 if (!WritePartitionsToDisk(PartitionList
))
2761 DPRINT("WritePartitionsToDisk() failed\n");
2762 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
2767 * In all cases, whether or not we are going to perform a formatting,
2768 * we must perform a filesystem check of both the system and the
2769 * installation partitions.
2771 InstallPartition
->NeedsCheck
= TRUE
;
2772 if (PartitionList
->SystemPartition
!= InstallPartition
)
2773 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2776 * In case we just repair an existing installation, or make
2777 * an unattended setup without formatting, just go to the
2778 * filesystem check step.
2780 if (RepairUpdateFlag
)
2781 return CHECK_FILE_SYSTEM_PAGE
;
2783 if (IsUnattendedSetup
&& !USetupData
.FormatPartition
)
2784 return CHECK_FILE_SYSTEM_PAGE
;
2787 // ASSERT(PartitionList->SystemPartition->IsPartitioned);
2789 /* Reset the filesystem list for each partition that is to be formatted */
2790 ResetFileSystemList();
2792 PreviousFormatState
= FormatState
;
2793 switch (FormatState
)
2798 * We start by formatting the system partition in case it is new
2799 * (it didn't exist before) and is not the same as the installation
2800 * partition. Otherwise we just require a filesystem check on it,
2801 * and start by formatting the installation partition instead.
2804 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2806 if ((PartitionList
->SystemPartition
!= InstallPartition
) &&
2807 (PartitionList
->SystemPartition
->FormatState
== Unformatted
))
2809 TempPartition
= PartitionList
->SystemPartition
;
2810 TempPartition
->NeedsCheck
= TRUE
;
2812 // TODO: Should we let the user using a custom file-system,
2813 // or should we always use FAT(32) for it?
2814 // For "compatibility", FAT(32) would be best indeed.
2816 FormatState
= FormatSystemPartition
;
2817 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2821 TempPartition
= InstallPartition
;
2822 TempPartition
->NeedsCheck
= TRUE
;
2824 if (PartitionList
->SystemPartition
!= InstallPartition
)
2826 /* The system partition is separate, so it had better be formatted! */
2827 ASSERT((PartitionList
->SystemPartition
->FormatState
== Preformatted
) ||
2828 (PartitionList
->SystemPartition
->FormatState
== Formatted
));
2830 /* Require a filesystem check on the system partition too */
2831 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2834 FormatState
= FormatInstallPartition
;
2835 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2840 case FormatSystemPartition
:
2842 TempPartition
= InstallPartition
;
2843 TempPartition
->NeedsCheck
= TRUE
;
2845 FormatState
= FormatInstallPartition
;
2846 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2850 case FormatInstallPartition
:
2851 case FormatOtherPartition
:
2853 if (GetNextUnformattedPartition(PartitionList
,
2857 FormatState
= FormatOtherPartition
;
2858 TempPartition
->NeedsCheck
= TRUE
;
2860 if (FormatState
== FormatInstallPartition
)
2861 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2863 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2867 FormatState
= FormatDone
;
2869 if (FormatState
== FormatInstallPartition
)
2870 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2872 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2874 return CHECK_FILE_SYSTEM_PAGE
;
2881 DPRINT1("FormatState: FormatDone\n");
2882 return CHECK_FILE_SYSTEM_PAGE
;
2887 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2888 /* FIXME: show an error dialog */
2893 PartEntry
= TempPartition
;
2894 DiskEntry
= TempPartition
->DiskEntry
;
2896 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
2898 /* Adjust disk size */
2899 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2900 if (DiskSize
>= 10 * GB
) /* 10 GB */
2902 DiskSize
= DiskSize
/ GB
;
2903 DiskUnit
= MUIGetString(STRING_GB
);
2907 DiskSize
= DiskSize
/ MB
;
2908 DiskUnit
= MUIGetString(STRING_MB
);
2911 /* Adjust partition size */
2912 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2913 if (PartSize
>= 10 * GB
) /* 10 GB */
2915 PartSize
= PartSize
/ GB
;
2916 PartUnit
= MUIGetString(STRING_GB
);
2920 PartSize
= PartSize
/ MB
;
2921 PartUnit
= MUIGetString(STRING_MB
);
2924 /* Adjust partition type */
2925 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2927 ARRAYSIZE(PartTypeString
));
2929 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2931 if (PartEntry
->AutoCreate
)
2933 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2936 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2937 PartEntry
->PartitionNumber
,
2943 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2944 DiskEntry
->DiskNumber
,
2950 &DiskEntry
->DriverName
,
2951 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2952 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2955 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2957 PartEntry
->AutoCreate
= FALSE
;
2959 else if (PartEntry
->New
)
2961 switch (FormatState
)
2963 case FormatSystemPartition
:
2964 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2967 case FormatInstallPartition
:
2968 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2971 case FormatOtherPartition
:
2972 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2979 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2983 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2985 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2987 CONSOLE_PrintTextXY(8, 10,
2988 MUIGetString(STRING_HDDINFOUNK4
),
2989 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2990 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2991 PartEntry
->PartitionType
,
2997 CONSOLE_PrintTextXY(8, 10,
2999 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
3000 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
3006 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
3007 DiskEntry
->DiskNumber
,
3013 &DiskEntry
->DriverName
,
3014 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
3015 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
3019 ASSERT(FileSystemList
== NULL
);
3021 if (IsUnattendedSetup
)
3023 ASSERT(USetupData
.FormatPartition
);
3025 switch (USetupData
.FsType
)
3027 /* 1 is for BtrFS */
3029 DefaultFs
= L
"BTRFS";
3032 /* If we don't understand input, default to FAT */
3040 /* By default select the "FAT" file system */
3044 /* Create the file system list */
3045 // TODO: Display only the FSes compatible with the selected partition!
3046 FileSystemList
= CreateFileSystemList(6, 26,
3048 PartEntry
->FormatState
== Unformatted
,
3050 if (FileSystemList
== NULL
)
3052 /* FIXME: show an error dialog */
3056 if (IsUnattendedSetup
)
3058 ASSERT(USetupData
.FormatPartition
);
3059 return FORMAT_PARTITION_PAGE
;
3062 DrawFileSystemList(FileSystemList
);
3066 CONSOLE_ConInKey(Ir
);
3068 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3069 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3071 if (ConfirmQuit(Ir
))
3073 /* Reset the filesystem list */
3074 ResetFileSystemList();
3080 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3081 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
3083 /* Reset the formatter machine state */
3084 TempPartition
= NULL
;
3085 FormatState
= Start
;
3087 /* Reset the filesystem list */
3088 ResetFileSystemList();
3090 return SELECT_PARTITION_PAGE
;
3092 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3093 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
3095 ScrollDownFileSystemList(FileSystemList
);
3097 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3098 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
3100 ScrollUpFileSystemList(FileSystemList
);
3102 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
3104 if (!FileSystemList
->Selected
->FileSystem
)
3106 ASSERT(!TempPartition
->New
&& TempPartition
->FormatState
!= Unformatted
);
3109 * Skip formatting this partition. We will also ignore
3110 * filesystem checks on it, unless it is either the system
3111 * or the installation partition.
3113 if (TempPartition
!= PartitionList
->SystemPartition
&&
3114 TempPartition
!= InstallPartition
)
3116 PartEntry
->NeedsCheck
= FALSE
;
3119 return SELECT_FILE_SYSTEM_PAGE
;
3123 /* Format this partition */
3124 return FORMAT_PARTITION_PAGE
;
3129 FormatState
= PreviousFormatState
;
3131 return SELECT_FILE_SYSTEM_PAGE
;
3136 * Displays the FormatPartitionPage.
3139 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3140 * SelectPartitionPage (At once)
3144 * Sets InstallPartition->FormatState
3145 * Sets USetupData.DestinationRootPath
3148 * Number of the next page.
3151 FormatPartitionPage(PINPUT_RECORD Ir
)
3154 PPARTENTRY PartEntry
;
3155 PDISKENTRY DiskEntry
;
3156 PFILE_SYSTEM_ITEM SelectedFileSystem
;
3157 UNICODE_STRING PartitionRootPath
;
3158 WCHAR PathBuffer
[MAX_PATH
];
3159 CHAR Buffer
[MAX_PATH
];
3164 PPARTITION_INFORMATION PartitionInfo
;
3167 DPRINT("FormatPartitionPage()\n");
3169 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
3171 if (PartitionList
== NULL
|| TempPartition
== NULL
)
3173 /* FIXME: show an error dialog */
3177 PartEntry
= TempPartition
;
3178 DiskEntry
= TempPartition
->DiskEntry
;
3180 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3182 SelectedFileSystem
= FileSystemList
->Selected
;
3183 ASSERT(SelectedFileSystem
&& SelectedFileSystem
->FileSystem
);
3187 if (!IsUnattendedSetup
)
3188 CONSOLE_ConInKey(Ir
);
3190 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3191 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3193 if (ConfirmQuit(Ir
))
3195 /* Reset the filesystem list */
3196 ResetFileSystemList();
3202 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3204 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3206 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3208 /* FIXME: show an error dialog */
3210 /* Reset the filesystem list */
3211 ResetFileSystemList();
3217 CONSOLE_PrintTextXY(6, 12,
3218 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3219 DiskEntry
->Cylinders
,
3220 DiskEntry
->TracksPerCylinder
,
3221 DiskEntry
->SectorsPerTrack
,
3222 DiskEntry
->BytesPerSector
,
3223 DiskEntry
->Dirty
? '*' : ' ');
3227 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3229 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3231 CONSOLE_PrintTextXY(6, Line
,
3232 "%2u: %2lu %c %12I64u %12I64u %02x",
3234 PartitionInfo
->PartitionNumber
,
3235 PartitionInfo
->BootIndicator
? 'A' : '-',
3236 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3237 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3238 PartitionInfo
->PartitionType
);
3243 /* Commit the partition changes to the disk */
3244 Status
= WritePartitions(DiskEntry
);
3245 if (!NT_SUCCESS(Status
))
3247 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
3248 DiskEntry
->DiskNumber
, Status
);
3250 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3252 /* Reset the filesystem list */
3253 ResetFileSystemList();
3258 /* Set PartitionRootPath */
3259 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3260 L
"\\Device\\Harddisk%lu\\Partition%lu",
3261 DiskEntry
->DiskNumber
,
3262 PartEntry
->PartitionNumber
);
3263 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3264 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3266 /* Format the partition */
3267 Status
= FormatPartition(&PartitionRootPath
,
3268 SelectedFileSystem
->FileSystem
,
3269 SelectedFileSystem
->QuickFormat
);
3270 if (Status
== STATUS_NOT_SUPPORTED
)
3273 "Setup is currently unable to format a partition in %S.\n"
3275 " \x07 Press ENTER to continue Setup.\n"
3276 " \x07 Press F3 to quit Setup.",
3277 SelectedFileSystem
->FileSystem
);
3280 MUIGetString(STRING_QUITCONTINUE
),
3281 NULL
, POPUP_WAIT_NONE
);
3285 CONSOLE_ConInKey(Ir
);
3287 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3288 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3290 if (ConfirmQuit(Ir
))
3292 /* Reset the filesystem list */
3293 ResetFileSystemList();
3298 return SELECT_FILE_SYSTEM_PAGE
;
3301 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3303 return SELECT_FILE_SYSTEM_PAGE
;
3307 else if (!NT_SUCCESS(Status
))
3309 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3310 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3312 /* Reset the filesystem list */
3313 ResetFileSystemList();
3319 // TODO: Here, call a partlist.c function that update the actual FS name
3320 // and the label fields of the volume.
3322 PartEntry
->FormatState
= Formatted
;
3323 // PartEntry->FileSystem = FileSystem;
3324 PartEntry
->New
= FALSE
;
3327 CONSOLE_SetStatusText(" Done. Press any key ...");
3328 CONSOLE_ConInKey(Ir
);
3331 return SELECT_FILE_SYSTEM_PAGE
;
3335 return FORMAT_PARTITION_PAGE
;
3340 * Displays the CheckFileSystemPage.
3343 * InstallDirectoryPage (At once)
3347 * Inits or reloads FileSystemList
3350 * Number of the next page.
3353 CheckFileSystemPage(PINPUT_RECORD Ir
)
3356 PDISKENTRY DiskEntry
;
3357 PPARTENTRY PartEntry
;
3358 UNICODE_STRING PartitionRootPath
;
3359 WCHAR PathBuffer
[MAX_PATH
];
3360 CHAR Buffer
[MAX_PATH
];
3362 if (PartitionList
== NULL
)
3364 /* FIXME: show an error dialog */
3368 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3370 return INSTALL_DIRECTORY_PAGE
;
3373 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3375 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3377 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3379 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3380 PartEntry
->PartitionType
, (*PartEntry
->FileSystem
? PartEntry
->FileSystem
: L
"n/a"));
3382 /* HACK: Do not try to check a partition with an unknown filesystem */
3383 if (!*PartEntry
->FileSystem
)
3385 PartEntry
->NeedsCheck
= FALSE
;
3386 return CHECK_FILE_SYSTEM_PAGE
;
3389 /* Set PartitionRootPath */
3390 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3391 L
"\\Device\\Harddisk%lu\\Partition%lu",
3392 DiskEntry
->DiskNumber
,
3393 PartEntry
->PartitionNumber
);
3394 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3395 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3397 /* Check the partition */
3398 Status
= ChkdskPartition(&PartitionRootPath
, PartEntry
->FileSystem
);
3399 if (Status
== STATUS_NOT_SUPPORTED
)
3402 * Partition checking is not supported with the current filesystem,
3403 * so disable FS checks on it.
3405 PartEntry
->NeedsCheck
= FALSE
;
3407 RtlStringCbPrintfA(Buffer
,
3409 "Setup is currently unable to check a partition formatted in %S.\n"
3411 " \x07 Press ENTER to continue Setup.\n"
3412 " \x07 Press F3 to quit Setup.",
3413 PartEntry
->FileSystem
);
3416 MUIGetString(STRING_QUITCONTINUE
),
3417 NULL
, POPUP_WAIT_NONE
);
3421 CONSOLE_ConInKey(Ir
);
3423 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3424 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3426 if (ConfirmQuit(Ir
))
3429 return CHECK_FILE_SYSTEM_PAGE
;
3431 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3433 return CHECK_FILE_SYSTEM_PAGE
;
3437 else if (!NT_SUCCESS(Status
))
3439 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3440 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3441 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3442 "(Status 0x%08lx).\n", Status
);
3444 // MUIGetString(STRING_REBOOTCOMPUTER),
3445 MUIGetString(STRING_CONTINUE
),
3446 Ir
, POPUP_WAIT_ENTER
);
3448 // return QUIT_PAGE;
3451 PartEntry
->NeedsCheck
= FALSE
;
3452 return CHECK_FILE_SYSTEM_PAGE
;
3458 IN PCWSTR InstallDir
,
3459 IN PPARTENTRY PartEntry
)
3463 Status
= InitDestinationPaths(&USetupData
, InstallDir
, PartEntry
);
3465 if (!NT_SUCCESS(Status
))
3467 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status
);
3471 /* Initialize DestinationDriveLetter */
3472 DestinationDriveLetter
= PartEntry
->DriveLetter
;
3474 return STATUS_SUCCESS
;
3480 IN PCWSTR InstallDir
)
3484 Length
= wcslen(InstallDir
);
3486 // TODO: Add check for 8.3 too.
3488 /* Path must be at least 2 characters long */
3492 /* Path must start with a backslash */
3493 // if (InstallDir[0] != L'\\')
3496 /* Path must not end with a backslash */
3497 if (InstallDir
[Length
- 1] == L
'\\')
3500 /* Path must not contain whitespace characters */
3501 for (i
= 0; i
< Length
; i
++)
3503 if (iswspace(InstallDir
[i
]))
3507 /* Path component must not end with a dot */
3508 for (i
= 0; i
< Length
; i
++)
3510 if (InstallDir
[i
] == L
'\\' && i
> 0)
3512 if (InstallDir
[i
- 1] == L
'.')
3517 if (InstallDir
[Length
- 1] == L
'.')
3525 * Displays the InstallDirectoryPage.
3532 * Number of the next page.
3535 InstallDirectoryPage(PINPUT_RECORD Ir
)
3540 WCHAR InstallDir
[MAX_PATH
];
3542 /* We do not need the filesystem list anymore */
3543 ResetFileSystemList();
3545 if (PartitionList
== NULL
|| InstallPartition
== NULL
)
3547 /* FIXME: show an error dialog */
3551 // if (IsUnattendedSetup)
3552 if (RepairUpdateFlag
)
3553 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3554 else if (USetupData
.InstallationDirectory
[0])
3555 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3557 wcscpy(InstallDir
, L
"\\ReactOS");
3560 * Check the validity of the predefined 'InstallDir'. If we are either
3561 * in unattended setup or in update/repair mode, and the installation path
3562 * is valid, just perform the installation. Otherwise (either in the case
3563 * of an invalid path, or we are in regular setup), display the UI and allow
3564 * the user to specify a new installation path.
3566 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3568 Status
= BuildInstallPaths(InstallDir
, InstallPartition
);
3569 if (!NT_SUCCESS(Status
))
3571 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3572 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3573 MUIGetString(STRING_CONTINUE
),
3574 Ir
, POPUP_WAIT_ENTER
);
3579 * Check whether the user attempts to install ReactOS within the
3580 * installation source directory, or in a subdirectory thereof.
3581 * If so, fail with an error.
3583 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3585 PopupError("You cannot install ReactOS within the installation source directory!",
3586 MUIGetString(STRING_CONTINUE
),
3587 Ir
, POPUP_WAIT_ENTER
);
3588 return INSTALL_DIRECTORY_PAGE
;
3591 return PREPARE_COPY_PAGE
;
3594 Length
= wcslen(InstallDir
);
3597 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3598 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3599 CONSOLE_SetCursorXY(8 + Pos
, 11);
3600 CONSOLE_SetCursorType(TRUE
, TRUE
);
3604 CONSOLE_ConInKey(Ir
);
3606 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3607 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3609 CONSOLE_SetCursorType(TRUE
, FALSE
);
3611 if (ConfirmQuit(Ir
))
3614 CONSOLE_SetCursorType(TRUE
, TRUE
);
3617 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3618 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3622 memmove(&InstallDir
[Pos
],
3623 &InstallDir
[Pos
+ 1],
3624 (Length
- Pos
- 1) * sizeof(WCHAR
));
3625 InstallDir
[Length
- 1] = UNICODE_NULL
;
3628 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3629 CONSOLE_SetCursorXY(8 + Pos
, 11);
3632 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3633 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3636 CONSOLE_SetCursorXY(8 + Pos
, 11);
3638 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3639 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3642 CONSOLE_SetCursorXY(8 + Pos
, 11);
3644 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3645 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3650 CONSOLE_SetCursorXY(8 + Pos
, 11);
3653 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3654 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3659 CONSOLE_SetCursorXY(8 + Pos
, 11);
3662 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3664 CONSOLE_SetCursorType(TRUE
, FALSE
);
3667 * Check for the validity of the installation directory and pop up
3668 * an error if it is not the case. Then the user can fix its input.
3670 if (!IsValidPath(InstallDir
))
3672 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3673 return INSTALL_DIRECTORY_PAGE
;
3676 Status
= BuildInstallPaths(InstallDir
, InstallPartition
);
3677 if (!NT_SUCCESS(Status
))
3679 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3680 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3681 MUIGetString(STRING_CONTINUE
),
3682 Ir
, POPUP_WAIT_ENTER
);
3687 * Check whether the user attempts to install ReactOS within the
3688 * installation source directory, or in a subdirectory thereof.
3689 * If so, fail with an error.
3691 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3693 PopupError("You cannot install ReactOS within the installation source directory!",
3694 MUIGetString(STRING_CONTINUE
),
3695 Ir
, POPUP_WAIT_ENTER
);
3696 return INSTALL_DIRECTORY_PAGE
;
3699 return PREPARE_COPY_PAGE
;
3701 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3706 memmove(&InstallDir
[Pos
- 1],
3708 (Length
- Pos
) * sizeof(WCHAR
));
3709 InstallDir
[Length
- 1] = UNICODE_NULL
;
3713 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3714 CONSOLE_SetCursorXY(8 + Pos
, 11);
3717 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3721 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3722 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3725 memmove(&InstallDir
[Pos
+ 1],
3727 (Length
- Pos
) * sizeof(WCHAR
));
3728 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3729 InstallDir
[Pos
] = c
;
3733 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3734 CONSOLE_SetCursorXY(8 + Pos
, 11);
3740 return INSTALL_DIRECTORY_PAGE
;
3744 // PSETUP_ERROR_ROUTINE
3748 IN PUSETUP_DATA pSetupData
,
3754 va_start(arg_ptr
, pSetupData
);
3756 if (pSetupData
->LastErrorNumber
>= ERROR_SUCCESS
&&
3757 pSetupData
->LastErrorNumber
< ERROR_LAST_ERROR_CODE
)
3759 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3760 MUIDisplayErrorV(pSetupData
->LastErrorNumber
, &Ir
, POPUP_WAIT_ENTER
, arg_ptr
);
3767 * Displays the PrepareCopyPage.
3770 * FileCopyPage(At once)
3774 * Calls PrepareFileCopy
3777 * Number of the next page.
3780 PrepareCopyPage(PINPUT_RECORD Ir
)
3782 // ERROR_NUMBER ErrorNumber;
3785 MUIDisplayPage(PREPARE_COPY_PAGE
);
3787 /* ErrorNumber = */ Success
= PrepareFileCopy(&USetupData
, NULL
);
3788 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success
)
3790 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3794 return FILE_COPY_PAGE
;
3797 typedef struct _COPYCONTEXT
3799 ULONG TotalOperations
;
3800 ULONG CompletedOperations
;
3801 PPROGRESSBAR ProgressBar
;
3802 PPROGRESSBAR MemoryBars
[4];
3803 } COPYCONTEXT
, *PCOPYCONTEXT
;
3806 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3809 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3811 /* Get the memory information from the system */
3812 NtQuerySystemInformation(SystemPerformanceInformation
,
3817 /* Check if this is initial setup */
3820 /* Set maximum limits to be total RAM pages */
3821 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3822 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3823 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3826 /* Set current values */
3827 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3828 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3829 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3834 FileCopyCallback(PVOID Context
,
3839 PCOPYCONTEXT CopyContext
= (PCOPYCONTEXT
)Context
;
3840 PFILEPATHS_W FilePathInfo
;
3841 PCWSTR SrcFileName
, DstFileName
;
3843 switch (Notification
)
3845 case SPFILENOTIFY_STARTSUBQUEUE
:
3847 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3848 CopyContext
->CompletedOperations
= 0;
3849 ProgressSetStepCount(CopyContext
->ProgressBar
,
3850 CopyContext
->TotalOperations
);
3851 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3855 case SPFILENOTIFY_STARTDELETE
:
3856 case SPFILENOTIFY_STARTRENAME
:
3857 case SPFILENOTIFY_STARTCOPY
:
3859 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3861 if (Notification
== SPFILENOTIFY_STARTDELETE
)
3863 /* Display delete message */
3864 ASSERT(Param2
== FILEOP_DELETE
);
3866 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3867 if (DstFileName
) ++DstFileName
;
3868 else DstFileName
= FilePathInfo
->Target
;
3870 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING
),
3873 else if (Notification
== SPFILENOTIFY_STARTRENAME
)
3875 /* Display move/rename message */
3876 ASSERT(Param2
== FILEOP_RENAME
);
3878 SrcFileName
= wcsrchr(FilePathInfo
->Source
, L
'\\');
3879 if (SrcFileName
) ++SrcFileName
;
3880 else SrcFileName
= FilePathInfo
->Source
;
3882 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3883 if (DstFileName
) ++DstFileName
;
3884 else DstFileName
= FilePathInfo
->Target
;
3886 if (!wcsicmp(SrcFileName
, DstFileName
))
3887 Param2
= STRING_MOVING
;
3889 Param2
= STRING_RENAMING
;
3891 CONSOLE_SetStatusText(MUIGetString(Param2
),
3892 SrcFileName
, DstFileName
);
3894 else if (Notification
== SPFILENOTIFY_STARTCOPY
)
3896 /* Display copy message */
3897 ASSERT(Param2
== FILEOP_COPY
);
3899 /* NOTE: When extracting from CABs the Source is the CAB name */
3900 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3901 if (DstFileName
) ++DstFileName
;
3902 else DstFileName
= FilePathInfo
->Target
;
3904 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
),
3908 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3912 case SPFILENOTIFY_COPYERROR
:
3914 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3916 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3917 FilePathInfo
->Target
, FilePathInfo
->Win32Error
);
3921 case SPFILENOTIFY_ENDDELETE
:
3922 case SPFILENOTIFY_ENDRENAME
:
3923 case SPFILENOTIFY_ENDCOPY
:
3925 CopyContext
->CompletedOperations
++;
3927 /* SYSREG checkpoint */
3928 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3929 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3931 ProgressNextStep(CopyContext
->ProgressBar
);
3932 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3942 * Displays the FileCopyPage.
3945 * RegistryPage(At once)
3951 * Number of the next page.
3954 FileCopyPage(PINPUT_RECORD Ir
)
3956 COPYCONTEXT CopyContext
;
3959 MUIDisplayPage(FILE_COPY_PAGE
);
3961 /* Create context for the copy process */
3962 CopyContext
.TotalOperations
= 0;
3963 CopyContext
.CompletedOperations
= 0;
3965 /* Create the progress bar as well */
3966 CopyContext
.ProgressBar
= CreateProgressBar(13,
3973 MUIGetString(STRING_SETUPCOPYINGFILES
));
3975 // fit memory bars to screen width, distribute them uniform
3976 MemBarWidth
= (xScreen
- 26) / 5;
3977 MemBarWidth
-= MemBarWidth
% 2; // make even
3978 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3979 /* Create the paged pool progress bar */
3980 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
3989 /* Create the non paged pool progress bar */
3990 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (MemBarWidth
/ 2),
3992 (xScreen
/ 2) + (MemBarWidth
/ 2),
3994 (xScreen
/ 2)- (MemBarWidth
/ 2),
3999 /* Create the global memory progress bar */
4000 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - MemBarWidth
,
4004 xScreen
- 13 - MemBarWidth
,
4009 /* Do the file copying */
4010 DoFileCopy(&USetupData
, FileCopyCallback
, &CopyContext
);
4012 /* If we get here, we're done, so cleanup the progress bar */
4013 DestroyProgressBar(CopyContext
.ProgressBar
);
4014 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4015 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4016 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4018 /* Create the $winnt$.inf file */
4019 InstallSetupInfFile(&USetupData
);
4021 /* Go display the next page */
4022 return REGISTRY_PAGE
;
4028 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4030 /* WARNING: Please keep this lookup table in sync with the resources! */
4031 static const UINT StringIDs
[] =
4033 STRING_DONE
, /* Success */
4034 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4035 STRING_IMPORTFILE
, /* ImportRegHive */
4036 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4037 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4038 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4039 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4040 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4045 if (RegStatus
< ARRAYSIZE(StringIDs
))
4047 va_start(args
, RegStatus
);
4048 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4053 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4058 * Displays the RegistryPage.
4061 * SuccessPage (if RepairUpdate)
4062 * BootLoaderPage (default)
4066 * Calls UpdateRegistry
4069 * Number of the next page.
4072 RegistryPage(PINPUT_RECORD Ir
)
4076 MUIDisplayPage(REGISTRY_PAGE
);
4078 Error
= UpdateRegistry(&USetupData
,
4081 DestinationDriveLetter
,
4084 if (Error
!= ERROR_SUCCESS
)
4086 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4091 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4092 return BOOT_LOADER_PAGE
;
4098 * Displays the BootLoaderPage.
4101 * SuccessPage (if RepairUpdate)
4102 * BootLoaderHarddiskMbrPage
4103 * BootLoaderHarddiskVbrPage
4104 * BootLoaderFloppyPage
4109 * Calls RegInitializeRegistry
4110 * Calls ImportRegistryFile
4111 * Calls SetDefaultPagefile
4112 * Calls SetMountedDeviceValues
4115 * Number of the next page.
4118 BootLoaderPage(PINPUT_RECORD Ir
)
4120 UCHAR PartitionType
;
4121 BOOLEAN InstallOnFloppy
;
4123 WCHAR PathBuffer
[MAX_PATH
];
4125 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4127 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
&& PartitionList
->SystemPartition
->PartitionNumber
!= 0);
4129 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4130 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4131 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4132 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4133 PartitionList
->SystemPartition
->PartitionNumber
);
4134 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4135 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4137 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4139 /* For unattended setup, skip MBR installation or install on floppy if needed */
4140 if (IsUnattendedSetup
)
4142 if ((USetupData
.MBRInstallType
== 0) ||
4143 (USetupData
.MBRInstallType
== 1))
4150 * We may install an MBR or VBR, but before that, check whether
4151 * we need to actually install the VBR on floppy.
4153 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4155 DPRINT("Error: system partition invalid (unused)\n");
4156 InstallOnFloppy
= TRUE
;
4158 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4160 /* OS/2 boot manager partition */
4161 DPRINT("Found OS/2 boot manager partition\n");
4162 InstallOnFloppy
= TRUE
;
4164 else if (PartitionType
== PARTITION_LINUX
)
4166 /* Linux partition */
4167 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
4168 InstallOnFloppy
= FALSE
;
4170 else if (PartitionType
== PARTITION_IFS
)
4172 /* NTFS partition */
4173 DPRINT("Found NTFS partition\n");
4175 // FIXME: Make it FALSE when we'll support NTFS installation!
4176 InstallOnFloppy
= TRUE
;
4178 else if ((PartitionType
== PARTITION_FAT_12
) ||
4179 (PartitionType
== PARTITION_FAT_16
) ||
4180 (PartitionType
== PARTITION_HUGE
) ||
4181 (PartitionType
== PARTITION_XINT13
) ||
4182 (PartitionType
== PARTITION_FAT32
) ||
4183 (PartitionType
== PARTITION_FAT32_XINT13
))
4185 DPRINT("Found FAT partition\n");
4186 InstallOnFloppy
= FALSE
;
4190 /* Unknown partition */
4191 DPRINT("Unknown partition found\n");
4192 InstallOnFloppy
= TRUE
;
4195 /* We should install on floppy */
4196 if (InstallOnFloppy
)
4198 USetupData
.MBRInstallType
= 1;
4202 /* Is it an unattended install on hdd? */
4203 if (IsUnattendedSetup
)
4205 if ((USetupData
.MBRInstallType
== 2) ||
4206 (USetupData
.MBRInstallType
== 3))
4212 MUIDisplayPage(BOOT_LOADER_PAGE
);
4213 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4217 CONSOLE_ConInKey(Ir
);
4219 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4220 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4222 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4231 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4233 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4234 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4236 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4245 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4247 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4248 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
4250 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4254 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4256 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4257 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
4259 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4263 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4265 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4266 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4268 if (ConfirmQuit(Ir
))
4273 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4277 /* Install on both MBR and VBR */
4278 USetupData
.MBRInstallType
= 2;
4281 else if (Line
== 13)
4283 /* Install on VBR only */
4284 USetupData
.MBRInstallType
= 3;
4287 else if (Line
== 14)
4289 /* Install on floppy */
4290 USetupData
.MBRInstallType
= 1;
4293 else if (Line
== 15)
4295 /* Skip MBR installation */
4296 USetupData
.MBRInstallType
= 0;
4300 return BOOT_LOADER_PAGE
;
4305 switch (USetupData
.MBRInstallType
)
4307 /* Skip MBR installation */
4309 return SUCCESS_PAGE
;
4311 /* Install on floppy */
4313 return BOOT_LOADER_FLOPPY_PAGE
;
4315 /* Install on both MBR and VBR */
4317 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4319 /* Install on VBR only */
4321 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4324 return BOOT_LOADER_PAGE
;
4329 * Displays the BootLoaderFloppyPage.
4332 * SuccessPage (At once)
4336 * Calls InstallFatBootcodeToFloppy()
4339 * Number of the next page.
4342 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4346 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4348 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4352 CONSOLE_ConInKey(Ir
);
4354 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4355 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4357 if (ConfirmQuit(Ir
))
4362 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4364 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4365 &USetupData
.DestinationArcPath
);
4366 if (!NT_SUCCESS(Status
))
4368 if (Status
== STATUS_DEVICE_NOT_READY
)
4369 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4371 /* TODO: Print error message */
4372 return BOOT_LOADER_FLOPPY_PAGE
;
4375 return SUCCESS_PAGE
;
4379 return BOOT_LOADER_FLOPPY_PAGE
;
4384 * Displays the BootLoaderHarddiskVbrPage.
4387 * SuccessPage (At once)
4391 * Calls InstallVBRToPartition()
4394 * Number of the next page.
4397 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4401 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4402 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4403 &USetupData
.SourceRootPath
,
4404 &USetupData
.DestinationArcPath
,
4405 PartitionList
->SystemPartition
->PartitionType
);
4406 if (!NT_SUCCESS(Status
))
4408 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4409 PartitionList
->SystemPartition
->FileSystem
);
4413 return SUCCESS_PAGE
;
4418 * Displays the BootLoaderHarddiskMbrPage.
4421 * SuccessPage (At once)
4425 * Calls InstallVBRToPartition()
4426 * Calls InstallMbrBootCodeToDisk()
4429 * Number of the next page.
4432 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4435 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4437 /* Step 1: Write the VBR */
4438 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4439 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4440 &USetupData
.SourceRootPath
,
4441 &USetupData
.DestinationArcPath
,
4442 PartitionList
->SystemPartition
->PartitionType
);
4443 if (!NT_SUCCESS(Status
))
4445 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4446 PartitionList
->SystemPartition
->FileSystem
);
4450 /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */
4451 if (!IsSuperFloppy(PartitionList
->SystemPartition
->DiskEntry
))
4453 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4454 L
"\\Device\\Harddisk%d\\Partition0",
4455 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4456 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4457 &USetupData
.SourceRootPath
,
4458 DestinationDevicePathBuffer
);
4459 if (!NT_SUCCESS(Status
))
4461 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4462 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
, L
"MBR");
4467 return SUCCESS_PAGE
;
4472 * @name ProgressTimeOutStringHandler
4474 * Handles the generation (displaying) of the timeout
4475 * countdown to the screen dynamically.
4478 * A pointer to a progress bar.
4480 * @param AlwaysUpdate
4481 * Constantly update the progress bar (boolean type).
4484 * A pointer to a string buffer.
4486 * @param cchBufferSize
4487 * The buffer's size in number of characters.
4490 * TRUE or FALSE on function termination.
4495 ProgressTimeOutStringHandler(
4496 IN PPROGRESSBAR Bar
,
4497 IN BOOLEAN AlwaysUpdate
,
4499 IN SIZE_T cchBufferSize
)
4501 ULONG OldProgress
= Bar
->Progress
;
4503 if (Bar
->StepCount
== 0)
4509 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4512 /* Build the progress string if it has changed */
4513 if (Bar
->ProgressFormatText
&&
4514 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4516 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4517 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4526 * @name ProgressCountdown
4528 * Displays and draws a red-coloured progress bar with a countdown.
4529 * When the timeout is reached, the flush page is displayed for reboot.
4532 * A pointer to an input keyboard record.
4535 * Initial countdown value in seconds.
4543 IN PINPUT_RECORD Ir
,
4547 ULONG StartTime
, BarWidth
, TimerDiv
;
4549 LONG TimerValue
, OldTimerValue
;
4550 LARGE_INTEGER Timeout
;
4551 PPROGRESSBAR ProgressBar
;
4552 BOOLEAN RefreshProgress
= TRUE
;
4554 /* Bail out if the timeout is already zero */
4558 /* Create the timeout progress bar and set it up */
4559 ProgressBar
= CreateProgressBarEx(13,
4566 FOREGROUND_RED
| BACKGROUND_BLUE
,
4569 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4570 ProgressTimeOutStringHandler
);
4572 BarWidth
= max(1, ProgressBar
->Width
);
4573 TimerValue
= TimeOut
* BarWidth
;
4574 ProgressSetStepCount(ProgressBar
, TimerValue
);
4576 StartTime
= NtGetTickCount();
4579 TimerDiv
= 1000 / BarWidth
;
4580 TimerDiv
= max(1, TimerDiv
);
4581 OldTimerValue
= TimerValue
;
4584 /* Decrease the timer */
4587 * Compute how much time the previous operations took.
4588 * This allows us in particular to take account for any time
4589 * elapsed if something slowed down.
4591 TimeElapsed
= NtGetTickCount() - StartTime
;
4592 if (TimeElapsed
>= TimerDiv
)
4594 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4595 TimeElapsed
/= TimerDiv
;
4596 StartTime
+= (TimerDiv
* TimeElapsed
);
4598 if (TimeElapsed
<= TimerValue
)
4599 TimerValue
-= TimeElapsed
;
4603 RefreshProgress
= TRUE
;
4606 if (RefreshProgress
)
4608 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4609 RefreshProgress
= FALSE
;
4612 /* Stop when the timer reaches zero */
4613 if (TimerValue
<= 0)
4616 /* Check for user key presses */
4619 * If the timer is used, use a passive wait of maximum 1 second
4620 * while monitoring for incoming console input events, so that
4621 * we are still able to display the timing count.
4624 /* Wait a maximum of 1 second for input events */
4625 TimeElapsed
= NtGetTickCount() - StartTime
;
4626 if (TimeElapsed
< TimerDiv
)
4628 /* Convert the time to NT Format */
4629 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4630 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4634 Status
= STATUS_TIMEOUT
;
4637 /* Check whether the input event has been signaled, or a timeout happened */
4638 if (Status
== STATUS_TIMEOUT
)
4642 if (Status
!= STATUS_WAIT_0
)
4644 /* An error happened, bail out */
4645 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4649 /* Check for an ENTER key press */
4650 while (CONSOLE_ConInKeyPeek(Ir
))
4652 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4654 /* Found it, stop waiting */
4661 /* Destroy the progress bar and quit */
4662 DestroyProgressBar(ProgressBar
);
4667 * Displays the QuitPage.
4670 * FlushPage (At once)
4676 * Number of the next page.
4679 QuitPage(PINPUT_RECORD Ir
)
4681 MUIDisplayPage(QUIT_PAGE
);
4683 /* Destroy the NTOS installations list */
4684 if (NtOsInstallsList
!= NULL
)
4686 DestroyGenericList(NtOsInstallsList
, TRUE
);
4687 NtOsInstallsList
= NULL
;
4690 /* Destroy the partition list */
4691 if (PartitionList
!= NULL
)
4693 DestroyPartitionList(PartitionList
);
4694 PartitionList
= NULL
;
4697 /* Reset the formatter machine state */
4698 TempPartition
= NULL
;
4699 FormatState
= Start
;
4701 /* Destroy the filesystem list */
4702 ResetFileSystemList();
4704 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4706 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4707 ProgressCountdown(Ir
, 15);
4713 * Displays the SuccessPage.
4716 * FlushPage (At once)
4722 * Number of the next page.
4725 SuccessPage(PINPUT_RECORD Ir
)
4727 MUIDisplayPage(SUCCESS_PAGE
);
4729 if (IsUnattendedSetup
)
4732 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4733 ProgressCountdown(Ir
, 15);
4739 * Displays the FlushPage.
4742 * RebootPage (At once)
4745 * Number of the next page.
4748 FlushPage(PINPUT_RECORD Ir
)
4750 MUIDisplayPage(FLUSH_PAGE
);
4756 * The start routine and page management
4766 InfSetHeap(ProcessHeap
);
4768 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4769 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4770 if (!NT_SUCCESS(Status
))
4771 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4773 /* Initialize the user-mode PnP manager */
4774 Status
= InitializeUserModePnpManager(&USetupData
.SetupInf
);
4775 if (!NT_SUCCESS(Status
))
4778 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status
);
4781 if (!CONSOLE_Init())
4783 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4784 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4785 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4787 /* We failed to initialize the video, just quit the installer */
4788 return STATUS_APP_INIT_FAILURE
;
4791 /* Initialize Setup, phase 0 */
4792 InitializeSetup(&USetupData
, 0);
4793 USetupData
.ErrorRoutine
= USetupErrorRoutine
;
4795 /* Hide the cursor and clear the screen and keyboard buffer */
4796 CONSOLE_SetCursorType(TRUE
, FALSE
);
4797 CONSOLE_ClearScreen();
4800 /* Global Initialization page */
4801 Page
= SetupStartPage(&Ir
);
4803 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4805 CONSOLE_ClearScreen();
4808 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4815 Page
= LanguagePage(&Ir
);
4820 Page
= WelcomePage(&Ir
);
4825 Page
= LicensePage(&Ir
);
4829 case INSTALL_INTRO_PAGE
:
4830 Page
= InstallIntroPage(&Ir
);
4834 case SCSI_CONTROLLER_PAGE
:
4835 Page
= ScsiControllerPage(&Ir
);
4838 case OEM_DRIVER_PAGE
:
4839 Page
= OemDriverPage(&Ir
);
4843 case DEVICE_SETTINGS_PAGE
:
4844 Page
= DeviceSettingsPage(&Ir
);
4847 case COMPUTER_SETTINGS_PAGE
:
4848 Page
= ComputerSettingsPage(&Ir
);
4851 case DISPLAY_SETTINGS_PAGE
:
4852 Page
= DisplaySettingsPage(&Ir
);
4855 case KEYBOARD_SETTINGS_PAGE
:
4856 Page
= KeyboardSettingsPage(&Ir
);
4859 case LAYOUT_SETTINGS_PAGE
:
4860 Page
= LayoutSettingsPage(&Ir
);
4863 case SELECT_PARTITION_PAGE
:
4864 Page
= SelectPartitionPage(&Ir
);
4867 case CREATE_PRIMARY_PARTITION_PAGE
:
4868 Page
= CreatePrimaryPartitionPage(&Ir
);
4871 case CREATE_EXTENDED_PARTITION_PAGE
:
4872 Page
= CreateExtendedPartitionPage(&Ir
);
4875 case CREATE_LOGICAL_PARTITION_PAGE
:
4876 Page
= CreateLogicalPartitionPage(&Ir
);
4879 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4880 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4883 case DELETE_PARTITION_PAGE
:
4884 Page
= DeletePartitionPage(&Ir
);
4887 case SELECT_FILE_SYSTEM_PAGE
:
4888 Page
= SelectFileSystemPage(&Ir
);
4891 case FORMAT_PARTITION_PAGE
:
4892 Page
= FormatPartitionPage(&Ir
);
4895 case CHECK_FILE_SYSTEM_PAGE
:
4896 Page
= CheckFileSystemPage(&Ir
);
4899 case INSTALL_DIRECTORY_PAGE
:
4900 Page
= InstallDirectoryPage(&Ir
);
4903 case PREPARE_COPY_PAGE
:
4904 Page
= PrepareCopyPage(&Ir
);
4907 case FILE_COPY_PAGE
:
4908 Page
= FileCopyPage(&Ir
);
4912 Page
= RegistryPage(&Ir
);
4915 case BOOT_LOADER_PAGE
:
4916 Page
= BootLoaderPage(&Ir
);
4919 case BOOT_LOADER_FLOPPY_PAGE
:
4920 Page
= BootLoaderFloppyPage(&Ir
);
4923 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
4924 Page
= BootLoaderHarddiskMbrPage(&Ir
);
4927 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
4928 Page
= BootLoaderHarddiskVbrPage(&Ir
);
4932 case REPAIR_INTRO_PAGE
:
4933 Page
= RepairIntroPage(&Ir
);
4936 case UPGRADE_REPAIR_PAGE
:
4937 Page
= UpgradeRepairPage(&Ir
);
4941 Page
= SuccessPage(&Ir
);
4945 Page
= FlushPage(&Ir
);
4949 Page
= QuitPage(&Ir
);
4953 case SETUP_INIT_PAGE
:
4960 /* Terminate the user-mode PnP manager */
4961 TerminateUserModePnpManager();
4963 /* Setup has finished */
4964 FinishSetup(&USetupData
);
4966 if (Page
== RECOVERY_PAGE
)
4972 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
4973 NtShutdownSystem(ShutdownReboot
);
4974 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
4976 return STATUS_SUCCESS
;
4981 NtProcessStartup(PPEB Peb
)
4986 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
4988 ProcessHeap
= Peb
->ProcessHeap
;
4990 NtQuerySystemTime(&Time
);
4992 Status
= RunUSetup();
4994 if (NT_SUCCESS(Status
))
4997 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
4998 * a protective waiting.
4999 * This wait is needed because, since we are started as SMSS.EXE,
5000 * the NT kernel explicitly waits 5 seconds for the initial process
5001 * SMSS.EXE to initialize (as a protective measure), and otherwise
5002 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5004 Time
.QuadPart
+= 50000000;
5005 NtDelayExecution(FALSE
, &Time
);
5009 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5010 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5011 0, 0, NULL
, 0, NULL
);
5014 NtTerminateProcess(NtCurrentProcess(), Status
);