3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
41 /* GLOBALS & LOCALS *********************************************************/
44 BOOLEAN IsUnattendedSetup
= FALSE
;
46 static USETUP_DATA USetupData
;
48 /* Partition where to perform the installation */
49 static PPARTENTRY InstallPartition
= NULL
;
50 // static PPARTENTRY SystemPartition = NULL; // The system partition we will actually use (can be different from PartitionList->SystemPartition in case we install on removable disk)
52 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
53 static WCHAR DestinationDriveLetter
;
58 PCWSTR SelectedLanguageId
;
59 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
60 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
62 static BOOLEAN RepairUpdateFlag
= FALSE
;
64 /* Global partition list on the system */
65 static PPARTLIST PartitionList
= NULL
;
67 /* Currently selected partition entry in the list */
68 static PPARTENTRY CurrentPartition
= NULL
;
70 /* List of supported file systems for the partition to be formatted */
71 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
73 /* Machine state for the formatter */
74 static PPARTENTRY TempPartition
= NULL
;
75 static FORMATMACHINESTATE FormatState
= Start
;
77 /*****************************************************/
79 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
80 static PGENERIC_LIST NtOsInstallsList
= NULL
;
83 /* FUNCTIONS ****************************************************************/
86 PrintString(char* fmt
,...)
90 UNICODE_STRING UnicodeString
;
91 ANSI_STRING AnsiString
;
94 vsprintf(buffer
, fmt
, ap
);
97 RtlInitAnsiString(&AnsiString
, buffer
);
98 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
99 NtDisplayString(&UnicodeString
);
100 RtlFreeUnicodeString(&UnicodeString
);
105 DrawBox(IN SHORT xLeft
,
113 /* Draw upper left corner */
116 FillConsoleOutputCharacterA(StdOutput
,
122 /* Draw upper edge */
125 FillConsoleOutputCharacterA(StdOutput
,
131 /* Draw upper right corner */
132 coPos
.X
= xLeft
+ Width
- 1;
134 FillConsoleOutputCharacterA(StdOutput
,
140 /* Draw right edge, inner space and left edge */
141 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
144 FillConsoleOutputCharacterA(StdOutput
,
151 FillConsoleOutputCharacterA(StdOutput
,
157 coPos
.X
= xLeft
+ Width
- 1;
158 FillConsoleOutputCharacterA(StdOutput
,
165 /* Draw lower left corner */
167 coPos
.Y
= yTop
+ Height
- 1;
168 FillConsoleOutputCharacterA(StdOutput
,
174 /* Draw lower edge */
176 coPos
.Y
= yTop
+ Height
- 1;
177 FillConsoleOutputCharacterA(StdOutput
,
183 /* Draw lower right corner */
184 coPos
.X
= xLeft
+ Width
- 1;
185 coPos
.Y
= yTop
+ Height
- 1;
186 FillConsoleOutputCharacterA(StdOutput
,
195 PopupError(PCCH Text
,
213 /* Count text lines and longest line */
220 p
= strchr(pnext
, '\n');
224 Length
= strlen(pnext
);
229 Length
= (ULONG
)(p
- pnext
);
235 if (Length
> MaxLength
)
244 /* Check length of status line */
247 Length
= strlen(Status
);
249 if (Length
> MaxLength
)
253 Width
= MaxLength
+ 4;
259 yTop
= (yScreen
- Height
) / 2;
260 xLeft
= (xScreen
- Width
) / 2;
263 /* Set screen attributes */
265 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
267 FillConsoleOutputAttribute(StdOutput
,
268 FOREGROUND_RED
| BACKGROUND_WHITE
,
274 DrawBox(xLeft
, yTop
, Width
, Height
);
276 /* Print message text */
281 p
= strchr(pnext
, '\n');
285 Length
= strlen(pnext
);
290 Length
= (ULONG
)(p
- pnext
);
297 WriteConsoleOutputCharacterA(StdOutput
,
311 /* Print separator line and status text */
314 coPos
.Y
= yTop
+ Height
- 3;
316 FillConsoleOutputCharacterA(StdOutput
,
323 FillConsoleOutputCharacterA(StdOutput
,
329 coPos
.X
= xLeft
+ Width
- 1;
330 FillConsoleOutputCharacterA(StdOutput
,
338 WriteConsoleOutputCharacterA(StdOutput
,
340 min(strlen(Status
), (SIZE_T
)Width
- 4),
345 if (WaitEvent
== POPUP_WAIT_NONE
)
350 CONSOLE_ConInKey(Ir
);
352 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
353 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
365 * FALSE: Don't quit setup.
368 ConfirmQuit(PINPUT_RECORD Ir
)
371 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
375 CONSOLE_ConInKey(Ir
);
377 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
378 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
383 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
397 PGENERIC_LIST_ENTRY ListEntry
;
400 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
402 if (USetupData
.LayoutList
== NULL
)
404 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
405 if (USetupData
.LayoutList
== NULL
)
407 /* FIXME: Handle error! */
412 /* Search for default layout (if provided) */
413 if (pszNewLayout
!= NULL
)
415 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
416 ListEntry
= GetNextListEntry(ListEntry
))
418 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
420 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
430 GetSettingDescription(
431 IN PGENERIC_LIST_ENTRY Entry
,
433 IN SIZE_T cchBufferSize
)
435 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
436 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
441 GetNTOSInstallationName(
442 IN PGENERIC_LIST_ENTRY Entry
,
444 IN SIZE_T cchBufferSize
)
446 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
447 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
449 if (PartEntry
&& PartEntry
->DriveLetter
)
451 /* We have retrieved a partition that is mounted */
452 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
454 PartEntry
->DriveLetter
,
455 NtOsInstall
->PathComponent
,
456 NtOsInstall
->InstallationName
);
460 /* We failed somewhere, just show the NT path */
461 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
463 &NtOsInstall
->SystemNtPath
,
464 NtOsInstall
->InstallationName
);
470 * Displays the LanguagePage.
472 * Next pages: WelcomePage, QuitPage
475 * Init SelectedLanguageId
476 * Init USetupData.LanguageId
479 * Number of the next page.
482 LanguagePage(PINPUT_RECORD Ir
)
484 GENERIC_LIST_UI ListUi
;
485 PCWSTR NewLanguageId
;
486 BOOL RefreshPage
= FALSE
;
488 /* Initialize the computer settings list */
489 if (USetupData
.LanguageList
== NULL
)
491 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
492 if (USetupData
.LanguageList
== NULL
)
494 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
499 SelectedLanguageId
= DefaultLanguage
;
500 USetupData
.LanguageId
= 0;
503 SetConsoleCodePage();
507 * If there is no language or just a single one in the list,
508 * skip the language selection process altogether.
510 if (GetNumberOfListEntries(USetupData
.LanguageList
) <= 1)
512 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
516 InitGenericListUi(&ListUi
, USetupData
.LanguageList
, GetSettingDescription
);
517 DrawGenericList(&ListUi
,
522 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
524 MUIDisplayPage(LANGUAGE_PAGE
);
528 CONSOLE_ConInKey(Ir
);
530 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
531 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
533 ScrollDownGenericList(&ListUi
);
536 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
537 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
539 ScrollUpGenericList(&ListUi
);
542 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
543 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
545 ScrollPageDownGenericList(&ListUi
);
548 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
549 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
551 ScrollPageUpGenericList(&ListUi
);
554 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
555 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
560 RedrawGenericList(&ListUi
);
562 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
564 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
567 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
569 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
571 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
577 SetConsoleCodePage();
581 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
584 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
590 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
593 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
595 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
597 /* Clear the language page */
598 MUIClearPage(LANGUAGE_PAGE
);
600 SelectedLanguageId
= NewLanguageId
;
603 SetConsoleCodePage();
605 /* Redraw language selection page in native language */
606 MUIDisplayPage(LANGUAGE_PAGE
);
621 * LanguagePage (at once, default)
622 * InstallIntroPage (at once, if unattended)
627 * Init USetupData.SourcePath
628 * Init USetupData.SourceRootPath
629 * Init USetupData.SourceRootDir
630 * Init USetupData.SetupInf
631 * Init USetupData.RequiredPartitionDiskSpace
632 * Init IsUnattendedSetup
633 * If unattended, init *List and sets the Codepage
634 * If unattended, init SelectedLanguageId
635 * If unattended, init USetupData.LanguageId
638 * Number of the next page.
641 SetupStartPage(PINPUT_RECORD Ir
)
644 PGENERIC_LIST_ENTRY ListEntry
;
647 MUIDisplayPage(SETUP_INIT_PAGE
);
649 /* Initialize Setup, phase 1 */
650 Error
= InitializeSetup(&USetupData
, 1);
651 if (Error
!= ERROR_SUCCESS
)
653 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
657 /* Initialize the user-mode PnP manager */
658 if (!EnableUserModePnpManager())
659 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
661 /* Wait for any immediate pending installations to finish */
662 if (WaitNoPendingInstallEvents(NULL
) != STATUS_WAIT_0
)
663 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
665 CheckUnattendedSetup(&USetupData
);
667 if (IsUnattendedSetup
)
669 // TODO: Read options from inf
670 /* Load the hardware, language and keyboard layout lists */
672 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
673 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
674 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
676 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
679 SelectedLanguageId
= DefaultLanguage
;
680 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
681 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
683 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
685 /* first we hack LanguageList */
686 for (ListEntry
= GetFirstListEntry(USetupData
.LanguageList
); ListEntry
;
687 ListEntry
= GetNextListEntry(ListEntry
))
689 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
690 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
692 DPRINT("found %S in LanguageList\n", LocaleId
);
693 SetCurrentListEntry(USetupData
.LanguageList
, ListEntry
);
699 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
700 ListEntry
= GetNextListEntry(ListEntry
))
702 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
703 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
705 DPRINT("found %S in LayoutList\n", LocaleId
);
706 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
711 SetConsoleCodePage();
713 return INSTALL_INTRO_PAGE
;
716 return LANGUAGE_PAGE
;
721 * Displays the WelcomePage.
724 * InstallIntroPage (default)
731 * Number of the next page.
734 WelcomePage(PINPUT_RECORD Ir
)
736 MUIDisplayPage(WELCOME_PAGE
);
740 CONSOLE_ConInKey(Ir
);
742 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
743 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
750 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
752 return INSTALL_INTRO_PAGE
;
754 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
756 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
758 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
769 * Displays the License page.
772 * WelcomePage (default)
775 * Number of the next page.
778 LicensePage(PINPUT_RECORD Ir
)
780 MUIDisplayPage(LICENSE_PAGE
);
784 CONSOLE_ConInKey(Ir
);
786 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
797 * Displays the RepairIntroPage.
800 * RebootPage (default)
806 * Number of the next page.
809 RepairIntroPage(PINPUT_RECORD Ir
)
811 MUIDisplayPage(REPAIR_INTRO_PAGE
);
815 CONSOLE_ConInKey(Ir
);
817 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
821 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
823 RepairUpdateFlag
= TRUE
;
824 return INSTALL_INTRO_PAGE
;
826 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
828 return RECOVERY_PAGE
;
830 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
831 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
837 return REPAIR_INTRO_PAGE
;
841 * Displays the UpgradeRepairPage.
844 * RebootPage (default)
850 * Number of the next page.
853 UpgradeRepairPage(PINPUT_RECORD Ir
)
855 GENERIC_LIST_UI ListUi
;
858 if (PartitionList
== NULL
)
860 PartitionList
= CreatePartitionList();
861 if (PartitionList
== NULL
)
863 /* FIXME: show an error dialog */
864 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
867 else if (IsListEmpty(&PartitionList
->DiskListHead
))
869 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
873 /* Reset the formatter machine state */
874 TempPartition
= NULL
;
879 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
880 if (!NtOsInstallsList
)
881 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
884 * If there is no available installation (or just a single one??) that can
885 * be updated in the list, just continue with the regular installation.
887 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
889 RepairUpdateFlag
= FALSE
;
891 // return INSTALL_INTRO_PAGE;
892 return DEVICE_SETTINGS_PAGE
;
893 // return SCSI_CONTROLLER_PAGE;
896 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
898 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
899 DrawGenericList(&ListUi
,
904 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
907 CONSOLE_ConInKey(Ir
);
909 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
911 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
913 case VK_DOWN
: /* DOWN */
914 ScrollDownGenericList(&ListUi
);
917 ScrollUpGenericList(&ListUi
);
919 case VK_NEXT
: /* PAGE DOWN */
920 ScrollPageDownGenericList(&ListUi
);
922 case VK_PRIOR
: /* PAGE UP */
923 ScrollPageUpGenericList(&ListUi
);
930 RedrawGenericList(&ListUi
);
933 case VK_ESCAPE
: /* ESC */
935 RestoreGenericListUiState(&ListUi
);
936 // return nextPage; // prevPage;
938 // return INSTALL_INTRO_PAGE;
939 return DEVICE_SETTINGS_PAGE
;
940 // return SCSI_CONTROLLER_PAGE;
946 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
947 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
948 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
950 /* Retrieve the current installation */
951 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
953 CurrentInstallation
=
954 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
956 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
957 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
959 RepairUpdateFlag
= TRUE
;
962 /***/return INSTALL_INTRO_PAGE
;/***/
964 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
965 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
967 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
972 return UPGRADE_REPAIR_PAGE
;
977 * Displays the InstallIntroPage.
980 * DeviceSettingsPage (At once if repair or update is selected)
981 * SelectPartitionPage (At once if unattended setup)
982 * DeviceSettingsPage (default)
986 * Number of the next page.
989 InstallIntroPage(PINPUT_RECORD Ir
)
991 if (RepairUpdateFlag
)
993 #if 1 /* Old code that looks good */
995 // return SELECT_PARTITION_PAGE;
996 return DEVICE_SETTINGS_PAGE
;
998 #else /* Possible new code? */
1000 return DEVICE_SETTINGS_PAGE
;
1001 // return SCSI_CONTROLLER_PAGE;
1006 if (IsUnattendedSetup
)
1007 return SELECT_PARTITION_PAGE
;
1009 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1013 CONSOLE_ConInKey(Ir
);
1015 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1016 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1018 if (ConfirmQuit(Ir
))
1023 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1025 return UPGRADE_REPAIR_PAGE
;
1029 return INSTALL_INTRO_PAGE
;
1035 ScsiControllerPage(PINPUT_RECORD Ir
)
1037 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1039 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1041 /* FIXME: print loaded mass storage driver descriptions */
1043 CONSOLE_SetTextXY(8, 10, "TEST device");
1046 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1050 CONSOLE_ConInKey(Ir
);
1052 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1053 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1055 if (ConfirmQuit(Ir
))
1060 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1062 return DEVICE_SETTINGS_PAGE
;
1066 return SCSI_CONTROLLER_PAGE
;
1070 OemDriverPage(PINPUT_RECORD Ir
)
1072 // MUIDisplayPage(OEM_DRIVER_PAGE);
1074 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1076 /* FIXME: Implement!! */
1078 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1082 CONSOLE_ConInKey(Ir
);
1084 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1085 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1087 if (ConfirmQuit(Ir
))
1092 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1094 return DEVICE_SETTINGS_PAGE
;
1098 return OEM_DRIVER_PAGE
;
1104 * Displays the DeviceSettingsPage.
1107 * SelectPartitionPage (At once if repair or update is selected)
1108 * ComputerSettingsPage
1109 * DisplaySettingsPage
1110 * KeyboardSettingsPage
1111 * LayoutsettingsPage
1112 * SelectPartitionPage
1116 * Init USetupData.ComputerList
1117 * Init USetupData.DisplayList
1118 * Init USetupData.KeyboardList
1119 * Init USetupData.LayoutList
1122 * Number of the next page.
1125 DeviceSettingsPage(PINPUT_RECORD Ir
)
1127 static ULONG Line
= 16;
1129 /* Initialize the computer settings list */
1130 if (USetupData
.ComputerList
== NULL
)
1132 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
1133 if (USetupData
.ComputerList
== NULL
)
1135 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1140 /* Initialize the display settings list */
1141 if (USetupData
.DisplayList
== NULL
)
1143 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
1144 if (USetupData
.DisplayList
== NULL
)
1146 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1151 /* Initialize the keyboard settings list */
1152 if (USetupData
.KeyboardList
== NULL
)
1154 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
1155 if (USetupData
.KeyboardList
== NULL
)
1157 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1162 /* Initialize the keyboard layout list */
1163 if (USetupData
.LayoutList
== NULL
)
1165 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1166 if (USetupData
.LayoutList
== NULL
)
1168 /* FIXME: report error */
1169 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1174 if (RepairUpdateFlag
)
1175 return SELECT_PARTITION_PAGE
;
1177 // if (IsUnattendedSetup)
1178 // return SELECT_PARTITION_PAGE;
1180 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1182 DrawGenericListCurrentItem(USetupData
.ComputerList
, GetSettingDescription
, 25, 11);
1183 DrawGenericListCurrentItem(USetupData
.DisplayList
, GetSettingDescription
, 25, 12);
1184 DrawGenericListCurrentItem(USetupData
.KeyboardList
, GetSettingDescription
, 25, 13);
1185 DrawGenericListCurrentItem(USetupData
.LayoutList
, GetSettingDescription
, 25, 14);
1187 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1191 CONSOLE_ConInKey(Ir
);
1193 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1194 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1196 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1200 else if (Line
== 16)
1205 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1207 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1208 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1210 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1214 else if (Line
== 16)
1219 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1221 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1222 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1224 if (ConfirmQuit(Ir
))
1229 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1232 return COMPUTER_SETTINGS_PAGE
;
1233 else if (Line
== 12)
1234 return DISPLAY_SETTINGS_PAGE
;
1235 else if (Line
== 13)
1236 return KEYBOARD_SETTINGS_PAGE
;
1237 else if (Line
== 14)
1238 return LAYOUT_SETTINGS_PAGE
;
1239 else if (Line
== 16)
1240 return SELECT_PARTITION_PAGE
;
1244 return DEVICE_SETTINGS_PAGE
;
1249 * Handles generic selection lists.
1252 * GenericList: The list to handle.
1253 * nextPage: The page it needs to jump to after this page.
1254 * Ir: The PINPUT_RECORD
1257 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1258 PAGE_NUMBER nextPage
,
1263 CONSOLE_ConInKey(Ir
);
1265 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1266 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1268 ScrollDownGenericList(ListUi
);
1270 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1271 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1273 ScrollUpGenericList(ListUi
);
1275 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1276 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1278 ScrollPageDownGenericList(ListUi
);
1280 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1281 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1283 ScrollPageUpGenericList(ListUi
);
1285 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1286 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1288 if (ConfirmQuit(Ir
))
1291 RedrawGenericList(ListUi
);
1293 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1294 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1296 RestoreGenericListUiState(ListUi
);
1297 return nextPage
; // Use some "prevPage;" instead?
1299 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1303 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1306 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1313 * Displays the ComputerSettingsPage.
1316 * DeviceSettingsPage
1320 * Number of the next page.
1323 ComputerSettingsPage(PINPUT_RECORD Ir
)
1325 GENERIC_LIST_UI ListUi
;
1326 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1328 InitGenericListUi(&ListUi
, USetupData
.ComputerList
, GetSettingDescription
);
1329 DrawGenericList(&ListUi
,
1334 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1339 * Displays the DisplaySettingsPage.
1342 * DeviceSettingsPage
1346 * Number of the next page.
1349 DisplaySettingsPage(PINPUT_RECORD Ir
)
1351 GENERIC_LIST_UI ListUi
;
1352 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1354 InitGenericListUi(&ListUi
, USetupData
.DisplayList
, GetSettingDescription
);
1355 DrawGenericList(&ListUi
,
1360 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1365 * Displays the KeyboardSettingsPage.
1368 * DeviceSettingsPage
1372 * Number of the next page.
1375 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1377 GENERIC_LIST_UI ListUi
;
1378 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1380 InitGenericListUi(&ListUi
, USetupData
.KeyboardList
, GetSettingDescription
);
1381 DrawGenericList(&ListUi
,
1386 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1391 * Displays the LayoutSettingsPage.
1394 * DeviceSettingsPage
1398 * Number of the next page.
1401 LayoutSettingsPage(PINPUT_RECORD Ir
)
1403 GENERIC_LIST_UI ListUi
;
1404 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1406 InitGenericListUi(&ListUi
, USetupData
.LayoutList
, GetSettingDescription
);
1407 DrawGenericList(&ListUi
,
1412 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1417 IsDiskSizeValid(PPARTENTRY PartEntry
)
1421 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1422 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1424 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1426 /* Partition is too small so ask for another one */
1427 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1438 * Displays the SelectPartitionPage.
1441 * SelectFileSystemPage (At once if unattended)
1442 * SelectFileSystemPage (Default if free space is selected)
1443 * CreatePrimaryPartitionPage
1444 * CreateExtendedPartitionPage
1445 * CreateLogicalPartitionPage
1446 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1447 * DeletePartitionPage
1451 * Set InstallShortcut (only if not unattended + free space is selected)
1454 * Number of the next page.
1457 SelectPartitionPage(PINPUT_RECORD Ir
)
1462 if (PartitionList
== NULL
)
1464 PartitionList
= CreatePartitionList();
1465 if (PartitionList
== NULL
)
1467 /* FIXME: show an error dialog */
1468 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1471 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1473 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1477 /* Reset the formatter machine state */
1478 TempPartition
= NULL
;
1479 FormatState
= Start
;
1482 if (RepairUpdateFlag
)
1484 ASSERT(CurrentInstallation
);
1486 /* Determine the selected installation disk & partition */
1487 InstallPartition
= SelectPartition(PartitionList
,
1488 CurrentInstallation
->DiskNumber
,
1489 CurrentInstallation
->PartitionNumber
);
1490 if (!InstallPartition
)
1492 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1495 ASSERT(!IsContainerPartition(InstallPartition
->PartitionType
));
1497 return SELECT_FILE_SYSTEM_PAGE
;
1500 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1502 InitPartitionListUi(&ListUi
, PartitionList
,
1507 DrawPartitionList(&ListUi
);
1509 if (IsUnattendedSetup
)
1511 /* Determine the selected installation disk & partition */
1512 InstallPartition
= SelectPartition(PartitionList
,
1513 USetupData
.DestinationDiskNumber
,
1514 USetupData
.DestinationPartitionNumber
);
1515 if (!InstallPartition
)
1517 CurrentPartition
= ListUi
.CurrentPartition
;
1519 if (USetupData
.AutoPartition
)
1521 ASSERT(CurrentPartition
!= NULL
);
1522 ASSERT(!IsContainerPartition(CurrentPartition
->PartitionType
));
1524 if (CurrentPartition
->LogicalPartition
)
1526 CreateLogicalPartition(PartitionList
,
1528 CurrentPartition
->SectorCount
.QuadPart
,
1533 CreatePrimaryPartition(PartitionList
,
1535 CurrentPartition
->SectorCount
.QuadPart
,
1539 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1540 if (!IsDiskSizeValid(CurrentPartition
))
1542 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1543 USetupData
.RequiredPartitionDiskSpace
);
1544 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1547 InstallPartition
= CurrentPartition
;
1548 return SELECT_FILE_SYSTEM_PAGE
;
1553 ASSERT(!IsContainerPartition(InstallPartition
->PartitionType
));
1555 DrawPartitionList(&ListUi
); // FIXME: Doesn't make much sense...
1557 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1558 if (!IsDiskSizeValid(InstallPartition
))
1560 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1561 USetupData
.RequiredPartitionDiskSpace
);
1562 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1565 return SELECT_FILE_SYSTEM_PAGE
;
1571 CurrentPartition
= ListUi
.CurrentPartition
;
1573 /* Update status text */
1574 if (CurrentPartition
== NULL
)
1576 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1578 else if (CurrentPartition
->LogicalPartition
)
1580 if (CurrentPartition
->IsPartitioned
)
1582 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1586 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1591 if (CurrentPartition
->IsPartitioned
)
1593 if (IsContainerPartition(CurrentPartition
->PartitionType
))
1595 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1599 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1604 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1608 CONSOLE_ConInKey(Ir
);
1610 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1611 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1613 if (ConfirmQuit(Ir
))
1615 DestroyPartitionList(PartitionList
);
1616 PartitionList
= NULL
;
1622 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1623 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1625 ScrollDownPartitionList(&ListUi
);
1627 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1628 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1630 ScrollUpPartitionList(&ListUi
);
1632 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1634 ASSERT(CurrentPartition
!= NULL
);
1636 if (IsContainerPartition(CurrentPartition
->PartitionType
))
1637 continue; // return SELECT_PARTITION_PAGE;
1639 if (CurrentPartition
->IsPartitioned
== FALSE
)
1641 if (CurrentPartition
->LogicalPartition
)
1643 Error
= LogicalPartitionCreationChecks(CurrentPartition
);
1644 if (Error
!= NOT_AN_ERROR
)
1646 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1647 return SELECT_PARTITION_PAGE
;
1650 CreateLogicalPartition(PartitionList
,
1657 Error
= PrimaryPartitionCreationChecks(CurrentPartition
);
1658 if (Error
!= NOT_AN_ERROR
)
1660 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1661 return SELECT_PARTITION_PAGE
;
1664 CreatePrimaryPartition(PartitionList
,
1671 if (!IsDiskSizeValid(CurrentPartition
))
1673 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1674 USetupData
.RequiredPartitionDiskSpace
);
1675 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1678 InstallPartition
= CurrentPartition
;
1679 return SELECT_FILE_SYSTEM_PAGE
;
1681 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1683 ASSERT(CurrentPartition
!= NULL
);
1685 if (CurrentPartition
->LogicalPartition
== FALSE
)
1687 Error
= PrimaryPartitionCreationChecks(CurrentPartition
);
1688 if (Error
!= NOT_AN_ERROR
)
1690 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1691 return SELECT_PARTITION_PAGE
;
1694 return CREATE_PRIMARY_PARTITION_PAGE
;
1697 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1699 ASSERT(CurrentPartition
!= NULL
);
1701 if (CurrentPartition
->LogicalPartition
== FALSE
)
1703 Error
= ExtendedPartitionCreationChecks(CurrentPartition
);
1704 if (Error
!= NOT_AN_ERROR
)
1706 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1707 return SELECT_PARTITION_PAGE
;
1710 return CREATE_EXTENDED_PARTITION_PAGE
;
1713 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1715 ASSERT(CurrentPartition
!= NULL
);
1717 if (CurrentPartition
->LogicalPartition
)
1719 Error
= LogicalPartitionCreationChecks(CurrentPartition
);
1720 if (Error
!= NOT_AN_ERROR
)
1722 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1723 return SELECT_PARTITION_PAGE
;
1726 return CREATE_LOGICAL_PARTITION_PAGE
;
1729 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1731 UNICODE_STRING CurrentPartitionU
;
1732 WCHAR PathBuffer
[MAX_PATH
];
1734 ASSERT(CurrentPartition
!= NULL
);
1736 if (CurrentPartition
->IsPartitioned
== FALSE
)
1738 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1739 return SELECT_PARTITION_PAGE
;
1742 // TODO: Do something similar before trying to format the partition?
1743 if (!CurrentPartition
->New
&&
1744 !IsContainerPartition(CurrentPartition
->PartitionType
) &&
1745 CurrentPartition
->FormatState
!= Unformatted
)
1747 ASSERT(CurrentPartition
->PartitionNumber
!= 0);
1749 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1750 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1751 CurrentPartition
->DiskEntry
->DiskNumber
,
1752 CurrentPartition
->PartitionNumber
);
1753 RtlInitUnicodeString(&CurrentPartitionU
, PathBuffer
);
1756 * Check whether the user attempts to delete the partition on which
1757 * the installation source is present. If so, fail with an error.
1759 // &USetupData.SourceRootPath
1760 if (RtlPrefixUnicodeString(&CurrentPartitionU
, &USetupData
.SourcePath
, TRUE
))
1762 PopupError("You cannot delete the partition containing the installation source!",
1763 MUIGetString(STRING_CONTINUE
),
1764 Ir
, POPUP_WAIT_ENTER
);
1765 return SELECT_PARTITION_PAGE
;
1769 // FIXME TODO: PartitionList->SystemPartition is not yet initialized!!!!
1770 if (CurrentPartition
== PartitionList
->SystemPartition
||
1771 CurrentPartition
->BootIndicator
)
1773 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1776 return DELETE_PARTITION_PAGE
;
1780 return SELECT_PARTITION_PAGE
;
1784 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1785 /* Restriction for MaxSize */
1786 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1789 ShowPartitionSizeInputBox(SHORT Left
,
1813 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1818 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1819 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1822 WriteConsoleOutputCharacterA(StdOutput
,
1828 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1829 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1831 WriteConsoleOutputCharacterA(StdOutput
,
1837 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1838 Length
= wcslen(InputBuffer
);
1840 CONSOLE_SetInputTextXY(iLeft
,
1842 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1844 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1845 CONSOLE_SetCursorType(TRUE
, TRUE
);
1849 CONSOLE_ConInKey(&Ir
);
1851 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1852 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1857 InputBuffer
[0] = UNICODE_NULL
;
1858 CONSOLE_SetCursorType(TRUE
, FALSE
);
1861 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1863 CONSOLE_SetCursorType(TRUE
, FALSE
);
1866 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1871 InputBuffer
[0] = UNICODE_NULL
;
1872 CONSOLE_SetCursorType(TRUE
, FALSE
);
1875 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1876 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1879 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1881 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1882 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1885 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1887 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1888 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1893 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1896 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1897 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1902 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1905 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1906 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1910 memmove(&InputBuffer
[Pos
],
1911 &InputBuffer
[Pos
+ 1],
1912 (Length
- Pos
- 1) * sizeof(WCHAR
));
1913 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1916 CONSOLE_SetInputTextXY(iLeft
,
1918 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1920 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1923 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1928 memmove(&InputBuffer
[Pos
- 1],
1930 (Length
- Pos
) * sizeof(WCHAR
));
1931 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1935 CONSOLE_SetInputTextXY(iLeft
,
1937 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1939 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1942 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1944 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1946 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1948 if ((ch
>= L
'0') && (ch
<= L
'9'))
1951 memmove(&InputBuffer
[Pos
+ 1],
1953 (Length
- Pos
) * sizeof(WCHAR
));
1954 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1955 InputBuffer
[Pos
] = ch
;
1959 CONSOLE_SetInputTextXY(iLeft
,
1961 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1963 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1972 * Displays the CreatePrimaryPartitionPage.
1975 * SelectPartitionPage
1976 * SelectFileSystemPage (default)
1980 * Number of the next page.
1983 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1985 PPARTENTRY PartEntry
;
1986 PDISKENTRY DiskEntry
;
1989 WCHAR InputBuffer
[50];
1993 ULONGLONG SectorCount
;
1996 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
1998 /* FIXME: show an error dialog */
2002 PartEntry
= CurrentPartition
;
2003 DiskEntry
= CurrentPartition
->DiskEntry
;
2005 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2007 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
2009 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2011 if (DiskSize
>= 10 * GB
) /* 10 GB */
2013 DiskSize
= DiskSize
/ GB
;
2014 Unit
= MUIGetString(STRING_GB
);
2019 DiskSize
= DiskSize
/ MB
;
2023 Unit
= MUIGetString(STRING_MB
);
2026 if (DiskEntry
->DriverName
.Length
> 0)
2028 CONSOLE_PrintTextXY(6, 10,
2029 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2032 DiskEntry
->DiskNumber
,
2036 &DiskEntry
->DriverName
,
2037 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2038 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2043 CONSOLE_PrintTextXY(6, 10,
2044 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2047 DiskEntry
->DiskNumber
,
2051 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2052 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2056 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2059 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2060 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2063 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2065 PartEntry
= CurrentPartition
;
2068 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2070 if (MaxSize
> PARTITION_MAXSIZE
)
2071 MaxSize
= PARTITION_MAXSIZE
;
2073 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2074 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2078 if (ConfirmQuit(Ir
))
2085 return SELECT_PARTITION_PAGE
;
2089 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2097 if (PartSize
> MaxSize
)
2103 /* Convert to bytes */
2104 if (PartSize
== MaxSize
)
2106 /* Use all of the unpartitioned disk space */
2107 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2111 /* Calculate the sector count from the size in MB */
2112 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2114 /* But never get larger than the unpartitioned disk space */
2115 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2116 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2119 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2121 CreatePrimaryPartition(PartitionList
,
2126 return SELECT_PARTITION_PAGE
;
2130 return CREATE_PRIMARY_PARTITION_PAGE
;
2135 * Displays the CreateExtendedPartitionPage.
2138 * SelectPartitionPage (default)
2142 * Number of the next page.
2145 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2147 PPARTENTRY PartEntry
;
2148 PDISKENTRY DiskEntry
;
2151 WCHAR InputBuffer
[50];
2155 ULONGLONG SectorCount
;
2158 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2160 /* FIXME: show an error dialog */
2164 PartEntry
= CurrentPartition
;
2165 DiskEntry
= CurrentPartition
->DiskEntry
;
2167 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2169 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2171 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2173 if (DiskSize
>= 10 * GB
) /* 10 GB */
2175 DiskSize
= DiskSize
/ GB
;
2176 Unit
= MUIGetString(STRING_GB
);
2181 DiskSize
= DiskSize
/ MB
;
2185 Unit
= MUIGetString(STRING_MB
);
2188 if (DiskEntry
->DriverName
.Length
> 0)
2190 CONSOLE_PrintTextXY(6, 10,
2191 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2194 DiskEntry
->DiskNumber
,
2198 &DiskEntry
->DriverName
,
2199 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2200 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2205 CONSOLE_PrintTextXY(6, 10,
2206 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2209 DiskEntry
->DiskNumber
,
2213 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2214 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2218 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2221 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2222 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2225 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2227 PartEntry
= CurrentPartition
;
2230 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2232 if (MaxSize
> PARTITION_MAXSIZE
)
2233 MaxSize
= PARTITION_MAXSIZE
;
2235 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2236 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2240 if (ConfirmQuit(Ir
))
2247 return SELECT_PARTITION_PAGE
;
2251 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2259 if (PartSize
> MaxSize
)
2265 /* Convert to bytes */
2266 if (PartSize
== MaxSize
)
2268 /* Use all of the unpartitioned disk space */
2269 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2273 /* Calculate the sector count from the size in MB */
2274 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2276 /* But never get larger than the unpartitioned disk space */
2277 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2278 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2281 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2283 CreateExtendedPartition(PartitionList
,
2287 return SELECT_PARTITION_PAGE
;
2291 return CREATE_EXTENDED_PARTITION_PAGE
;
2296 * Displays the CreateLogicalPartitionPage.
2299 * SelectFileSystemPage (default)
2303 * Number of the next page.
2306 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2308 PPARTENTRY PartEntry
;
2309 PDISKENTRY DiskEntry
;
2312 WCHAR InputBuffer
[50];
2316 ULONGLONG SectorCount
;
2319 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2321 /* FIXME: show an error dialog */
2325 PartEntry
= CurrentPartition
;
2326 DiskEntry
= CurrentPartition
->DiskEntry
;
2328 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2330 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2332 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2334 if (DiskSize
>= 10 * GB
) /* 10 GB */
2336 DiskSize
= DiskSize
/ GB
;
2337 Unit
= MUIGetString(STRING_GB
);
2342 DiskSize
= DiskSize
/ MB
;
2346 Unit
= MUIGetString(STRING_MB
);
2349 if (DiskEntry
->DriverName
.Length
> 0)
2351 CONSOLE_PrintTextXY(6, 10,
2352 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2355 DiskEntry
->DiskNumber
,
2359 &DiskEntry
->DriverName
,
2360 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2361 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2366 CONSOLE_PrintTextXY(6, 10,
2367 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2370 DiskEntry
->DiskNumber
,
2374 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2375 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2379 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2382 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2383 CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2386 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2388 PartEntry
= CurrentPartition
;
2391 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2393 if (MaxSize
> PARTITION_MAXSIZE
)
2394 MaxSize
= PARTITION_MAXSIZE
;
2396 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2397 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2401 if (ConfirmQuit(Ir
))
2408 return SELECT_PARTITION_PAGE
;
2412 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2420 if (PartSize
> MaxSize
)
2426 /* Convert to bytes */
2427 if (PartSize
== MaxSize
)
2429 /* Use all of the unpartitioned disk space */
2430 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2434 /* Calculate the sector count from the size in MB */
2435 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2437 /* But never get larger than the unpartitioned disk space */
2438 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2439 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2442 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2444 CreateLogicalPartition(PartitionList
,
2449 return SELECT_PARTITION_PAGE
;
2453 return CREATE_LOGICAL_PARTITION_PAGE
;
2458 * Displays the ConfirmDeleteSystemPartitionPage.
2461 * DeletePartitionPage (default)
2462 * SelectPartitionPage
2465 * Number of the next page.
2468 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2470 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2474 CONSOLE_ConInKey(Ir
);
2476 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2477 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2479 if (ConfirmQuit(Ir
))
2484 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2486 return DELETE_PARTITION_PAGE
;
2488 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2490 return SELECT_PARTITION_PAGE
;
2494 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2499 * Displays the DeletePartitionPage.
2502 * SelectPartitionPage (default)
2506 * Number of the next page.
2509 DeletePartitionPage(PINPUT_RECORD Ir
)
2511 PPARTENTRY PartEntry
;
2512 PDISKENTRY DiskEntry
;
2516 CHAR PartTypeString
[32];
2518 if (PartitionList
== NULL
|| CurrentPartition
== NULL
)
2520 /* FIXME: show an error dialog */
2524 PartEntry
= CurrentPartition
;
2525 DiskEntry
= CurrentPartition
->DiskEntry
;
2527 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2529 /* Adjust partition type */
2530 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2532 ARRAYSIZE(PartTypeString
));
2534 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2536 if (PartSize
>= 10 * GB
) /* 10 GB */
2538 PartSize
= PartSize
/ GB
;
2539 Unit
= MUIGetString(STRING_GB
);
2543 if (PartSize
>= 10 * MB
) /* 10 MB */
2545 PartSize
= PartSize
/ MB
;
2546 Unit
= MUIGetString(STRING_MB
);
2550 PartSize
= PartSize
/ KB
;
2551 Unit
= MUIGetString(STRING_KB
);
2554 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2556 CONSOLE_PrintTextXY(6, 10,
2557 MUIGetString(STRING_HDDINFOUNK2
),
2558 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2559 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2560 PartEntry
->PartitionType
,
2566 CONSOLE_PrintTextXY(6, 10,
2567 " %c%c %s %I64u %s",
2568 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2569 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2575 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2577 if (DiskSize
>= 10 * GB
) /* 10 GB */
2579 DiskSize
= DiskSize
/ GB
;
2580 Unit
= MUIGetString(STRING_GB
);
2585 DiskSize
= DiskSize
/ MB
;
2589 Unit
= MUIGetString(STRING_MB
);
2592 if (DiskEntry
->DriverName
.Length
> 0)
2594 CONSOLE_PrintTextXY(6, 12,
2595 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2598 DiskEntry
->DiskNumber
,
2602 &DiskEntry
->DriverName
,
2603 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2604 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2609 CONSOLE_PrintTextXY(6, 12,
2610 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2613 DiskEntry
->DiskNumber
,
2617 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2618 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2624 CONSOLE_ConInKey(Ir
);
2626 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2627 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2629 if (ConfirmQuit(Ir
))
2634 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2636 return SELECT_PARTITION_PAGE
;
2638 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2640 DeletePartition(PartitionList
,
2643 return SELECT_PARTITION_PAGE
;
2647 return DELETE_PARTITION_PAGE
;
2652 ResetFileSystemList(VOID
)
2654 if (!FileSystemList
)
2657 DestroyFileSystemList(FileSystemList
);
2658 FileSystemList
= NULL
;
2662 * Displays the SelectFileSystemPage.
2665 * CheckFileSystemPage (At once if RepairUpdate is selected)
2666 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2667 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2668 * SelectPartitionPage (If the user aborts)
2669 * FormatPartitionPage (Default)
2673 * Calls UpdatePartitionType()
2674 * Calls CheckActiveSystemPartition()
2677 * Number of the next page.
2680 SelectFileSystemPage(PINPUT_RECORD Ir
)
2682 PPARTENTRY PartEntry
;
2683 PDISKENTRY DiskEntry
;
2688 CHAR PartTypeString
[32];
2689 FORMATMACHINESTATE PreviousFormatState
;
2692 DPRINT("SelectFileSystemPage()\n");
2694 if (PartitionList
== NULL
|| InstallPartition
== NULL
)
2696 /* FIXME: show an error dialog */
2700 /* Find or set the active system partition when starting formatting */
2701 if (FormatState
== Start
)
2703 /* Find or set the active system partition */
2704 CheckActiveSystemPartition(PartitionList
,
2706 InstallPartition
->DiskEntry
,
2708 if (PartitionList
->SystemPartition
== NULL
)
2710 /* FIXME: show an error dialog */
2712 // Error dialog should say that we cannot find a suitable
2713 // system partition and create one on the system. At this point,
2714 // it may be nice to ask the user whether he wants to continue,
2715 // or use an external drive as the system drive/partition
2716 // (e.g. floppy, USB drive, etc...)
2722 * If the system partition can be created in some
2723 * non-partitioned space, create it now.
2725 if (!PartitionList
->SystemPartition
->IsPartitioned
)
2727 // if (IsUnattendedSetup)
2729 CreatePrimaryPartition(PartitionList
,
2730 PartitionList
->SystemPartition
,
2731 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart,
2733 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2740 /* Commit all partition changes to all the disks */
2741 if (!WritePartitionsToDisk(PartitionList
))
2743 DPRINT("WritePartitionsToDisk() failed\n");
2744 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
2749 * In all cases, whether or not we are going to perform a formatting,
2750 * we must perform a filesystem check of both the system and the
2751 * installation partitions.
2753 InstallPartition
->NeedsCheck
= TRUE
;
2754 if (PartitionList
->SystemPartition
!= InstallPartition
)
2755 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2758 * In case we just repair an existing installation, or make
2759 * an unattended setup without formatting, just go to the
2760 * filesystem check step.
2762 if (RepairUpdateFlag
)
2763 return CHECK_FILE_SYSTEM_PAGE
;
2765 if (IsUnattendedSetup
&& !USetupData
.FormatPartition
)
2766 return CHECK_FILE_SYSTEM_PAGE
;
2769 // ASSERT(PartitionList->SystemPartition->IsPartitioned);
2771 /* Reset the filesystem list for each partition that is to be formatted */
2772 ResetFileSystemList();
2774 PreviousFormatState
= FormatState
;
2775 switch (FormatState
)
2780 * We start by formatting the system partition in case it is new
2781 * (it didn't exist before) and is not the same as the installation
2782 * partition. Otherwise we just require a filesystem check on it,
2783 * and start by formatting the installation partition instead.
2786 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
);
2788 if ((PartitionList
->SystemPartition
!= InstallPartition
) &&
2789 (PartitionList
->SystemPartition
->FormatState
== Unformatted
))
2791 TempPartition
= PartitionList
->SystemPartition
;
2792 TempPartition
->NeedsCheck
= TRUE
;
2794 // TODO: Should we let the user using a custom file-system,
2795 // or should we always use FAT(32) for it?
2796 // For "compatibility", FAT(32) would be best indeed.
2798 FormatState
= FormatSystemPartition
;
2799 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2803 TempPartition
= InstallPartition
;
2804 TempPartition
->NeedsCheck
= TRUE
;
2806 if (PartitionList
->SystemPartition
!= InstallPartition
)
2808 /* The system partition is separate, so it had better be formatted! */
2809 ASSERT((PartitionList
->SystemPartition
->FormatState
== Preformatted
) ||
2810 (PartitionList
->SystemPartition
->FormatState
== Formatted
));
2812 /* Require a filesystem check on the system partition too */
2813 PartitionList
->SystemPartition
->NeedsCheck
= TRUE
;
2816 FormatState
= FormatInstallPartition
;
2817 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2822 case FormatSystemPartition
:
2824 TempPartition
= InstallPartition
;
2825 TempPartition
->NeedsCheck
= TRUE
;
2827 FormatState
= FormatInstallPartition
;
2828 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2832 case FormatInstallPartition
:
2833 case FormatOtherPartition
:
2835 if (GetNextUnformattedPartition(PartitionList
,
2839 FormatState
= FormatOtherPartition
;
2840 TempPartition
->NeedsCheck
= TRUE
;
2842 if (FormatState
== FormatInstallPartition
)
2843 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2845 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2849 FormatState
= FormatDone
;
2851 if (FormatState
== FormatInstallPartition
)
2852 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2854 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2856 return CHECK_FILE_SYSTEM_PAGE
;
2863 DPRINT1("FormatState: FormatDone\n");
2864 return CHECK_FILE_SYSTEM_PAGE
;
2869 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2870 /* FIXME: show an error dialog */
2875 PartEntry
= TempPartition
;
2876 DiskEntry
= TempPartition
->DiskEntry
;
2878 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
2880 /* Adjust disk size */
2881 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2882 if (DiskSize
>= 10 * GB
) /* 10 GB */
2884 DiskSize
= DiskSize
/ GB
;
2885 DiskUnit
= MUIGetString(STRING_GB
);
2889 DiskSize
= DiskSize
/ MB
;
2890 DiskUnit
= MUIGetString(STRING_MB
);
2893 /* Adjust partition size */
2894 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2895 if (PartSize
>= 10 * GB
) /* 10 GB */
2897 PartSize
= PartSize
/ GB
;
2898 PartUnit
= MUIGetString(STRING_GB
);
2902 PartSize
= PartSize
/ MB
;
2903 PartUnit
= MUIGetString(STRING_MB
);
2906 /* Adjust partition type */
2907 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2909 ARRAYSIZE(PartTypeString
));
2911 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2913 if (PartEntry
->AutoCreate
)
2915 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2918 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2919 PartEntry
->PartitionNumber
,
2925 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2926 DiskEntry
->DiskNumber
,
2932 &DiskEntry
->DriverName
,
2933 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2934 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
2937 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2939 PartEntry
->AutoCreate
= FALSE
;
2941 else if (PartEntry
->New
)
2943 switch (FormatState
)
2945 case FormatSystemPartition
:
2946 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2949 case FormatInstallPartition
:
2950 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2953 case FormatOtherPartition
:
2954 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2961 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2965 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2967 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2969 CONSOLE_PrintTextXY(8, 10,
2970 MUIGetString(STRING_HDDINFOUNK4
),
2971 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2972 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2973 PartEntry
->PartitionType
,
2979 CONSOLE_PrintTextXY(8, 10,
2981 (PartEntry
->DriveLetter
== 0) ? '-' : (CHAR
)PartEntry
->DriveLetter
,
2982 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2988 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2989 DiskEntry
->DiskNumber
,
2995 &DiskEntry
->DriverName
,
2996 DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
? "MBR" :
2997 DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
? "GPT" :
3001 ASSERT(FileSystemList
== NULL
);
3003 if (IsUnattendedSetup
)
3005 ASSERT(USetupData
.FormatPartition
);
3007 switch (USetupData
.FsType
)
3009 /* 1 is for BtrFS */
3011 DefaultFs
= L
"BTRFS";
3014 /* If we don't understand input, default to FAT */
3022 /* By default select the "FAT" file system */
3026 /* Create the file system list */
3027 // TODO: Display only the FSes compatible with the selected partition!
3028 FileSystemList
= CreateFileSystemList(6, 26,
3030 PartEntry
->FormatState
== Unformatted
,
3032 if (FileSystemList
== NULL
)
3034 /* FIXME: show an error dialog */
3038 if (IsUnattendedSetup
)
3040 ASSERT(USetupData
.FormatPartition
);
3041 return FORMAT_PARTITION_PAGE
;
3044 DrawFileSystemList(FileSystemList
);
3048 CONSOLE_ConInKey(Ir
);
3050 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3051 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3053 if (ConfirmQuit(Ir
))
3055 /* Reset the filesystem list */
3056 ResetFileSystemList();
3062 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3063 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
3065 /* Reset the formatter machine state */
3066 TempPartition
= NULL
;
3067 FormatState
= Start
;
3069 /* Reset the filesystem list */
3070 ResetFileSystemList();
3072 return SELECT_PARTITION_PAGE
;
3074 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3075 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
3077 ScrollDownFileSystemList(FileSystemList
);
3079 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3080 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
3082 ScrollUpFileSystemList(FileSystemList
);
3084 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
3086 if (!FileSystemList
->Selected
->FileSystem
)
3088 ASSERT(!TempPartition
->New
&& TempPartition
->FormatState
!= Unformatted
);
3091 * Skip formatting this partition. We will also ignore
3092 * filesystem checks on it, unless it is either the system
3093 * or the installation partition.
3095 if (TempPartition
!= PartitionList
->SystemPartition
&&
3096 TempPartition
!= InstallPartition
)
3098 PartEntry
->NeedsCheck
= FALSE
;
3101 return SELECT_FILE_SYSTEM_PAGE
;
3105 /* Format this partition */
3106 return FORMAT_PARTITION_PAGE
;
3111 FormatState
= PreviousFormatState
;
3113 return SELECT_FILE_SYSTEM_PAGE
;
3118 * Displays the FormatPartitionPage.
3121 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3122 * SelectPartitionPage (At once)
3126 * Sets InstallPartition->FormatState
3127 * Sets USetupData.DestinationRootPath
3130 * Number of the next page.
3133 FormatPartitionPage(PINPUT_RECORD Ir
)
3136 PPARTENTRY PartEntry
;
3137 PDISKENTRY DiskEntry
;
3138 PFILE_SYSTEM_ITEM SelectedFileSystem
;
3139 UNICODE_STRING PartitionRootPath
;
3140 WCHAR PathBuffer
[MAX_PATH
];
3141 CHAR Buffer
[MAX_PATH
];
3146 PPARTITION_INFORMATION PartitionInfo
;
3149 DPRINT("FormatPartitionPage()\n");
3151 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
3153 if (PartitionList
== NULL
|| TempPartition
== NULL
)
3155 /* FIXME: show an error dialog */
3159 PartEntry
= TempPartition
;
3160 DiskEntry
= TempPartition
->DiskEntry
;
3162 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3164 SelectedFileSystem
= FileSystemList
->Selected
;
3165 ASSERT(SelectedFileSystem
&& SelectedFileSystem
->FileSystem
);
3169 if (!IsUnattendedSetup
)
3170 CONSOLE_ConInKey(Ir
);
3172 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3173 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3175 if (ConfirmQuit(Ir
))
3177 /* Reset the filesystem list */
3178 ResetFileSystemList();
3184 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3186 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3188 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3190 /* FIXME: show an error dialog */
3192 /* Reset the filesystem list */
3193 ResetFileSystemList();
3199 CONSOLE_PrintTextXY(6, 12,
3200 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3201 DiskEntry
->Cylinders
,
3202 DiskEntry
->TracksPerCylinder
,
3203 DiskEntry
->SectorsPerTrack
,
3204 DiskEntry
->BytesPerSector
,
3205 DiskEntry
->Dirty
? '*' : ' ');
3209 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3211 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3213 CONSOLE_PrintTextXY(6, Line
,
3214 "%2u: %2lu %c %12I64u %12I64u %02x",
3216 PartitionInfo
->PartitionNumber
,
3217 PartitionInfo
->BootIndicator
? 'A' : '-',
3218 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3219 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3220 PartitionInfo
->PartitionType
);
3225 /* Commit the partition changes to the disk */
3226 Status
= WritePartitions(DiskEntry
);
3227 if (!NT_SUCCESS(Status
))
3229 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
3230 DiskEntry
->DiskNumber
, Status
);
3232 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3234 /* Reset the filesystem list */
3235 ResetFileSystemList();
3240 /* Set PartitionRootPath */
3241 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3242 L
"\\Device\\Harddisk%lu\\Partition%lu",
3243 DiskEntry
->DiskNumber
,
3244 PartEntry
->PartitionNumber
);
3245 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3246 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3248 /* Format the partition */
3249 Status
= FormatPartition(&PartitionRootPath
,
3250 SelectedFileSystem
->FileSystem
,
3251 SelectedFileSystem
->QuickFormat
);
3252 if (Status
== STATUS_NOT_SUPPORTED
)
3255 "Setup is currently unable to format a partition in %S.\n"
3257 " \x07 Press ENTER to continue Setup.\n"
3258 " \x07 Press F3 to quit Setup.",
3259 SelectedFileSystem
->FileSystem
);
3262 MUIGetString(STRING_QUITCONTINUE
),
3263 NULL
, POPUP_WAIT_NONE
);
3267 CONSOLE_ConInKey(Ir
);
3269 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3270 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3272 if (ConfirmQuit(Ir
))
3274 /* Reset the filesystem list */
3275 ResetFileSystemList();
3280 return SELECT_FILE_SYSTEM_PAGE
;
3283 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3285 return SELECT_FILE_SYSTEM_PAGE
;
3289 else if (!NT_SUCCESS(Status
))
3291 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3292 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3294 /* Reset the filesystem list */
3295 ResetFileSystemList();
3301 // TODO: Here, call a partlist.c function that update the actual FS name
3302 // and the label fields of the volume.
3304 PartEntry
->FormatState
= Formatted
;
3305 // PartEntry->FileSystem = FileSystem;
3306 PartEntry
->New
= FALSE
;
3309 CONSOLE_SetStatusText(" Done. Press any key ...");
3310 CONSOLE_ConInKey(Ir
);
3313 return SELECT_FILE_SYSTEM_PAGE
;
3317 return FORMAT_PARTITION_PAGE
;
3322 * Displays the CheckFileSystemPage.
3325 * InstallDirectoryPage (At once)
3329 * Inits or reloads FileSystemList
3332 * Number of the next page.
3335 CheckFileSystemPage(PINPUT_RECORD Ir
)
3338 PDISKENTRY DiskEntry
;
3339 PPARTENTRY PartEntry
;
3340 UNICODE_STRING PartitionRootPath
;
3341 WCHAR PathBuffer
[MAX_PATH
];
3342 CHAR Buffer
[MAX_PATH
];
3344 if (PartitionList
== NULL
)
3346 /* FIXME: show an error dialog */
3350 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3352 return INSTALL_DIRECTORY_PAGE
;
3355 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
3357 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3359 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3361 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3362 PartEntry
->PartitionType
, (*PartEntry
->FileSystem
? PartEntry
->FileSystem
: L
"n/a"));
3364 /* HACK: Do not try to check a partition with an unknown filesystem */
3365 if (!*PartEntry
->FileSystem
)
3367 PartEntry
->NeedsCheck
= FALSE
;
3368 return CHECK_FILE_SYSTEM_PAGE
;
3371 /* Set PartitionRootPath */
3372 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3373 L
"\\Device\\Harddisk%lu\\Partition%lu",
3374 DiskEntry
->DiskNumber
,
3375 PartEntry
->PartitionNumber
);
3376 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3377 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3379 /* Check the partition */
3380 Status
= ChkdskPartition(&PartitionRootPath
, PartEntry
->FileSystem
);
3381 if (Status
== STATUS_NOT_SUPPORTED
)
3384 * Partition checking is not supported with the current filesystem,
3385 * so disable FS checks on it.
3387 PartEntry
->NeedsCheck
= FALSE
;
3390 "Setup is currently unable to check a partition formatted in %S.\n"
3392 " \x07 Press ENTER to continue Setup.\n"
3393 " \x07 Press F3 to quit Setup.",
3394 PartEntry
->FileSystem
);
3397 MUIGetString(STRING_QUITCONTINUE
),
3398 NULL
, POPUP_WAIT_NONE
);
3402 CONSOLE_ConInKey(Ir
);
3404 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3405 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3407 if (ConfirmQuit(Ir
))
3410 return CHECK_FILE_SYSTEM_PAGE
;
3412 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3414 return CHECK_FILE_SYSTEM_PAGE
;
3418 else if (!NT_SUCCESS(Status
))
3420 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3421 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3422 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3423 "(Status 0x%08lx).\n", Status
);
3425 // MUIGetString(STRING_REBOOTCOMPUTER),
3426 MUIGetString(STRING_CONTINUE
),
3427 Ir
, POPUP_WAIT_ENTER
);
3429 // return QUIT_PAGE;
3432 PartEntry
->NeedsCheck
= FALSE
;
3433 return CHECK_FILE_SYSTEM_PAGE
;
3439 IN PCWSTR InstallDir
,
3440 IN PPARTENTRY PartEntry
)
3444 Status
= InitDestinationPaths(&USetupData
, InstallDir
, PartEntry
);
3446 if (!NT_SUCCESS(Status
))
3448 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status
);
3452 /* Initialize DestinationDriveLetter */
3453 DestinationDriveLetter
= PartEntry
->DriveLetter
;
3455 return STATUS_SUCCESS
;
3461 IN PCWSTR InstallDir
)
3465 Length
= wcslen(InstallDir
);
3467 // TODO: Add check for 8.3 too.
3469 /* Path must be at least 2 characters long */
3473 /* Path must start with a backslash */
3474 // if (InstallDir[0] != L'\\')
3477 /* Path must not end with a backslash */
3478 if (InstallDir
[Length
- 1] == L
'\\')
3481 /* Path must not contain whitespace characters */
3482 for (i
= 0; i
< Length
; i
++)
3484 if (iswspace(InstallDir
[i
]))
3488 /* Path component must not end with a dot */
3489 for (i
= 0; i
< Length
; i
++)
3491 if (InstallDir
[i
] == L
'\\' && i
> 0)
3493 if (InstallDir
[i
- 1] == L
'.')
3498 if (InstallDir
[Length
- 1] == L
'.')
3506 * Displays the InstallDirectoryPage.
3513 * Number of the next page.
3516 InstallDirectoryPage(PINPUT_RECORD Ir
)
3521 WCHAR InstallDir
[MAX_PATH
];
3523 /* We do not need the filesystem list anymore */
3524 ResetFileSystemList();
3526 if (PartitionList
== NULL
|| InstallPartition
== NULL
)
3528 /* FIXME: show an error dialog */
3532 // if (IsUnattendedSetup)
3533 if (RepairUpdateFlag
)
3534 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3535 else if (USetupData
.InstallationDirectory
[0])
3536 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3538 wcscpy(InstallDir
, L
"\\ReactOS");
3541 * Check the validity of the predefined 'InstallDir'. If we are either
3542 * in unattended setup or in update/repair mode, and the installation path
3543 * is valid, just perform the installation. Otherwise (either in the case
3544 * of an invalid path, or we are in regular setup), display the UI and allow
3545 * the user to specify a new installation path.
3547 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3549 Status
= BuildInstallPaths(InstallDir
, InstallPartition
);
3550 if (!NT_SUCCESS(Status
))
3552 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3553 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3554 MUIGetString(STRING_CONTINUE
),
3555 Ir
, POPUP_WAIT_ENTER
);
3560 * Check whether the user attempts to install ReactOS within the
3561 * installation source directory, or in a subdirectory thereof.
3562 * If so, fail with an error.
3564 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3566 PopupError("You cannot install ReactOS within the installation source directory!",
3567 MUIGetString(STRING_CONTINUE
),
3568 Ir
, POPUP_WAIT_ENTER
);
3569 return INSTALL_DIRECTORY_PAGE
;
3572 return PREPARE_COPY_PAGE
;
3575 Length
= wcslen(InstallDir
);
3578 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3579 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3580 CONSOLE_SetCursorXY(8 + Pos
, 11);
3581 CONSOLE_SetCursorType(TRUE
, TRUE
);
3585 CONSOLE_ConInKey(Ir
);
3587 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3588 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3590 CONSOLE_SetCursorType(TRUE
, FALSE
);
3592 if (ConfirmQuit(Ir
))
3595 CONSOLE_SetCursorType(TRUE
, TRUE
);
3598 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3599 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3603 memmove(&InstallDir
[Pos
],
3604 &InstallDir
[Pos
+ 1],
3605 (Length
- Pos
- 1) * sizeof(WCHAR
));
3606 InstallDir
[Length
- 1] = UNICODE_NULL
;
3609 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3610 CONSOLE_SetCursorXY(8 + Pos
, 11);
3613 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3614 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3617 CONSOLE_SetCursorXY(8 + Pos
, 11);
3619 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3620 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3623 CONSOLE_SetCursorXY(8 + Pos
, 11);
3625 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3626 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3631 CONSOLE_SetCursorXY(8 + Pos
, 11);
3634 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3635 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3640 CONSOLE_SetCursorXY(8 + Pos
, 11);
3643 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3645 CONSOLE_SetCursorType(TRUE
, FALSE
);
3648 * Check for the validity of the installation directory and pop up
3649 * an error if it is not the case. Then the user can fix its input.
3651 if (!IsValidPath(InstallDir
))
3653 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3654 return INSTALL_DIRECTORY_PAGE
;
3657 Status
= BuildInstallPaths(InstallDir
, InstallPartition
);
3658 if (!NT_SUCCESS(Status
))
3660 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status
);
3661 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3662 MUIGetString(STRING_CONTINUE
),
3663 Ir
, POPUP_WAIT_ENTER
);
3668 * Check whether the user attempts to install ReactOS within the
3669 * installation source directory, or in a subdirectory thereof.
3670 * If so, fail with an error.
3672 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3674 PopupError("You cannot install ReactOS within the installation source directory!",
3675 MUIGetString(STRING_CONTINUE
),
3676 Ir
, POPUP_WAIT_ENTER
);
3677 return INSTALL_DIRECTORY_PAGE
;
3680 return PREPARE_COPY_PAGE
;
3682 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3687 memmove(&InstallDir
[Pos
- 1],
3689 (Length
- Pos
) * sizeof(WCHAR
));
3690 InstallDir
[Length
- 1] = UNICODE_NULL
;
3694 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3695 CONSOLE_SetCursorXY(8 + Pos
, 11);
3698 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3702 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3703 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3706 memmove(&InstallDir
[Pos
+ 1],
3708 (Length
- Pos
) * sizeof(WCHAR
));
3709 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3710 InstallDir
[Pos
] = c
;
3714 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3715 CONSOLE_SetCursorXY(8 + Pos
, 11);
3721 return INSTALL_DIRECTORY_PAGE
;
3725 // PSETUP_ERROR_ROUTINE
3729 IN PUSETUP_DATA pSetupData
,
3735 va_start(arg_ptr
, pSetupData
);
3737 if (pSetupData
->LastErrorNumber
>= ERROR_SUCCESS
&&
3738 pSetupData
->LastErrorNumber
< ERROR_LAST_ERROR_CODE
)
3740 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3741 MUIDisplayErrorV(pSetupData
->LastErrorNumber
, &Ir
, POPUP_WAIT_ENTER
, arg_ptr
);
3748 * Displays the PrepareCopyPage.
3751 * FileCopyPage(At once)
3755 * Calls PrepareFileCopy
3758 * Number of the next page.
3761 PrepareCopyPage(PINPUT_RECORD Ir
)
3763 // ERROR_NUMBER ErrorNumber;
3766 MUIDisplayPage(PREPARE_COPY_PAGE
);
3768 /* ErrorNumber = */ Success
= PrepareFileCopy(&USetupData
, NULL
);
3769 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success
)
3771 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3775 return FILE_COPY_PAGE
;
3778 typedef struct _COPYCONTEXT
3780 ULONG TotalOperations
;
3781 ULONG CompletedOperations
;
3782 PPROGRESSBAR ProgressBar
;
3783 PPROGRESSBAR MemoryBars
[4];
3784 } COPYCONTEXT
, *PCOPYCONTEXT
;
3787 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3790 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3792 /* Get the memory information from the system */
3793 NtQuerySystemInformation(SystemPerformanceInformation
,
3798 /* Check if this is initial setup */
3801 /* Set maximum limits to be total RAM pages */
3802 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3803 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3804 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3807 /* Set current values */
3808 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3809 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3810 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3815 FileCopyCallback(PVOID Context
,
3820 PCOPYCONTEXT CopyContext
= (PCOPYCONTEXT
)Context
;
3821 PFILEPATHS_W FilePathInfo
;
3822 PCWSTR SrcFileName
, DstFileName
;
3824 switch (Notification
)
3826 case SPFILENOTIFY_STARTSUBQUEUE
:
3828 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3829 CopyContext
->CompletedOperations
= 0;
3830 ProgressSetStepCount(CopyContext
->ProgressBar
,
3831 CopyContext
->TotalOperations
);
3832 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3836 case SPFILENOTIFY_STARTDELETE
:
3837 case SPFILENOTIFY_STARTRENAME
:
3838 case SPFILENOTIFY_STARTCOPY
:
3840 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3842 if (Notification
== SPFILENOTIFY_STARTDELETE
)
3844 /* Display delete message */
3845 ASSERT(Param2
== FILEOP_DELETE
);
3847 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3848 if (DstFileName
) ++DstFileName
;
3849 else DstFileName
= FilePathInfo
->Target
;
3851 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING
),
3854 else if (Notification
== SPFILENOTIFY_STARTRENAME
)
3856 /* Display move/rename message */
3857 ASSERT(Param2
== FILEOP_RENAME
);
3859 SrcFileName
= wcsrchr(FilePathInfo
->Source
, L
'\\');
3860 if (SrcFileName
) ++SrcFileName
;
3861 else SrcFileName
= FilePathInfo
->Source
;
3863 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3864 if (DstFileName
) ++DstFileName
;
3865 else DstFileName
= FilePathInfo
->Target
;
3867 if (!wcsicmp(SrcFileName
, DstFileName
))
3868 Param2
= STRING_MOVING
;
3870 Param2
= STRING_RENAMING
;
3872 CONSOLE_SetStatusText(MUIGetString(Param2
),
3873 SrcFileName
, DstFileName
);
3875 else if (Notification
== SPFILENOTIFY_STARTCOPY
)
3877 /* Display copy message */
3878 ASSERT(Param2
== FILEOP_COPY
);
3880 /* NOTE: When extracting from CABs the Source is the CAB name */
3881 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
3882 if (DstFileName
) ++DstFileName
;
3883 else DstFileName
= FilePathInfo
->Target
;
3885 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
),
3889 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3893 case SPFILENOTIFY_COPYERROR
:
3895 FilePathInfo
= (PFILEPATHS_W
)Param1
;
3897 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3898 FilePathInfo
->Target
, FilePathInfo
->Win32Error
);
3902 case SPFILENOTIFY_ENDDELETE
:
3903 case SPFILENOTIFY_ENDRENAME
:
3904 case SPFILENOTIFY_ENDCOPY
:
3906 CopyContext
->CompletedOperations
++;
3908 /* SYSREG checkpoint */
3909 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3910 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3912 ProgressNextStep(CopyContext
->ProgressBar
);
3913 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3923 * Displays the FileCopyPage.
3926 * RegistryPage(At once)
3932 * Number of the next page.
3935 FileCopyPage(PINPUT_RECORD Ir
)
3937 COPYCONTEXT CopyContext
;
3940 MUIDisplayPage(FILE_COPY_PAGE
);
3942 /* Create context for the copy process */
3943 CopyContext
.TotalOperations
= 0;
3944 CopyContext
.CompletedOperations
= 0;
3946 /* Create the progress bar as well */
3947 CopyContext
.ProgressBar
= CreateProgressBar(13,
3954 MUIGetString(STRING_SETUPCOPYINGFILES
));
3956 // fit memory bars to screen width, distribute them uniform
3957 MemBarWidth
= (xScreen
- 26) / 5;
3958 MemBarWidth
-= MemBarWidth
% 2; // make even
3959 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3960 /* Create the paged pool progress bar */
3961 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
3970 /* Create the non paged pool progress bar */
3971 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (MemBarWidth
/ 2),
3973 (xScreen
/ 2) + (MemBarWidth
/ 2),
3975 (xScreen
/ 2)- (MemBarWidth
/ 2),
3980 /* Create the global memory progress bar */
3981 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - MemBarWidth
,
3985 xScreen
- 13 - MemBarWidth
,
3990 /* Do the file copying */
3991 DoFileCopy(&USetupData
, FileCopyCallback
, &CopyContext
);
3993 /* If we get here, we're done, so cleanup the progress bar */
3994 DestroyProgressBar(CopyContext
.ProgressBar
);
3995 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
3996 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
3997 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
3999 /* Create the $winnt$.inf file */
4000 InstallSetupInfFile(&USetupData
);
4002 /* Go display the next page */
4003 return REGISTRY_PAGE
;
4009 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4011 /* WARNING: Please keep this lookup table in sync with the resources! */
4012 static const UINT StringIDs
[] =
4014 STRING_DONE
, /* Success */
4015 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4016 STRING_IMPORTFILE
, /* ImportRegHive */
4017 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4018 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4019 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4020 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4021 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4026 if (RegStatus
< ARRAYSIZE(StringIDs
))
4028 va_start(args
, RegStatus
);
4029 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4034 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4039 * Displays the RegistryPage.
4042 * SuccessPage (if RepairUpdate)
4043 * BootLoaderPage (default)
4047 * Calls UpdateRegistry
4050 * Number of the next page.
4053 RegistryPage(PINPUT_RECORD Ir
)
4057 MUIDisplayPage(REGISTRY_PAGE
);
4059 Error
= UpdateRegistry(&USetupData
,
4062 DestinationDriveLetter
,
4065 if (Error
!= ERROR_SUCCESS
)
4067 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4072 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4073 return BOOT_LOADER_PAGE
;
4079 * Displays the BootLoaderPage.
4082 * SuccessPage (if RepairUpdate)
4083 * BootLoaderHarddiskMbrPage
4084 * BootLoaderHarddiskVbrPage
4085 * BootLoaderFloppyPage
4090 * Calls RegInitializeRegistry
4091 * Calls ImportRegistryFile
4092 * Calls SetDefaultPagefile
4093 * Calls SetMountedDeviceValues
4096 * Number of the next page.
4099 BootLoaderPage(PINPUT_RECORD Ir
)
4101 UCHAR PartitionType
;
4102 BOOLEAN InstallOnFloppy
;
4104 WCHAR PathBuffer
[MAX_PATH
];
4106 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4108 ASSERT(PartitionList
->SystemPartition
->IsPartitioned
&& PartitionList
->SystemPartition
->PartitionNumber
!= 0);
4110 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4111 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4112 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4113 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4114 PartitionList
->SystemPartition
->PartitionNumber
);
4115 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4116 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4118 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4120 /* For unattended setup, skip MBR installation or install on floppy if needed */
4121 if (IsUnattendedSetup
)
4123 if ((USetupData
.MBRInstallType
== 0) ||
4124 (USetupData
.MBRInstallType
== 1))
4131 * We may install an MBR or VBR, but before that, check whether
4132 * we need to actually install the VBR on floppy.
4134 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4136 DPRINT("Error: system partition invalid (unused)\n");
4137 InstallOnFloppy
= TRUE
;
4139 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4141 /* OS/2 boot manager partition */
4142 DPRINT("Found OS/2 boot manager partition\n");
4143 InstallOnFloppy
= TRUE
;
4145 else if (PartitionType
== PARTITION_LINUX
)
4147 /* Linux partition */
4148 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
4149 InstallOnFloppy
= FALSE
;
4151 else if (PartitionType
== PARTITION_IFS
)
4153 /* NTFS partition */
4154 DPRINT("Found NTFS partition\n");
4156 // FIXME: Make it FALSE when we'll support NTFS installation!
4157 InstallOnFloppy
= TRUE
;
4159 else if ((PartitionType
== PARTITION_FAT_12
) ||
4160 (PartitionType
== PARTITION_FAT_16
) ||
4161 (PartitionType
== PARTITION_HUGE
) ||
4162 (PartitionType
== PARTITION_XINT13
) ||
4163 (PartitionType
== PARTITION_FAT32
) ||
4164 (PartitionType
== PARTITION_FAT32_XINT13
))
4166 DPRINT("Found FAT partition\n");
4167 InstallOnFloppy
= FALSE
;
4171 /* Unknown partition */
4172 DPRINT("Unknown partition found\n");
4173 InstallOnFloppy
= TRUE
;
4176 /* We should install on floppy */
4177 if (InstallOnFloppy
)
4179 USetupData
.MBRInstallType
= 1;
4183 /* Is it an unattended install on hdd? */
4184 if (IsUnattendedSetup
)
4186 if ((USetupData
.MBRInstallType
== 2) ||
4187 (USetupData
.MBRInstallType
== 3))
4193 MUIDisplayPage(BOOT_LOADER_PAGE
);
4194 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4198 CONSOLE_ConInKey(Ir
);
4200 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4201 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4203 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4212 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4214 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4215 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4217 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4226 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4228 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4229 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
4231 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4235 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4237 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4238 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
4240 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4244 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4246 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4247 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4249 if (ConfirmQuit(Ir
))
4254 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4258 /* Install on both MBR and VBR */
4259 USetupData
.MBRInstallType
= 2;
4262 else if (Line
== 13)
4264 /* Install on VBR only */
4265 USetupData
.MBRInstallType
= 3;
4268 else if (Line
== 14)
4270 /* Install on floppy */
4271 USetupData
.MBRInstallType
= 1;
4274 else if (Line
== 15)
4276 /* Skip MBR installation */
4277 USetupData
.MBRInstallType
= 0;
4281 return BOOT_LOADER_PAGE
;
4286 switch (USetupData
.MBRInstallType
)
4288 /* Skip MBR installation */
4290 return SUCCESS_PAGE
;
4292 /* Install on floppy */
4294 return BOOT_LOADER_FLOPPY_PAGE
;
4296 /* Install on both MBR and VBR */
4298 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4300 /* Install on VBR only */
4302 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4305 return BOOT_LOADER_PAGE
;
4310 * Displays the BootLoaderFloppyPage.
4313 * SuccessPage (At once)
4317 * Calls InstallFatBootcodeToFloppy()
4320 * Number of the next page.
4323 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4327 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4329 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4333 CONSOLE_ConInKey(Ir
);
4335 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4336 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4338 if (ConfirmQuit(Ir
))
4343 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4345 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4346 &USetupData
.DestinationArcPath
);
4347 if (!NT_SUCCESS(Status
))
4349 if (Status
== STATUS_DEVICE_NOT_READY
)
4350 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4352 /* TODO: Print error message */
4353 return BOOT_LOADER_FLOPPY_PAGE
;
4356 return SUCCESS_PAGE
;
4360 return BOOT_LOADER_FLOPPY_PAGE
;
4365 * Displays the BootLoaderHarddiskVbrPage.
4368 * SuccessPage (At once)
4372 * Calls InstallVBRToPartition()
4375 * Number of the next page.
4378 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4382 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4383 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4384 &USetupData
.SourceRootPath
,
4385 &USetupData
.DestinationArcPath
,
4386 PartitionList
->SystemPartition
->PartitionType
);
4387 if (!NT_SUCCESS(Status
))
4389 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4390 PartitionList
->SystemPartition
->FileSystem
);
4394 return SUCCESS_PAGE
;
4399 * Displays the BootLoaderHarddiskMbrPage.
4402 * SuccessPage (At once)
4406 * Calls InstallVBRToPartition()
4407 * Calls InstallMbrBootCodeToDisk()
4410 * Number of the next page.
4413 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4416 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4418 /* Step 1: Write the VBR */
4419 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4420 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4421 &USetupData
.SourceRootPath
,
4422 &USetupData
.DestinationArcPath
,
4423 PartitionList
->SystemPartition
->PartitionType
);
4424 if (!NT_SUCCESS(Status
))
4426 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
,
4427 PartitionList
->SystemPartition
->FileSystem
);
4431 /* Step 2: Write the MBR */
4432 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4433 L
"\\Device\\Harddisk%d\\Partition0",
4434 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4435 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4436 &USetupData
.SourceRootPath
,
4437 DestinationDevicePathBuffer
);
4438 if (!NT_SUCCESS(Status
))
4440 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4441 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
, L
"MBR");
4445 return SUCCESS_PAGE
;
4450 * @name ProgressTimeOutStringHandler
4452 * Handles the generation (displaying) of the timeout
4453 * countdown to the screen dynamically.
4456 * A pointer to a progress bar.
4458 * @param AlwaysUpdate
4459 * Constantly update the progress bar (boolean type).
4462 * A pointer to a string buffer.
4464 * @param cchBufferSize
4465 * The buffer's size in number of characters.
4468 * TRUE or FALSE on function termination.
4473 ProgressTimeOutStringHandler(
4474 IN PPROGRESSBAR Bar
,
4475 IN BOOLEAN AlwaysUpdate
,
4477 IN SIZE_T cchBufferSize
)
4479 ULONG OldProgress
= Bar
->Progress
;
4481 if (Bar
->StepCount
== 0)
4487 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4490 /* Build the progress string if it has changed */
4491 if (Bar
->ProgressFormatText
&&
4492 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4494 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4495 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4504 * @name ProgressCountdown
4506 * Displays and draws a red-coloured progress bar with a countdown.
4507 * When the timeout is reached, the flush page is displayed for reboot.
4510 * A pointer to an input keyboard record.
4513 * Initial countdown value in seconds.
4521 IN PINPUT_RECORD Ir
,
4525 ULONG StartTime
, BarWidth
, TimerDiv
;
4527 LONG TimerValue
, OldTimerValue
;
4528 LARGE_INTEGER Timeout
;
4529 PPROGRESSBAR ProgressBar
;
4530 BOOLEAN RefreshProgress
= TRUE
;
4532 /* Bail out if the timeout is already zero */
4536 /* Create the timeout progress bar and set it up */
4537 ProgressBar
= CreateProgressBarEx(13,
4544 FOREGROUND_RED
| BACKGROUND_BLUE
,
4547 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4548 ProgressTimeOutStringHandler
);
4550 BarWidth
= max(1, ProgressBar
->Width
);
4551 TimerValue
= TimeOut
* BarWidth
;
4552 ProgressSetStepCount(ProgressBar
, TimerValue
);
4554 StartTime
= NtGetTickCount();
4557 TimerDiv
= 1000 / BarWidth
;
4558 TimerDiv
= max(1, TimerDiv
);
4559 OldTimerValue
= TimerValue
;
4562 /* Decrease the timer */
4565 * Compute how much time the previous operations took.
4566 * This allows us in particular to take account for any time
4567 * elapsed if something slowed down.
4569 TimeElapsed
= NtGetTickCount() - StartTime
;
4570 if (TimeElapsed
>= TimerDiv
)
4572 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4573 TimeElapsed
/= TimerDiv
;
4574 StartTime
+= (TimerDiv
* TimeElapsed
);
4576 if (TimeElapsed
<= TimerValue
)
4577 TimerValue
-= TimeElapsed
;
4581 RefreshProgress
= TRUE
;
4584 if (RefreshProgress
)
4586 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4587 RefreshProgress
= FALSE
;
4590 /* Stop when the timer reaches zero */
4591 if (TimerValue
<= 0)
4594 /* Check for user key presses */
4597 * If the timer is used, use a passive wait of maximum 1 second
4598 * while monitoring for incoming console input events, so that
4599 * we are still able to display the timing count.
4602 /* Wait a maximum of 1 second for input events */
4603 TimeElapsed
= NtGetTickCount() - StartTime
;
4604 if (TimeElapsed
< TimerDiv
)
4606 /* Convert the time to NT Format */
4607 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4608 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4612 Status
= STATUS_TIMEOUT
;
4615 /* Check whether the input event has been signaled, or a timeout happened */
4616 if (Status
== STATUS_TIMEOUT
)
4620 if (Status
!= STATUS_WAIT_0
)
4622 /* An error happened, bail out */
4623 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4627 /* Check for an ENTER key press */
4628 while (CONSOLE_ConInKeyPeek(Ir
))
4630 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4632 /* Found it, stop waiting */
4639 /* Destroy the progress bar and quit */
4640 DestroyProgressBar(ProgressBar
);
4645 * Displays the QuitPage.
4648 * FlushPage (At once)
4654 * Number of the next page.
4657 QuitPage(PINPUT_RECORD Ir
)
4659 MUIDisplayPage(QUIT_PAGE
);
4661 /* Destroy the NTOS installations list */
4662 if (NtOsInstallsList
!= NULL
)
4664 DestroyGenericList(NtOsInstallsList
, TRUE
);
4665 NtOsInstallsList
= NULL
;
4668 /* Destroy the partition list */
4669 if (PartitionList
!= NULL
)
4671 DestroyPartitionList(PartitionList
);
4672 PartitionList
= NULL
;
4675 /* Reset the formatter machine state */
4676 TempPartition
= NULL
;
4677 FormatState
= Start
;
4679 /* Destroy the filesystem list */
4680 ResetFileSystemList();
4682 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4684 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4685 ProgressCountdown(Ir
, 15);
4691 * Displays the SuccessPage.
4694 * FlushPage (At once)
4700 * Number of the next page.
4703 SuccessPage(PINPUT_RECORD Ir
)
4705 MUIDisplayPage(SUCCESS_PAGE
);
4707 if (IsUnattendedSetup
)
4710 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4711 ProgressCountdown(Ir
, 15);
4717 * Displays the FlushPage.
4720 * RebootPage (At once)
4723 * Number of the next page.
4726 FlushPage(PINPUT_RECORD Ir
)
4728 MUIDisplayPage(FLUSH_PAGE
);
4734 * The start routine and page management
4744 InfSetHeap(ProcessHeap
);
4746 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4747 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4748 if (!NT_SUCCESS(Status
))
4749 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4751 /* Initialize the user-mode PnP manager */
4752 Status
= InitializeUserModePnpManager(&USetupData
.SetupInf
);
4753 if (!NT_SUCCESS(Status
))
4756 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status
);
4759 if (!CONSOLE_Init())
4761 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4762 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4763 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4765 /* We failed to initialize the video, just quit the installer */
4766 return STATUS_APP_INIT_FAILURE
;
4769 /* Initialize Setup, phase 0 */
4770 InitializeSetup(&USetupData
, 0);
4771 USetupData
.ErrorRoutine
= USetupErrorRoutine
;
4773 /* Hide the cursor and clear the screen and keyboard buffer */
4774 CONSOLE_SetCursorType(TRUE
, FALSE
);
4775 CONSOLE_ClearScreen();
4778 /* Global Initialization page */
4779 Page
= SetupStartPage(&Ir
);
4781 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4783 CONSOLE_ClearScreen();
4786 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4793 Page
= LanguagePage(&Ir
);
4798 Page
= WelcomePage(&Ir
);
4803 Page
= LicensePage(&Ir
);
4807 case INSTALL_INTRO_PAGE
:
4808 Page
= InstallIntroPage(&Ir
);
4812 case SCSI_CONTROLLER_PAGE
:
4813 Page
= ScsiControllerPage(&Ir
);
4816 case OEM_DRIVER_PAGE
:
4817 Page
= OemDriverPage(&Ir
);
4821 case DEVICE_SETTINGS_PAGE
:
4822 Page
= DeviceSettingsPage(&Ir
);
4825 case COMPUTER_SETTINGS_PAGE
:
4826 Page
= ComputerSettingsPage(&Ir
);
4829 case DISPLAY_SETTINGS_PAGE
:
4830 Page
= DisplaySettingsPage(&Ir
);
4833 case KEYBOARD_SETTINGS_PAGE
:
4834 Page
= KeyboardSettingsPage(&Ir
);
4837 case LAYOUT_SETTINGS_PAGE
:
4838 Page
= LayoutSettingsPage(&Ir
);
4841 case SELECT_PARTITION_PAGE
:
4842 Page
= SelectPartitionPage(&Ir
);
4845 case CREATE_PRIMARY_PARTITION_PAGE
:
4846 Page
= CreatePrimaryPartitionPage(&Ir
);
4849 case CREATE_EXTENDED_PARTITION_PAGE
:
4850 Page
= CreateExtendedPartitionPage(&Ir
);
4853 case CREATE_LOGICAL_PARTITION_PAGE
:
4854 Page
= CreateLogicalPartitionPage(&Ir
);
4857 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4858 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4861 case DELETE_PARTITION_PAGE
:
4862 Page
= DeletePartitionPage(&Ir
);
4865 case SELECT_FILE_SYSTEM_PAGE
:
4866 Page
= SelectFileSystemPage(&Ir
);
4869 case FORMAT_PARTITION_PAGE
:
4870 Page
= FormatPartitionPage(&Ir
);
4873 case CHECK_FILE_SYSTEM_PAGE
:
4874 Page
= CheckFileSystemPage(&Ir
);
4877 case INSTALL_DIRECTORY_PAGE
:
4878 Page
= InstallDirectoryPage(&Ir
);
4881 case PREPARE_COPY_PAGE
:
4882 Page
= PrepareCopyPage(&Ir
);
4885 case FILE_COPY_PAGE
:
4886 Page
= FileCopyPage(&Ir
);
4890 Page
= RegistryPage(&Ir
);
4893 case BOOT_LOADER_PAGE
:
4894 Page
= BootLoaderPage(&Ir
);
4897 case BOOT_LOADER_FLOPPY_PAGE
:
4898 Page
= BootLoaderFloppyPage(&Ir
);
4901 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
4902 Page
= BootLoaderHarddiskMbrPage(&Ir
);
4905 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
4906 Page
= BootLoaderHarddiskVbrPage(&Ir
);
4910 case REPAIR_INTRO_PAGE
:
4911 Page
= RepairIntroPage(&Ir
);
4914 case UPGRADE_REPAIR_PAGE
:
4915 Page
= UpgradeRepairPage(&Ir
);
4919 Page
= SuccessPage(&Ir
);
4923 Page
= FlushPage(&Ir
);
4927 Page
= QuitPage(&Ir
);
4931 case SETUP_INIT_PAGE
:
4938 /* Terminate the user-mode PnP manager */
4939 TerminateUserModePnpManager();
4941 /* Setup has finished */
4942 FinishSetup(&USetupData
);
4944 if (Page
== RECOVERY_PAGE
)
4950 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
4951 NtShutdownSystem(ShutdownReboot
);
4952 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
4954 return STATUS_SUCCESS
;
4959 NtProcessStartup(PPEB Peb
)
4964 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
4966 ProcessHeap
= Peb
->ProcessHeap
;
4968 NtQuerySystemTime(&Time
);
4970 Status
= RunUSetup();
4972 if (NT_SUCCESS(Status
))
4975 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
4976 * a protective waiting.
4977 * This wait is needed because, since we are started as SMSS.EXE,
4978 * the NT kernel explicitly waits 5 seconds for the initial process
4979 * SMSS.EXE to initialize (as a protective measure), and otherwise
4980 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
4982 Time
.QuadPart
+= 50000000;
4983 NtDelayExecution(FALSE
, &Time
);
4987 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
4988 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
4989 0, 0, NULL
, 0, NULL
);
4992 NtTerminateProcess(NtCurrentProcess(), Status
);