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
;
3266 * Displays the InstallDirectoryPage.
3273 * Number of the next page.
3276 InstallDirectoryPage(PINPUT_RECORD Ir
)
3278 PDISKENTRY DiskEntry
;
3279 PPARTENTRY PartEntry
;
3280 WCHAR InstallDir
[MAX_PATH
];
3284 /* We do not need the filesystem list anymore */
3285 if (FileSystemList
!= NULL
)
3287 DestroyFileSystemList(FileSystemList
);
3288 FileSystemList
= NULL
;
3291 if (PartitionList
== NULL
||
3292 PartitionList
->CurrentDisk
== NULL
||
3293 PartitionList
->CurrentPartition
== NULL
)
3295 /* FIXME: show an error dialog */
3299 DiskEntry
= PartitionList
->CurrentDisk
;
3300 PartEntry
= PartitionList
->CurrentPartition
;
3302 // if (IsUnattendedSetup)
3303 if (RepairUpdateFlag
)
3304 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3305 else if (USetupData
.InstallationDirectory
[0])
3306 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3308 wcscpy(InstallDir
, L
"\\ReactOS");
3311 * Check the validity of the predefined 'InstallDir'. If we are either
3312 * in unattended setup or in update/repair mode, and the installation path
3313 * is valid, just perform the installation. Otherwise (either in the case
3314 * of an invalid path, or we are in regular setup), display the UI and allow
3315 * the user to specify a new installation path.
3317 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3319 BuildInstallPaths(InstallDir
,
3324 * Check whether the user attempts to install ReactOS within the
3325 * installation source directory, or in a subdirectory thereof.
3326 * If so, fail with an error.
3328 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3330 PopupError("You cannot install ReactOS within the installation source directory!",
3331 MUIGetString(STRING_CONTINUE
),
3332 Ir
, POPUP_WAIT_ENTER
);
3333 return INSTALL_DIRECTORY_PAGE
;
3336 return PREPARE_COPY_PAGE
;
3339 Length
= wcslen(InstallDir
);
3342 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3343 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3344 CONSOLE_SetCursorXY(8 + Pos
, 11);
3345 CONSOLE_SetCursorType(TRUE
, TRUE
);
3349 CONSOLE_ConInKey(Ir
);
3351 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3352 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3354 CONSOLE_SetCursorType(TRUE
, FALSE
);
3356 if (ConfirmQuit(Ir
))
3359 CONSOLE_SetCursorType(TRUE
, TRUE
);
3362 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3363 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3367 memmove(&InstallDir
[Pos
],
3368 &InstallDir
[Pos
+ 1],
3369 (Length
- Pos
- 1) * sizeof(WCHAR
));
3370 InstallDir
[Length
- 1] = UNICODE_NULL
;
3373 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3374 CONSOLE_SetCursorXY(8 + Pos
, 11);
3377 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3378 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3381 CONSOLE_SetCursorXY(8 + Pos
, 11);
3383 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3384 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3387 CONSOLE_SetCursorXY(8 + Pos
, 11);
3389 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3390 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3395 CONSOLE_SetCursorXY(8 + Pos
, 11);
3398 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3399 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3404 CONSOLE_SetCursorXY(8 + Pos
, 11);
3407 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3409 CONSOLE_SetCursorType(TRUE
, FALSE
);
3412 * Check for the validity of the installation directory and pop up
3413 * an error if it is not the case. Then the user can fix its input.
3415 if (!IsValidPath(InstallDir
))
3417 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3418 return INSTALL_DIRECTORY_PAGE
;
3421 BuildInstallPaths(InstallDir
,
3426 * Check whether the user attempts to install ReactOS within the
3427 * installation source directory, or in a subdirectory thereof.
3428 * If so, fail with an error.
3430 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3432 PopupError("You cannot install ReactOS within the installation source directory!",
3433 MUIGetString(STRING_CONTINUE
),
3434 Ir
, POPUP_WAIT_ENTER
);
3435 return INSTALL_DIRECTORY_PAGE
;
3438 return PREPARE_COPY_PAGE
;
3440 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3445 memmove(&InstallDir
[Pos
- 1],
3447 (Length
- Pos
) * sizeof(WCHAR
));
3448 InstallDir
[Length
- 1] = UNICODE_NULL
;
3452 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3453 CONSOLE_SetCursorXY(8 + Pos
, 11);
3456 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3460 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3461 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3464 memmove(&InstallDir
[Pos
+ 1],
3466 (Length
- Pos
) * sizeof(WCHAR
));
3467 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3468 InstallDir
[Pos
] = c
;
3472 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3473 CONSOLE_SetCursorXY(8 + Pos
, 11);
3479 return INSTALL_DIRECTORY_PAGE
;
3484 AddSectionToCopyQueueCab(HINF InfFile
,
3486 PWCHAR SourceCabinet
,
3487 PCUNICODE_STRING DestinationPath
,
3490 INFCONTEXT FilesContext
;
3491 INFCONTEXT DirContext
;
3493 PWCHAR FileKeyValue
;
3495 PWCHAR TargetFileName
;
3498 * This code enumerates the list of files in reactos.dff / reactos.inf
3499 * that need to be extracted from reactos.cab and be installed in their
3500 * respective directories.
3503 /* Search for the SectionName section */
3504 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3506 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3511 * Enumerate the files in the section and add them to the file queue.
3515 /* Get source file name and target directory id */
3516 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3518 /* FIXME: Handle error! */
3519 DPRINT1("INF_GetData() failed\n");
3523 /* Get optional target file name */
3524 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3525 TargetFileName
= NULL
;
3527 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3529 /* Lookup target directory */
3530 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3532 /* FIXME: Handle error! */
3533 DPRINT1("SetupFindFirstLine() failed\n");
3534 INF_FreeData(FileKeyName
);
3535 INF_FreeData(FileKeyValue
);
3536 INF_FreeData(TargetFileName
);
3540 INF_FreeData(FileKeyValue
);
3542 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3544 /* FIXME: Handle error! */
3545 DPRINT1("INF_GetData() failed\n");
3546 INF_FreeData(FileKeyName
);
3547 INF_FreeData(TargetFileName
);
3551 if (!SetupQueueCopy(SetupFileQueue
,
3553 USetupData
.SourceRootPath
.Buffer
,
3554 USetupData
.SourceRootDir
.Buffer
,
3559 /* FIXME: Handle error! */
3560 DPRINT1("SetupQueueCopy() failed\n");
3563 INF_FreeData(FileKeyName
);
3564 INF_FreeData(TargetFileName
);
3565 INF_FreeData(DirKeyValue
);
3566 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3573 AddSectionToCopyQueue(HINF InfFile
,
3575 PWCHAR SourceCabinet
,
3576 PCUNICODE_STRING DestinationPath
,
3579 INFCONTEXT FilesContext
;
3580 INFCONTEXT DirContext
;
3582 PWCHAR FileKeyValue
;
3584 PWCHAR TargetFileName
;
3585 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3588 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3591 * This code enumerates the list of files in txtsetup.sif
3592 * that need to be installed in their respective directories.
3595 /* Search for the SectionName section */
3596 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3598 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3603 * Enumerate the files in the section and add them to the file queue.
3607 /* Get source file name */
3608 if (!INF_GetDataField(&FilesContext
, 0, &FileKeyName
))
3610 /* FIXME: Handle error! */
3611 DPRINT1("INF_GetData() failed\n");
3615 /* Get target directory id */
3616 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3618 /* FIXME: Handle error! */
3619 DPRINT1("INF_GetData() failed\n");
3620 INF_FreeData(FileKeyName
);
3624 /* Get optional target file name */
3625 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3626 TargetFileName
= NULL
;
3627 else if (!*TargetFileName
)
3628 TargetFileName
= NULL
;
3630 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3632 /* Lookup target directory */
3633 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3635 /* FIXME: Handle error! */
3636 DPRINT1("SetupFindFirstLine() failed\n");
3637 INF_FreeData(FileKeyName
);
3638 INF_FreeData(FileKeyValue
);
3639 INF_FreeData(TargetFileName
);
3643 INF_FreeData(FileKeyValue
);
3645 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3647 /* FIXME: Handle error! */
3648 DPRINT1("INF_GetData() failed\n");
3649 INF_FreeData(FileKeyName
);
3650 INF_FreeData(TargetFileName
);
3654 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3656 /* Installation path */
3657 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3659 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3660 USetupData
.SourceRootDir
.Buffer
);
3662 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3664 else if (DirKeyValue
[0] == L
'\\')
3667 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3669 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3672 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3674 else // if (DirKeyValue[0] != L'\\')
3676 /* Path relative to the installation path */
3677 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3679 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3680 USetupData
.SourceRootDir
.Buffer
, DirKeyValue
);
3682 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3685 if (!SetupQueueCopy(SetupFileQueue
,
3687 USetupData
.SourceRootPath
.Buffer
,
3688 CompleteOrigDirName
,
3693 /* FIXME: Handle error! */
3694 DPRINT1("SetupQueueCopy() failed\n");
3697 INF_FreeData(FileKeyName
);
3698 INF_FreeData(TargetFileName
);
3699 INF_FreeData(DirKeyValue
);
3700 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3707 PrepareCopyPageInfFile(HINF InfFile
,
3708 PWCHAR SourceCabinet
,
3712 INFCONTEXT DirContext
;
3713 PWCHAR AdditionalSectionName
= NULL
;
3715 WCHAR PathBuffer
[MAX_PATH
];
3717 /* Add common files */
3718 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3721 /* Add specific files depending of computer type */
3722 if (SourceCabinet
== NULL
)
3724 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3727 if (AdditionalSectionName
)
3729 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3734 /* Create directories */
3738 * Copying files to USetupData.DestinationRootPath should be done from within
3739 * the SystemPartitionFiles section.
3740 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3741 * For installing to USetupData.DestinationPath specify just '\' .
3744 /* Get destination path */
3745 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), USetupData
.DestinationPath
.Buffer
);
3747 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3749 /* Create the install directory */
3750 Status
= SetupCreateDirectory(PathBuffer
);
3751 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3753 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3754 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3758 /* Search for the 'Directories' section */
3759 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3762 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3764 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3769 /* Enumerate the directory values and create the subdirectories */
3772 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3778 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3780 /* Installation path */
3781 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3783 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3784 USetupData
.DestinationPath
.Buffer
);
3786 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3788 else if (DirKeyValue
[0] == L
'\\')
3791 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3793 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3794 USetupData
.DestinationRootPath
.Buffer
, DirKeyValue
);
3796 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3798 Status
= SetupCreateDirectory(PathBuffer
);
3799 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3801 INF_FreeData(DirKeyValue
);
3802 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3803 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3807 else // if (DirKeyValue[0] != L'\\')
3809 /* Path relative to the installation path */
3810 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3812 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3813 USetupData
.DestinationPath
.Buffer
, DirKeyValue
);
3815 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3817 Status
= SetupCreateDirectory(PathBuffer
);
3818 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3820 INF_FreeData(DirKeyValue
);
3821 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3822 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3827 INF_FreeData(DirKeyValue
);
3828 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3835 * Displays the PrepareCopyPage.
3838 * FileCopyPage(At once)
3842 * Inits SetupFileQueue
3843 * Calls PrepareCopyPageInfFile
3846 * Number of the next page.
3849 PrepareCopyPage(PINPUT_RECORD Ir
)
3852 WCHAR PathBuffer
[MAX_PATH
];
3853 INFCONTEXT CabinetsContext
;
3859 MUIDisplayPage(PREPARE_COPY_PAGE
);
3861 /* Create the file queue */
3862 SetupFileQueue
= SetupOpenFileQueue();
3863 if (SetupFileQueue
== NULL
)
3865 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3869 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3871 /* FIXME: show an error dialog */
3875 /* Search for the 'Cabinets' section */
3876 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3878 return FILE_COPY_PAGE
;
3882 * Enumerate the directory values in the 'Cabinets'
3883 * section and parse their inf files.
3887 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3890 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3891 USetupData
.SourcePath
.Buffer
, KeyValue
);
3893 CabinetInitialize();
3894 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3895 CabinetSetCabinetName(PathBuffer
);
3897 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3899 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3901 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3902 if (InfFileData
== NULL
)
3904 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3910 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3911 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3915 InfHandle
= INF_OpenBufferedFileA((PSTR
)InfFileData
,
3919 USetupData
.LanguageId
,
3922 if (InfHandle
== INVALID_HANDLE_VALUE
)
3924 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3930 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3932 /* FIXME: show an error dialog */
3935 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3937 return FILE_COPY_PAGE
;
3943 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3946 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3948 /* Get the memory information from the system */
3949 NtQuerySystemInformation(SystemPerformanceInformation
,
3954 /* Check if this is initial setup */
3957 /* Set maximum limits to be total RAM pages */
3958 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3959 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3960 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3963 /* Set current values */
3964 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3965 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3966 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3972 FileCopyCallback(PVOID Context
,
3977 PCOPYCONTEXT CopyContext
;
3979 CopyContext
= (PCOPYCONTEXT
)Context
;
3981 switch (Notification
)
3983 case SPFILENOTIFY_STARTSUBQUEUE
:
3984 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3985 ProgressSetStepCount(CopyContext
->ProgressBar
,
3986 CopyContext
->TotalOperations
);
3987 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3990 case SPFILENOTIFY_STARTCOPY
:
3991 /* Display copy message */
3992 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3993 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3996 case SPFILENOTIFY_ENDCOPY
:
3997 CopyContext
->CompletedOperations
++;
3999 /* SYSREG checkpoint */
4000 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
4001 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4003 ProgressNextStep(CopyContext
->ProgressBar
);
4004 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4013 * Displays the FileCopyPage.
4016 * RegistryPage(At once)
4019 * Calls SetupCommitFileQueueW
4020 * Calls SetupCloseFileQueue
4023 * Number of the next page.
4026 FileCopyPage(PINPUT_RECORD Ir
)
4028 COPYCONTEXT CopyContext
;
4029 unsigned int mem_bar_width
;
4031 MUIDisplayPage(FILE_COPY_PAGE
);
4033 /* Create context for the copy process */
4034 CopyContext
.DestinationRootPath
= USetupData
.DestinationRootPath
.Buffer
;
4035 CopyContext
.InstallPath
= InstallPath
.Buffer
;
4036 CopyContext
.TotalOperations
= 0;
4037 CopyContext
.CompletedOperations
= 0;
4039 /* Create the progress bar as well */
4040 CopyContext
.ProgressBar
= CreateProgressBar(13,
4047 MUIGetString(STRING_SETUPCOPYINGFILES
));
4049 // fit memory bars to screen width, distribute them uniform
4050 mem_bar_width
= (xScreen
- 26) / 5;
4051 mem_bar_width
-= mem_bar_width
% 2; // make even
4052 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4053 /* Create the paged pool progress bar */
4054 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4063 /* Create the non paged pool progress bar */
4064 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4066 (xScreen
/ 2) + (mem_bar_width
/ 2),
4068 (xScreen
/ 2)- (mem_bar_width
/ 2),
4073 /* Create the global memory progress bar */
4074 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4078 xScreen
- 13 - mem_bar_width
,
4083 /* Do the file copying */
4084 SetupCommitFileQueueW(NULL
,
4089 /* If we get here, we're done, so cleanup the queue and progress bar */
4090 SetupCloseFileQueue(SetupFileQueue
);
4091 DestroyProgressBar(CopyContext
.ProgressBar
);
4092 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4093 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4094 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4096 /* Create the $winnt$.inf file */
4097 InstallSetupInfFile(&USetupData
);
4099 /* Go display the next page */
4100 return REGISTRY_PAGE
;
4106 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4108 /* WARNING: Please keep this lookup table in sync with the resources! */
4109 static const UINT StringIDs
[] =
4111 STRING_DONE
, /* Success */
4112 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4113 STRING_IMPORTFILE
, /* ImportRegHive */
4114 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4115 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4116 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4117 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4118 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4123 if (RegStatus
< ARRAYSIZE(StringIDs
))
4125 va_start(args
, RegStatus
);
4126 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4131 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4136 * Displays the RegistryPage.
4139 * SuccessPage (if RepairUpdate)
4140 * BootLoaderPage (default)
4144 * Calls UpdateRegistry
4147 * Number of the next page.
4150 RegistryPage(PINPUT_RECORD Ir
)
4154 MUIDisplayPage(REGISTRY_PAGE
);
4156 Error
= UpdateRegistry(SetupInf
,
4160 DestinationDriveLetter
,
4166 if (Error
!= ERROR_SUCCESS
)
4168 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4173 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4174 return BOOT_LOADER_PAGE
;
4180 * Displays the BootLoaderPage.
4183 * SuccessPage (if RepairUpdate)
4184 * BootLoaderHarddiskMbrPage
4185 * BootLoaderHarddiskVbrPage
4186 * BootLoaderFloppyPage
4191 * Calls RegInitializeRegistry
4192 * Calls ImportRegistryFile
4193 * Calls SetDefaultPagefile
4194 * Calls SetMountedDeviceValues
4197 * Number of the next page.
4200 BootLoaderPage(PINPUT_RECORD Ir
)
4202 UCHAR PartitionType
;
4203 BOOLEAN InstallOnFloppy
;
4205 WCHAR PathBuffer
[MAX_PATH
];
4207 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4209 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4210 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4211 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4212 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4213 PartitionList
->SystemPartition
->PartitionNumber
);
4214 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4215 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4217 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4219 /* For unattended setup, skip MBR installation or install on floppy if needed */
4220 if (IsUnattendedSetup
)
4222 if ((USetupData
.MBRInstallType
== 0) ||
4223 (USetupData
.MBRInstallType
== 1))
4230 * We may install an MBR or VBR, but before that, check whether
4231 * we need to actually install the VBR on floppy.
4233 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4235 DPRINT("Error: system partition invalid (unused)\n");
4236 InstallOnFloppy
= TRUE
;
4238 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4240 /* OS/2 boot manager partition */
4241 DPRINT("Found OS/2 boot manager partition\n");
4242 InstallOnFloppy
= TRUE
;
4244 else if (PartitionType
== PARTITION_EXT2
)
4246 /* Linux EXT2 partition */
4247 DPRINT("Found Linux EXT2 partition\n");
4248 InstallOnFloppy
= FALSE
;
4250 else if (PartitionType
== PARTITION_IFS
)
4252 /* NTFS partition */
4253 DPRINT("Found NTFS partition\n");
4255 // FIXME: Make it FALSE when we'll support NTFS installation!
4256 InstallOnFloppy
= TRUE
;
4258 else if ((PartitionType
== PARTITION_FAT_12
) ||
4259 (PartitionType
== PARTITION_FAT_16
) ||
4260 (PartitionType
== PARTITION_HUGE
) ||
4261 (PartitionType
== PARTITION_XINT13
) ||
4262 (PartitionType
== PARTITION_FAT32
) ||
4263 (PartitionType
== PARTITION_FAT32_XINT13
))
4265 DPRINT("Found FAT partition\n");
4266 InstallOnFloppy
= FALSE
;
4270 /* Unknown partition */
4271 DPRINT("Unknown partition found\n");
4272 InstallOnFloppy
= TRUE
;
4275 /* We should install on floppy */
4276 if (InstallOnFloppy
)
4278 USetupData
.MBRInstallType
= 1;
4282 /* Is it an unattended install on hdd? */
4283 if (IsUnattendedSetup
)
4285 if ((USetupData
.MBRInstallType
== 2) ||
4286 (USetupData
.MBRInstallType
== 3))
4292 MUIDisplayPage(BOOT_LOADER_PAGE
);
4293 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4297 CONSOLE_ConInKey(Ir
);
4299 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4300 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4302 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4311 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4313 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4314 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4316 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4325 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4327 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4328 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4330 if (ConfirmQuit(Ir
))
4335 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4339 /* Install on both MBR and VBR */
4340 USetupData
.MBRInstallType
= 2;
4343 else if (Line
== 13)
4345 /* Install on VBR only */
4346 USetupData
.MBRInstallType
= 3;
4349 else if (Line
== 14)
4351 /* Install on floppy */
4352 USetupData
.MBRInstallType
= 1;
4355 else if (Line
== 15)
4357 /* Skip MBR installation */
4358 USetupData
.MBRInstallType
= 0;
4362 return BOOT_LOADER_PAGE
;
4367 switch (USetupData
.MBRInstallType
)
4369 /* Skip MBR installation */
4371 return SUCCESS_PAGE
;
4373 /* Install on floppy */
4375 return BOOT_LOADER_FLOPPY_PAGE
;
4377 /* Install on both MBR and VBR */
4379 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4381 /* Install on VBR only */
4383 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4386 return BOOT_LOADER_PAGE
;
4391 * Displays the BootLoaderFloppyPage.
4394 * SuccessPage (At once)
4398 * Calls InstallFatBootcodeToFloppy()
4401 * Number of the next page.
4404 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4408 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4410 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4414 CONSOLE_ConInKey(Ir
);
4416 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4417 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4419 if (ConfirmQuit(Ir
))
4424 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4426 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4427 &USetupData
.DestinationArcPath
);
4428 if (!NT_SUCCESS(Status
))
4430 if (Status
== STATUS_DEVICE_NOT_READY
)
4431 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4433 /* TODO: Print error message */
4434 return BOOT_LOADER_FLOPPY_PAGE
;
4437 return SUCCESS_PAGE
;
4441 return BOOT_LOADER_FLOPPY_PAGE
;
4446 * Displays the BootLoaderHarddiskVbrPage.
4449 * SuccessPage (At once)
4453 * Calls InstallVBRToPartition()
4456 * Number of the next page.
4459 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4463 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4464 &USetupData
.SourceRootPath
,
4465 &USetupData
.DestinationArcPath
,
4466 PartitionList
->SystemPartition
->PartitionType
);
4467 if (!NT_SUCCESS(Status
))
4469 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4473 return SUCCESS_PAGE
;
4478 * Displays the BootLoaderHarddiskMbrPage.
4481 * SuccessPage (At once)
4485 * Calls InstallVBRToPartition()
4486 * Calls InstallMbrBootCodeToDisk()
4489 * Number of the next page.
4492 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4495 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4497 /* Step 1: Write the VBR */
4498 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4499 &USetupData
.SourceRootPath
,
4500 &USetupData
.DestinationArcPath
,
4501 PartitionList
->SystemPartition
->PartitionType
);
4502 if (!NT_SUCCESS(Status
))
4504 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4508 /* Step 2: Write the MBR */
4509 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4510 L
"\\Device\\Harddisk%d\\Partition0",
4511 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4512 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4513 &USetupData
.SourceRootPath
,
4514 DestinationDevicePathBuffer
);
4515 if (!NT_SUCCESS(Status
))
4517 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4518 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4522 return SUCCESS_PAGE
;
4527 * @name ProgressTimeOutStringHandler
4529 * Handles the generation (displaying) of the timeout
4530 * countdown to the screen dynamically.
4533 * A pointer to a progress bar.
4535 * @param AlwaysUpdate
4536 * Constantly update the progress bar (boolean type).
4539 * A pointer to a string buffer.
4541 * @param cchBufferSize
4542 * The buffer's size in number of characters.
4545 * TRUE or FALSE on function termination.
4550 ProgressTimeOutStringHandler(
4551 IN PPROGRESSBAR Bar
,
4552 IN BOOLEAN AlwaysUpdate
,
4554 IN SIZE_T cchBufferSize
)
4556 ULONG OldProgress
= Bar
->Progress
;
4558 if (Bar
->StepCount
== 0)
4564 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4567 /* Build the progress string if it has changed */
4568 if (Bar
->ProgressFormatText
&&
4569 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4571 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4572 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4581 * @name ProgressCountdown
4583 * Displays and draws a red-coloured progress bar with a countdown.
4584 * When the timeout is reached, the flush page is displayed for reboot.
4587 * A pointer to an input keyboard record.
4590 * Initial countdown value in seconds.
4598 IN PINPUT_RECORD Ir
,
4602 ULONG StartTime
, BarWidth
, TimerDiv
;
4604 LONG TimerValue
, OldTimerValue
;
4605 LARGE_INTEGER Timeout
;
4606 PPROGRESSBAR ProgressBar
;
4607 BOOLEAN RefreshProgress
= TRUE
;
4609 /* Bail out if the timeout is already zero */
4613 /* Create the timeout progress bar and set it up */
4614 ProgressBar
= CreateProgressBarEx(13,
4621 FOREGROUND_RED
| BACKGROUND_BLUE
,
4624 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4625 ProgressTimeOutStringHandler
);
4627 BarWidth
= max(1, ProgressBar
->Width
);
4628 TimerValue
= TimeOut
* BarWidth
;
4629 ProgressSetStepCount(ProgressBar
, TimerValue
);
4631 StartTime
= NtGetTickCount();
4634 TimerDiv
= 1000 / BarWidth
;
4635 TimerDiv
= max(1, TimerDiv
);
4636 OldTimerValue
= TimerValue
;
4639 /* Decrease the timer */
4642 * Compute how much time the previous operations took.
4643 * This allows us in particular to take account for any time
4644 * elapsed if something slowed down.
4646 TimeElapsed
= NtGetTickCount() - StartTime
;
4647 if (TimeElapsed
>= TimerDiv
)
4649 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4650 TimeElapsed
/= TimerDiv
;
4651 StartTime
+= (TimerDiv
* TimeElapsed
);
4653 if (TimeElapsed
<= TimerValue
)
4654 TimerValue
-= TimeElapsed
;
4658 RefreshProgress
= TRUE
;
4661 if (RefreshProgress
)
4663 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4664 RefreshProgress
= FALSE
;
4667 /* Stop when the timer reaches zero */
4668 if (TimerValue
<= 0)
4671 /* Check for user key presses */
4674 * If the timer is used, use a passive wait of maximum 1 second
4675 * while monitoring for incoming console input events, so that
4676 * we are still able to display the timing count.
4679 /* Wait a maximum of 1 second for input events */
4680 TimeElapsed
= NtGetTickCount() - StartTime
;
4681 if (TimeElapsed
< TimerDiv
)
4683 /* Convert the time to NT Format */
4684 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4685 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4689 Status
= STATUS_TIMEOUT
;
4692 /* Check whether the input event has been signaled, or a timeout happened */
4693 if (Status
== STATUS_TIMEOUT
)
4697 if (Status
!= STATUS_WAIT_0
)
4699 /* An error happened, bail out */
4700 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4704 /* Check for an ENTER key press */
4705 while (CONSOLE_ConInKeyPeek(Ir
))
4707 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4709 /* Found it, stop waiting */
4716 /* Destroy the progress bar and quit */
4717 DestroyProgressBar(ProgressBar
);
4722 * Displays the QuitPage.
4725 * FlushPage (At once)
4731 * Number of the next page.
4734 QuitPage(PINPUT_RECORD Ir
)
4736 MUIDisplayPage(QUIT_PAGE
);
4738 /* Destroy the NTOS installations list */
4739 if (NtOsInstallsList
!= NULL
)
4741 DestroyGenericList(NtOsInstallsList
, TRUE
);
4742 NtOsInstallsList
= NULL
;
4745 /* Destroy the partition list */
4746 if (PartitionList
!= NULL
)
4748 DestroyPartitionList(PartitionList
);
4749 PartitionList
= NULL
;
4751 TempPartition
= NULL
;
4752 FormatState
= Start
;
4754 /* Destroy the filesystem list */
4755 if (FileSystemList
!= NULL
)
4757 DestroyFileSystemList(FileSystemList
);
4758 FileSystemList
= NULL
;
4761 /* Destroy the computer settings list */
4762 if (ComputerList
!= NULL
)
4764 DestroyGenericList(ComputerList
, TRUE
);
4765 ComputerList
= NULL
;
4768 /* Destroy the display settings list */
4769 if (DisplayList
!= NULL
)
4771 DestroyGenericList(DisplayList
, TRUE
);
4775 /* Destroy the keyboard settings list */
4776 if (KeyboardList
!= NULL
)
4778 DestroyGenericList(KeyboardList
, TRUE
);
4779 KeyboardList
= NULL
;
4782 /* Destroy the keyboard layout list */
4783 if (LayoutList
!= NULL
)
4785 DestroyGenericList(LayoutList
, TRUE
);
4789 /* Destroy the languages list */
4790 if (LanguageList
!= NULL
)
4792 DestroyGenericList(LanguageList
, FALSE
);
4793 LanguageList
= NULL
;
4796 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4798 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4799 ProgressCountdown(Ir
, 15);
4805 * Displays the SuccessPage.
4808 * FlushPage (At once)
4814 * Number of the next page.
4817 SuccessPage(PINPUT_RECORD Ir
)
4819 MUIDisplayPage(SUCCESS_PAGE
);
4821 if (IsUnattendedSetup
)
4824 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4825 ProgressCountdown(Ir
, 15);
4831 * Displays the FlushPage.
4834 * RebootPage (At once)
4837 * Number of the next page.
4840 FlushPage(PINPUT_RECORD Ir
)
4842 MUIDisplayPage(FLUSH_PAGE
);
4848 PnpEventThread(IN LPVOID lpParameter
);
4852 * The start routine and page management
4862 InfSetHeap(ProcessHeap
);
4864 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4865 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4866 if (!NT_SUCCESS(Status
))
4867 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4869 /* Create the PnP thread in suspended state */
4870 Status
= RtlCreateUserThread(NtCurrentProcess(),
4880 if (!NT_SUCCESS(Status
))
4883 if (!CONSOLE_Init())
4885 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4886 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4887 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4889 /* We failed to initialize the video, just quit the installer */
4890 return STATUS_APP_INIT_FAILURE
;
4893 /* Initialize global unicode strings */
4894 RtlInitUnicodeString(&USetupData
.SourcePath
, NULL
);
4895 RtlInitUnicodeString(&USetupData
.SourceRootPath
, NULL
);
4896 RtlInitUnicodeString(&USetupData
.SourceRootDir
, NULL
);
4897 RtlInitUnicodeString(&InstallPath
, NULL
);
4898 RtlInitUnicodeString(&USetupData
.DestinationPath
, NULL
);
4899 RtlInitUnicodeString(&USetupData
.DestinationArcPath
, NULL
);
4900 RtlInitUnicodeString(&USetupData
.DestinationRootPath
, NULL
);
4901 RtlInitUnicodeString(&USetupData
.SystemRootPath
, NULL
);
4903 /* Hide the cursor */
4904 CONSOLE_SetCursorType(TRUE
, FALSE
);
4906 /* Global Initialization page */
4907 CONSOLE_ClearScreen();
4909 Page
= SetupStartPage(&Ir
);
4911 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4913 CONSOLE_ClearScreen();
4916 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4923 Page
= LanguagePage(&Ir
);
4928 Page
= WelcomePage(&Ir
);
4933 Page
= LicensePage(&Ir
);
4937 case INSTALL_INTRO_PAGE
:
4938 Page
= InstallIntroPage(&Ir
);
4942 case SCSI_CONTROLLER_PAGE
:
4943 Page
= ScsiControllerPage(&Ir
);
4946 case OEM_DRIVER_PAGE
:
4947 Page
= OemDriverPage(&Ir
);
4951 case DEVICE_SETTINGS_PAGE
:
4952 Page
= DeviceSettingsPage(&Ir
);
4955 case COMPUTER_SETTINGS_PAGE
:
4956 Page
= ComputerSettingsPage(&Ir
);
4959 case DISPLAY_SETTINGS_PAGE
:
4960 Page
= DisplaySettingsPage(&Ir
);
4963 case KEYBOARD_SETTINGS_PAGE
:
4964 Page
= KeyboardSettingsPage(&Ir
);
4967 case LAYOUT_SETTINGS_PAGE
:
4968 Page
= LayoutSettingsPage(&Ir
);
4971 case SELECT_PARTITION_PAGE
:
4972 Page
= SelectPartitionPage(&Ir
);
4975 case CREATE_PRIMARY_PARTITION_PAGE
:
4976 Page
= CreatePrimaryPartitionPage(&Ir
);
4979 case CREATE_EXTENDED_PARTITION_PAGE
:
4980 Page
= CreateExtendedPartitionPage(&Ir
);
4983 case CREATE_LOGICAL_PARTITION_PAGE
:
4984 Page
= CreateLogicalPartitionPage(&Ir
);
4987 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4988 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4991 case DELETE_PARTITION_PAGE
:
4992 Page
= DeletePartitionPage(&Ir
);
4995 case SELECT_FILE_SYSTEM_PAGE
:
4996 Page
= SelectFileSystemPage(&Ir
);
4999 case FORMAT_PARTITION_PAGE
:
5000 Page
= FormatPartitionPage(&Ir
);
5003 case CHECK_FILE_SYSTEM_PAGE
:
5004 Page
= CheckFileSystemPage(&Ir
);
5007 case INSTALL_DIRECTORY_PAGE
:
5008 Page
= InstallDirectoryPage(&Ir
);
5011 case PREPARE_COPY_PAGE
:
5012 Page
= PrepareCopyPage(&Ir
);
5015 case FILE_COPY_PAGE
:
5016 Page
= FileCopyPage(&Ir
);
5020 Page
= RegistryPage(&Ir
);
5023 case BOOT_LOADER_PAGE
:
5024 Page
= BootLoaderPage(&Ir
);
5027 case BOOT_LOADER_FLOPPY_PAGE
:
5028 Page
= BootLoaderFloppyPage(&Ir
);
5031 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5032 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5035 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5036 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5040 case REPAIR_INTRO_PAGE
:
5041 Page
= RepairIntroPage(&Ir
);
5044 case UPGRADE_REPAIR_PAGE
:
5045 Page
= UpgradeRepairPage(&Ir
);
5049 Page
= SuccessPage(&Ir
);
5053 Page
= FlushPage(&Ir
);
5057 Page
= QuitPage(&Ir
);
5066 SetupCloseInfFile(SetupInf
);
5068 if (Page
== RECOVERY_PAGE
)
5074 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5075 NtShutdownSystem(ShutdownReboot
);
5076 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5078 return STATUS_SUCCESS
;
5083 NtProcessStartup(PPEB Peb
)
5088 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5090 ProcessHeap
= Peb
->ProcessHeap
;
5092 NtQuerySystemTime(&Time
);
5094 Status
= RunUSetup();
5096 if (NT_SUCCESS(Status
))
5099 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5100 * a protective waiting.
5101 * This wait is needed because, since we are started as SMSS.EXE,
5102 * the NT kernel explicitly waits 5 seconds for the initial process
5103 * SMSS.EXE to initialize (as a protective measure), and otherwise
5104 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5106 Time
.QuadPart
+= 50000000;
5107 NtDelayExecution(FALSE
, &Time
);
5111 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5112 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5113 0, 0, NULL
, 0, NULL
);
5116 NtTerminateProcess(NtCurrentProcess(), Status
);