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 *********************************************************/
44 BOOLEAN IsUnattendedSetup
= FALSE
;
45 static USETUP_DATA USetupData
;
48 * NOTE: Technically only used for the COPYCONTEXT InstallPath member
49 * for the filequeue functionality.
51 static UNICODE_STRING InstallPath
;
53 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
54 static WCHAR DestinationDriveLetter
;
59 PCWSTR SelectedLanguageId
;
60 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
61 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
63 static BOOLEAN RepairUpdateFlag
= FALSE
;
65 static HANDLE hPnpThread
= NULL
;
67 static PPARTLIST PartitionList
= NULL
;
68 static PPARTENTRY TempPartition
= NULL
;
69 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
70 static FORMATMACHINESTATE FormatState
= Start
;
72 /*****************************************************/
76 static HSPFILEQ SetupFileQueue
= NULL
;
78 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
79 static PGENERIC_LIST NtOsInstallsList
= NULL
;
81 static PGENERIC_LIST ComputerList
= NULL
;
82 static PGENERIC_LIST DisplayList
= NULL
;
83 static PGENERIC_LIST KeyboardList
= NULL
;
84 static PGENERIC_LIST LayoutList
= NULL
;
85 static PGENERIC_LIST LanguageList
= NULL
;
88 /* FUNCTIONS ****************************************************************/
91 PrintString(char* fmt
,...)
95 UNICODE_STRING UnicodeString
;
96 ANSI_STRING AnsiString
;
99 vsprintf(buffer
, fmt
, ap
);
102 RtlInitAnsiString(&AnsiString
, buffer
);
103 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
104 NtDisplayString(&UnicodeString
);
105 RtlFreeUnicodeString(&UnicodeString
);
110 DrawBox(IN SHORT xLeft
,
118 /* Draw upper left corner */
121 FillConsoleOutputCharacterA(StdOutput
,
127 /* Draw upper edge */
130 FillConsoleOutputCharacterA(StdOutput
,
136 /* Draw upper right corner */
137 coPos
.X
= xLeft
+ Width
- 1;
139 FillConsoleOutputCharacterA(StdOutput
,
145 /* Draw right edge, inner space and left edge */
146 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
149 FillConsoleOutputCharacterA(StdOutput
,
156 FillConsoleOutputCharacterA(StdOutput
,
162 coPos
.X
= xLeft
+ Width
- 1;
163 FillConsoleOutputCharacterA(StdOutput
,
170 /* Draw lower left corner */
172 coPos
.Y
= yTop
+ Height
- 1;
173 FillConsoleOutputCharacterA(StdOutput
,
179 /* Draw lower edge */
181 coPos
.Y
= yTop
+ Height
- 1;
182 FillConsoleOutputCharacterA(StdOutput
,
188 /* Draw lower right corner */
189 coPos
.X
= xLeft
+ Width
- 1;
190 coPos
.Y
= yTop
+ Height
- 1;
191 FillConsoleOutputCharacterA(StdOutput
,
200 PopupError(PCCH Text
,
218 /* Count text lines and longest line */
225 p
= strchr(pnext
, '\n');
229 Length
= strlen(pnext
);
234 Length
= (ULONG
)(p
- pnext
);
240 if (Length
> MaxLength
)
249 /* Check length of status line */
252 Length
= strlen(Status
);
254 if (Length
> MaxLength
)
258 Width
= MaxLength
+ 4;
264 yTop
= (yScreen
- Height
) / 2;
265 xLeft
= (xScreen
- Width
) / 2;
268 /* Set screen attributes */
270 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
272 FillConsoleOutputAttribute(StdOutput
,
273 FOREGROUND_RED
| BACKGROUND_WHITE
,
279 DrawBox(xLeft
, yTop
, Width
, Height
);
281 /* Print message text */
286 p
= strchr(pnext
, '\n');
290 Length
= strlen(pnext
);
295 Length
= (ULONG
)(p
- pnext
);
302 WriteConsoleOutputCharacterA(StdOutput
,
316 /* Print separator line and status text */
319 coPos
.Y
= yTop
+ Height
- 3;
321 FillConsoleOutputCharacterA(StdOutput
,
328 FillConsoleOutputCharacterA(StdOutput
,
334 coPos
.X
= xLeft
+ Width
- 1;
335 FillConsoleOutputCharacterA(StdOutput
,
343 WriteConsoleOutputCharacterA(StdOutput
,
345 min(strlen(Status
), (SIZE_T
)Width
- 4),
350 if (WaitEvent
== POPUP_WAIT_NONE
)
355 CONSOLE_ConInKey(Ir
);
357 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
358 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
370 * FALSE: Don't quit setup.
373 ConfirmQuit(PINPUT_RECORD Ir
)
376 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
380 CONSOLE_ConInKey(Ir
);
382 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
383 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
388 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
402 PGENERIC_LIST_ENTRY ListEntry
;
405 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
407 if (LayoutList
== NULL
)
409 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
410 if (LayoutList
== NULL
)
412 /* FIXME: Handle error! */
417 /* Search for default layout (if provided) */
418 if (pszNewLayout
!= NULL
)
420 for (ListEntry
= GetFirstListEntry(LayoutList
); ListEntry
;
421 ListEntry
= GetNextListEntry(ListEntry
))
423 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
425 SetCurrentListEntry(LayoutList
, ListEntry
);
435 GetSettingDescription(
436 IN PGENERIC_LIST_ENTRY Entry
,
438 IN SIZE_T cchBufferSize
)
440 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
441 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
446 GetNTOSInstallationName(
447 IN PGENERIC_LIST_ENTRY Entry
,
449 IN SIZE_T cchBufferSize
)
451 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
452 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
454 if (PartEntry
&& PartEntry
->DriveLetter
)
456 /* We have retrieved a partition that is mounted */
457 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
459 PartEntry
->DriveLetter
,
460 NtOsInstall
->PathComponent
,
461 NtOsInstall
->InstallationName
);
465 /* We failed somewhere, just show the NT path */
466 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
468 &NtOsInstall
->SystemNtPath
,
469 NtOsInstall
->InstallationName
);
475 * Displays the LanguagePage.
477 * Next pages: WelcomePage, QuitPage
480 * Init SelectedLanguageId
481 * Init USetupData.LanguageId
484 * Number of the next page.
487 LanguagePage(PINPUT_RECORD Ir
)
489 GENERIC_LIST_UI ListUi
;
490 PCWSTR NewLanguageId
;
491 BOOL RefreshPage
= FALSE
;
493 /* Initialize the computer settings list */
494 if (LanguageList
== NULL
)
496 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
497 if (LanguageList
== NULL
)
499 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
504 SelectedLanguageId
= DefaultLanguage
;
505 USetupData
.LanguageId
= 0;
508 SetConsoleCodePage();
512 * If there is no language or just a single one in the list,
513 * skip the language selection process altogether.
515 if (GetNumberOfListEntries(LanguageList
) <= 1)
517 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
521 InitGenericListUi(&ListUi
, LanguageList
, GetSettingDescription
);
522 DrawGenericList(&ListUi
,
527 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
529 MUIDisplayPage(LANGUAGE_PAGE
);
533 CONSOLE_ConInKey(Ir
);
535 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
536 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
538 ScrollDownGenericList(&ListUi
);
541 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
542 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
544 ScrollUpGenericList(&ListUi
);
547 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
548 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
550 ScrollPageDownGenericList(&ListUi
);
553 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
554 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
556 ScrollPageUpGenericList(&ListUi
);
559 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
560 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
565 RedrawGenericList(&ListUi
);
567 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
569 ASSERT(GetNumberOfListEntries(LanguageList
) >= 1);
572 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(LanguageList
)))->Id
;
574 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
576 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
582 SetConsoleCodePage();
586 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
589 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
595 ASSERT(GetNumberOfListEntries(LanguageList
) >= 1);
598 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(LanguageList
)))->Id
;
600 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
602 /* Clear the language page */
603 MUIClearPage(LANGUAGE_PAGE
);
605 SelectedLanguageId
= NewLanguageId
;
608 SetConsoleCodePage();
610 /* Redraw language selection page in native language */
611 MUIDisplayPage(LANGUAGE_PAGE
);
626 * LanguagePage (at once, default)
627 * InstallIntroPage (at once, if unattended)
632 * Init USetupData.SourcePath
633 * Init USetupData.SourceRootPath
634 * Init USetupData.SourceRootDir
636 * Init USetupData.RequiredPartitionDiskSpace
637 * Init IsUnattendedSetup
638 * If unattended, init *List and sets the Codepage
639 * If unattended, init SelectedLanguageId
640 * If unattended, init USetupData.LanguageId
643 * Number of the next page.
646 SetupStartPage(PINPUT_RECORD Ir
)
650 PGENERIC_LIST_ENTRY ListEntry
;
653 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
655 /* Get the source path and source root path */
656 Status
= GetSourcePaths(&USetupData
.SourcePath
,
657 &USetupData
.SourceRootPath
,
658 &USetupData
.SourceRootDir
);
659 if (!NT_SUCCESS(Status
))
661 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
662 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
665 DPRINT1("SourcePath: '%wZ'\n", &USetupData
.SourcePath
);
666 DPRINT1("SourceRootPath: '%wZ'\n", &USetupData
.SourceRootPath
);
667 DPRINT1("SourceRootDir: '%wZ'\n", &USetupData
.SourceRootDir
);
669 /* Load 'txtsetup.sif' from the installation media */
670 Error
= LoadSetupInf(&SetupInf
, &USetupData
);
671 if (Error
!= ERROR_SUCCESS
)
673 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
677 /* Start the PnP thread */
678 if (hPnpThread
!= NULL
)
680 NtResumeThread(hPnpThread
, NULL
);
684 CheckUnattendedSetup(&USetupData
);
686 if (IsUnattendedSetup
)
688 // TODO: Read options from inf
689 /* Load the hardware, language and keyboard layout lists */
691 ComputerList
= CreateComputerTypeList(SetupInf
);
692 DisplayList
= CreateDisplayDriverList(SetupInf
);
693 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
695 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
698 SelectedLanguageId
= DefaultLanguage
;
699 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
700 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
702 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
704 /* first we hack LanguageList */
705 for (ListEntry
= GetFirstListEntry(LanguageList
); ListEntry
;
706 ListEntry
= GetNextListEntry(ListEntry
))
708 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
709 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
711 DPRINT("found %S in LanguageList\n", LocaleId
);
712 SetCurrentListEntry(LanguageList
, ListEntry
);
718 for (ListEntry
= GetFirstListEntry(LayoutList
); ListEntry
;
719 ListEntry
= GetNextListEntry(ListEntry
))
721 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
722 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
724 DPRINT("found %S in LayoutList\n", LocaleId
);
725 SetCurrentListEntry(LayoutList
, ListEntry
);
730 SetConsoleCodePage();
732 return INSTALL_INTRO_PAGE
;
735 return LANGUAGE_PAGE
;
740 * Displays the WelcomePage.
743 * InstallIntroPage (default)
750 * Number of the next page.
753 WelcomePage(PINPUT_RECORD Ir
)
755 MUIDisplayPage(WELCOME_PAGE
);
759 CONSOLE_ConInKey(Ir
);
761 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
762 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
769 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
771 return INSTALL_INTRO_PAGE
;
773 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
775 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
777 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
788 * Displays the License page.
791 * WelcomePage (default)
794 * Number of the next page.
797 LicensePage(PINPUT_RECORD Ir
)
799 MUIDisplayPage(LICENSE_PAGE
);
803 CONSOLE_ConInKey(Ir
);
805 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
816 * Displays the RepairIntroPage.
819 * RebootPage (default)
825 * Number of the next page.
828 RepairIntroPage(PINPUT_RECORD Ir
)
830 MUIDisplayPage(REPAIR_INTRO_PAGE
);
834 CONSOLE_ConInKey(Ir
);
836 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
840 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
842 RepairUpdateFlag
= TRUE
;
843 return INSTALL_INTRO_PAGE
;
845 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
847 return RECOVERY_PAGE
;
849 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
850 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
856 return REPAIR_INTRO_PAGE
;
860 * Displays the UpgradeRepairPage.
863 * RebootPage (default)
869 * Number of the next page.
872 UpgradeRepairPage(PINPUT_RECORD Ir
)
874 GENERIC_LIST_UI ListUi
;
877 if (PartitionList
== NULL
)
879 PartitionList
= CreatePartitionList();
880 if (PartitionList
== NULL
)
882 /* FIXME: show an error dialog */
883 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
886 else if (IsListEmpty(&PartitionList
->DiskListHead
))
888 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
892 TempPartition
= NULL
;
897 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
898 if (!NtOsInstallsList
)
899 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
902 * If there is no available installation (or just a single one??) that can
903 * be updated in the list, just continue with the regular installation.
905 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
907 RepairUpdateFlag
= FALSE
;
909 // return INSTALL_INTRO_PAGE;
910 return DEVICE_SETTINGS_PAGE
;
911 // return SCSI_CONTROLLER_PAGE;
914 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
916 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
917 DrawGenericList(&ListUi
,
922 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
925 CONSOLE_ConInKey(Ir
);
927 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
929 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
931 case VK_DOWN
: /* DOWN */
932 ScrollDownGenericList(&ListUi
);
935 ScrollUpGenericList(&ListUi
);
937 case VK_NEXT
: /* PAGE DOWN */
938 ScrollPageDownGenericList(&ListUi
);
940 case VK_PRIOR
: /* PAGE UP */
941 ScrollPageUpGenericList(&ListUi
);
948 RedrawGenericList(&ListUi
);
951 case VK_ESCAPE
: /* ESC */
953 RestoreGenericListUiState(&ListUi
);
954 // return nextPage; // prevPage;
956 // return INSTALL_INTRO_PAGE;
957 return DEVICE_SETTINGS_PAGE
;
958 // return SCSI_CONTROLLER_PAGE;
964 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
965 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
966 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
968 /* Retrieve the current installation */
969 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
971 CurrentInstallation
=
972 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
974 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
975 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
977 RepairUpdateFlag
= TRUE
;
980 /***/return INSTALL_INTRO_PAGE
;/***/
982 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
983 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
985 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
990 return UPGRADE_REPAIR_PAGE
;
995 * Displays the InstallIntroPage.
998 * DeviceSettingsPage (At once if repair or update is selected)
999 * SelectPartitionPage (At once if unattended setup)
1000 * DeviceSettingsPage (default)
1004 * Number of the next page.
1007 InstallIntroPage(PINPUT_RECORD Ir
)
1009 if (RepairUpdateFlag
)
1011 #if 1 /* Old code that looks good */
1013 // return SELECT_PARTITION_PAGE;
1014 return DEVICE_SETTINGS_PAGE
;
1016 #else /* Possible new code? */
1018 return DEVICE_SETTINGS_PAGE
;
1019 // return SCSI_CONTROLLER_PAGE;
1024 if (IsUnattendedSetup
)
1025 return SELECT_PARTITION_PAGE
;
1027 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1031 CONSOLE_ConInKey(Ir
);
1033 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1034 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1036 if (ConfirmQuit(Ir
))
1041 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1043 return UPGRADE_REPAIR_PAGE
;
1047 return INSTALL_INTRO_PAGE
;
1053 ScsiControllerPage(PINPUT_RECORD Ir
)
1055 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1057 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1059 /* FIXME: print loaded mass storage driver descriptions */
1061 CONSOLE_SetTextXY(8, 10, "TEST device");
1064 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1068 CONSOLE_ConInKey(Ir
);
1070 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1071 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1073 if (ConfirmQuit(Ir
))
1078 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1080 return DEVICE_SETTINGS_PAGE
;
1084 return SCSI_CONTROLLER_PAGE
;
1088 OemDriverPage(PINPUT_RECORD Ir
)
1090 // MUIDisplayPage(OEM_DRIVER_PAGE);
1092 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1094 /* FIXME: Implement!! */
1096 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1100 CONSOLE_ConInKey(Ir
);
1102 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1103 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1105 if (ConfirmQuit(Ir
))
1110 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1112 return DEVICE_SETTINGS_PAGE
;
1116 return OEM_DRIVER_PAGE
;
1122 * Displays the DeviceSettingsPage.
1125 * SelectPartitionPage (At once if repair or update is selected)
1126 * ComputerSettingsPage
1127 * DisplaySettingsPage
1128 * KeyboardSettingsPage
1129 * LayoutsettingsPage
1130 * SelectPartitionPage
1140 * Number of the next page.
1143 DeviceSettingsPage(PINPUT_RECORD Ir
)
1145 static ULONG Line
= 16;
1147 /* Initialize the computer settings list */
1148 if (ComputerList
== NULL
)
1150 ComputerList
= CreateComputerTypeList(SetupInf
);
1151 if (ComputerList
== NULL
)
1153 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1158 /* Initialize the display settings list */
1159 if (DisplayList
== NULL
)
1161 DisplayList
= CreateDisplayDriverList(SetupInf
);
1162 if (DisplayList
== NULL
)
1164 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1169 /* Initialize the keyboard settings list */
1170 if (KeyboardList
== NULL
)
1172 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1173 if (KeyboardList
== NULL
)
1175 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1180 /* Initialize the keyboard layout list */
1181 if (LayoutList
== NULL
)
1183 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1184 if (LayoutList
== NULL
)
1186 /* FIXME: report error */
1187 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1192 if (RepairUpdateFlag
)
1193 return SELECT_PARTITION_PAGE
;
1195 // if (IsUnattendedSetup)
1196 // return SELECT_PARTITION_PAGE;
1198 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1200 DrawGenericListCurrentItem(ComputerList
, GetSettingDescription
, 25, 11);
1201 DrawGenericListCurrentItem(DisplayList
, GetSettingDescription
, 25, 12);
1202 DrawGenericListCurrentItem(KeyboardList
, GetSettingDescription
, 25, 13);
1203 DrawGenericListCurrentItem(LayoutList
, GetSettingDescription
, 25, 14);
1205 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1209 CONSOLE_ConInKey(Ir
);
1211 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1212 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1214 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1218 else if (Line
== 16)
1223 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1225 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1226 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1228 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1232 else if (Line
== 16)
1237 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1239 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1240 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1242 if (ConfirmQuit(Ir
))
1247 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1250 return COMPUTER_SETTINGS_PAGE
;
1251 else if (Line
== 12)
1252 return DISPLAY_SETTINGS_PAGE
;
1253 else if (Line
== 13)
1254 return KEYBOARD_SETTINGS_PAGE
;
1255 else if (Line
== 14)
1256 return LAYOUT_SETTINGS_PAGE
;
1257 else if (Line
== 16)
1258 return SELECT_PARTITION_PAGE
;
1262 return DEVICE_SETTINGS_PAGE
;
1267 * Handles generic selection lists.
1270 * GenericList: The list to handle.
1271 * nextPage: The page it needs to jump to after this page.
1272 * Ir: The PINPUT_RECORD
1275 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1276 PAGE_NUMBER nextPage
,
1281 CONSOLE_ConInKey(Ir
);
1283 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1284 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1286 ScrollDownGenericList(ListUi
);
1288 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1289 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1291 ScrollUpGenericList(ListUi
);
1293 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1294 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1296 ScrollPageDownGenericList(ListUi
);
1298 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1299 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1301 ScrollPageUpGenericList(ListUi
);
1303 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1304 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1306 if (ConfirmQuit(Ir
))
1309 RedrawGenericList(ListUi
);
1311 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1312 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1314 RestoreGenericListUiState(ListUi
);
1315 return nextPage
; // Use some "prevPage;" instead?
1317 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1321 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1324 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1331 * Displays the ComputerSettingsPage.
1334 * DeviceSettingsPage
1338 * Number of the next page.
1341 ComputerSettingsPage(PINPUT_RECORD Ir
)
1343 GENERIC_LIST_UI ListUi
;
1344 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1346 InitGenericListUi(&ListUi
, ComputerList
, GetSettingDescription
);
1347 DrawGenericList(&ListUi
,
1352 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1357 * Displays the DisplaySettingsPage.
1360 * DeviceSettingsPage
1364 * Number of the next page.
1367 DisplaySettingsPage(PINPUT_RECORD Ir
)
1369 GENERIC_LIST_UI ListUi
;
1370 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1372 InitGenericListUi(&ListUi
, DisplayList
, GetSettingDescription
);
1373 DrawGenericList(&ListUi
,
1378 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1383 * Displays the KeyboardSettingsPage.
1386 * DeviceSettingsPage
1390 * Number of the next page.
1393 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1395 GENERIC_LIST_UI ListUi
;
1396 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1398 InitGenericListUi(&ListUi
, KeyboardList
, GetSettingDescription
);
1399 DrawGenericList(&ListUi
,
1404 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1409 * Displays the LayoutSettingsPage.
1412 * DeviceSettingsPage
1416 * Number of the next page.
1419 LayoutSettingsPage(PINPUT_RECORD Ir
)
1421 GENERIC_LIST_UI ListUi
;
1422 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1424 InitGenericListUi(&ListUi
, LayoutList
, GetSettingDescription
);
1425 DrawGenericList(&ListUi
,
1430 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1435 IsDiskSizeValid(PPARTENTRY PartEntry
)
1439 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1440 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1442 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1444 /* Partition is too small so ask for another one */
1445 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1456 * Displays the SelectPartitionPage.
1459 * SelectFileSystemPage (At once if unattended)
1460 * SelectFileSystemPage (Default if free space is selected)
1461 * CreatePrimaryPartitionPage
1462 * CreateExtendedPartitionPage
1463 * CreateLogicalPartitionPage
1464 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1465 * DeletePartitionPage
1469 * Set InstallShortcut (only if not unattended + free space is selected)
1472 * Number of the next page.
1475 SelectPartitionPage(PINPUT_RECORD Ir
)
1480 if (PartitionList
== NULL
)
1482 PartitionList
= CreatePartitionList();
1483 if (PartitionList
== NULL
)
1485 /* FIXME: show an error dialog */
1486 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1489 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1491 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1495 TempPartition
= NULL
;
1496 FormatState
= Start
;
1499 if (RepairUpdateFlag
)
1501 /* Determine the selected installation disk & partition */
1502 if (!SelectPartition(PartitionList
,
1503 CurrentInstallation
->DiskNumber
,
1504 CurrentInstallation
->PartitionNumber
))
1506 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1510 return SELECT_FILE_SYSTEM_PAGE
;
1513 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1515 InitPartitionListUi(&ListUi
, PartitionList
,
1520 DrawPartitionList(&ListUi
);
1522 if (IsUnattendedSetup
)
1524 if (!SelectPartition(PartitionList
,
1525 USetupData
.DestinationDiskNumber
,
1526 USetupData
.DestinationPartitionNumber
))
1528 if (USetupData
.AutoPartition
)
1530 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1532 CreateLogicalPartition(PartitionList
,
1533 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1538 CreatePrimaryPartition(PartitionList
,
1539 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1543 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1544 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1546 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1547 USetupData
.RequiredPartitionDiskSpace
);
1548 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1551 return SELECT_FILE_SYSTEM_PAGE
;
1556 DrawPartitionList(&ListUi
);
1558 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1559 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1561 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1562 USetupData
.RequiredPartitionDiskSpace
);
1563 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1566 return SELECT_FILE_SYSTEM_PAGE
;
1572 /* Update status text */
1573 if (PartitionList
->CurrentPartition
== NULL
)
1575 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1577 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1579 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1581 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1585 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1590 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1592 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1594 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1598 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1603 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1607 CONSOLE_ConInKey(Ir
);
1609 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1610 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1612 if (ConfirmQuit(Ir
))
1614 DestroyPartitionList(PartitionList
);
1615 PartitionList
= NULL
;
1621 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1622 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1624 ScrollDownPartitionList(&ListUi
);
1626 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1627 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1629 ScrollUpPartitionList(&ListUi
);
1631 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1633 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1634 continue; // return SELECT_PARTITION_PAGE;
1636 if (PartitionList
->CurrentPartition
== NULL
||
1637 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1639 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1641 CreateLogicalPartition(PartitionList
,
1647 CreatePrimaryPartition(PartitionList
,
1653 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1655 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1656 USetupData
.RequiredPartitionDiskSpace
);
1657 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1660 return SELECT_FILE_SYSTEM_PAGE
;
1662 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1664 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1666 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1667 if (Error
!= NOT_AN_ERROR
)
1669 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1670 return SELECT_PARTITION_PAGE
;
1673 return CREATE_PRIMARY_PARTITION_PAGE
;
1676 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1678 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1680 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1681 if (Error
!= NOT_AN_ERROR
)
1683 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1684 return SELECT_PARTITION_PAGE
;
1687 return CREATE_EXTENDED_PARTITION_PAGE
;
1690 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1692 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1694 Error
= LogicalPartitionCreationChecks(PartitionList
);
1695 if (Error
!= NOT_AN_ERROR
)
1697 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1698 return SELECT_PARTITION_PAGE
;
1701 return CREATE_LOGICAL_PARTITION_PAGE
;
1704 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1706 WCHAR PathBuffer
[MAX_PATH
];
1707 UNICODE_STRING CurrentPartition
;
1709 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1711 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1712 return SELECT_PARTITION_PAGE
;
1715 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1716 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1717 PartitionList
->CurrentDisk
->DiskNumber
,
1718 PartitionList
->CurrentPartition
->PartitionNumber
);
1719 RtlInitUnicodeString(&CurrentPartition
, PathBuffer
);
1722 * Check whether the user attempts to delete the partition on which
1723 * the installation source is present. If so, fail with an error.
1725 // &USetupData.SourceRootPath
1726 if (RtlPrefixUnicodeString(&CurrentPartition
, &USetupData
.SourcePath
, TRUE
))
1728 PopupError("You cannot delete the partition containing the installation source!",
1729 MUIGetString(STRING_CONTINUE
),
1730 Ir
, POPUP_WAIT_ENTER
);
1731 return SELECT_PARTITION_PAGE
;
1734 if (PartitionList
->CurrentPartition
->BootIndicator
||
1735 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1737 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1740 return DELETE_PARTITION_PAGE
;
1744 return SELECT_PARTITION_PAGE
;
1748 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1749 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1750 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1753 ShowPartitionSizeInputBox(SHORT Left
,
1777 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1782 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1783 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1786 WriteConsoleOutputCharacterA(StdOutput
,
1792 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1793 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1795 WriteConsoleOutputCharacterA(StdOutput
,
1801 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1802 Length
= wcslen(InputBuffer
);
1804 CONSOLE_SetInputTextXY(iLeft
,
1806 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1808 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1809 CONSOLE_SetCursorType(TRUE
, TRUE
);
1813 CONSOLE_ConInKey(&Ir
);
1815 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1816 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1821 InputBuffer
[0] = UNICODE_NULL
;
1822 CONSOLE_SetCursorType(TRUE
, FALSE
);
1825 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1827 CONSOLE_SetCursorType(TRUE
, FALSE
);
1830 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1835 InputBuffer
[0] = UNICODE_NULL
;
1836 CONSOLE_SetCursorType(TRUE
, FALSE
);
1839 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1840 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1843 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1845 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1846 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1849 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1851 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1852 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1857 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1860 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1861 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1866 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1869 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1870 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1874 memmove(&InputBuffer
[Pos
],
1875 &InputBuffer
[Pos
+ 1],
1876 (Length
- Pos
- 1) * sizeof(WCHAR
));
1877 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1880 CONSOLE_SetInputTextXY(iLeft
,
1882 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1884 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1887 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1892 memmove(&InputBuffer
[Pos
- 1],
1894 (Length
- Pos
) * sizeof(WCHAR
));
1895 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1899 CONSOLE_SetInputTextXY(iLeft
,
1901 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1903 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1906 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1908 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1910 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1912 if ((ch
>= L
'0') && (ch
<= L
'9'))
1915 memmove(&InputBuffer
[Pos
+ 1],
1917 (Length
- Pos
) * sizeof(WCHAR
));
1918 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1919 InputBuffer
[Pos
] = ch
;
1923 CONSOLE_SetInputTextXY(iLeft
,
1925 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1927 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1936 * Displays the CreatePrimaryPartitionPage.
1939 * SelectPartitionPage
1940 * SelectFileSystemPage (default)
1944 * Number of the next page.
1947 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1949 PDISKENTRY DiskEntry
;
1950 PPARTENTRY PartEntry
;
1953 WCHAR InputBuffer
[50];
1957 ULONGLONG SectorCount
;
1960 if (PartitionList
== NULL
||
1961 PartitionList
->CurrentDisk
== NULL
||
1962 PartitionList
->CurrentPartition
== NULL
)
1964 /* FIXME: show an error dialog */
1968 DiskEntry
= PartitionList
->CurrentDisk
;
1969 PartEntry
= PartitionList
->CurrentPartition
;
1971 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1973 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1975 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1977 if (DiskSize
>= 10 * GB
) /* 10 GB */
1979 DiskSize
= DiskSize
/ GB
;
1980 Unit
= MUIGetString(STRING_GB
);
1985 DiskSize
= DiskSize
/ MB
;
1989 Unit
= MUIGetString(STRING_MB
);
1992 if (DiskEntry
->DriverName
.Length
> 0)
1994 CONSOLE_PrintTextXY(6, 10,
1995 MUIGetString(STRING_HDINFOPARTCREATE_1
),
1998 DiskEntry
->DiskNumber
,
2002 &DiskEntry
->DriverName
,
2003 DiskEntry
->NoMbr
? "GPT" : "MBR");
2007 CONSOLE_PrintTextXY(6, 10,
2008 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2011 DiskEntry
->DiskNumber
,
2015 DiskEntry
->NoMbr
? "GPT" : "MBR");
2018 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2021 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2022 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2025 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2027 PartEntry
= PartitionList
->CurrentPartition
;
2030 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2032 if (MaxSize
> PARTITION_MAXSIZE
)
2033 MaxSize
= PARTITION_MAXSIZE
;
2035 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2036 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2040 if (ConfirmQuit(Ir
))
2047 return SELECT_PARTITION_PAGE
;
2051 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2059 if (PartSize
> MaxSize
)
2065 /* Convert to bytes */
2066 if (PartSize
== MaxSize
)
2068 /* Use all of the unpartitioned disk space */
2069 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2073 /* Calculate the sector count from the size in MB */
2074 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2076 /* But never get larger than the unpartitioned disk space */
2077 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2078 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2081 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2083 CreatePrimaryPartition(PartitionList
,
2087 return SELECT_PARTITION_PAGE
;
2091 return CREATE_PRIMARY_PARTITION_PAGE
;
2096 * Displays the CreateExtendedPartitionPage.
2099 * SelectPartitionPage (default)
2103 * Number of the next page.
2106 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2108 PDISKENTRY DiskEntry
;
2109 PPARTENTRY PartEntry
;
2112 WCHAR InputBuffer
[50];
2116 ULONGLONG SectorCount
;
2119 if (PartitionList
== NULL
||
2120 PartitionList
->CurrentDisk
== NULL
||
2121 PartitionList
->CurrentPartition
== NULL
)
2123 /* FIXME: show an error dialog */
2127 DiskEntry
= PartitionList
->CurrentDisk
;
2128 PartEntry
= PartitionList
->CurrentPartition
;
2130 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2132 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2134 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2136 if (DiskSize
>= 10 * GB
) /* 10 GB */
2138 DiskSize
= DiskSize
/ GB
;
2139 Unit
= MUIGetString(STRING_GB
);
2144 DiskSize
= DiskSize
/ MB
;
2148 Unit
= MUIGetString(STRING_MB
);
2151 if (DiskEntry
->DriverName
.Length
> 0)
2153 CONSOLE_PrintTextXY(6, 10,
2154 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2157 DiskEntry
->DiskNumber
,
2161 &DiskEntry
->DriverName
,
2162 DiskEntry
->NoMbr
? "GPT" : "MBR");
2166 CONSOLE_PrintTextXY(6, 10,
2167 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2170 DiskEntry
->DiskNumber
,
2174 DiskEntry
->NoMbr
? "GPT" : "MBR");
2177 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2180 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2181 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2184 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2186 PartEntry
= PartitionList
->CurrentPartition
;
2189 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2191 if (MaxSize
> PARTITION_MAXSIZE
)
2192 MaxSize
= PARTITION_MAXSIZE
;
2194 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2195 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2199 if (ConfirmQuit(Ir
))
2206 return SELECT_PARTITION_PAGE
;
2210 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2218 if (PartSize
> MaxSize
)
2224 /* Convert to bytes */
2225 if (PartSize
== MaxSize
)
2227 /* Use all of the unpartitioned disk space */
2228 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2232 /* Calculate the sector count from the size in MB */
2233 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2235 /* But never get larger than the unpartitioned disk space */
2236 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2237 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2240 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2242 CreateExtendedPartition(PartitionList
,
2245 return SELECT_PARTITION_PAGE
;
2249 return CREATE_EXTENDED_PARTITION_PAGE
;
2254 * Displays the CreateLogicalPartitionPage.
2257 * SelectFileSystemPage (default)
2261 * Number of the next page.
2264 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2266 PDISKENTRY DiskEntry
;
2267 PPARTENTRY PartEntry
;
2270 WCHAR InputBuffer
[50];
2274 ULONGLONG SectorCount
;
2277 if (PartitionList
== NULL
||
2278 PartitionList
->CurrentDisk
== NULL
||
2279 PartitionList
->CurrentPartition
== NULL
)
2281 /* FIXME: show an error dialog */
2285 DiskEntry
= PartitionList
->CurrentDisk
;
2286 PartEntry
= PartitionList
->CurrentPartition
;
2288 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2290 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2292 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2294 if (DiskSize
>= 10 * GB
) /* 10 GB */
2296 DiskSize
= DiskSize
/ GB
;
2297 Unit
= MUIGetString(STRING_GB
);
2302 DiskSize
= DiskSize
/ MB
;
2306 Unit
= MUIGetString(STRING_MB
);
2309 if (DiskEntry
->DriverName
.Length
> 0)
2311 CONSOLE_PrintTextXY(6, 10,
2312 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2315 DiskEntry
->DiskNumber
,
2319 &DiskEntry
->DriverName
,
2320 DiskEntry
->NoMbr
? "GPT" : "MBR");
2324 CONSOLE_PrintTextXY(6, 10,
2325 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2328 DiskEntry
->DiskNumber
,
2332 DiskEntry
->NoMbr
? "GPT" : "MBR");
2335 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2338 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2339 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2342 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2344 PartEntry
= PartitionList
->CurrentPartition
;
2347 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2349 if (MaxSize
> PARTITION_MAXSIZE
)
2350 MaxSize
= PARTITION_MAXSIZE
;
2352 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2353 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2357 if (ConfirmQuit(Ir
))
2364 return SELECT_PARTITION_PAGE
;
2368 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2376 if (PartSize
> MaxSize
)
2382 /* Convert to bytes */
2383 if (PartSize
== MaxSize
)
2385 /* Use all of the unpartitioned disk space */
2386 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2390 /* Calculate the sector count from the size in MB */
2391 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2393 /* But never get larger than the unpartitioned disk space */
2394 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2395 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2398 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2400 CreateLogicalPartition(PartitionList
,
2404 return SELECT_PARTITION_PAGE
;
2408 return CREATE_LOGICAL_PARTITION_PAGE
;
2413 * Displays the ConfirmDeleteSystemPartitionPage.
2416 * DeletePartitionPage (default)
2417 * SelectPartitionPage
2420 * Number of the next page.
2423 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2425 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2429 CONSOLE_ConInKey(Ir
);
2431 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2432 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2434 if (ConfirmQuit(Ir
))
2439 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2441 return DELETE_PARTITION_PAGE
;
2443 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2445 return SELECT_PARTITION_PAGE
;
2449 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2454 * Displays the DeletePartitionPage.
2457 * SelectPartitionPage (default)
2461 * Number of the next page.
2464 DeletePartitionPage(PINPUT_RECORD Ir
)
2466 PDISKENTRY DiskEntry
;
2467 PPARTENTRY PartEntry
;
2471 CHAR PartTypeString
[32];
2473 if (PartitionList
== NULL
||
2474 PartitionList
->CurrentDisk
== NULL
||
2475 PartitionList
->CurrentPartition
== NULL
)
2477 /* FIXME: show an error dialog */
2481 DiskEntry
= PartitionList
->CurrentDisk
;
2482 PartEntry
= PartitionList
->CurrentPartition
;
2484 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2486 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2488 ARRAYSIZE(PartTypeString
));
2490 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2492 if (PartSize
>= 10 * GB
) /* 10 GB */
2494 PartSize
= PartSize
/ GB
;
2495 Unit
= MUIGetString(STRING_GB
);
2499 if (PartSize
>= 10 * MB
) /* 10 MB */
2501 PartSize
= PartSize
/ MB
;
2502 Unit
= MUIGetString(STRING_MB
);
2506 PartSize
= PartSize
/ KB
;
2507 Unit
= MUIGetString(STRING_KB
);
2510 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2512 CONSOLE_PrintTextXY(6, 10,
2513 MUIGetString(STRING_HDDINFOUNK2
),
2514 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2515 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2516 PartEntry
->PartitionType
,
2522 CONSOLE_PrintTextXY(6, 10,
2523 " %c%c %s %I64u %s",
2524 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2525 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2531 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2533 if (DiskSize
>= 10 * GB
) /* 10 GB */
2535 DiskSize
= DiskSize
/ GB
;
2536 Unit
= MUIGetString(STRING_GB
);
2541 DiskSize
= DiskSize
/ MB
;
2545 Unit
= MUIGetString(STRING_MB
);
2548 if (DiskEntry
->DriverName
.Length
> 0)
2550 CONSOLE_PrintTextXY(6, 12,
2551 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2554 DiskEntry
->DiskNumber
,
2558 &DiskEntry
->DriverName
,
2559 DiskEntry
->NoMbr
? "GPT" : "MBR");
2563 CONSOLE_PrintTextXY(6, 12,
2564 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2567 DiskEntry
->DiskNumber
,
2571 DiskEntry
->NoMbr
? "GPT" : "MBR");
2576 CONSOLE_ConInKey(Ir
);
2578 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2579 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2581 if (ConfirmQuit(Ir
))
2586 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2588 return SELECT_PARTITION_PAGE
;
2590 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2592 DeleteCurrentPartition(PartitionList
);
2594 return SELECT_PARTITION_PAGE
;
2598 return DELETE_PARTITION_PAGE
;
2603 * Displays the SelectFileSystemPage.
2606 * CheckFileSystemPage (At once if RepairUpdate is selected)
2607 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2608 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2609 * SelectPartitionPage (If the user aborts)
2610 * FormatPartitionPage (Default)
2614 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2615 * Calls CheckActiveSystemPartition()
2618 * Number of the next page.
2621 SelectFileSystemPage(PINPUT_RECORD Ir
)
2623 PDISKENTRY DiskEntry
;
2624 PPARTENTRY PartEntry
;
2629 CHAR PartTypeString
[32];
2630 FORMATMACHINESTATE PreviousFormatState
;
2632 DPRINT("SelectFileSystemPage()\n");
2634 if (PartitionList
== NULL
||
2635 PartitionList
->CurrentDisk
== NULL
||
2636 PartitionList
->CurrentPartition
== NULL
)
2638 /* FIXME: show an error dialog */
2642 /* Find or set the active system partition */
2643 CheckActiveSystemPartition(PartitionList
);
2644 if (PartitionList
->SystemPartition
== NULL
)
2646 /* FIXME: show an error dialog */
2648 // Error dialog should say that we cannot find a suitable
2649 // system partition and create one on the system. At this point,
2650 // it may be nice to ask the user whether he wants to continue,
2651 // or use an external drive as the system drive/partition
2652 // (e.g. floppy, USB drive, etc...)
2657 PreviousFormatState
= FormatState
;
2658 switch (FormatState
)
2662 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2664 TempPartition
= PartitionList
->SystemPartition
;
2665 TempPartition
->NeedsCheck
= TRUE
;
2667 FormatState
= FormatSystemPartition
;
2668 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2672 TempPartition
= PartitionList
->CurrentPartition
;
2673 TempPartition
->NeedsCheck
= TRUE
;
2675 FormatState
= FormatInstallPartition
;
2676 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2681 case FormatSystemPartition
:
2683 TempPartition
= PartitionList
->CurrentPartition
;
2684 TempPartition
->NeedsCheck
= TRUE
;
2686 FormatState
= FormatInstallPartition
;
2687 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2691 case FormatInstallPartition
:
2693 if (GetNextUnformattedPartition(PartitionList
,
2697 FormatState
= FormatOtherPartition
;
2698 TempPartition
->NeedsCheck
= TRUE
;
2699 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2703 FormatState
= FormatDone
;
2704 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2705 return CHECK_FILE_SYSTEM_PAGE
;
2710 case FormatOtherPartition
:
2712 if (GetNextUnformattedPartition(PartitionList
,
2716 FormatState
= FormatOtherPartition
;
2717 TempPartition
->NeedsCheck
= TRUE
;
2718 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2722 FormatState
= FormatDone
;
2723 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2724 return CHECK_FILE_SYSTEM_PAGE
;
2731 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2732 /* FIXME: show an error dialog */
2737 PartEntry
= TempPartition
;
2738 DiskEntry
= PartEntry
->DiskEntry
;
2740 /* Adjust disk size */
2741 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2742 if (DiskSize
>= 10 * GB
) /* 10 GB */
2744 DiskSize
= DiskSize
/ GB
;
2745 DiskUnit
= MUIGetString(STRING_GB
);
2749 DiskSize
= DiskSize
/ MB
;
2750 DiskUnit
= MUIGetString(STRING_MB
);
2753 /* Adjust partition size */
2754 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2755 if (PartSize
>= 10 * GB
) /* 10 GB */
2757 PartSize
= PartSize
/ GB
;
2758 PartUnit
= MUIGetString(STRING_GB
);
2762 PartSize
= PartSize
/ MB
;
2763 PartUnit
= MUIGetString(STRING_MB
);
2766 /* Adjust partition type */
2767 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2769 ARRAYSIZE(PartTypeString
));
2771 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2773 if (PartEntry
->AutoCreate
)
2775 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2778 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2779 PartEntry
->PartitionNumber
,
2785 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2786 DiskEntry
->DiskNumber
,
2792 &DiskEntry
->DriverName
,
2793 DiskEntry
->NoMbr
? "GPT" : "MBR");
2795 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2797 PartEntry
->AutoCreate
= FALSE
;
2799 else if (PartEntry
->New
)
2801 switch (FormatState
)
2803 case FormatSystemPartition
:
2804 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2807 case FormatInstallPartition
:
2808 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2811 case FormatOtherPartition
:
2812 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2819 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2823 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2825 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2827 CONSOLE_PrintTextXY(8, 10,
2828 MUIGetString(STRING_HDDINFOUNK4
),
2829 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2830 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2831 PartEntry
->PartitionType
,
2837 CONSOLE_PrintTextXY(8, 10,
2839 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2840 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2846 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2847 DiskEntry
->DiskNumber
,
2853 &DiskEntry
->DriverName
,
2854 DiskEntry
->NoMbr
? "GPT" : "MBR");
2857 if (FileSystemList
== NULL
)
2859 /* Create the file system list, and by default select the "FAT" file system */
2860 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2861 if (FileSystemList
== NULL
)
2863 /* FIXME: show an error dialog */
2868 if (RepairUpdateFlag
)
2870 return CHECK_FILE_SYSTEM_PAGE
;
2871 //return SELECT_PARTITION_PAGE;
2874 if (IsUnattendedSetup
)
2876 if (USetupData
.FormatPartition
)
2879 * We use whatever currently selected file system we have
2880 * (by default, this is "FAT", as per the initialization
2881 * performed above). Note that it may be interesting to specify
2882 * which file system to use in unattended installations, in the
2883 * txtsetup.sif file.
2885 return FORMAT_PARTITION_PAGE
;
2888 return CHECK_FILE_SYSTEM_PAGE
;
2891 DrawFileSystemList(FileSystemList
);
2895 CONSOLE_ConInKey(Ir
);
2897 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2898 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2900 if (ConfirmQuit(Ir
))
2905 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2906 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2908 FormatState
= Start
;
2909 return SELECT_PARTITION_PAGE
;
2911 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2912 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2914 ScrollDownFileSystemList(FileSystemList
);
2916 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2917 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2919 ScrollUpFileSystemList(FileSystemList
);
2921 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2923 if (!FileSystemList
->Selected
->FileSystem
)
2924 return SELECT_FILE_SYSTEM_PAGE
;
2926 return FORMAT_PARTITION_PAGE
;
2930 FormatState
= PreviousFormatState
;
2932 return SELECT_FILE_SYSTEM_PAGE
;
2937 * Displays the FormatPartitionPage.
2940 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2941 * SelectPartitionPage (At once)
2945 * Sets PartitionList->CurrentPartition->FormatState
2946 * Sets USetupData.DestinationRootPath
2949 * Number of the next page.
2952 FormatPartitionPage(PINPUT_RECORD Ir
)
2955 PDISKENTRY DiskEntry
;
2956 PPARTENTRY PartEntry
;
2957 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2958 UNICODE_STRING PartitionRootPath
;
2959 WCHAR PathBuffer
[MAX_PATH
];
2960 CHAR Buffer
[MAX_PATH
];
2965 PPARTITION_INFORMATION PartitionInfo
;
2968 DPRINT("FormatPartitionPage()\n");
2970 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2972 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2974 /* FIXME: show an error dialog */
2978 PartEntry
= TempPartition
;
2979 DiskEntry
= PartEntry
->DiskEntry
;
2981 SelectedFileSystem
= FileSystemList
->Selected
;
2985 if (!IsUnattendedSetup
)
2987 CONSOLE_ConInKey(Ir
);
2990 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2991 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2993 if (ConfirmQuit(Ir
))
2998 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3000 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3002 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3004 /* FIXME: show an error dialog */
3009 CONSOLE_PrintTextXY(6, 12,
3010 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3011 DiskEntry
->Cylinders
,
3012 DiskEntry
->TracksPerCylinder
,
3013 DiskEntry
->SectorsPerTrack
,
3014 DiskEntry
->BytesPerSector
,
3015 DiskEntry
->Dirty
? '*' : ' ');
3019 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3021 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3023 CONSOLE_PrintTextXY(6, Line
,
3024 "%2u: %2lu %c %12I64u %12I64u %02x",
3026 PartitionInfo
->PartitionNumber
,
3027 PartitionInfo
->BootIndicator
? 'A' : '-',
3028 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3029 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3030 PartitionInfo
->PartitionType
);
3035 /* Commit the partition changes to the disk */
3036 if (!WritePartitionsToDisk(PartitionList
))
3038 DPRINT("WritePartitionsToDisk() failed\n");
3039 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3043 /* Set PartitionRootPath */
3044 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3045 L
"\\Device\\Harddisk%lu\\Partition%lu",
3046 DiskEntry
->DiskNumber
,
3047 PartEntry
->PartitionNumber
);
3048 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3049 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3051 /* Format the partition */
3052 if (SelectedFileSystem
->FileSystem
)
3054 Status
= FormatPartition(&PartitionRootPath
,
3055 SelectedFileSystem
);
3056 if (Status
== STATUS_NOT_SUPPORTED
)
3059 "Setup is currently unable to format a partition in %S.\n"
3061 " \x07 Press ENTER to continue Setup.\n"
3062 " \x07 Press F3 to quit Setup.",
3063 SelectedFileSystem
->FileSystem
->FileSystemName
);
3066 MUIGetString(STRING_QUITCONTINUE
),
3067 NULL
, POPUP_WAIT_NONE
);
3071 CONSOLE_ConInKey(Ir
);
3073 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3074 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3076 if (ConfirmQuit(Ir
))
3079 return SELECT_FILE_SYSTEM_PAGE
;
3081 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3083 return SELECT_FILE_SYSTEM_PAGE
;
3087 else if (!NT_SUCCESS(Status
))
3089 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3090 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3094 PartEntry
->FormatState
= Formatted
;
3095 // PartEntry->FileSystem = FileSystem;
3096 PartEntry
->New
= FALSE
;
3100 CONSOLE_SetStatusText(" Done. Press any key ...");
3101 CONSOLE_ConInKey(Ir
);
3104 return SELECT_FILE_SYSTEM_PAGE
;
3108 return FORMAT_PARTITION_PAGE
;
3113 * Displays the CheckFileSystemPage.
3116 * InstallDirectoryPage (At once)
3120 * Inits or reloads FileSystemList
3123 * Number of the next page.
3126 CheckFileSystemPage(PINPUT_RECORD Ir
)
3129 PDISKENTRY DiskEntry
;
3130 PPARTENTRY PartEntry
;
3131 PFILE_SYSTEM CurrentFileSystem
;
3132 UNICODE_STRING PartitionRootPath
;
3133 WCHAR PathBuffer
[MAX_PATH
];
3134 CHAR Buffer
[MAX_PATH
];
3136 if (PartitionList
== NULL
)
3138 /* FIXME: show an error dialog */
3142 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3144 return INSTALL_DIRECTORY_PAGE
;
3147 /* Set PartitionRootPath */
3148 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3149 L
"\\Device\\Harddisk%lu\\Partition%lu",
3150 DiskEntry
->DiskNumber
,
3151 PartEntry
->PartitionNumber
);
3152 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3153 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3155 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3157 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3159 CurrentFileSystem
= PartEntry
->FileSystem
;
3160 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3161 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3163 /* HACK: Do not try to check a partition with an unknown filesystem */
3164 if (CurrentFileSystem
== NULL
)
3166 PartEntry
->NeedsCheck
= FALSE
;
3167 return CHECK_FILE_SYSTEM_PAGE
;
3170 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3171 if (Status
== STATUS_NOT_SUPPORTED
)
3174 "Setup is currently unable to check a partition formatted in %S.\n"
3176 " \x07 Press ENTER to continue Setup.\n"
3177 " \x07 Press F3 to quit Setup.",
3178 CurrentFileSystem
->FileSystemName
);
3181 MUIGetString(STRING_QUITCONTINUE
),
3182 NULL
, POPUP_WAIT_NONE
);
3186 CONSOLE_ConInKey(Ir
);
3188 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3189 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3191 if (ConfirmQuit(Ir
))
3194 return CHECK_FILE_SYSTEM_PAGE
;
3196 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3198 PartEntry
->NeedsCheck
= FALSE
;
3199 return CHECK_FILE_SYSTEM_PAGE
;
3203 else if (!NT_SUCCESS(Status
))
3205 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3206 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3207 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3208 "(Status 0x%08lx).\n", Status
);
3210 // MUIGetString(STRING_REBOOTCOMPUTER),
3211 MUIGetString(STRING_CONTINUE
),
3212 Ir
, POPUP_WAIT_ENTER
);
3214 // return QUIT_PAGE;
3217 PartEntry
->NeedsCheck
= FALSE
;
3218 return CHECK_FILE_SYSTEM_PAGE
;
3223 BuildInstallPaths(PWSTR InstallDir
,
3224 PDISKENTRY DiskEntry
,
3225 PPARTENTRY PartEntry
)
3227 WCHAR PathBuffer
[MAX_PATH
];
3229 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3230 /* Create 'InstallPath' string */
3231 RtlFreeUnicodeString(&InstallPath
);
3232 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3234 /* Create 'USetupData.DestinationRootPath' string */
3235 RtlFreeUnicodeString(&USetupData
.DestinationRootPath
);
3236 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3237 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3238 DiskEntry
->DiskNumber
,
3239 PartEntry
->PartitionNumber
);
3240 RtlCreateUnicodeString(&USetupData
.DestinationRootPath
, PathBuffer
);
3241 DPRINT("DestinationRootPath: %wZ\n", &USetupData
.DestinationRootPath
);
3243 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3244 /* Create 'USetupData.DestinationPath' string */
3245 RtlFreeUnicodeString(&USetupData
.DestinationPath
);
3246 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3247 USetupData
.DestinationRootPath
.Buffer
, InstallDir
);
3248 RtlCreateUnicodeString(&USetupData
.DestinationPath
, PathBuffer
);
3250 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3251 /* Create 'USetupData.DestinationArcPath' */
3252 RtlFreeUnicodeString(&USetupData
.DestinationArcPath
);
3253 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3254 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3255 DiskEntry
->BiosDiskNumber
,
3256 PartEntry
->PartitionNumber
);
3257 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3258 RtlCreateUnicodeString(&USetupData
.DestinationArcPath
, PathBuffer
);
3260 /* Initialize DestinationDriveLetter */
3261 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3267 IN PCWSTR InstallDir
)
3271 Length
= wcslen(InstallDir
);
3273 // TODO: Add check for 8.3 too.
3275 /* Path must be at least 2 characters long */
3279 /* Path must start with a backslash */
3280 // if (InstallDir[0] != L'\\')
3283 /* Path must not end with a backslash */
3284 if (InstallDir
[Length
- 1] == L
'\\')
3287 /* Path must not contain whitespace characters */
3288 for (i
= 0; i
< Length
; i
++)
3290 if (iswspace(InstallDir
[i
]))
3294 /* Path component must not end with a dot */
3295 for (i
= 0; i
< Length
; i
++)
3297 if (InstallDir
[i
] == L
'\\' && i
> 0)
3299 if (InstallDir
[i
- 1] == L
'.')
3304 if (InstallDir
[Length
- 1] == L
'.')
3312 * Displays the InstallDirectoryPage.
3319 * Number of the next page.
3322 InstallDirectoryPage(PINPUT_RECORD Ir
)
3324 PDISKENTRY DiskEntry
;
3325 PPARTENTRY PartEntry
;
3326 WCHAR InstallDir
[MAX_PATH
];
3330 /* We do not need the filesystem list anymore */
3331 if (FileSystemList
!= NULL
)
3333 DestroyFileSystemList(FileSystemList
);
3334 FileSystemList
= NULL
;
3337 if (PartitionList
== NULL
||
3338 PartitionList
->CurrentDisk
== NULL
||
3339 PartitionList
->CurrentPartition
== NULL
)
3341 /* FIXME: show an error dialog */
3345 DiskEntry
= PartitionList
->CurrentDisk
;
3346 PartEntry
= PartitionList
->CurrentPartition
;
3348 // if (IsUnattendedSetup)
3349 if (RepairUpdateFlag
)
3350 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3351 else if (USetupData
.InstallationDirectory
[0])
3352 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3354 wcscpy(InstallDir
, L
"\\ReactOS");
3357 * Check the validity of the predefined 'InstallDir'. If we are either
3358 * in unattended setup or in update/repair mode, and the installation path
3359 * is valid, just perform the installation. Otherwise (either in the case
3360 * of an invalid path, or we are in regular setup), display the UI and allow
3361 * the user to specify a new installation path.
3363 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3365 BuildInstallPaths(InstallDir
,
3370 * Check whether the user attempts to install ReactOS within the
3371 * installation source directory, or in a subdirectory thereof.
3372 * If so, fail with an error.
3374 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3376 PopupError("You cannot install ReactOS within the installation source directory!",
3377 MUIGetString(STRING_CONTINUE
),
3378 Ir
, POPUP_WAIT_ENTER
);
3379 return INSTALL_DIRECTORY_PAGE
;
3382 return PREPARE_COPY_PAGE
;
3385 Length
= wcslen(InstallDir
);
3388 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3389 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3390 CONSOLE_SetCursorXY(8 + Pos
, 11);
3391 CONSOLE_SetCursorType(TRUE
, TRUE
);
3395 CONSOLE_ConInKey(Ir
);
3397 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3398 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3400 CONSOLE_SetCursorType(TRUE
, FALSE
);
3402 if (ConfirmQuit(Ir
))
3405 CONSOLE_SetCursorType(TRUE
, TRUE
);
3408 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3409 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3413 memmove(&InstallDir
[Pos
],
3414 &InstallDir
[Pos
+ 1],
3415 (Length
- Pos
- 1) * sizeof(WCHAR
));
3416 InstallDir
[Length
- 1] = UNICODE_NULL
;
3419 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3420 CONSOLE_SetCursorXY(8 + Pos
, 11);
3423 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3424 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3427 CONSOLE_SetCursorXY(8 + Pos
, 11);
3429 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3430 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3433 CONSOLE_SetCursorXY(8 + Pos
, 11);
3435 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3436 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3441 CONSOLE_SetCursorXY(8 + Pos
, 11);
3444 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3445 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3450 CONSOLE_SetCursorXY(8 + Pos
, 11);
3453 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3455 CONSOLE_SetCursorType(TRUE
, FALSE
);
3458 * Check for the validity of the installation directory and pop up
3459 * an error if it is not the case. Then the user can fix its input.
3461 if (!IsValidPath(InstallDir
))
3463 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3464 return INSTALL_DIRECTORY_PAGE
;
3467 BuildInstallPaths(InstallDir
,
3472 * Check whether the user attempts to install ReactOS within the
3473 * installation source directory, or in a subdirectory thereof.
3474 * If so, fail with an error.
3476 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3478 PopupError("You cannot install ReactOS within the installation source directory!",
3479 MUIGetString(STRING_CONTINUE
),
3480 Ir
, POPUP_WAIT_ENTER
);
3481 return INSTALL_DIRECTORY_PAGE
;
3484 return PREPARE_COPY_PAGE
;
3486 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3491 memmove(&InstallDir
[Pos
- 1],
3493 (Length
- Pos
) * sizeof(WCHAR
));
3494 InstallDir
[Length
- 1] = UNICODE_NULL
;
3498 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3499 CONSOLE_SetCursorXY(8 + Pos
, 11);
3502 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3506 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3507 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3510 memmove(&InstallDir
[Pos
+ 1],
3512 (Length
- Pos
) * sizeof(WCHAR
));
3513 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3514 InstallDir
[Pos
] = c
;
3518 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3519 CONSOLE_SetCursorXY(8 + Pos
, 11);
3525 return INSTALL_DIRECTORY_PAGE
;
3530 AddSectionToCopyQueueCab(HINF InfFile
,
3532 PWCHAR SourceCabinet
,
3533 PCUNICODE_STRING DestinationPath
,
3536 INFCONTEXT FilesContext
;
3537 INFCONTEXT DirContext
;
3539 PWCHAR FileKeyValue
;
3541 PWCHAR TargetFileName
;
3544 * This code enumerates the list of files in reactos.dff / reactos.inf
3545 * that need to be extracted from reactos.cab and be installed in their
3546 * respective directories.
3549 /* Search for the SectionName section */
3550 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3552 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3557 * Enumerate the files in the section and add them to the file queue.
3561 /* Get source file name and target directory id */
3562 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3564 /* FIXME: Handle error! */
3565 DPRINT1("INF_GetData() failed\n");
3569 /* Get optional target file name */
3570 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3571 TargetFileName
= NULL
;
3573 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3575 /* Lookup target directory */
3576 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3578 /* FIXME: Handle error! */
3579 DPRINT1("SetupFindFirstLine() failed\n");
3580 INF_FreeData(FileKeyName
);
3581 INF_FreeData(FileKeyValue
);
3582 INF_FreeData(TargetFileName
);
3586 INF_FreeData(FileKeyValue
);
3588 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3590 /* FIXME: Handle error! */
3591 DPRINT1("INF_GetData() failed\n");
3592 INF_FreeData(FileKeyName
);
3593 INF_FreeData(TargetFileName
);
3597 if (!SetupQueueCopy(SetupFileQueue
,
3599 USetupData
.SourceRootPath
.Buffer
,
3600 USetupData
.SourceRootDir
.Buffer
,
3605 /* FIXME: Handle error! */
3606 DPRINT1("SetupQueueCopy() failed\n");
3609 INF_FreeData(FileKeyName
);
3610 INF_FreeData(TargetFileName
);
3611 INF_FreeData(DirKeyValue
);
3612 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3619 AddSectionToCopyQueue(HINF InfFile
,
3621 PWCHAR SourceCabinet
,
3622 PCUNICODE_STRING DestinationPath
,
3625 INFCONTEXT FilesContext
;
3626 INFCONTEXT DirContext
;
3628 PWCHAR FileKeyValue
;
3630 PWCHAR TargetFileName
;
3631 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3634 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3637 * This code enumerates the list of files in txtsetup.sif
3638 * that need to be installed in their respective directories.
3641 /* Search for the SectionName section */
3642 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3644 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3649 * Enumerate the files in the section and add them to the file queue.
3653 /* Get source file name */
3654 if (!INF_GetDataField(&FilesContext
, 0, &FileKeyName
))
3656 /* FIXME: Handle error! */
3657 DPRINT1("INF_GetData() failed\n");
3661 /* Get target directory id */
3662 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3664 /* FIXME: Handle error! */
3665 DPRINT1("INF_GetData() failed\n");
3666 INF_FreeData(FileKeyName
);
3670 /* Get optional target file name */
3671 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3672 TargetFileName
= NULL
;
3673 else if (!*TargetFileName
)
3674 TargetFileName
= NULL
;
3676 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3678 /* Lookup target directory */
3679 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3681 /* FIXME: Handle error! */
3682 DPRINT1("SetupFindFirstLine() failed\n");
3683 INF_FreeData(FileKeyName
);
3684 INF_FreeData(FileKeyValue
);
3685 INF_FreeData(TargetFileName
);
3689 INF_FreeData(FileKeyValue
);
3691 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3693 /* FIXME: Handle error! */
3694 DPRINT1("INF_GetData() failed\n");
3695 INF_FreeData(FileKeyName
);
3696 INF_FreeData(TargetFileName
);
3700 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3702 /* Installation path */
3703 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3705 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3706 USetupData
.SourceRootDir
.Buffer
);
3708 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3710 else if (DirKeyValue
[0] == L
'\\')
3713 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3715 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3718 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3720 else // if (DirKeyValue[0] != L'\\')
3722 /* Path relative to the installation path */
3723 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3725 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3726 USetupData
.SourceRootDir
.Buffer
, DirKeyValue
);
3728 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3731 if (!SetupQueueCopy(SetupFileQueue
,
3733 USetupData
.SourceRootPath
.Buffer
,
3734 CompleteOrigDirName
,
3739 /* FIXME: Handle error! */
3740 DPRINT1("SetupQueueCopy() failed\n");
3743 INF_FreeData(FileKeyName
);
3744 INF_FreeData(TargetFileName
);
3745 INF_FreeData(DirKeyValue
);
3746 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3753 PrepareCopyPageInfFile(HINF InfFile
,
3754 PWCHAR SourceCabinet
,
3758 INFCONTEXT DirContext
;
3759 PWCHAR AdditionalSectionName
= NULL
;
3761 WCHAR PathBuffer
[MAX_PATH
];
3763 /* Add common files */
3764 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3767 /* Add specific files depending of computer type */
3768 if (SourceCabinet
== NULL
)
3770 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3773 if (AdditionalSectionName
)
3775 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3780 /* Create directories */
3784 * Copying files to USetupData.DestinationRootPath should be done from within
3785 * the SystemPartitionFiles section.
3786 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3787 * For installing to USetupData.DestinationPath specify just '\' .
3790 /* Get destination path */
3791 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), USetupData
.DestinationPath
.Buffer
);
3793 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3795 /* Create the install directory */
3796 Status
= SetupCreateDirectory(PathBuffer
);
3797 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3799 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3800 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3804 /* Search for the 'Directories' section */
3805 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3808 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3810 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3815 /* Enumerate the directory values and create the subdirectories */
3818 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3824 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3826 /* Installation path */
3827 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3829 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3830 USetupData
.DestinationPath
.Buffer
);
3832 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3834 else if (DirKeyValue
[0] == L
'\\')
3837 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3839 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3840 USetupData
.DestinationRootPath
.Buffer
, DirKeyValue
);
3842 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3844 Status
= SetupCreateDirectory(PathBuffer
);
3845 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3847 INF_FreeData(DirKeyValue
);
3848 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3849 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3853 else // if (DirKeyValue[0] != L'\\')
3855 /* Path relative to the installation path */
3856 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3858 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3859 USetupData
.DestinationPath
.Buffer
, DirKeyValue
);
3861 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3863 Status
= SetupCreateDirectory(PathBuffer
);
3864 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3866 INF_FreeData(DirKeyValue
);
3867 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3868 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3873 INF_FreeData(DirKeyValue
);
3874 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3881 * Displays the PrepareCopyPage.
3884 * FileCopyPage(At once)
3888 * Inits SetupFileQueue
3889 * Calls PrepareCopyPageInfFile
3892 * Number of the next page.
3895 PrepareCopyPage(PINPUT_RECORD Ir
)
3898 WCHAR PathBuffer
[MAX_PATH
];
3899 INFCONTEXT CabinetsContext
;
3905 MUIDisplayPage(PREPARE_COPY_PAGE
);
3907 /* Create the file queue */
3908 SetupFileQueue
= SetupOpenFileQueue();
3909 if (SetupFileQueue
== NULL
)
3911 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3915 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3917 /* FIXME: show an error dialog */
3921 /* Search for the 'Cabinets' section */
3922 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3924 return FILE_COPY_PAGE
;
3928 * Enumerate the directory values in the 'Cabinets'
3929 * section and parse their inf files.
3933 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3936 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3937 USetupData
.SourcePath
.Buffer
, KeyValue
);
3939 CabinetInitialize();
3940 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3941 CabinetSetCabinetName(PathBuffer
);
3943 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3945 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3947 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3948 if (InfFileData
== NULL
)
3950 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3956 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3957 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3961 InfHandle
= INF_OpenBufferedFileA((PSTR
)InfFileData
,
3965 USetupData
.LanguageId
,
3968 if (InfHandle
== INVALID_HANDLE_VALUE
)
3970 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3976 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3978 /* FIXME: show an error dialog */
3981 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3983 return FILE_COPY_PAGE
;
3989 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3992 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3994 /* Get the memory information from the system */
3995 NtQuerySystemInformation(SystemPerformanceInformation
,
4000 /* Check if this is initial setup */
4003 /* Set maximum limits to be total RAM pages */
4004 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
4005 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
4006 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
4009 /* Set current values */
4010 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
4011 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
4012 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
4018 FileCopyCallback(PVOID Context
,
4023 PCOPYCONTEXT CopyContext
;
4025 CopyContext
= (PCOPYCONTEXT
)Context
;
4027 switch (Notification
)
4029 case SPFILENOTIFY_STARTSUBQUEUE
:
4030 CopyContext
->TotalOperations
= (ULONG
)Param2
;
4031 ProgressSetStepCount(CopyContext
->ProgressBar
,
4032 CopyContext
->TotalOperations
);
4033 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
4036 case SPFILENOTIFY_STARTCOPY
:
4037 /* Display copy message */
4038 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
4039 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4042 case SPFILENOTIFY_ENDCOPY
:
4043 CopyContext
->CompletedOperations
++;
4045 /* SYSREG checkpoint */
4046 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
4047 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4049 ProgressNextStep(CopyContext
->ProgressBar
);
4050 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4059 * Displays the FileCopyPage.
4062 * RegistryPage(At once)
4065 * Calls SetupCommitFileQueueW
4066 * Calls SetupCloseFileQueue
4069 * Number of the next page.
4072 FileCopyPage(PINPUT_RECORD Ir
)
4074 COPYCONTEXT CopyContext
;
4075 unsigned int mem_bar_width
;
4077 MUIDisplayPage(FILE_COPY_PAGE
);
4079 /* Create context for the copy process */
4080 CopyContext
.DestinationRootPath
= USetupData
.DestinationRootPath
.Buffer
;
4081 CopyContext
.InstallPath
= InstallPath
.Buffer
;
4082 CopyContext
.TotalOperations
= 0;
4083 CopyContext
.CompletedOperations
= 0;
4085 /* Create the progress bar as well */
4086 CopyContext
.ProgressBar
= CreateProgressBar(13,
4093 MUIGetString(STRING_SETUPCOPYINGFILES
));
4095 // fit memory bars to screen width, distribute them uniform
4096 mem_bar_width
= (xScreen
- 26) / 5;
4097 mem_bar_width
-= mem_bar_width
% 2; // make even
4098 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4099 /* Create the paged pool progress bar */
4100 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4109 /* Create the non paged pool progress bar */
4110 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4112 (xScreen
/ 2) + (mem_bar_width
/ 2),
4114 (xScreen
/ 2)- (mem_bar_width
/ 2),
4119 /* Create the global memory progress bar */
4120 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4124 xScreen
- 13 - mem_bar_width
,
4129 /* Do the file copying */
4130 SetupCommitFileQueueW(NULL
,
4135 /* If we get here, we're done, so cleanup the queue and progress bar */
4136 SetupCloseFileQueue(SetupFileQueue
);
4137 DestroyProgressBar(CopyContext
.ProgressBar
);
4138 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4139 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4140 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4142 /* Create the $winnt$.inf file */
4143 InstallSetupInfFile(&USetupData
);
4145 /* Go display the next page */
4146 return REGISTRY_PAGE
;
4152 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4154 /* WARNING: Please keep this lookup table in sync with the resources! */
4155 static const UINT StringIDs
[] =
4157 STRING_DONE
, /* Success */
4158 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4159 STRING_IMPORTFILE
, /* ImportRegHive */
4160 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4161 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4162 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4163 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4164 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4169 if (RegStatus
< ARRAYSIZE(StringIDs
))
4171 va_start(args
, RegStatus
);
4172 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4177 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4182 * Displays the RegistryPage.
4185 * SuccessPage (if RepairUpdate)
4186 * BootLoaderPage (default)
4190 * Calls UpdateRegistry
4193 * Number of the next page.
4196 RegistryPage(PINPUT_RECORD Ir
)
4200 MUIDisplayPage(REGISTRY_PAGE
);
4202 Error
= UpdateRegistry(SetupInf
,
4206 DestinationDriveLetter
,
4212 if (Error
!= ERROR_SUCCESS
)
4214 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4219 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4220 return BOOT_LOADER_PAGE
;
4226 * Displays the BootLoaderPage.
4229 * SuccessPage (if RepairUpdate)
4230 * BootLoaderHarddiskMbrPage
4231 * BootLoaderHarddiskVbrPage
4232 * BootLoaderFloppyPage
4237 * Calls RegInitializeRegistry
4238 * Calls ImportRegistryFile
4239 * Calls SetDefaultPagefile
4240 * Calls SetMountedDeviceValues
4243 * Number of the next page.
4246 BootLoaderPage(PINPUT_RECORD Ir
)
4248 UCHAR PartitionType
;
4249 BOOLEAN InstallOnFloppy
;
4251 WCHAR PathBuffer
[MAX_PATH
];
4253 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4255 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4256 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4257 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4258 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4259 PartitionList
->SystemPartition
->PartitionNumber
);
4260 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4261 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4263 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4265 /* For unattended setup, skip MBR installation or install on floppy if needed */
4266 if (IsUnattendedSetup
)
4268 if ((USetupData
.MBRInstallType
== 0) ||
4269 (USetupData
.MBRInstallType
== 1))
4276 * We may install an MBR or VBR, but before that, check whether
4277 * we need to actually install the VBR on floppy.
4279 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4281 DPRINT("Error: system partition invalid (unused)\n");
4282 InstallOnFloppy
= TRUE
;
4284 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4286 /* OS/2 boot manager partition */
4287 DPRINT("Found OS/2 boot manager partition\n");
4288 InstallOnFloppy
= TRUE
;
4290 else if (PartitionType
== PARTITION_EXT2
)
4292 /* Linux EXT2 partition */
4293 DPRINT("Found Linux EXT2 partition\n");
4294 InstallOnFloppy
= FALSE
;
4296 else if (PartitionType
== PARTITION_IFS
)
4298 /* NTFS partition */
4299 DPRINT("Found NTFS partition\n");
4301 // FIXME: Make it FALSE when we'll support NTFS installation!
4302 InstallOnFloppy
= TRUE
;
4304 else if ((PartitionType
== PARTITION_FAT_12
) ||
4305 (PartitionType
== PARTITION_FAT_16
) ||
4306 (PartitionType
== PARTITION_HUGE
) ||
4307 (PartitionType
== PARTITION_XINT13
) ||
4308 (PartitionType
== PARTITION_FAT32
) ||
4309 (PartitionType
== PARTITION_FAT32_XINT13
))
4311 DPRINT("Found FAT partition\n");
4312 InstallOnFloppy
= FALSE
;
4316 /* Unknown partition */
4317 DPRINT("Unknown partition found\n");
4318 InstallOnFloppy
= TRUE
;
4321 /* We should install on floppy */
4322 if (InstallOnFloppy
)
4324 USetupData
.MBRInstallType
= 1;
4328 /* Is it an unattended install on hdd? */
4329 if (IsUnattendedSetup
)
4331 if ((USetupData
.MBRInstallType
== 2) ||
4332 (USetupData
.MBRInstallType
== 3))
4338 MUIDisplayPage(BOOT_LOADER_PAGE
);
4339 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4343 CONSOLE_ConInKey(Ir
);
4345 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4346 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4348 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4357 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4359 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4360 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4362 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4371 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4373 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4374 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4376 if (ConfirmQuit(Ir
))
4381 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4385 /* Install on both MBR and VBR */
4386 USetupData
.MBRInstallType
= 2;
4389 else if (Line
== 13)
4391 /* Install on VBR only */
4392 USetupData
.MBRInstallType
= 3;
4395 else if (Line
== 14)
4397 /* Install on floppy */
4398 USetupData
.MBRInstallType
= 1;
4401 else if (Line
== 15)
4403 /* Skip MBR installation */
4404 USetupData
.MBRInstallType
= 0;
4408 return BOOT_LOADER_PAGE
;
4413 switch (USetupData
.MBRInstallType
)
4415 /* Skip MBR installation */
4417 return SUCCESS_PAGE
;
4419 /* Install on floppy */
4421 return BOOT_LOADER_FLOPPY_PAGE
;
4423 /* Install on both MBR and VBR */
4425 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4427 /* Install on VBR only */
4429 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4432 return BOOT_LOADER_PAGE
;
4437 * Displays the BootLoaderFloppyPage.
4440 * SuccessPage (At once)
4444 * Calls InstallFatBootcodeToFloppy()
4447 * Number of the next page.
4450 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4454 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4456 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4460 CONSOLE_ConInKey(Ir
);
4462 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4463 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4465 if (ConfirmQuit(Ir
))
4470 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4472 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4473 &USetupData
.DestinationArcPath
);
4474 if (!NT_SUCCESS(Status
))
4476 if (Status
== STATUS_DEVICE_NOT_READY
)
4477 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4479 /* TODO: Print error message */
4480 return BOOT_LOADER_FLOPPY_PAGE
;
4483 return SUCCESS_PAGE
;
4487 return BOOT_LOADER_FLOPPY_PAGE
;
4492 * Displays the BootLoaderHarddiskVbrPage.
4495 * SuccessPage (At once)
4499 * Calls InstallVBRToPartition()
4502 * Number of the next page.
4505 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4509 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4510 &USetupData
.SourceRootPath
,
4511 &USetupData
.DestinationArcPath
,
4512 PartitionList
->SystemPartition
->PartitionType
);
4513 if (!NT_SUCCESS(Status
))
4515 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4519 return SUCCESS_PAGE
;
4524 * Displays the BootLoaderHarddiskMbrPage.
4527 * SuccessPage (At once)
4531 * Calls InstallVBRToPartition()
4532 * Calls InstallMbrBootCodeToDisk()
4535 * Number of the next page.
4538 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4541 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4543 /* Step 1: Write the VBR */
4544 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4545 &USetupData
.SourceRootPath
,
4546 &USetupData
.DestinationArcPath
,
4547 PartitionList
->SystemPartition
->PartitionType
);
4548 if (!NT_SUCCESS(Status
))
4550 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4554 /* Step 2: Write the MBR */
4555 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4556 L
"\\Device\\Harddisk%d\\Partition0",
4557 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4558 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4559 &USetupData
.SourceRootPath
,
4560 DestinationDevicePathBuffer
);
4561 if (!NT_SUCCESS(Status
))
4563 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4564 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4568 return SUCCESS_PAGE
;
4573 * @name ProgressTimeOutStringHandler
4575 * Handles the generation (displaying) of the timeout
4576 * countdown to the screen dynamically.
4579 * A pointer to a progress bar.
4581 * @param AlwaysUpdate
4582 * Constantly update the progress bar (boolean type).
4585 * A pointer to a string buffer.
4587 * @param cchBufferSize
4588 * The buffer's size in number of characters.
4591 * TRUE or FALSE on function termination.
4596 ProgressTimeOutStringHandler(
4597 IN PPROGRESSBAR Bar
,
4598 IN BOOLEAN AlwaysUpdate
,
4600 IN SIZE_T cchBufferSize
)
4602 ULONG OldProgress
= Bar
->Progress
;
4604 if (Bar
->StepCount
== 0)
4610 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4613 /* Build the progress string if it has changed */
4614 if (Bar
->ProgressFormatText
&&
4615 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4617 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4618 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4627 * @name ProgressCountdown
4629 * Displays and draws a red-coloured progress bar with a countdown.
4630 * When the timeout is reached, the flush page is displayed for reboot.
4633 * A pointer to an input keyboard record.
4636 * Initial countdown value in seconds.
4644 IN PINPUT_RECORD Ir
,
4648 ULONG StartTime
, BarWidth
, TimerDiv
;
4650 LONG TimerValue
, OldTimerValue
;
4651 LARGE_INTEGER Timeout
;
4652 PPROGRESSBAR ProgressBar
;
4653 BOOLEAN RefreshProgress
= TRUE
;
4655 /* Bail out if the timeout is already zero */
4659 /* Create the timeout progress bar and set it up */
4660 ProgressBar
= CreateProgressBarEx(13,
4667 FOREGROUND_RED
| BACKGROUND_BLUE
,
4670 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4671 ProgressTimeOutStringHandler
);
4673 BarWidth
= max(1, ProgressBar
->Width
);
4674 TimerValue
= TimeOut
* BarWidth
;
4675 ProgressSetStepCount(ProgressBar
, TimerValue
);
4677 StartTime
= NtGetTickCount();
4680 TimerDiv
= 1000 / BarWidth
;
4681 TimerDiv
= max(1, TimerDiv
);
4682 OldTimerValue
= TimerValue
;
4685 /* Decrease the timer */
4688 * Compute how much time the previous operations took.
4689 * This allows us in particular to take account for any time
4690 * elapsed if something slowed down.
4692 TimeElapsed
= NtGetTickCount() - StartTime
;
4693 if (TimeElapsed
>= TimerDiv
)
4695 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4696 TimeElapsed
/= TimerDiv
;
4697 StartTime
+= (TimerDiv
* TimeElapsed
);
4699 if (TimeElapsed
<= TimerValue
)
4700 TimerValue
-= TimeElapsed
;
4704 RefreshProgress
= TRUE
;
4707 if (RefreshProgress
)
4709 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4710 RefreshProgress
= FALSE
;
4713 /* Stop when the timer reaches zero */
4714 if (TimerValue
<= 0)
4717 /* Check for user key presses */
4720 * If the timer is used, use a passive wait of maximum 1 second
4721 * while monitoring for incoming console input events, so that
4722 * we are still able to display the timing count.
4725 /* Wait a maximum of 1 second for input events */
4726 TimeElapsed
= NtGetTickCount() - StartTime
;
4727 if (TimeElapsed
< TimerDiv
)
4729 /* Convert the time to NT Format */
4730 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4731 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4735 Status
= STATUS_TIMEOUT
;
4738 /* Check whether the input event has been signaled, or a timeout happened */
4739 if (Status
== STATUS_TIMEOUT
)
4743 if (Status
!= STATUS_WAIT_0
)
4745 /* An error happened, bail out */
4746 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4750 /* Check for an ENTER key press */
4751 while (CONSOLE_ConInKeyPeek(Ir
))
4753 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4755 /* Found it, stop waiting */
4762 /* Destroy the progress bar and quit */
4763 DestroyProgressBar(ProgressBar
);
4768 * Displays the QuitPage.
4771 * FlushPage (At once)
4777 * Number of the next page.
4780 QuitPage(PINPUT_RECORD Ir
)
4782 MUIDisplayPage(QUIT_PAGE
);
4784 /* Destroy the NTOS installations list */
4785 if (NtOsInstallsList
!= NULL
)
4787 DestroyGenericList(NtOsInstallsList
, TRUE
);
4788 NtOsInstallsList
= NULL
;
4791 /* Destroy the partition list */
4792 if (PartitionList
!= NULL
)
4794 DestroyPartitionList(PartitionList
);
4795 PartitionList
= NULL
;
4797 TempPartition
= NULL
;
4798 FormatState
= Start
;
4800 /* Destroy the filesystem list */
4801 if (FileSystemList
!= NULL
)
4803 DestroyFileSystemList(FileSystemList
);
4804 FileSystemList
= NULL
;
4807 /* Destroy the computer settings list */
4808 if (ComputerList
!= NULL
)
4810 DestroyGenericList(ComputerList
, TRUE
);
4811 ComputerList
= NULL
;
4814 /* Destroy the display settings list */
4815 if (DisplayList
!= NULL
)
4817 DestroyGenericList(DisplayList
, TRUE
);
4821 /* Destroy the keyboard settings list */
4822 if (KeyboardList
!= NULL
)
4824 DestroyGenericList(KeyboardList
, TRUE
);
4825 KeyboardList
= NULL
;
4828 /* Destroy the keyboard layout list */
4829 if (LayoutList
!= NULL
)
4831 DestroyGenericList(LayoutList
, TRUE
);
4835 /* Destroy the languages list */
4836 if (LanguageList
!= NULL
)
4838 DestroyGenericList(LanguageList
, FALSE
);
4839 LanguageList
= NULL
;
4842 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4844 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4845 ProgressCountdown(Ir
, 15);
4851 * Displays the SuccessPage.
4854 * FlushPage (At once)
4860 * Number of the next page.
4863 SuccessPage(PINPUT_RECORD Ir
)
4865 MUIDisplayPage(SUCCESS_PAGE
);
4867 if (IsUnattendedSetup
)
4870 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4871 ProgressCountdown(Ir
, 15);
4877 * Displays the FlushPage.
4880 * RebootPage (At once)
4883 * Number of the next page.
4886 FlushPage(PINPUT_RECORD Ir
)
4888 MUIDisplayPage(FLUSH_PAGE
);
4894 PnpEventThread(IN LPVOID lpParameter
);
4898 * The start routine and page management
4908 InfSetHeap(ProcessHeap
);
4910 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4911 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4912 if (!NT_SUCCESS(Status
))
4913 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4915 /* Create the PnP thread in suspended state */
4916 Status
= RtlCreateUserThread(NtCurrentProcess(),
4926 if (!NT_SUCCESS(Status
))
4929 if (!CONSOLE_Init())
4931 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4932 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4933 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4935 /* We failed to initialize the video, just quit the installer */
4936 return STATUS_APP_INIT_FAILURE
;
4939 /* Initialize global unicode strings */
4940 RtlInitUnicodeString(&USetupData
.SourcePath
, NULL
);
4941 RtlInitUnicodeString(&USetupData
.SourceRootPath
, NULL
);
4942 RtlInitUnicodeString(&USetupData
.SourceRootDir
, NULL
);
4943 RtlInitUnicodeString(&InstallPath
, NULL
);
4944 RtlInitUnicodeString(&USetupData
.DestinationPath
, NULL
);
4945 RtlInitUnicodeString(&USetupData
.DestinationArcPath
, NULL
);
4946 RtlInitUnicodeString(&USetupData
.DestinationRootPath
, NULL
);
4947 RtlInitUnicodeString(&USetupData
.SystemRootPath
, NULL
);
4949 /* Hide the cursor */
4950 CONSOLE_SetCursorType(TRUE
, FALSE
);
4952 /* Global Initialization page */
4953 CONSOLE_ClearScreen();
4955 Page
= SetupStartPage(&Ir
);
4957 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4959 CONSOLE_ClearScreen();
4962 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4969 Page
= LanguagePage(&Ir
);
4974 Page
= WelcomePage(&Ir
);
4979 Page
= LicensePage(&Ir
);
4983 case INSTALL_INTRO_PAGE
:
4984 Page
= InstallIntroPage(&Ir
);
4988 case SCSI_CONTROLLER_PAGE
:
4989 Page
= ScsiControllerPage(&Ir
);
4992 case OEM_DRIVER_PAGE
:
4993 Page
= OemDriverPage(&Ir
);
4997 case DEVICE_SETTINGS_PAGE
:
4998 Page
= DeviceSettingsPage(&Ir
);
5001 case COMPUTER_SETTINGS_PAGE
:
5002 Page
= ComputerSettingsPage(&Ir
);
5005 case DISPLAY_SETTINGS_PAGE
:
5006 Page
= DisplaySettingsPage(&Ir
);
5009 case KEYBOARD_SETTINGS_PAGE
:
5010 Page
= KeyboardSettingsPage(&Ir
);
5013 case LAYOUT_SETTINGS_PAGE
:
5014 Page
= LayoutSettingsPage(&Ir
);
5017 case SELECT_PARTITION_PAGE
:
5018 Page
= SelectPartitionPage(&Ir
);
5021 case CREATE_PRIMARY_PARTITION_PAGE
:
5022 Page
= CreatePrimaryPartitionPage(&Ir
);
5025 case CREATE_EXTENDED_PARTITION_PAGE
:
5026 Page
= CreateExtendedPartitionPage(&Ir
);
5029 case CREATE_LOGICAL_PARTITION_PAGE
:
5030 Page
= CreateLogicalPartitionPage(&Ir
);
5033 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5034 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5037 case DELETE_PARTITION_PAGE
:
5038 Page
= DeletePartitionPage(&Ir
);
5041 case SELECT_FILE_SYSTEM_PAGE
:
5042 Page
= SelectFileSystemPage(&Ir
);
5045 case FORMAT_PARTITION_PAGE
:
5046 Page
= FormatPartitionPage(&Ir
);
5049 case CHECK_FILE_SYSTEM_PAGE
:
5050 Page
= CheckFileSystemPage(&Ir
);
5053 case INSTALL_DIRECTORY_PAGE
:
5054 Page
= InstallDirectoryPage(&Ir
);
5057 case PREPARE_COPY_PAGE
:
5058 Page
= PrepareCopyPage(&Ir
);
5061 case FILE_COPY_PAGE
:
5062 Page
= FileCopyPage(&Ir
);
5066 Page
= RegistryPage(&Ir
);
5069 case BOOT_LOADER_PAGE
:
5070 Page
= BootLoaderPage(&Ir
);
5073 case BOOT_LOADER_FLOPPY_PAGE
:
5074 Page
= BootLoaderFloppyPage(&Ir
);
5077 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5078 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5081 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5082 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5086 case REPAIR_INTRO_PAGE
:
5087 Page
= RepairIntroPage(&Ir
);
5090 case UPGRADE_REPAIR_PAGE
:
5091 Page
= UpgradeRepairPage(&Ir
);
5095 Page
= SuccessPage(&Ir
);
5099 Page
= FlushPage(&Ir
);
5103 Page
= QuitPage(&Ir
);
5112 SetupCloseInfFile(SetupInf
);
5114 if (Page
== RECOVERY_PAGE
)
5120 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5121 NtShutdownSystem(ShutdownReboot
);
5122 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5124 return STATUS_SUCCESS
;
5129 NtProcessStartup(PPEB Peb
)
5134 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5136 ProcessHeap
= Peb
->ProcessHeap
;
5138 NtQuerySystemTime(&Time
);
5140 Status
= RunUSetup();
5142 if (NT_SUCCESS(Status
))
5145 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5146 * a protective waiting.
5147 * This wait is needed because, since we are started as SMSS.EXE,
5148 * the NT kernel explicitly waits 5 seconds for the initial process
5149 * SMSS.EXE to initialize (as a protective measure), and otherwise
5150 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5152 Time
.QuadPart
+= 50000000;
5153 NtDelayExecution(FALSE
, &Time
);
5157 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5158 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5159 0, 0, NULL
, 0, NULL
);
5162 NtTerminateProcess(NtCurrentProcess(), Status
);