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 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
40 /* GLOBALS & LOCALS *********************************************************/
43 BOOLEAN IsUnattendedSetup
= FALSE
;
45 static USETUP_DATA USetupData
;
47 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
48 static WCHAR DestinationDriveLetter
;
53 PCWSTR SelectedLanguageId
;
54 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
55 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
57 static BOOLEAN RepairUpdateFlag
= FALSE
;
59 static HANDLE hPnpThread
= NULL
;
61 static PPARTLIST PartitionList
= NULL
;
62 static PPARTENTRY TempPartition
= NULL
;
63 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
64 static FORMATMACHINESTATE FormatState
= Start
;
66 /*****************************************************/
68 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
69 static PGENERIC_LIST NtOsInstallsList
= NULL
;
72 /* FUNCTIONS ****************************************************************/
75 PrintString(char* fmt
,...)
79 UNICODE_STRING UnicodeString
;
80 ANSI_STRING AnsiString
;
83 vsprintf(buffer
, fmt
, ap
);
86 RtlInitAnsiString(&AnsiString
, buffer
);
87 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
88 NtDisplayString(&UnicodeString
);
89 RtlFreeUnicodeString(&UnicodeString
);
94 DrawBox(IN SHORT xLeft
,
102 /* Draw upper left corner */
105 FillConsoleOutputCharacterA(StdOutput
,
111 /* Draw upper edge */
114 FillConsoleOutputCharacterA(StdOutput
,
120 /* Draw upper right corner */
121 coPos
.X
= xLeft
+ Width
- 1;
123 FillConsoleOutputCharacterA(StdOutput
,
129 /* Draw right edge, inner space and left edge */
130 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
133 FillConsoleOutputCharacterA(StdOutput
,
140 FillConsoleOutputCharacterA(StdOutput
,
146 coPos
.X
= xLeft
+ Width
- 1;
147 FillConsoleOutputCharacterA(StdOutput
,
154 /* Draw lower left corner */
156 coPos
.Y
= yTop
+ Height
- 1;
157 FillConsoleOutputCharacterA(StdOutput
,
163 /* Draw lower edge */
165 coPos
.Y
= yTop
+ Height
- 1;
166 FillConsoleOutputCharacterA(StdOutput
,
172 /* Draw lower right corner */
173 coPos
.X
= xLeft
+ Width
- 1;
174 coPos
.Y
= yTop
+ Height
- 1;
175 FillConsoleOutputCharacterA(StdOutput
,
184 PopupError(PCCH Text
,
202 /* Count text lines and longest line */
209 p
= strchr(pnext
, '\n');
213 Length
= strlen(pnext
);
218 Length
= (ULONG
)(p
- pnext
);
224 if (Length
> MaxLength
)
233 /* Check length of status line */
236 Length
= strlen(Status
);
238 if (Length
> MaxLength
)
242 Width
= MaxLength
+ 4;
248 yTop
= (yScreen
- Height
) / 2;
249 xLeft
= (xScreen
- Width
) / 2;
252 /* Set screen attributes */
254 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
256 FillConsoleOutputAttribute(StdOutput
,
257 FOREGROUND_RED
| BACKGROUND_WHITE
,
263 DrawBox(xLeft
, yTop
, Width
, Height
);
265 /* Print message text */
270 p
= strchr(pnext
, '\n');
274 Length
= strlen(pnext
);
279 Length
= (ULONG
)(p
- pnext
);
286 WriteConsoleOutputCharacterA(StdOutput
,
300 /* Print separator line and status text */
303 coPos
.Y
= yTop
+ Height
- 3;
305 FillConsoleOutputCharacterA(StdOutput
,
312 FillConsoleOutputCharacterA(StdOutput
,
318 coPos
.X
= xLeft
+ Width
- 1;
319 FillConsoleOutputCharacterA(StdOutput
,
327 WriteConsoleOutputCharacterA(StdOutput
,
329 min(strlen(Status
), (SIZE_T
)Width
- 4),
334 if (WaitEvent
== POPUP_WAIT_NONE
)
339 CONSOLE_ConInKey(Ir
);
341 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
342 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
354 * FALSE: Don't quit setup.
357 ConfirmQuit(PINPUT_RECORD Ir
)
360 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
364 CONSOLE_ConInKey(Ir
);
366 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
367 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
372 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
386 PGENERIC_LIST_ENTRY ListEntry
;
389 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
391 if (USetupData
.LayoutList
== NULL
)
393 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
394 if (USetupData
.LayoutList
== NULL
)
396 /* FIXME: Handle error! */
401 /* Search for default layout (if provided) */
402 if (pszNewLayout
!= NULL
)
404 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
405 ListEntry
= GetNextListEntry(ListEntry
))
407 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
409 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
419 GetSettingDescription(
420 IN PGENERIC_LIST_ENTRY Entry
,
422 IN SIZE_T cchBufferSize
)
424 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
425 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
430 GetNTOSInstallationName(
431 IN PGENERIC_LIST_ENTRY Entry
,
433 IN SIZE_T cchBufferSize
)
435 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
436 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
438 if (PartEntry
&& PartEntry
->DriveLetter
)
440 /* We have retrieved a partition that is mounted */
441 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
443 PartEntry
->DriveLetter
,
444 NtOsInstall
->PathComponent
,
445 NtOsInstall
->InstallationName
);
449 /* We failed somewhere, just show the NT path */
450 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
452 &NtOsInstall
->SystemNtPath
,
453 NtOsInstall
->InstallationName
);
459 * Displays the LanguagePage.
461 * Next pages: WelcomePage, QuitPage
464 * Init SelectedLanguageId
465 * Init USetupData.LanguageId
468 * Number of the next page.
471 LanguagePage(PINPUT_RECORD Ir
)
473 GENERIC_LIST_UI ListUi
;
474 PCWSTR NewLanguageId
;
475 BOOL RefreshPage
= FALSE
;
477 /* Initialize the computer settings list */
478 if (USetupData
.LanguageList
== NULL
)
480 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
481 if (USetupData
.LanguageList
== NULL
)
483 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
488 SelectedLanguageId
= DefaultLanguage
;
489 USetupData
.LanguageId
= 0;
492 SetConsoleCodePage();
496 * If there is no language or just a single one in the list,
497 * skip the language selection process altogether.
499 if (GetNumberOfListEntries(USetupData
.LanguageList
) <= 1)
501 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
505 InitGenericListUi(&ListUi
, USetupData
.LanguageList
, GetSettingDescription
);
506 DrawGenericList(&ListUi
,
511 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
513 MUIDisplayPage(LANGUAGE_PAGE
);
517 CONSOLE_ConInKey(Ir
);
519 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
520 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
522 ScrollDownGenericList(&ListUi
);
525 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
526 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
528 ScrollUpGenericList(&ListUi
);
531 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
532 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
534 ScrollPageDownGenericList(&ListUi
);
537 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
538 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
540 ScrollPageUpGenericList(&ListUi
);
543 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
544 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
549 RedrawGenericList(&ListUi
);
551 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
553 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
556 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
558 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
560 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
566 SetConsoleCodePage();
570 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
573 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
579 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
582 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
584 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
586 /* Clear the language page */
587 MUIClearPage(LANGUAGE_PAGE
);
589 SelectedLanguageId
= NewLanguageId
;
592 SetConsoleCodePage();
594 /* Redraw language selection page in native language */
595 MUIDisplayPage(LANGUAGE_PAGE
);
610 * LanguagePage (at once, default)
611 * InstallIntroPage (at once, if unattended)
616 * Init USetupData.SourcePath
617 * Init USetupData.SourceRootPath
618 * Init USetupData.SourceRootDir
619 * Init USetupData.SetupInf
620 * Init USetupData.RequiredPartitionDiskSpace
621 * Init IsUnattendedSetup
622 * If unattended, init *List and sets the Codepage
623 * If unattended, init SelectedLanguageId
624 * If unattended, init USetupData.LanguageId
627 * Number of the next page.
630 SetupStartPage(PINPUT_RECORD Ir
)
633 PGENERIC_LIST_ENTRY ListEntry
;
636 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
638 /* Initialize Setup, phase 1 */
639 Error
= InitializeSetup(&USetupData
, 1);
640 if (Error
!= ERROR_SUCCESS
)
642 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
646 /* Start the PnP thread */
647 if (hPnpThread
!= NULL
)
649 NtResumeThread(hPnpThread
, NULL
);
653 CheckUnattendedSetup(&USetupData
);
655 if (IsUnattendedSetup
)
657 // TODO: Read options from inf
658 /* Load the hardware, language and keyboard layout lists */
660 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
661 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
662 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
664 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
667 SelectedLanguageId
= DefaultLanguage
;
668 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
669 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
671 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
673 /* first we hack LanguageList */
674 for (ListEntry
= GetFirstListEntry(USetupData
.LanguageList
); ListEntry
;
675 ListEntry
= GetNextListEntry(ListEntry
))
677 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
678 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
680 DPRINT("found %S in LanguageList\n", LocaleId
);
681 SetCurrentListEntry(USetupData
.LanguageList
, ListEntry
);
687 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
688 ListEntry
= GetNextListEntry(ListEntry
))
690 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
691 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
693 DPRINT("found %S in LayoutList\n", LocaleId
);
694 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
699 SetConsoleCodePage();
701 return INSTALL_INTRO_PAGE
;
704 return LANGUAGE_PAGE
;
709 * Displays the WelcomePage.
712 * InstallIntroPage (default)
719 * Number of the next page.
722 WelcomePage(PINPUT_RECORD Ir
)
724 MUIDisplayPage(WELCOME_PAGE
);
728 CONSOLE_ConInKey(Ir
);
730 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
731 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
738 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
740 return INSTALL_INTRO_PAGE
;
742 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
744 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
746 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
757 * Displays the License page.
760 * WelcomePage (default)
763 * Number of the next page.
766 LicensePage(PINPUT_RECORD Ir
)
768 MUIDisplayPage(LICENSE_PAGE
);
772 CONSOLE_ConInKey(Ir
);
774 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
785 * Displays the RepairIntroPage.
788 * RebootPage (default)
794 * Number of the next page.
797 RepairIntroPage(PINPUT_RECORD Ir
)
799 MUIDisplayPage(REPAIR_INTRO_PAGE
);
803 CONSOLE_ConInKey(Ir
);
805 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
809 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
811 RepairUpdateFlag
= TRUE
;
812 return INSTALL_INTRO_PAGE
;
814 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
816 return RECOVERY_PAGE
;
818 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
819 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
825 return REPAIR_INTRO_PAGE
;
829 * Displays the UpgradeRepairPage.
832 * RebootPage (default)
838 * Number of the next page.
841 UpgradeRepairPage(PINPUT_RECORD Ir
)
843 GENERIC_LIST_UI ListUi
;
846 if (PartitionList
== NULL
)
848 PartitionList
= CreatePartitionList();
849 if (PartitionList
== NULL
)
851 /* FIXME: show an error dialog */
852 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
855 else if (IsListEmpty(&PartitionList
->DiskListHead
))
857 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
861 TempPartition
= NULL
;
866 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
867 if (!NtOsInstallsList
)
868 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
871 * If there is no available installation (or just a single one??) that can
872 * be updated in the list, just continue with the regular installation.
874 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
876 RepairUpdateFlag
= FALSE
;
878 // return INSTALL_INTRO_PAGE;
879 return DEVICE_SETTINGS_PAGE
;
880 // return SCSI_CONTROLLER_PAGE;
883 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
885 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
886 DrawGenericList(&ListUi
,
891 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
894 CONSOLE_ConInKey(Ir
);
896 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
898 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
900 case VK_DOWN
: /* DOWN */
901 ScrollDownGenericList(&ListUi
);
904 ScrollUpGenericList(&ListUi
);
906 case VK_NEXT
: /* PAGE DOWN */
907 ScrollPageDownGenericList(&ListUi
);
909 case VK_PRIOR
: /* PAGE UP */
910 ScrollPageUpGenericList(&ListUi
);
917 RedrawGenericList(&ListUi
);
920 case VK_ESCAPE
: /* ESC */
922 RestoreGenericListUiState(&ListUi
);
923 // return nextPage; // prevPage;
925 // return INSTALL_INTRO_PAGE;
926 return DEVICE_SETTINGS_PAGE
;
927 // return SCSI_CONTROLLER_PAGE;
933 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
934 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
935 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
937 /* Retrieve the current installation */
938 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
940 CurrentInstallation
=
941 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
943 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
944 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
946 RepairUpdateFlag
= TRUE
;
949 /***/return INSTALL_INTRO_PAGE
;/***/
951 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
952 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
954 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
959 return UPGRADE_REPAIR_PAGE
;
964 * Displays the InstallIntroPage.
967 * DeviceSettingsPage (At once if repair or update is selected)
968 * SelectPartitionPage (At once if unattended setup)
969 * DeviceSettingsPage (default)
973 * Number of the next page.
976 InstallIntroPage(PINPUT_RECORD Ir
)
978 if (RepairUpdateFlag
)
980 #if 1 /* Old code that looks good */
982 // return SELECT_PARTITION_PAGE;
983 return DEVICE_SETTINGS_PAGE
;
985 #else /* Possible new code? */
987 return DEVICE_SETTINGS_PAGE
;
988 // return SCSI_CONTROLLER_PAGE;
993 if (IsUnattendedSetup
)
994 return SELECT_PARTITION_PAGE
;
996 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1000 CONSOLE_ConInKey(Ir
);
1002 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1003 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1005 if (ConfirmQuit(Ir
))
1010 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1012 return UPGRADE_REPAIR_PAGE
;
1016 return INSTALL_INTRO_PAGE
;
1022 ScsiControllerPage(PINPUT_RECORD Ir
)
1024 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1026 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1028 /* FIXME: print loaded mass storage driver descriptions */
1030 CONSOLE_SetTextXY(8, 10, "TEST device");
1033 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1037 CONSOLE_ConInKey(Ir
);
1039 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1040 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1042 if (ConfirmQuit(Ir
))
1047 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1049 return DEVICE_SETTINGS_PAGE
;
1053 return SCSI_CONTROLLER_PAGE
;
1057 OemDriverPage(PINPUT_RECORD Ir
)
1059 // MUIDisplayPage(OEM_DRIVER_PAGE);
1061 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1063 /* FIXME: Implement!! */
1065 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1069 CONSOLE_ConInKey(Ir
);
1071 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1072 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1074 if (ConfirmQuit(Ir
))
1079 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1081 return DEVICE_SETTINGS_PAGE
;
1085 return OEM_DRIVER_PAGE
;
1091 * Displays the DeviceSettingsPage.
1094 * SelectPartitionPage (At once if repair or update is selected)
1095 * ComputerSettingsPage
1096 * DisplaySettingsPage
1097 * KeyboardSettingsPage
1098 * LayoutsettingsPage
1099 * SelectPartitionPage
1103 * Init USetupData.ComputerList
1104 * Init USetupData.DisplayList
1105 * Init USetupData.KeyboardList
1106 * Init USetupData.LayoutList
1109 * Number of the next page.
1112 DeviceSettingsPage(PINPUT_RECORD Ir
)
1114 static ULONG Line
= 16;
1116 /* Initialize the computer settings list */
1117 if (USetupData
.ComputerList
== NULL
)
1119 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
1120 if (USetupData
.ComputerList
== NULL
)
1122 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1127 /* Initialize the display settings list */
1128 if (USetupData
.DisplayList
== NULL
)
1130 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
1131 if (USetupData
.DisplayList
== NULL
)
1133 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1138 /* Initialize the keyboard settings list */
1139 if (USetupData
.KeyboardList
== NULL
)
1141 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
1142 if (USetupData
.KeyboardList
== NULL
)
1144 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1149 /* Initialize the keyboard layout list */
1150 if (USetupData
.LayoutList
== NULL
)
1152 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1153 if (USetupData
.LayoutList
== NULL
)
1155 /* FIXME: report error */
1156 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1161 if (RepairUpdateFlag
)
1162 return SELECT_PARTITION_PAGE
;
1164 // if (IsUnattendedSetup)
1165 // return SELECT_PARTITION_PAGE;
1167 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1169 DrawGenericListCurrentItem(USetupData
.ComputerList
, GetSettingDescription
, 25, 11);
1170 DrawGenericListCurrentItem(USetupData
.DisplayList
, GetSettingDescription
, 25, 12);
1171 DrawGenericListCurrentItem(USetupData
.KeyboardList
, GetSettingDescription
, 25, 13);
1172 DrawGenericListCurrentItem(USetupData
.LayoutList
, GetSettingDescription
, 25, 14);
1174 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1178 CONSOLE_ConInKey(Ir
);
1180 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1181 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1183 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1187 else if (Line
== 16)
1192 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1194 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1195 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1197 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1201 else if (Line
== 16)
1206 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1208 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1209 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1211 if (ConfirmQuit(Ir
))
1216 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1219 return COMPUTER_SETTINGS_PAGE
;
1220 else if (Line
== 12)
1221 return DISPLAY_SETTINGS_PAGE
;
1222 else if (Line
== 13)
1223 return KEYBOARD_SETTINGS_PAGE
;
1224 else if (Line
== 14)
1225 return LAYOUT_SETTINGS_PAGE
;
1226 else if (Line
== 16)
1227 return SELECT_PARTITION_PAGE
;
1231 return DEVICE_SETTINGS_PAGE
;
1236 * Handles generic selection lists.
1239 * GenericList: The list to handle.
1240 * nextPage: The page it needs to jump to after this page.
1241 * Ir: The PINPUT_RECORD
1244 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1245 PAGE_NUMBER nextPage
,
1250 CONSOLE_ConInKey(Ir
);
1252 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1253 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1255 ScrollDownGenericList(ListUi
);
1257 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1258 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1260 ScrollUpGenericList(ListUi
);
1262 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1263 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1265 ScrollPageDownGenericList(ListUi
);
1267 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1268 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1270 ScrollPageUpGenericList(ListUi
);
1272 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1273 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1275 if (ConfirmQuit(Ir
))
1278 RedrawGenericList(ListUi
);
1280 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1281 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1283 RestoreGenericListUiState(ListUi
);
1284 return nextPage
; // Use some "prevPage;" instead?
1286 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1290 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1293 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1300 * Displays the ComputerSettingsPage.
1303 * DeviceSettingsPage
1307 * Number of the next page.
1310 ComputerSettingsPage(PINPUT_RECORD Ir
)
1312 GENERIC_LIST_UI ListUi
;
1313 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1315 InitGenericListUi(&ListUi
, USetupData
.ComputerList
, GetSettingDescription
);
1316 DrawGenericList(&ListUi
,
1321 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1326 * Displays the DisplaySettingsPage.
1329 * DeviceSettingsPage
1333 * Number of the next page.
1336 DisplaySettingsPage(PINPUT_RECORD Ir
)
1338 GENERIC_LIST_UI ListUi
;
1339 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1341 InitGenericListUi(&ListUi
, USetupData
.DisplayList
, GetSettingDescription
);
1342 DrawGenericList(&ListUi
,
1347 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1352 * Displays the KeyboardSettingsPage.
1355 * DeviceSettingsPage
1359 * Number of the next page.
1362 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1364 GENERIC_LIST_UI ListUi
;
1365 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1367 InitGenericListUi(&ListUi
, USetupData
.KeyboardList
, GetSettingDescription
);
1368 DrawGenericList(&ListUi
,
1373 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1378 * Displays the LayoutSettingsPage.
1381 * DeviceSettingsPage
1385 * Number of the next page.
1388 LayoutSettingsPage(PINPUT_RECORD Ir
)
1390 GENERIC_LIST_UI ListUi
;
1391 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1393 InitGenericListUi(&ListUi
, USetupData
.LayoutList
, GetSettingDescription
);
1394 DrawGenericList(&ListUi
,
1399 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1404 IsDiskSizeValid(PPARTENTRY PartEntry
)
1408 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1409 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1411 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1413 /* Partition is too small so ask for another one */
1414 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1425 * Displays the SelectPartitionPage.
1428 * SelectFileSystemPage (At once if unattended)
1429 * SelectFileSystemPage (Default if free space is selected)
1430 * CreatePrimaryPartitionPage
1431 * CreateExtendedPartitionPage
1432 * CreateLogicalPartitionPage
1433 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1434 * DeletePartitionPage
1438 * Set InstallShortcut (only if not unattended + free space is selected)
1441 * Number of the next page.
1444 SelectPartitionPage(PINPUT_RECORD Ir
)
1449 if (PartitionList
== NULL
)
1451 PartitionList
= CreatePartitionList();
1452 if (PartitionList
== NULL
)
1454 /* FIXME: show an error dialog */
1455 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1458 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1460 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1464 TempPartition
= NULL
;
1465 FormatState
= Start
;
1468 if (RepairUpdateFlag
)
1470 /* Determine the selected installation disk & partition */
1471 if (!SelectPartition(PartitionList
,
1472 CurrentInstallation
->DiskNumber
,
1473 CurrentInstallation
->PartitionNumber
))
1475 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1479 return SELECT_FILE_SYSTEM_PAGE
;
1482 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1484 InitPartitionListUi(&ListUi
, PartitionList
,
1489 DrawPartitionList(&ListUi
);
1491 if (IsUnattendedSetup
)
1493 if (!SelectPartition(PartitionList
,
1494 USetupData
.DestinationDiskNumber
,
1495 USetupData
.DestinationPartitionNumber
))
1497 if (USetupData
.AutoPartition
)
1499 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1501 CreateLogicalPartition(PartitionList
,
1502 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1507 CreatePrimaryPartition(PartitionList
,
1508 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1512 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1513 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1515 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1516 USetupData
.RequiredPartitionDiskSpace
);
1517 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1520 return SELECT_FILE_SYSTEM_PAGE
;
1525 DrawPartitionList(&ListUi
);
1527 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1528 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1530 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1531 USetupData
.RequiredPartitionDiskSpace
);
1532 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1535 return SELECT_FILE_SYSTEM_PAGE
;
1541 /* Update status text */
1542 if (PartitionList
->CurrentPartition
== NULL
)
1544 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1546 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1548 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1550 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1554 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1559 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1561 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1563 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1567 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1572 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1576 CONSOLE_ConInKey(Ir
);
1578 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1579 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1581 if (ConfirmQuit(Ir
))
1583 DestroyPartitionList(PartitionList
);
1584 PartitionList
= NULL
;
1590 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1591 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1593 ScrollDownPartitionList(&ListUi
);
1595 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1596 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1598 ScrollUpPartitionList(&ListUi
);
1600 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1602 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1603 continue; // return SELECT_PARTITION_PAGE;
1605 if (PartitionList
->CurrentPartition
== NULL
||
1606 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1608 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1610 CreateLogicalPartition(PartitionList
,
1616 CreatePrimaryPartition(PartitionList
,
1622 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1624 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1625 USetupData
.RequiredPartitionDiskSpace
);
1626 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1629 return SELECT_FILE_SYSTEM_PAGE
;
1631 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1633 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1635 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1636 if (Error
!= NOT_AN_ERROR
)
1638 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1639 return SELECT_PARTITION_PAGE
;
1642 return CREATE_PRIMARY_PARTITION_PAGE
;
1645 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1647 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1649 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1650 if (Error
!= NOT_AN_ERROR
)
1652 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1653 return SELECT_PARTITION_PAGE
;
1656 return CREATE_EXTENDED_PARTITION_PAGE
;
1659 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1661 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1663 Error
= LogicalPartitionCreationChecks(PartitionList
);
1664 if (Error
!= NOT_AN_ERROR
)
1666 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1667 return SELECT_PARTITION_PAGE
;
1670 return CREATE_LOGICAL_PARTITION_PAGE
;
1673 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1675 WCHAR PathBuffer
[MAX_PATH
];
1676 UNICODE_STRING CurrentPartition
;
1678 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1680 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1681 return SELECT_PARTITION_PAGE
;
1684 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1685 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1686 PartitionList
->CurrentDisk
->DiskNumber
,
1687 PartitionList
->CurrentPartition
->PartitionNumber
);
1688 RtlInitUnicodeString(&CurrentPartition
, PathBuffer
);
1691 * Check whether the user attempts to delete the partition on which
1692 * the installation source is present. If so, fail with an error.
1694 // &USetupData.SourceRootPath
1695 if (RtlPrefixUnicodeString(&CurrentPartition
, &USetupData
.SourcePath
, TRUE
))
1697 PopupError("You cannot delete the partition containing the installation source!",
1698 MUIGetString(STRING_CONTINUE
),
1699 Ir
, POPUP_WAIT_ENTER
);
1700 return SELECT_PARTITION_PAGE
;
1703 if (PartitionList
->CurrentPartition
->BootIndicator
||
1704 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1706 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1709 return DELETE_PARTITION_PAGE
;
1713 return SELECT_PARTITION_PAGE
;
1717 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1718 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1719 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1722 ShowPartitionSizeInputBox(SHORT Left
,
1746 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1751 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1752 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1755 WriteConsoleOutputCharacterA(StdOutput
,
1761 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1762 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1764 WriteConsoleOutputCharacterA(StdOutput
,
1770 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1771 Length
= wcslen(InputBuffer
);
1773 CONSOLE_SetInputTextXY(iLeft
,
1775 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1777 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1778 CONSOLE_SetCursorType(TRUE
, TRUE
);
1782 CONSOLE_ConInKey(&Ir
);
1784 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1785 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1790 InputBuffer
[0] = UNICODE_NULL
;
1791 CONSOLE_SetCursorType(TRUE
, FALSE
);
1794 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1796 CONSOLE_SetCursorType(TRUE
, FALSE
);
1799 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1804 InputBuffer
[0] = UNICODE_NULL
;
1805 CONSOLE_SetCursorType(TRUE
, FALSE
);
1808 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1809 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1812 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1814 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1815 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1818 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1820 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1821 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1826 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1829 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1830 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1835 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1838 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1839 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1843 memmove(&InputBuffer
[Pos
],
1844 &InputBuffer
[Pos
+ 1],
1845 (Length
- Pos
- 1) * sizeof(WCHAR
));
1846 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1849 CONSOLE_SetInputTextXY(iLeft
,
1851 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1853 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1856 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1861 memmove(&InputBuffer
[Pos
- 1],
1863 (Length
- Pos
) * sizeof(WCHAR
));
1864 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1868 CONSOLE_SetInputTextXY(iLeft
,
1870 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1872 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1875 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1877 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1879 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1881 if ((ch
>= L
'0') && (ch
<= L
'9'))
1884 memmove(&InputBuffer
[Pos
+ 1],
1886 (Length
- Pos
) * sizeof(WCHAR
));
1887 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1888 InputBuffer
[Pos
] = ch
;
1892 CONSOLE_SetInputTextXY(iLeft
,
1894 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1896 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1905 * Displays the CreatePrimaryPartitionPage.
1908 * SelectPartitionPage
1909 * SelectFileSystemPage (default)
1913 * Number of the next page.
1916 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1918 PDISKENTRY DiskEntry
;
1919 PPARTENTRY PartEntry
;
1922 WCHAR InputBuffer
[50];
1926 ULONGLONG SectorCount
;
1929 if (PartitionList
== NULL
||
1930 PartitionList
->CurrentDisk
== NULL
||
1931 PartitionList
->CurrentPartition
== NULL
)
1933 /* FIXME: show an error dialog */
1937 DiskEntry
= PartitionList
->CurrentDisk
;
1938 PartEntry
= PartitionList
->CurrentPartition
;
1940 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1942 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1944 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1946 if (DiskSize
>= 10 * GB
) /* 10 GB */
1948 DiskSize
= DiskSize
/ GB
;
1949 Unit
= MUIGetString(STRING_GB
);
1954 DiskSize
= DiskSize
/ MB
;
1958 Unit
= MUIGetString(STRING_MB
);
1961 if (DiskEntry
->DriverName
.Length
> 0)
1963 CONSOLE_PrintTextXY(6, 10,
1964 MUIGetString(STRING_HDINFOPARTCREATE_1
),
1967 DiskEntry
->DiskNumber
,
1971 &DiskEntry
->DriverName
,
1972 DiskEntry
->NoMbr
? "GPT" : "MBR");
1976 CONSOLE_PrintTextXY(6, 10,
1977 MUIGetString(STRING_HDINFOPARTCREATE_2
),
1980 DiskEntry
->DiskNumber
,
1984 DiskEntry
->NoMbr
? "GPT" : "MBR");
1987 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
1990 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1991 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
1994 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
1996 PartEntry
= PartitionList
->CurrentPartition
;
1999 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2001 if (MaxSize
> PARTITION_MAXSIZE
)
2002 MaxSize
= PARTITION_MAXSIZE
;
2004 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2005 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2009 if (ConfirmQuit(Ir
))
2016 return SELECT_PARTITION_PAGE
;
2020 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2028 if (PartSize
> MaxSize
)
2034 /* Convert to bytes */
2035 if (PartSize
== MaxSize
)
2037 /* Use all of the unpartitioned disk space */
2038 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2042 /* Calculate the sector count from the size in MB */
2043 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2045 /* But never get larger than the unpartitioned disk space */
2046 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2047 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2050 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2052 CreatePrimaryPartition(PartitionList
,
2056 return SELECT_PARTITION_PAGE
;
2060 return CREATE_PRIMARY_PARTITION_PAGE
;
2065 * Displays the CreateExtendedPartitionPage.
2068 * SelectPartitionPage (default)
2072 * Number of the next page.
2075 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2077 PDISKENTRY DiskEntry
;
2078 PPARTENTRY PartEntry
;
2081 WCHAR InputBuffer
[50];
2085 ULONGLONG SectorCount
;
2088 if (PartitionList
== NULL
||
2089 PartitionList
->CurrentDisk
== NULL
||
2090 PartitionList
->CurrentPartition
== NULL
)
2092 /* FIXME: show an error dialog */
2096 DiskEntry
= PartitionList
->CurrentDisk
;
2097 PartEntry
= PartitionList
->CurrentPartition
;
2099 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2101 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2103 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2105 if (DiskSize
>= 10 * GB
) /* 10 GB */
2107 DiskSize
= DiskSize
/ GB
;
2108 Unit
= MUIGetString(STRING_GB
);
2113 DiskSize
= DiskSize
/ MB
;
2117 Unit
= MUIGetString(STRING_MB
);
2120 if (DiskEntry
->DriverName
.Length
> 0)
2122 CONSOLE_PrintTextXY(6, 10,
2123 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2126 DiskEntry
->DiskNumber
,
2130 &DiskEntry
->DriverName
,
2131 DiskEntry
->NoMbr
? "GPT" : "MBR");
2135 CONSOLE_PrintTextXY(6, 10,
2136 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2139 DiskEntry
->DiskNumber
,
2143 DiskEntry
->NoMbr
? "GPT" : "MBR");
2146 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2149 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2150 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2153 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2155 PartEntry
= PartitionList
->CurrentPartition
;
2158 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2160 if (MaxSize
> PARTITION_MAXSIZE
)
2161 MaxSize
= PARTITION_MAXSIZE
;
2163 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2164 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2168 if (ConfirmQuit(Ir
))
2175 return SELECT_PARTITION_PAGE
;
2179 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2187 if (PartSize
> MaxSize
)
2193 /* Convert to bytes */
2194 if (PartSize
== MaxSize
)
2196 /* Use all of the unpartitioned disk space */
2197 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2201 /* Calculate the sector count from the size in MB */
2202 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2204 /* But never get larger than the unpartitioned disk space */
2205 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2206 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2209 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2211 CreateExtendedPartition(PartitionList
,
2214 return SELECT_PARTITION_PAGE
;
2218 return CREATE_EXTENDED_PARTITION_PAGE
;
2223 * Displays the CreateLogicalPartitionPage.
2226 * SelectFileSystemPage (default)
2230 * Number of the next page.
2233 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2235 PDISKENTRY DiskEntry
;
2236 PPARTENTRY PartEntry
;
2239 WCHAR InputBuffer
[50];
2243 ULONGLONG SectorCount
;
2246 if (PartitionList
== NULL
||
2247 PartitionList
->CurrentDisk
== NULL
||
2248 PartitionList
->CurrentPartition
== NULL
)
2250 /* FIXME: show an error dialog */
2254 DiskEntry
= PartitionList
->CurrentDisk
;
2255 PartEntry
= PartitionList
->CurrentPartition
;
2257 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2259 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2261 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2263 if (DiskSize
>= 10 * GB
) /* 10 GB */
2265 DiskSize
= DiskSize
/ GB
;
2266 Unit
= MUIGetString(STRING_GB
);
2271 DiskSize
= DiskSize
/ MB
;
2275 Unit
= MUIGetString(STRING_MB
);
2278 if (DiskEntry
->DriverName
.Length
> 0)
2280 CONSOLE_PrintTextXY(6, 10,
2281 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2284 DiskEntry
->DiskNumber
,
2288 &DiskEntry
->DriverName
,
2289 DiskEntry
->NoMbr
? "GPT" : "MBR");
2293 CONSOLE_PrintTextXY(6, 10,
2294 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2297 DiskEntry
->DiskNumber
,
2301 DiskEntry
->NoMbr
? "GPT" : "MBR");
2304 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2307 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2308 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2311 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2313 PartEntry
= PartitionList
->CurrentPartition
;
2316 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2318 if (MaxSize
> PARTITION_MAXSIZE
)
2319 MaxSize
= PARTITION_MAXSIZE
;
2321 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2322 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2326 if (ConfirmQuit(Ir
))
2333 return SELECT_PARTITION_PAGE
;
2337 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2345 if (PartSize
> MaxSize
)
2351 /* Convert to bytes */
2352 if (PartSize
== MaxSize
)
2354 /* Use all of the unpartitioned disk space */
2355 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2359 /* Calculate the sector count from the size in MB */
2360 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2362 /* But never get larger than the unpartitioned disk space */
2363 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2364 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2367 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2369 CreateLogicalPartition(PartitionList
,
2373 return SELECT_PARTITION_PAGE
;
2377 return CREATE_LOGICAL_PARTITION_PAGE
;
2382 * Displays the ConfirmDeleteSystemPartitionPage.
2385 * DeletePartitionPage (default)
2386 * SelectPartitionPage
2389 * Number of the next page.
2392 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2394 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2398 CONSOLE_ConInKey(Ir
);
2400 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2401 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2403 if (ConfirmQuit(Ir
))
2408 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2410 return DELETE_PARTITION_PAGE
;
2412 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2414 return SELECT_PARTITION_PAGE
;
2418 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2423 * Displays the DeletePartitionPage.
2426 * SelectPartitionPage (default)
2430 * Number of the next page.
2433 DeletePartitionPage(PINPUT_RECORD Ir
)
2435 PDISKENTRY DiskEntry
;
2436 PPARTENTRY PartEntry
;
2440 CHAR PartTypeString
[32];
2442 if (PartitionList
== NULL
||
2443 PartitionList
->CurrentDisk
== NULL
||
2444 PartitionList
->CurrentPartition
== NULL
)
2446 /* FIXME: show an error dialog */
2450 DiskEntry
= PartitionList
->CurrentDisk
;
2451 PartEntry
= PartitionList
->CurrentPartition
;
2453 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2455 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2457 ARRAYSIZE(PartTypeString
));
2459 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2461 if (PartSize
>= 10 * GB
) /* 10 GB */
2463 PartSize
= PartSize
/ GB
;
2464 Unit
= MUIGetString(STRING_GB
);
2468 if (PartSize
>= 10 * MB
) /* 10 MB */
2470 PartSize
= PartSize
/ MB
;
2471 Unit
= MUIGetString(STRING_MB
);
2475 PartSize
= PartSize
/ KB
;
2476 Unit
= MUIGetString(STRING_KB
);
2479 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2481 CONSOLE_PrintTextXY(6, 10,
2482 MUIGetString(STRING_HDDINFOUNK2
),
2483 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2484 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2485 PartEntry
->PartitionType
,
2491 CONSOLE_PrintTextXY(6, 10,
2492 " %c%c %s %I64u %s",
2493 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2494 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2500 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2502 if (DiskSize
>= 10 * GB
) /* 10 GB */
2504 DiskSize
= DiskSize
/ GB
;
2505 Unit
= MUIGetString(STRING_GB
);
2510 DiskSize
= DiskSize
/ MB
;
2514 Unit
= MUIGetString(STRING_MB
);
2517 if (DiskEntry
->DriverName
.Length
> 0)
2519 CONSOLE_PrintTextXY(6, 12,
2520 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2523 DiskEntry
->DiskNumber
,
2527 &DiskEntry
->DriverName
,
2528 DiskEntry
->NoMbr
? "GPT" : "MBR");
2532 CONSOLE_PrintTextXY(6, 12,
2533 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2536 DiskEntry
->DiskNumber
,
2540 DiskEntry
->NoMbr
? "GPT" : "MBR");
2545 CONSOLE_ConInKey(Ir
);
2547 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2548 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2550 if (ConfirmQuit(Ir
))
2555 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2557 return SELECT_PARTITION_PAGE
;
2559 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2561 DeleteCurrentPartition(PartitionList
);
2563 return SELECT_PARTITION_PAGE
;
2567 return DELETE_PARTITION_PAGE
;
2572 * Displays the SelectFileSystemPage.
2575 * CheckFileSystemPage (At once if RepairUpdate is selected)
2576 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2577 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2578 * SelectPartitionPage (If the user aborts)
2579 * FormatPartitionPage (Default)
2583 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2584 * Calls CheckActiveSystemPartition()
2587 * Number of the next page.
2590 SelectFileSystemPage(PINPUT_RECORD Ir
)
2592 PDISKENTRY DiskEntry
;
2593 PPARTENTRY PartEntry
;
2598 CHAR PartTypeString
[32];
2599 FORMATMACHINESTATE PreviousFormatState
;
2601 DPRINT("SelectFileSystemPage()\n");
2603 if (PartitionList
== NULL
||
2604 PartitionList
->CurrentDisk
== NULL
||
2605 PartitionList
->CurrentPartition
== NULL
)
2607 /* FIXME: show an error dialog */
2611 /* Find or set the active system partition */
2612 CheckActiveSystemPartition(PartitionList
);
2613 if (PartitionList
->SystemPartition
== NULL
)
2615 /* FIXME: show an error dialog */
2617 // Error dialog should say that we cannot find a suitable
2618 // system partition and create one on the system. At this point,
2619 // it may be nice to ask the user whether he wants to continue,
2620 // or use an external drive as the system drive/partition
2621 // (e.g. floppy, USB drive, etc...)
2626 PreviousFormatState
= FormatState
;
2627 switch (FormatState
)
2631 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2633 TempPartition
= PartitionList
->SystemPartition
;
2634 TempPartition
->NeedsCheck
= TRUE
;
2636 FormatState
= FormatSystemPartition
;
2637 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2641 TempPartition
= PartitionList
->CurrentPartition
;
2642 TempPartition
->NeedsCheck
= TRUE
;
2644 FormatState
= FormatInstallPartition
;
2645 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2650 case FormatSystemPartition
:
2652 TempPartition
= PartitionList
->CurrentPartition
;
2653 TempPartition
->NeedsCheck
= TRUE
;
2655 FormatState
= FormatInstallPartition
;
2656 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2660 case FormatInstallPartition
:
2662 if (GetNextUnformattedPartition(PartitionList
,
2666 FormatState
= FormatOtherPartition
;
2667 TempPartition
->NeedsCheck
= TRUE
;
2668 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2672 FormatState
= FormatDone
;
2673 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2674 return CHECK_FILE_SYSTEM_PAGE
;
2679 case FormatOtherPartition
:
2681 if (GetNextUnformattedPartition(PartitionList
,
2685 FormatState
= FormatOtherPartition
;
2686 TempPartition
->NeedsCheck
= TRUE
;
2687 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2691 FormatState
= FormatDone
;
2692 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2693 return CHECK_FILE_SYSTEM_PAGE
;
2700 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2701 /* FIXME: show an error dialog */
2706 PartEntry
= TempPartition
;
2707 DiskEntry
= PartEntry
->DiskEntry
;
2709 /* Adjust disk size */
2710 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2711 if (DiskSize
>= 10 * GB
) /* 10 GB */
2713 DiskSize
= DiskSize
/ GB
;
2714 DiskUnit
= MUIGetString(STRING_GB
);
2718 DiskSize
= DiskSize
/ MB
;
2719 DiskUnit
= MUIGetString(STRING_MB
);
2722 /* Adjust partition size */
2723 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2724 if (PartSize
>= 10 * GB
) /* 10 GB */
2726 PartSize
= PartSize
/ GB
;
2727 PartUnit
= MUIGetString(STRING_GB
);
2731 PartSize
= PartSize
/ MB
;
2732 PartUnit
= MUIGetString(STRING_MB
);
2735 /* Adjust partition type */
2736 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2738 ARRAYSIZE(PartTypeString
));
2740 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2742 if (PartEntry
->AutoCreate
)
2744 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2747 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2748 PartEntry
->PartitionNumber
,
2754 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2755 DiskEntry
->DiskNumber
,
2761 &DiskEntry
->DriverName
,
2762 DiskEntry
->NoMbr
? "GPT" : "MBR");
2764 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2766 PartEntry
->AutoCreate
= FALSE
;
2768 else if (PartEntry
->New
)
2770 switch (FormatState
)
2772 case FormatSystemPartition
:
2773 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2776 case FormatInstallPartition
:
2777 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2780 case FormatOtherPartition
:
2781 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2788 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2792 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2794 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2796 CONSOLE_PrintTextXY(8, 10,
2797 MUIGetString(STRING_HDDINFOUNK4
),
2798 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2799 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2800 PartEntry
->PartitionType
,
2806 CONSOLE_PrintTextXY(8, 10,
2808 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2809 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2815 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2816 DiskEntry
->DiskNumber
,
2822 &DiskEntry
->DriverName
,
2823 DiskEntry
->NoMbr
? "GPT" : "MBR");
2826 if (FileSystemList
== NULL
)
2828 /* Create the file system list, and by default select the "FAT" file system */
2829 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2830 if (FileSystemList
== NULL
)
2832 /* FIXME: show an error dialog */
2837 if (RepairUpdateFlag
)
2839 return CHECK_FILE_SYSTEM_PAGE
;
2840 //return SELECT_PARTITION_PAGE;
2843 if (IsUnattendedSetup
)
2845 if (USetupData
.FormatPartition
)
2848 * We use whatever currently selected file system we have
2849 * (by default, this is "FAT", as per the initialization
2850 * performed above). Note that it may be interesting to specify
2851 * which file system to use in unattended installations, in the
2852 * txtsetup.sif file.
2854 return FORMAT_PARTITION_PAGE
;
2857 return CHECK_FILE_SYSTEM_PAGE
;
2860 DrawFileSystemList(FileSystemList
);
2864 CONSOLE_ConInKey(Ir
);
2866 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2867 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2869 if (ConfirmQuit(Ir
))
2874 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2875 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2877 FormatState
= Start
;
2878 return SELECT_PARTITION_PAGE
;
2880 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2881 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2883 ScrollDownFileSystemList(FileSystemList
);
2885 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2886 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2888 ScrollUpFileSystemList(FileSystemList
);
2890 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2892 if (!FileSystemList
->Selected
->FileSystem
)
2893 return SELECT_FILE_SYSTEM_PAGE
;
2895 return FORMAT_PARTITION_PAGE
;
2899 FormatState
= PreviousFormatState
;
2901 return SELECT_FILE_SYSTEM_PAGE
;
2906 * Displays the FormatPartitionPage.
2909 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2910 * SelectPartitionPage (At once)
2914 * Sets PartitionList->CurrentPartition->FormatState
2915 * Sets USetupData.DestinationRootPath
2918 * Number of the next page.
2921 FormatPartitionPage(PINPUT_RECORD Ir
)
2924 PDISKENTRY DiskEntry
;
2925 PPARTENTRY PartEntry
;
2926 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2927 UNICODE_STRING PartitionRootPath
;
2928 WCHAR PathBuffer
[MAX_PATH
];
2929 CHAR Buffer
[MAX_PATH
];
2934 PPARTITION_INFORMATION PartitionInfo
;
2937 DPRINT("FormatPartitionPage()\n");
2939 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2941 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2943 /* FIXME: show an error dialog */
2947 PartEntry
= TempPartition
;
2948 DiskEntry
= PartEntry
->DiskEntry
;
2950 SelectedFileSystem
= FileSystemList
->Selected
;
2954 if (!IsUnattendedSetup
)
2956 CONSOLE_ConInKey(Ir
);
2959 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2960 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2962 if (ConfirmQuit(Ir
))
2967 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
2969 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2971 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
2973 /* FIXME: show an error dialog */
2978 CONSOLE_PrintTextXY(6, 12,
2979 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2980 DiskEntry
->Cylinders
,
2981 DiskEntry
->TracksPerCylinder
,
2982 DiskEntry
->SectorsPerTrack
,
2983 DiskEntry
->BytesPerSector
,
2984 DiskEntry
->Dirty
? '*' : ' ');
2988 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
2990 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
2992 CONSOLE_PrintTextXY(6, Line
,
2993 "%2u: %2lu %c %12I64u %12I64u %02x",
2995 PartitionInfo
->PartitionNumber
,
2996 PartitionInfo
->BootIndicator
? 'A' : '-',
2997 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
2998 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
2999 PartitionInfo
->PartitionType
);
3004 /* Commit the partition changes to the disk */
3005 if (!WritePartitionsToDisk(PartitionList
))
3007 DPRINT("WritePartitionsToDisk() failed\n");
3008 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3012 /* Set PartitionRootPath */
3013 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3014 L
"\\Device\\Harddisk%lu\\Partition%lu",
3015 DiskEntry
->DiskNumber
,
3016 PartEntry
->PartitionNumber
);
3017 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3018 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3020 /* Format the partition */
3021 if (SelectedFileSystem
->FileSystem
)
3023 Status
= FormatPartition(&PartitionRootPath
,
3024 SelectedFileSystem
);
3025 if (Status
== STATUS_NOT_SUPPORTED
)
3028 "Setup is currently unable to format a partition in %S.\n"
3030 " \x07 Press ENTER to continue Setup.\n"
3031 " \x07 Press F3 to quit Setup.",
3032 SelectedFileSystem
->FileSystem
->FileSystemName
);
3035 MUIGetString(STRING_QUITCONTINUE
),
3036 NULL
, POPUP_WAIT_NONE
);
3040 CONSOLE_ConInKey(Ir
);
3042 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3043 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3045 if (ConfirmQuit(Ir
))
3048 return SELECT_FILE_SYSTEM_PAGE
;
3050 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3052 return SELECT_FILE_SYSTEM_PAGE
;
3056 else if (!NT_SUCCESS(Status
))
3058 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3059 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3063 PartEntry
->FormatState
= Formatted
;
3064 // PartEntry->FileSystem = FileSystem;
3065 PartEntry
->New
= FALSE
;
3069 CONSOLE_SetStatusText(" Done. Press any key ...");
3070 CONSOLE_ConInKey(Ir
);
3073 return SELECT_FILE_SYSTEM_PAGE
;
3077 return FORMAT_PARTITION_PAGE
;
3082 * Displays the CheckFileSystemPage.
3085 * InstallDirectoryPage (At once)
3089 * Inits or reloads FileSystemList
3092 * Number of the next page.
3095 CheckFileSystemPage(PINPUT_RECORD Ir
)
3098 PDISKENTRY DiskEntry
;
3099 PPARTENTRY PartEntry
;
3100 PFILE_SYSTEM CurrentFileSystem
;
3101 UNICODE_STRING PartitionRootPath
;
3102 WCHAR PathBuffer
[MAX_PATH
];
3103 CHAR Buffer
[MAX_PATH
];
3105 if (PartitionList
== NULL
)
3107 /* FIXME: show an error dialog */
3111 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3113 return INSTALL_DIRECTORY_PAGE
;
3116 /* Set PartitionRootPath */
3117 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3118 L
"\\Device\\Harddisk%lu\\Partition%lu",
3119 DiskEntry
->DiskNumber
,
3120 PartEntry
->PartitionNumber
);
3121 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3122 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3124 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3126 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3128 CurrentFileSystem
= PartEntry
->FileSystem
;
3129 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3130 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3132 /* HACK: Do not try to check a partition with an unknown filesystem */
3133 if (CurrentFileSystem
== NULL
)
3135 PartEntry
->NeedsCheck
= FALSE
;
3136 return CHECK_FILE_SYSTEM_PAGE
;
3139 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3140 if (Status
== STATUS_NOT_SUPPORTED
)
3143 "Setup is currently unable to check a partition formatted in %S.\n"
3145 " \x07 Press ENTER to continue Setup.\n"
3146 " \x07 Press F3 to quit Setup.",
3147 CurrentFileSystem
->FileSystemName
);
3150 MUIGetString(STRING_QUITCONTINUE
),
3151 NULL
, POPUP_WAIT_NONE
);
3155 CONSOLE_ConInKey(Ir
);
3157 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3158 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3160 if (ConfirmQuit(Ir
))
3163 return CHECK_FILE_SYSTEM_PAGE
;
3165 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3167 PartEntry
->NeedsCheck
= FALSE
;
3168 return CHECK_FILE_SYSTEM_PAGE
;
3172 else if (!NT_SUCCESS(Status
))
3174 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3175 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3176 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3177 "(Status 0x%08lx).\n", Status
);
3179 // MUIGetString(STRING_REBOOTCOMPUTER),
3180 MUIGetString(STRING_CONTINUE
),
3181 Ir
, POPUP_WAIT_ENTER
);
3183 // return QUIT_PAGE;
3186 PartEntry
->NeedsCheck
= FALSE
;
3187 return CHECK_FILE_SYSTEM_PAGE
;
3192 BuildInstallPaths(PWSTR InstallDir
,
3193 PDISKENTRY DiskEntry
,
3194 PPARTENTRY PartEntry
)
3198 Status
= InitDestinationPaths(&USetupData
, InstallDir
, DiskEntry
, PartEntry
);
3199 // TODO: Check Status
3200 UNREFERENCED_PARAMETER(Status
);
3202 /* Initialize DestinationDriveLetter */
3203 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3209 IN PCWSTR InstallDir
)
3213 Length
= wcslen(InstallDir
);
3215 // TODO: Add check for 8.3 too.
3217 /* Path must be at least 2 characters long */
3221 /* Path must start with a backslash */
3222 // if (InstallDir[0] != L'\\')
3225 /* Path must not end with a backslash */
3226 if (InstallDir
[Length
- 1] == L
'\\')
3229 /* Path must not contain whitespace characters */
3230 for (i
= 0; i
< Length
; i
++)
3232 if (iswspace(InstallDir
[i
]))
3236 /* Path component must not end with a dot */
3237 for (i
= 0; i
< Length
; i
++)
3239 if (InstallDir
[i
] == L
'\\' && i
> 0)
3241 if (InstallDir
[i
- 1] == L
'.')
3246 if (InstallDir
[Length
- 1] == L
'.')
3254 * Displays the InstallDirectoryPage.
3261 * Number of the next page.
3264 InstallDirectoryPage(PINPUT_RECORD Ir
)
3266 PDISKENTRY DiskEntry
;
3267 PPARTENTRY PartEntry
;
3268 WCHAR InstallDir
[MAX_PATH
];
3272 /* We do not need the filesystem list anymore */
3273 if (FileSystemList
!= NULL
)
3275 DestroyFileSystemList(FileSystemList
);
3276 FileSystemList
= NULL
;
3279 if (PartitionList
== NULL
||
3280 PartitionList
->CurrentDisk
== NULL
||
3281 PartitionList
->CurrentPartition
== NULL
)
3283 /* FIXME: show an error dialog */
3287 DiskEntry
= PartitionList
->CurrentDisk
;
3288 PartEntry
= PartitionList
->CurrentPartition
;
3290 // if (IsUnattendedSetup)
3291 if (RepairUpdateFlag
)
3292 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3293 else if (USetupData
.InstallationDirectory
[0])
3294 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3296 wcscpy(InstallDir
, L
"\\ReactOS");
3299 * Check the validity of the predefined 'InstallDir'. If we are either
3300 * in unattended setup or in update/repair mode, and the installation path
3301 * is valid, just perform the installation. Otherwise (either in the case
3302 * of an invalid path, or we are in regular setup), display the UI and allow
3303 * the user to specify a new installation path.
3305 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3307 BuildInstallPaths(InstallDir
,
3312 * Check whether the user attempts to install ReactOS within the
3313 * installation source directory, or in a subdirectory thereof.
3314 * If so, fail with an error.
3316 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3318 PopupError("You cannot install ReactOS within the installation source directory!",
3319 MUIGetString(STRING_CONTINUE
),
3320 Ir
, POPUP_WAIT_ENTER
);
3321 return INSTALL_DIRECTORY_PAGE
;
3324 return PREPARE_COPY_PAGE
;
3327 Length
= wcslen(InstallDir
);
3330 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3331 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3332 CONSOLE_SetCursorXY(8 + Pos
, 11);
3333 CONSOLE_SetCursorType(TRUE
, TRUE
);
3337 CONSOLE_ConInKey(Ir
);
3339 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3340 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3342 CONSOLE_SetCursorType(TRUE
, FALSE
);
3344 if (ConfirmQuit(Ir
))
3347 CONSOLE_SetCursorType(TRUE
, TRUE
);
3350 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3351 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3355 memmove(&InstallDir
[Pos
],
3356 &InstallDir
[Pos
+ 1],
3357 (Length
- Pos
- 1) * sizeof(WCHAR
));
3358 InstallDir
[Length
- 1] = UNICODE_NULL
;
3361 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3362 CONSOLE_SetCursorXY(8 + Pos
, 11);
3365 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3366 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3369 CONSOLE_SetCursorXY(8 + Pos
, 11);
3371 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3372 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3375 CONSOLE_SetCursorXY(8 + Pos
, 11);
3377 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3378 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3383 CONSOLE_SetCursorXY(8 + Pos
, 11);
3386 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3387 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3392 CONSOLE_SetCursorXY(8 + Pos
, 11);
3395 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3397 CONSOLE_SetCursorType(TRUE
, FALSE
);
3400 * Check for the validity of the installation directory and pop up
3401 * an error if it is not the case. Then the user can fix its input.
3403 if (!IsValidPath(InstallDir
))
3405 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3406 return INSTALL_DIRECTORY_PAGE
;
3409 BuildInstallPaths(InstallDir
,
3414 * Check whether the user attempts to install ReactOS within the
3415 * installation source directory, or in a subdirectory thereof.
3416 * If so, fail with an error.
3418 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3420 PopupError("You cannot install ReactOS within the installation source directory!",
3421 MUIGetString(STRING_CONTINUE
),
3422 Ir
, POPUP_WAIT_ENTER
);
3423 return INSTALL_DIRECTORY_PAGE
;
3426 return PREPARE_COPY_PAGE
;
3428 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3433 memmove(&InstallDir
[Pos
- 1],
3435 (Length
- Pos
) * sizeof(WCHAR
));
3436 InstallDir
[Length
- 1] = UNICODE_NULL
;
3440 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3441 CONSOLE_SetCursorXY(8 + Pos
, 11);
3444 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3448 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3449 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3452 memmove(&InstallDir
[Pos
+ 1],
3454 (Length
- Pos
) * sizeof(WCHAR
));
3455 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3456 InstallDir
[Pos
] = c
;
3460 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3461 CONSOLE_SetCursorXY(8 + Pos
, 11);
3467 return INSTALL_DIRECTORY_PAGE
;
3472 AddSectionToCopyQueueCab(HINF InfFile
,
3474 PWCHAR SourceCabinet
,
3475 PCUNICODE_STRING DestinationPath
,
3478 INFCONTEXT FilesContext
;
3479 INFCONTEXT DirContext
;
3481 PWCHAR FileKeyValue
;
3483 PWCHAR TargetFileName
;
3486 * This code enumerates the list of files in reactos.dff / reactos.inf
3487 * that need to be extracted from reactos.cab and be installed in their
3488 * respective directories.
3491 /* Search for the SectionName section */
3492 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3494 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3499 * Enumerate the files in the section and add them to the file queue.
3503 /* Get source file name and target directory id */
3504 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3506 /* FIXME: Handle error! */
3507 DPRINT1("INF_GetData() failed\n");
3511 /* Get optional target file name */
3512 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3513 TargetFileName
= NULL
;
3515 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3517 /* Lookup target directory */
3518 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3520 /* FIXME: Handle error! */
3521 DPRINT1("SetupFindFirstLine() failed\n");
3522 INF_FreeData(FileKeyName
);
3523 INF_FreeData(FileKeyValue
);
3524 INF_FreeData(TargetFileName
);
3528 INF_FreeData(FileKeyValue
);
3530 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3532 /* FIXME: Handle error! */
3533 DPRINT1("INF_GetData() failed\n");
3534 INF_FreeData(FileKeyName
);
3535 INF_FreeData(TargetFileName
);
3539 if (!SetupQueueCopy(USetupData
.SetupFileQueue
,
3541 USetupData
.SourceRootPath
.Buffer
,
3542 USetupData
.SourceRootDir
.Buffer
,
3547 /* FIXME: Handle error! */
3548 DPRINT1("SetupQueueCopy() failed\n");
3551 INF_FreeData(FileKeyName
);
3552 INF_FreeData(TargetFileName
);
3553 INF_FreeData(DirKeyValue
);
3554 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3561 AddSectionToCopyQueue(HINF InfFile
,
3563 PWCHAR SourceCabinet
,
3564 PCUNICODE_STRING DestinationPath
,
3567 INFCONTEXT FilesContext
;
3568 INFCONTEXT DirContext
;
3570 PWCHAR FileKeyValue
;
3572 PWCHAR TargetFileName
;
3573 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3576 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3579 * This code enumerates the list of files in txtsetup.sif
3580 * that need to be installed in their respective directories.
3583 /* Search for the SectionName section */
3584 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3586 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3591 * Enumerate the files in the section and add them to the file queue.
3595 /* Get source file name */
3596 if (!INF_GetDataField(&FilesContext
, 0, &FileKeyName
))
3598 /* FIXME: Handle error! */
3599 DPRINT1("INF_GetData() failed\n");
3603 /* Get target directory id */
3604 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3606 /* FIXME: Handle error! */
3607 DPRINT1("INF_GetData() failed\n");
3608 INF_FreeData(FileKeyName
);
3612 /* Get optional target file name */
3613 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3614 TargetFileName
= NULL
;
3615 else if (!*TargetFileName
)
3616 TargetFileName
= NULL
;
3618 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3620 /* Lookup target directory */
3621 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3623 /* FIXME: Handle error! */
3624 DPRINT1("SetupFindFirstLine() failed\n");
3625 INF_FreeData(FileKeyName
);
3626 INF_FreeData(FileKeyValue
);
3627 INF_FreeData(TargetFileName
);
3631 INF_FreeData(FileKeyValue
);
3633 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3635 /* FIXME: Handle error! */
3636 DPRINT1("INF_GetData() failed\n");
3637 INF_FreeData(FileKeyName
);
3638 INF_FreeData(TargetFileName
);
3642 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3644 /* Installation path */
3645 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3647 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3648 USetupData
.SourceRootDir
.Buffer
);
3650 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3652 else if (DirKeyValue
[0] == L
'\\')
3655 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3657 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3660 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3662 else // if (DirKeyValue[0] != L'\\')
3664 /* Path relative to the installation path */
3665 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3667 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3668 USetupData
.SourceRootDir
.Buffer
, DirKeyValue
);
3670 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3673 if (!SetupQueueCopy(USetupData
.SetupFileQueue
,
3675 USetupData
.SourceRootPath
.Buffer
,
3676 CompleteOrigDirName
,
3681 /* FIXME: Handle error! */
3682 DPRINT1("SetupQueueCopy() failed\n");
3685 INF_FreeData(FileKeyName
);
3686 INF_FreeData(TargetFileName
);
3687 INF_FreeData(DirKeyValue
);
3688 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3695 PrepareCopyPageInfFile(HINF InfFile
,
3696 PWCHAR SourceCabinet
,
3700 INFCONTEXT DirContext
;
3701 PWCHAR AdditionalSectionName
= NULL
;
3703 WCHAR PathBuffer
[MAX_PATH
];
3705 /* Add common files */
3706 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3709 /* Add specific files depending of computer type */
3710 if (SourceCabinet
== NULL
)
3712 if (!ProcessComputerFiles(InfFile
, USetupData
.ComputerList
, &AdditionalSectionName
))
3715 if (AdditionalSectionName
)
3717 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3722 /* Create directories */
3726 * Copying files to USetupData.DestinationRootPath should be done from within
3727 * the SystemPartitionFiles section.
3728 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3729 * For installing to USetupData.DestinationPath specify just '\' .
3732 /* Get destination path */
3733 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), USetupData
.DestinationPath
.Buffer
);
3735 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3737 /* Create the install directory */
3738 Status
= SetupCreateDirectory(PathBuffer
);
3739 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3741 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3742 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3746 /* Search for the 'Directories' section */
3747 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3750 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3752 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3757 /* Enumerate the directory values and create the subdirectories */
3760 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3766 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3768 /* Installation path */
3769 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3771 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3772 USetupData
.DestinationPath
.Buffer
);
3774 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3776 else if (DirKeyValue
[0] == L
'\\')
3779 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3781 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3782 USetupData
.DestinationRootPath
.Buffer
, DirKeyValue
);
3784 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3786 Status
= SetupCreateDirectory(PathBuffer
);
3787 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3789 INF_FreeData(DirKeyValue
);
3790 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3791 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3795 else // if (DirKeyValue[0] != L'\\')
3797 /* Path relative to the installation path */
3798 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3800 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3801 USetupData
.DestinationPath
.Buffer
, DirKeyValue
);
3803 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3805 Status
= SetupCreateDirectory(PathBuffer
);
3806 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3808 INF_FreeData(DirKeyValue
);
3809 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3810 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3815 INF_FreeData(DirKeyValue
);
3816 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3823 * Displays the PrepareCopyPage.
3826 * FileCopyPage(At once)
3830 * Inits SetupFileQueue
3831 * Calls PrepareCopyPageInfFile
3834 * Number of the next page.
3837 PrepareCopyPage(PINPUT_RECORD Ir
)
3840 WCHAR PathBuffer
[MAX_PATH
];
3841 INFCONTEXT CabinetsContext
;
3847 MUIDisplayPage(PREPARE_COPY_PAGE
);
3849 /* Create the file queue */
3850 USetupData
.SetupFileQueue
= SetupOpenFileQueue();
3851 if (USetupData
.SetupFileQueue
== NULL
)
3853 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3857 if (!PrepareCopyPageInfFile(USetupData
.SetupInf
, NULL
, Ir
))
3859 /* FIXME: show an error dialog */
3863 /* Search for the 'Cabinets' section */
3864 if (!SetupFindFirstLineW(USetupData
.SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3866 return FILE_COPY_PAGE
;
3870 * Enumerate the directory values in the 'Cabinets'
3871 * section and parse their inf files.
3875 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3878 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3879 USetupData
.SourcePath
.Buffer
, KeyValue
);
3881 CabinetInitialize();
3882 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3883 CabinetSetCabinetName(PathBuffer
);
3885 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3887 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3889 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3890 if (InfFileData
== NULL
)
3892 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3898 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3899 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3903 InfHandle
= INF_OpenBufferedFileA((PSTR
)InfFileData
,
3907 USetupData
.LanguageId
,
3910 if (InfHandle
== INVALID_HANDLE_VALUE
)
3912 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3918 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3920 /* FIXME: show an error dialog */
3923 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3925 return FILE_COPY_PAGE
;
3931 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3934 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3936 /* Get the memory information from the system */
3937 NtQuerySystemInformation(SystemPerformanceInformation
,
3942 /* Check if this is initial setup */
3945 /* Set maximum limits to be total RAM pages */
3946 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3947 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3948 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3951 /* Set current values */
3952 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3953 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3954 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3960 FileCopyCallback(PVOID Context
,
3965 PCOPYCONTEXT CopyContext
;
3967 CopyContext
= (PCOPYCONTEXT
)Context
;
3969 switch (Notification
)
3971 case SPFILENOTIFY_STARTSUBQUEUE
:
3972 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3973 ProgressSetStepCount(CopyContext
->ProgressBar
,
3974 CopyContext
->TotalOperations
);
3975 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3978 case SPFILENOTIFY_STARTCOPY
:
3979 /* Display copy message */
3980 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3981 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3984 case SPFILENOTIFY_ENDCOPY
:
3985 CopyContext
->CompletedOperations
++;
3987 /* SYSREG checkpoint */
3988 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3989 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3991 ProgressNextStep(CopyContext
->ProgressBar
);
3992 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4001 * Displays the FileCopyPage.
4004 * RegistryPage(At once)
4007 * Calls SetupCommitFileQueueW
4008 * Calls SetupCloseFileQueue
4011 * Number of the next page.
4014 FileCopyPage(PINPUT_RECORD Ir
)
4016 COPYCONTEXT CopyContext
;
4017 unsigned int mem_bar_width
;
4019 MUIDisplayPage(FILE_COPY_PAGE
);
4021 /* Create context for the copy process */
4022 CopyContext
.DestinationRootPath
= USetupData
.DestinationRootPath
.Buffer
;
4023 CopyContext
.InstallPath
= USetupData
.InstallPath
.Buffer
;
4024 CopyContext
.TotalOperations
= 0;
4025 CopyContext
.CompletedOperations
= 0;
4027 /* Create the progress bar as well */
4028 CopyContext
.ProgressBar
= CreateProgressBar(13,
4035 MUIGetString(STRING_SETUPCOPYINGFILES
));
4037 // fit memory bars to screen width, distribute them uniform
4038 mem_bar_width
= (xScreen
- 26) / 5;
4039 mem_bar_width
-= mem_bar_width
% 2; // make even
4040 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4041 /* Create the paged pool progress bar */
4042 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4051 /* Create the non paged pool progress bar */
4052 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4054 (xScreen
/ 2) + (mem_bar_width
/ 2),
4056 (xScreen
/ 2)- (mem_bar_width
/ 2),
4061 /* Create the global memory progress bar */
4062 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4066 xScreen
- 13 - mem_bar_width
,
4071 /* Do the file copying */
4072 SetupCommitFileQueueW(NULL
,
4073 USetupData
.SetupFileQueue
,
4077 /* If we get here, we're done, so cleanup the queue and progress bar */
4078 SetupCloseFileQueue(USetupData
.SetupFileQueue
);
4079 DestroyProgressBar(CopyContext
.ProgressBar
);
4080 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4081 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4082 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4084 /* Create the $winnt$.inf file */
4085 InstallSetupInfFile(&USetupData
);
4087 /* Go display the next page */
4088 return REGISTRY_PAGE
;
4094 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4096 /* WARNING: Please keep this lookup table in sync with the resources! */
4097 static const UINT StringIDs
[] =
4099 STRING_DONE
, /* Success */
4100 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4101 STRING_IMPORTFILE
, /* ImportRegHive */
4102 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4103 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4104 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4105 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4106 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4111 if (RegStatus
< ARRAYSIZE(StringIDs
))
4113 va_start(args
, RegStatus
);
4114 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4119 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4124 * Displays the RegistryPage.
4127 * SuccessPage (if RepairUpdate)
4128 * BootLoaderPage (default)
4132 * Calls UpdateRegistry
4135 * Number of the next page.
4138 RegistryPage(PINPUT_RECORD Ir
)
4142 MUIDisplayPage(REGISTRY_PAGE
);
4144 Error
= UpdateRegistry(USetupData
.SetupInf
,
4148 DestinationDriveLetter
,
4150 USetupData
.DisplayList
,
4151 USetupData
.LayoutList
,
4152 USetupData
.LanguageList
,
4154 if (Error
!= ERROR_SUCCESS
)
4156 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4161 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4162 return BOOT_LOADER_PAGE
;
4168 * Displays the BootLoaderPage.
4171 * SuccessPage (if RepairUpdate)
4172 * BootLoaderHarddiskMbrPage
4173 * BootLoaderHarddiskVbrPage
4174 * BootLoaderFloppyPage
4179 * Calls RegInitializeRegistry
4180 * Calls ImportRegistryFile
4181 * Calls SetDefaultPagefile
4182 * Calls SetMountedDeviceValues
4185 * Number of the next page.
4188 BootLoaderPage(PINPUT_RECORD Ir
)
4190 UCHAR PartitionType
;
4191 BOOLEAN InstallOnFloppy
;
4193 WCHAR PathBuffer
[MAX_PATH
];
4195 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4197 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4198 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4199 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4200 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4201 PartitionList
->SystemPartition
->PartitionNumber
);
4202 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4203 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4205 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4207 /* For unattended setup, skip MBR installation or install on floppy if needed */
4208 if (IsUnattendedSetup
)
4210 if ((USetupData
.MBRInstallType
== 0) ||
4211 (USetupData
.MBRInstallType
== 1))
4218 * We may install an MBR or VBR, but before that, check whether
4219 * we need to actually install the VBR on floppy.
4221 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4223 DPRINT("Error: system partition invalid (unused)\n");
4224 InstallOnFloppy
= TRUE
;
4226 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4228 /* OS/2 boot manager partition */
4229 DPRINT("Found OS/2 boot manager partition\n");
4230 InstallOnFloppy
= TRUE
;
4232 else if (PartitionType
== PARTITION_EXT2
)
4234 /* Linux EXT2 partition */
4235 DPRINT("Found Linux EXT2 partition\n");
4236 InstallOnFloppy
= FALSE
;
4238 else if (PartitionType
== PARTITION_IFS
)
4240 /* NTFS partition */
4241 DPRINT("Found NTFS partition\n");
4243 // FIXME: Make it FALSE when we'll support NTFS installation!
4244 InstallOnFloppy
= TRUE
;
4246 else if ((PartitionType
== PARTITION_FAT_12
) ||
4247 (PartitionType
== PARTITION_FAT_16
) ||
4248 (PartitionType
== PARTITION_HUGE
) ||
4249 (PartitionType
== PARTITION_XINT13
) ||
4250 (PartitionType
== PARTITION_FAT32
) ||
4251 (PartitionType
== PARTITION_FAT32_XINT13
))
4253 DPRINT("Found FAT partition\n");
4254 InstallOnFloppy
= FALSE
;
4258 /* Unknown partition */
4259 DPRINT("Unknown partition found\n");
4260 InstallOnFloppy
= TRUE
;
4263 /* We should install on floppy */
4264 if (InstallOnFloppy
)
4266 USetupData
.MBRInstallType
= 1;
4270 /* Is it an unattended install on hdd? */
4271 if (IsUnattendedSetup
)
4273 if ((USetupData
.MBRInstallType
== 2) ||
4274 (USetupData
.MBRInstallType
== 3))
4280 MUIDisplayPage(BOOT_LOADER_PAGE
);
4281 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4285 CONSOLE_ConInKey(Ir
);
4287 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4288 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4290 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4299 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4301 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4302 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4304 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4313 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4315 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4316 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4318 if (ConfirmQuit(Ir
))
4323 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4327 /* Install on both MBR and VBR */
4328 USetupData
.MBRInstallType
= 2;
4331 else if (Line
== 13)
4333 /* Install on VBR only */
4334 USetupData
.MBRInstallType
= 3;
4337 else if (Line
== 14)
4339 /* Install on floppy */
4340 USetupData
.MBRInstallType
= 1;
4343 else if (Line
== 15)
4345 /* Skip MBR installation */
4346 USetupData
.MBRInstallType
= 0;
4350 return BOOT_LOADER_PAGE
;
4355 switch (USetupData
.MBRInstallType
)
4357 /* Skip MBR installation */
4359 return SUCCESS_PAGE
;
4361 /* Install on floppy */
4363 return BOOT_LOADER_FLOPPY_PAGE
;
4365 /* Install on both MBR and VBR */
4367 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4369 /* Install on VBR only */
4371 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4374 return BOOT_LOADER_PAGE
;
4379 * Displays the BootLoaderFloppyPage.
4382 * SuccessPage (At once)
4386 * Calls InstallFatBootcodeToFloppy()
4389 * Number of the next page.
4392 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4396 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4398 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4402 CONSOLE_ConInKey(Ir
);
4404 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4405 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4407 if (ConfirmQuit(Ir
))
4412 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4414 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4415 &USetupData
.DestinationArcPath
);
4416 if (!NT_SUCCESS(Status
))
4418 if (Status
== STATUS_DEVICE_NOT_READY
)
4419 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4421 /* TODO: Print error message */
4422 return BOOT_LOADER_FLOPPY_PAGE
;
4425 return SUCCESS_PAGE
;
4429 return BOOT_LOADER_FLOPPY_PAGE
;
4434 * Displays the BootLoaderHarddiskVbrPage.
4437 * SuccessPage (At once)
4441 * Calls InstallVBRToPartition()
4444 * Number of the next page.
4447 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4451 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4452 &USetupData
.SourceRootPath
,
4453 &USetupData
.DestinationArcPath
,
4454 PartitionList
->SystemPartition
->PartitionType
);
4455 if (!NT_SUCCESS(Status
))
4457 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4461 return SUCCESS_PAGE
;
4466 * Displays the BootLoaderHarddiskMbrPage.
4469 * SuccessPage (At once)
4473 * Calls InstallVBRToPartition()
4474 * Calls InstallMbrBootCodeToDisk()
4477 * Number of the next page.
4480 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4483 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4485 /* Step 1: Write the VBR */
4486 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4487 &USetupData
.SourceRootPath
,
4488 &USetupData
.DestinationArcPath
,
4489 PartitionList
->SystemPartition
->PartitionType
);
4490 if (!NT_SUCCESS(Status
))
4492 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4496 /* Step 2: Write the MBR */
4497 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4498 L
"\\Device\\Harddisk%d\\Partition0",
4499 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4500 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4501 &USetupData
.SourceRootPath
,
4502 DestinationDevicePathBuffer
);
4503 if (!NT_SUCCESS(Status
))
4505 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4506 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4510 return SUCCESS_PAGE
;
4515 * @name ProgressTimeOutStringHandler
4517 * Handles the generation (displaying) of the timeout
4518 * countdown to the screen dynamically.
4521 * A pointer to a progress bar.
4523 * @param AlwaysUpdate
4524 * Constantly update the progress bar (boolean type).
4527 * A pointer to a string buffer.
4529 * @param cchBufferSize
4530 * The buffer's size in number of characters.
4533 * TRUE or FALSE on function termination.
4538 ProgressTimeOutStringHandler(
4539 IN PPROGRESSBAR Bar
,
4540 IN BOOLEAN AlwaysUpdate
,
4542 IN SIZE_T cchBufferSize
)
4544 ULONG OldProgress
= Bar
->Progress
;
4546 if (Bar
->StepCount
== 0)
4552 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4555 /* Build the progress string if it has changed */
4556 if (Bar
->ProgressFormatText
&&
4557 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4559 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4560 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4569 * @name ProgressCountdown
4571 * Displays and draws a red-coloured progress bar with a countdown.
4572 * When the timeout is reached, the flush page is displayed for reboot.
4575 * A pointer to an input keyboard record.
4578 * Initial countdown value in seconds.
4586 IN PINPUT_RECORD Ir
,
4590 ULONG StartTime
, BarWidth
, TimerDiv
;
4592 LONG TimerValue
, OldTimerValue
;
4593 LARGE_INTEGER Timeout
;
4594 PPROGRESSBAR ProgressBar
;
4595 BOOLEAN RefreshProgress
= TRUE
;
4597 /* Bail out if the timeout is already zero */
4601 /* Create the timeout progress bar and set it up */
4602 ProgressBar
= CreateProgressBarEx(13,
4609 FOREGROUND_RED
| BACKGROUND_BLUE
,
4612 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4613 ProgressTimeOutStringHandler
);
4615 BarWidth
= max(1, ProgressBar
->Width
);
4616 TimerValue
= TimeOut
* BarWidth
;
4617 ProgressSetStepCount(ProgressBar
, TimerValue
);
4619 StartTime
= NtGetTickCount();
4622 TimerDiv
= 1000 / BarWidth
;
4623 TimerDiv
= max(1, TimerDiv
);
4624 OldTimerValue
= TimerValue
;
4627 /* Decrease the timer */
4630 * Compute how much time the previous operations took.
4631 * This allows us in particular to take account for any time
4632 * elapsed if something slowed down.
4634 TimeElapsed
= NtGetTickCount() - StartTime
;
4635 if (TimeElapsed
>= TimerDiv
)
4637 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4638 TimeElapsed
/= TimerDiv
;
4639 StartTime
+= (TimerDiv
* TimeElapsed
);
4641 if (TimeElapsed
<= TimerValue
)
4642 TimerValue
-= TimeElapsed
;
4646 RefreshProgress
= TRUE
;
4649 if (RefreshProgress
)
4651 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4652 RefreshProgress
= FALSE
;
4655 /* Stop when the timer reaches zero */
4656 if (TimerValue
<= 0)
4659 /* Check for user key presses */
4662 * If the timer is used, use a passive wait of maximum 1 second
4663 * while monitoring for incoming console input events, so that
4664 * we are still able to display the timing count.
4667 /* Wait a maximum of 1 second for input events */
4668 TimeElapsed
= NtGetTickCount() - StartTime
;
4669 if (TimeElapsed
< TimerDiv
)
4671 /* Convert the time to NT Format */
4672 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4673 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4677 Status
= STATUS_TIMEOUT
;
4680 /* Check whether the input event has been signaled, or a timeout happened */
4681 if (Status
== STATUS_TIMEOUT
)
4685 if (Status
!= STATUS_WAIT_0
)
4687 /* An error happened, bail out */
4688 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4692 /* Check for an ENTER key press */
4693 while (CONSOLE_ConInKeyPeek(Ir
))
4695 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4697 /* Found it, stop waiting */
4704 /* Destroy the progress bar and quit */
4705 DestroyProgressBar(ProgressBar
);
4710 * Displays the QuitPage.
4713 * FlushPage (At once)
4719 * Number of the next page.
4722 QuitPage(PINPUT_RECORD Ir
)
4724 MUIDisplayPage(QUIT_PAGE
);
4726 /* Destroy the NTOS installations list */
4727 if (NtOsInstallsList
!= NULL
)
4729 DestroyGenericList(NtOsInstallsList
, TRUE
);
4730 NtOsInstallsList
= NULL
;
4733 /* Destroy the partition list */
4734 if (PartitionList
!= NULL
)
4736 DestroyPartitionList(PartitionList
);
4737 PartitionList
= NULL
;
4740 TempPartition
= NULL
;
4741 FormatState
= Start
;
4743 /* Destroy the filesystem list */
4744 if (FileSystemList
!= NULL
)
4746 DestroyFileSystemList(FileSystemList
);
4747 FileSystemList
= NULL
;
4750 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4752 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4753 ProgressCountdown(Ir
, 15);
4759 * Displays the SuccessPage.
4762 * FlushPage (At once)
4768 * Number of the next page.
4771 SuccessPage(PINPUT_RECORD Ir
)
4773 MUIDisplayPage(SUCCESS_PAGE
);
4775 if (IsUnattendedSetup
)
4778 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4779 ProgressCountdown(Ir
, 15);
4785 * Displays the FlushPage.
4788 * RebootPage (At once)
4791 * Number of the next page.
4794 FlushPage(PINPUT_RECORD Ir
)
4796 MUIDisplayPage(FLUSH_PAGE
);
4802 PnpEventThread(IN LPVOID lpParameter
);
4806 * The start routine and page management
4816 InfSetHeap(ProcessHeap
);
4818 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4819 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4820 if (!NT_SUCCESS(Status
))
4821 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4823 /* Create the PnP thread in suspended state */
4824 Status
= RtlCreateUserThread(NtCurrentProcess(),
4831 &USetupData
.SetupInf
,
4834 if (!NT_SUCCESS(Status
))
4837 if (!CONSOLE_Init())
4839 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4840 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4841 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4843 /* We failed to initialize the video, just quit the installer */
4844 return STATUS_APP_INIT_FAILURE
;
4847 /* Initialize Setup, phase 0 */
4848 InitializeSetup(&USetupData
, 0);
4850 /* Hide the cursor */
4851 CONSOLE_SetCursorType(TRUE
, FALSE
);
4853 /* Global Initialization page */
4854 CONSOLE_ClearScreen();
4856 Page
= SetupStartPage(&Ir
);
4858 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4860 CONSOLE_ClearScreen();
4863 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4870 Page
= LanguagePage(&Ir
);
4875 Page
= WelcomePage(&Ir
);
4880 Page
= LicensePage(&Ir
);
4884 case INSTALL_INTRO_PAGE
:
4885 Page
= InstallIntroPage(&Ir
);
4889 case SCSI_CONTROLLER_PAGE
:
4890 Page
= ScsiControllerPage(&Ir
);
4893 case OEM_DRIVER_PAGE
:
4894 Page
= OemDriverPage(&Ir
);
4898 case DEVICE_SETTINGS_PAGE
:
4899 Page
= DeviceSettingsPage(&Ir
);
4902 case COMPUTER_SETTINGS_PAGE
:
4903 Page
= ComputerSettingsPage(&Ir
);
4906 case DISPLAY_SETTINGS_PAGE
:
4907 Page
= DisplaySettingsPage(&Ir
);
4910 case KEYBOARD_SETTINGS_PAGE
:
4911 Page
= KeyboardSettingsPage(&Ir
);
4914 case LAYOUT_SETTINGS_PAGE
:
4915 Page
= LayoutSettingsPage(&Ir
);
4918 case SELECT_PARTITION_PAGE
:
4919 Page
= SelectPartitionPage(&Ir
);
4922 case CREATE_PRIMARY_PARTITION_PAGE
:
4923 Page
= CreatePrimaryPartitionPage(&Ir
);
4926 case CREATE_EXTENDED_PARTITION_PAGE
:
4927 Page
= CreateExtendedPartitionPage(&Ir
);
4930 case CREATE_LOGICAL_PARTITION_PAGE
:
4931 Page
= CreateLogicalPartitionPage(&Ir
);
4934 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4935 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4938 case DELETE_PARTITION_PAGE
:
4939 Page
= DeletePartitionPage(&Ir
);
4942 case SELECT_FILE_SYSTEM_PAGE
:
4943 Page
= SelectFileSystemPage(&Ir
);
4946 case FORMAT_PARTITION_PAGE
:
4947 Page
= FormatPartitionPage(&Ir
);
4950 case CHECK_FILE_SYSTEM_PAGE
:
4951 Page
= CheckFileSystemPage(&Ir
);
4954 case INSTALL_DIRECTORY_PAGE
:
4955 Page
= InstallDirectoryPage(&Ir
);
4958 case PREPARE_COPY_PAGE
:
4959 Page
= PrepareCopyPage(&Ir
);
4962 case FILE_COPY_PAGE
:
4963 Page
= FileCopyPage(&Ir
);
4967 Page
= RegistryPage(&Ir
);
4970 case BOOT_LOADER_PAGE
:
4971 Page
= BootLoaderPage(&Ir
);
4974 case BOOT_LOADER_FLOPPY_PAGE
:
4975 Page
= BootLoaderFloppyPage(&Ir
);
4978 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
4979 Page
= BootLoaderHarddiskMbrPage(&Ir
);
4982 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
4983 Page
= BootLoaderHarddiskVbrPage(&Ir
);
4987 case REPAIR_INTRO_PAGE
:
4988 Page
= RepairIntroPage(&Ir
);
4991 case UPGRADE_REPAIR_PAGE
:
4992 Page
= UpgradeRepairPage(&Ir
);
4996 Page
= SuccessPage(&Ir
);
5000 Page
= FlushPage(&Ir
);
5004 Page
= QuitPage(&Ir
);
5013 /* Setup has finished */
5014 FinishSetup(&USetupData
);
5016 if (Page
== RECOVERY_PAGE
)
5022 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5023 NtShutdownSystem(ShutdownReboot
);
5024 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5026 return STATUS_SUCCESS
;
5031 NtProcessStartup(PPEB Peb
)
5036 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5038 ProcessHeap
= Peb
->ProcessHeap
;
5040 NtQuerySystemTime(&Time
);
5042 Status
= RunUSetup();
5044 if (NT_SUCCESS(Status
))
5047 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5048 * a protective waiting.
5049 * This wait is needed because, since we are started as SMSS.EXE,
5050 * the NT kernel explicitly waits 5 seconds for the initial process
5051 * SMSS.EXE to initialize (as a protective measure), and otherwise
5052 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5054 Time
.QuadPart
+= 50000000;
5055 NtDelayExecution(FALSE
, &Time
);
5059 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5060 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5061 0, 0, NULL
, 0, NULL
);
5064 NtTerminateProcess(NtCurrentProcess(), Status
);