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)
43 /* GLOBALS & LOCALS *********************************************************/
47 BOOLEAN IsUnattendedSetup
= FALSE
;
48 static USETUP_DATA USetupData
;
51 * NOTE: Technically only used for the COPYCONTEXT InstallPath member
52 * for the filequeue functionality.
54 static UNICODE_STRING InstallPath
;
56 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
57 static WCHAR DestinationDriveLetter
;
62 PWCHAR SelectedLanguageId
;
63 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
64 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
66 static BOOLEAN RepairUpdateFlag
= FALSE
;
68 static HANDLE hPnpThread
= NULL
;
70 static PPARTLIST PartitionList
= NULL
;
71 static PPARTENTRY TempPartition
= NULL
;
72 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
73 static FORMATMACHINESTATE FormatState
= Start
;
75 /*****************************************************/
79 static HSPFILEQ SetupFileQueue
= NULL
;
81 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
82 static PGENERIC_LIST NtOsInstallsList
= NULL
;
84 static PGENERIC_LIST ComputerList
= NULL
;
85 static PGENERIC_LIST DisplayList
= NULL
;
86 static PGENERIC_LIST KeyboardList
= NULL
;
87 static PGENERIC_LIST LayoutList
= NULL
;
88 static PGENERIC_LIST LanguageList
= NULL
;
91 /* FUNCTIONS ****************************************************************/
94 PrintString(char* fmt
,...)
98 UNICODE_STRING UnicodeString
;
99 ANSI_STRING AnsiString
;
102 vsprintf(buffer
, fmt
, ap
);
105 RtlInitAnsiString(&AnsiString
, buffer
);
106 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
107 NtDisplayString(&UnicodeString
);
108 RtlFreeUnicodeString(&UnicodeString
);
113 DrawBox(IN SHORT xLeft
,
121 /* Draw upper left corner */
124 FillConsoleOutputCharacterA(StdOutput
,
130 /* Draw upper edge */
133 FillConsoleOutputCharacterA(StdOutput
,
139 /* Draw upper right corner */
140 coPos
.X
= xLeft
+ Width
- 1;
142 FillConsoleOutputCharacterA(StdOutput
,
148 /* Draw right edge, inner space and left edge */
149 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
152 FillConsoleOutputCharacterA(StdOutput
,
159 FillConsoleOutputCharacterA(StdOutput
,
165 coPos
.X
= xLeft
+ Width
- 1;
166 FillConsoleOutputCharacterA(StdOutput
,
173 /* Draw lower left corner */
175 coPos
.Y
= yTop
+ Height
- 1;
176 FillConsoleOutputCharacterA(StdOutput
,
182 /* Draw lower edge */
184 coPos
.Y
= yTop
+ Height
- 1;
185 FillConsoleOutputCharacterA(StdOutput
,
191 /* Draw lower right corner */
192 coPos
.X
= xLeft
+ Width
- 1;
193 coPos
.Y
= yTop
+ Height
- 1;
194 FillConsoleOutputCharacterA(StdOutput
,
203 PopupError(PCCH Text
,
221 /* Count text lines and longest line */
228 p
= strchr(pnext
, '\n');
232 Length
= strlen(pnext
);
237 Length
= (ULONG
)(p
- pnext
);
243 if (Length
> MaxLength
)
252 /* Check length of status line */
255 Length
= strlen(Status
);
257 if (Length
> MaxLength
)
261 Width
= MaxLength
+ 4;
267 yTop
= (yScreen
- Height
) / 2;
268 xLeft
= (xScreen
- Width
) / 2;
271 /* Set screen attributes */
273 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
275 FillConsoleOutputAttribute(StdOutput
,
276 FOREGROUND_RED
| BACKGROUND_WHITE
,
282 DrawBox(xLeft
, yTop
, Width
, Height
);
284 /* Print message text */
289 p
= strchr(pnext
, '\n');
293 Length
= strlen(pnext
);
298 Length
= (ULONG
)(p
- pnext
);
305 WriteConsoleOutputCharacterA(StdOutput
,
319 /* Print separator line and status text */
322 coPos
.Y
= yTop
+ Height
- 3;
324 FillConsoleOutputCharacterA(StdOutput
,
331 FillConsoleOutputCharacterA(StdOutput
,
337 coPos
.X
= xLeft
+ Width
- 1;
338 FillConsoleOutputCharacterA(StdOutput
,
346 WriteConsoleOutputCharacterA(StdOutput
,
348 min(strlen(Status
), (SIZE_T
)Width
- 4),
353 if (WaitEvent
== POPUP_WAIT_NONE
)
358 CONSOLE_ConInKey(Ir
);
360 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
361 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
373 * FALSE: Don't quit setup.
376 ConfirmQuit(PINPUT_RECORD Ir
)
379 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
383 CONSOLE_ConInKey(Ir
);
385 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
386 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
391 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
405 PGENERIC_LIST_ENTRY ListEntry
;
408 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
410 if (LayoutList
== NULL
)
412 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
413 if (LayoutList
== NULL
)
415 /* FIXME: Handle error! */
420 ListEntry
= GetFirstListEntry(LayoutList
);
422 /* Search for default layout (if provided) */
423 if (pszNewLayout
!= NULL
)
425 while (ListEntry
!= NULL
)
427 if (!wcscmp(pszNewLayout
, GetListEntryUserData(ListEntry
)))
429 SetCurrentListEntry(LayoutList
, ListEntry
);
433 ListEntry
= GetNextListEntry(ListEntry
);
440 * Displays the LanguagePage.
442 * Next pages: WelcomePage, QuitPage
445 * Init SelectedLanguageId
446 * Init USetupData.LanguageId
449 * Number of the next page.
452 LanguagePage(PINPUT_RECORD Ir
)
454 GENERIC_LIST_UI ListUi
;
455 PWCHAR NewLanguageId
;
456 BOOL RefreshPage
= FALSE
;
458 /* Initialize the computer settings list */
459 if (LanguageList
== NULL
)
461 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
462 if (LanguageList
== NULL
)
464 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
469 SelectedLanguageId
= DefaultLanguage
;
470 USetupData
.LanguageId
= 0;
473 SetConsoleCodePage();
476 /* If there's just a single language in the list skip
477 * the language selection process altogether! */
478 if (GenericListHasSingleEntry(LanguageList
))
480 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
484 InitGenericListUi(&ListUi
, LanguageList
);
485 DrawGenericList(&ListUi
,
491 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
493 MUIDisplayPage(LANGUAGE_PAGE
);
497 CONSOLE_ConInKey(Ir
);
499 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
500 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
502 ScrollDownGenericList(&ListUi
);
505 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
506 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
508 ScrollUpGenericList(&ListUi
);
511 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
512 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
514 ScrollPageDownGenericList(&ListUi
);
517 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
518 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
520 ScrollPageUpGenericList(&ListUi
);
523 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
524 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
529 RedrawGenericList(&ListUi
);
531 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
533 SelectedLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
535 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
537 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
543 SetConsoleCodePage();
547 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
550 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
556 NewLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
558 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
560 /* Clear the language page */
561 MUIClearPage(LANGUAGE_PAGE
);
563 SelectedLanguageId
= NewLanguageId
;
566 SetConsoleCodePage();
568 /* Redraw language selection page in native language */
569 MUIDisplayPage(LANGUAGE_PAGE
);
584 * LanguagePage (at once, default)
585 * InstallIntroPage (at once, if unattended)
590 * Init USetupData.SourcePath
591 * Init USetupData.SourceRootPath
592 * Init USetupData.SourceRootDir
594 * Init USetupData.RequiredPartitionDiskSpace
595 * Init IsUnattendedSetup
596 * If unattended, init *List and sets the Codepage
597 * If unattended, init SelectedLanguageId
598 * If unattended, init USetupData.LanguageId
601 * Number of the next page.
604 SetupStartPage(PINPUT_RECORD Ir
)
608 PGENERIC_LIST_ENTRY ListEntry
;
610 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
612 /* Get the source path and source root path */
613 Status
= GetSourcePaths(&USetupData
.SourcePath
,
614 &USetupData
.SourceRootPath
,
615 &USetupData
.SourceRootDir
);
616 if (!NT_SUCCESS(Status
))
618 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
619 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
622 DPRINT1("SourcePath: '%wZ'\n", &USetupData
.SourcePath
);
623 DPRINT1("SourceRootPath: '%wZ'\n", &USetupData
.SourceRootPath
);
624 DPRINT1("SourceRootDir: '%wZ'\n", &USetupData
.SourceRootDir
);
626 /* Load 'txtsetup.sif' from the installation media */
627 Error
= LoadSetupInf(&SetupInf
, &USetupData
);
628 if (Error
!= ERROR_SUCCESS
)
630 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
634 /* Start the PnP thread */
635 if (hPnpThread
!= NULL
)
637 NtResumeThread(hPnpThread
, NULL
);
641 CheckUnattendedSetup(&USetupData
);
643 if (IsUnattendedSetup
)
645 // TODO: Read options from inf
646 ComputerList
= CreateComputerTypeList(SetupInf
);
647 DisplayList
= CreateDisplayDriverList(SetupInf
);
648 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
650 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
653 SelectedLanguageId
= DefaultLanguage
;
654 wcscpy(SelectedLanguageId
, USetupData
.LocaleID
);
655 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
657 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
659 /* first we hack LanguageList */
660 ListEntry
= GetFirstListEntry(LanguageList
);
661 while (ListEntry
!= NULL
)
663 if (!wcsicmp(USetupData
.LocaleID
, GetListEntryUserData(ListEntry
)))
665 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry
));
666 SetCurrentListEntry(LanguageList
, ListEntry
);
670 ListEntry
= GetNextListEntry(ListEntry
);
674 ListEntry
= GetFirstListEntry(LayoutList
);
675 while (ListEntry
!= NULL
)
677 if (!wcsicmp(USetupData
.LocaleID
, GetListEntryUserData(ListEntry
)))
679 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry
));
680 SetCurrentListEntry(LayoutList
, ListEntry
);
684 ListEntry
= GetNextListEntry(ListEntry
);
687 SetConsoleCodePage();
689 return INSTALL_INTRO_PAGE
;
692 return LANGUAGE_PAGE
;
697 * Displays the WelcomePage.
700 * InstallIntroPage (default)
707 * Number of the next page.
710 WelcomePage(PINPUT_RECORD Ir
)
712 MUIDisplayPage(WELCOME_PAGE
);
716 CONSOLE_ConInKey(Ir
);
718 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
719 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
726 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
728 return INSTALL_INTRO_PAGE
;
730 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
732 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
734 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
745 * Displays the License page.
748 * WelcomePage (default)
751 * Number of the next page.
754 LicensePage(PINPUT_RECORD Ir
)
756 MUIDisplayPage(LICENSE_PAGE
);
760 CONSOLE_ConInKey(Ir
);
762 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
773 * Displays the RepairIntroPage.
776 * RebootPage (default)
782 * Number of the next page.
785 RepairIntroPage(PINPUT_RECORD Ir
)
787 MUIDisplayPage(REPAIR_INTRO_PAGE
);
791 CONSOLE_ConInKey(Ir
);
793 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
797 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
799 RepairUpdateFlag
= TRUE
;
800 return INSTALL_INTRO_PAGE
;
802 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
804 return RECOVERY_PAGE
;
806 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
807 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
813 return REPAIR_INTRO_PAGE
;
817 * Displays the UpgradeRepairPage.
820 * RebootPage (default)
826 * Number of the next page.
829 UpgradeRepairPage(PINPUT_RECORD Ir
)
831 GENERIC_LIST_UI ListUi
;
834 if (PartitionList
== NULL
)
836 PartitionList
= CreatePartitionList();
837 if (PartitionList
== NULL
)
839 /* FIXME: show an error dialog */
840 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
843 else if (IsListEmpty(&PartitionList
->DiskListHead
))
845 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
849 TempPartition
= NULL
;
854 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
855 if (!NtOsInstallsList
)
856 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
857 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
859 RepairUpdateFlag
= FALSE
;
861 // return INSTALL_INTRO_PAGE;
862 return DEVICE_SETTINGS_PAGE
;
863 // return SCSI_CONTROLLER_PAGE;
866 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
868 InitGenericListUi(&ListUi
, NtOsInstallsList
);
869 DrawGenericList(&ListUi
,
874 SaveGenericListState(NtOsInstallsList
);
876 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
879 CONSOLE_ConInKey(Ir
);
881 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
883 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
885 case VK_DOWN
: /* DOWN */
886 ScrollDownGenericList(&ListUi
);
889 ScrollUpGenericList(&ListUi
);
891 case VK_NEXT
: /* PAGE DOWN */
892 ScrollPageDownGenericList(&ListUi
);
894 case VK_PRIOR
: /* PAGE UP */
895 ScrollPageUpGenericList(&ListUi
);
902 RedrawGenericList(&ListUi
);
905 case VK_ESCAPE
: /* ESC */
907 RestoreGenericListState(NtOsInstallsList
);
908 // return nextPage; // prevPage;
910 // return INSTALL_INTRO_PAGE;
911 return DEVICE_SETTINGS_PAGE
;
912 // return SCSI_CONTROLLER_PAGE;
918 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
919 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
920 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
922 /* Retrieve the current installation */
923 CurrentInstallation
= (PNTOS_INSTALLATION
)GetListEntryUserData(GetCurrentListEntry(NtOsInstallsList
));
924 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
925 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
927 RepairUpdateFlag
= TRUE
;
930 /***/return INSTALL_INTRO_PAGE
;/***/
932 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
933 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
935 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
940 return UPGRADE_REPAIR_PAGE
;
945 * Displays the InstallIntroPage.
948 * DeviceSettingsPage (At once if repair or update is selected)
949 * SelectPartitionPage (At once if unattended setup)
950 * DeviceSettingsPage (default)
954 * Number of the next page.
957 InstallIntroPage(PINPUT_RECORD Ir
)
959 if (RepairUpdateFlag
)
961 #if 1 /* Old code that looks good */
963 // return SELECT_PARTITION_PAGE;
964 return DEVICE_SETTINGS_PAGE
;
966 #else /* Possible new code? */
968 return DEVICE_SETTINGS_PAGE
;
969 // return SCSI_CONTROLLER_PAGE;
974 if (IsUnattendedSetup
)
975 return SELECT_PARTITION_PAGE
;
977 MUIDisplayPage(INSTALL_INTRO_PAGE
);
981 CONSOLE_ConInKey(Ir
);
983 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
984 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
991 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
993 return UPGRADE_REPAIR_PAGE
;
997 return INSTALL_INTRO_PAGE
;
1003 ScsiControllerPage(PINPUT_RECORD Ir
)
1005 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1007 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1009 /* FIXME: print loaded mass storage driver descriptions */
1011 CONSOLE_SetTextXY(8, 10, "TEST device");
1014 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1018 CONSOLE_ConInKey(Ir
);
1020 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1021 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1023 if (ConfirmQuit(Ir
))
1028 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1030 return DEVICE_SETTINGS_PAGE
;
1034 return SCSI_CONTROLLER_PAGE
;
1038 OemDriverPage(PINPUT_RECORD Ir
)
1040 // MUIDisplayPage(OEM_DRIVER_PAGE);
1042 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1044 /* FIXME: Implement!! */
1046 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1050 CONSOLE_ConInKey(Ir
);
1052 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1053 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1055 if (ConfirmQuit(Ir
))
1060 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1062 return DEVICE_SETTINGS_PAGE
;
1066 return OEM_DRIVER_PAGE
;
1072 * Displays the DeviceSettingsPage.
1075 * SelectPartitionPage (At once if repair or update is selected)
1076 * ComputerSettingsPage
1077 * DisplaySettingsPage
1078 * KeyboardSettingsPage
1079 * LayoutsettingsPage
1080 * SelectPartitionPage
1090 * Number of the next page.
1093 DeviceSettingsPage(PINPUT_RECORD Ir
)
1095 static ULONG Line
= 16;
1096 CHAR CurrentItemText
[256];
1098 /* Initialize the computer settings list */
1099 if (ComputerList
== NULL
)
1101 ComputerList
= CreateComputerTypeList(SetupInf
);
1102 if (ComputerList
== NULL
)
1104 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1109 /* Initialize the display settings list */
1110 if (DisplayList
== NULL
)
1112 DisplayList
= CreateDisplayDriverList(SetupInf
);
1113 if (DisplayList
== NULL
)
1115 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1120 /* Initialize the keyboard settings list */
1121 if (KeyboardList
== NULL
)
1123 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1124 if (KeyboardList
== NULL
)
1126 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1131 /* Initialize the keyboard layout list */
1132 if (LayoutList
== NULL
)
1134 LayoutList
= CreateKeyboardLayoutList(SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1135 if (LayoutList
== NULL
)
1137 /* FIXME: report error */
1138 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1143 if (RepairUpdateFlag
)
1144 return SELECT_PARTITION_PAGE
;
1146 // if (IsUnattendedSetup)
1147 // return SELECT_PARTITION_PAGE;
1149 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1151 sprintf(CurrentItemText
, "%S", GetListEntryText(GetCurrentListEntry(ComputerList
)));
1152 CONSOLE_SetTextXY(25, 11, CurrentItemText
);
1153 sprintf(CurrentItemText
, "%S", GetListEntryText(GetCurrentListEntry(DisplayList
)));
1154 CONSOLE_SetTextXY(25, 12, CurrentItemText
);
1155 sprintf(CurrentItemText
, "%S", GetListEntryText(GetCurrentListEntry(KeyboardList
)));
1156 CONSOLE_SetTextXY(25, 13, CurrentItemText
);
1157 sprintf(CurrentItemText
, "%S", GetListEntryText(GetCurrentListEntry(LayoutList
)));
1158 CONSOLE_SetTextXY(25, 14, CurrentItemText
);
1160 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1164 CONSOLE_ConInKey(Ir
);
1166 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1167 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1169 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1173 else if (Line
== 16)
1178 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1180 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1181 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1183 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1187 else if (Line
== 16)
1192 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1194 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1195 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1197 if (ConfirmQuit(Ir
))
1202 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1205 return COMPUTER_SETTINGS_PAGE
;
1206 else if (Line
== 12)
1207 return DISPLAY_SETTINGS_PAGE
;
1208 else if (Line
== 13)
1209 return KEYBOARD_SETTINGS_PAGE
;
1210 else if (Line
== 14)
1211 return LAYOUT_SETTINGS_PAGE
;
1212 else if (Line
== 16)
1213 return SELECT_PARTITION_PAGE
;
1217 return DEVICE_SETTINGS_PAGE
;
1222 * Handles generic selection lists.
1225 * GenericList: The list to handle.
1226 * nextPage: The page it needs to jump to after this page.
1227 * Ir: The PINPUT_RECORD
1230 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1231 PAGE_NUMBER nextPage
,
1236 CONSOLE_ConInKey(Ir
);
1238 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1239 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1241 ScrollDownGenericList(ListUi
);
1243 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1244 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1246 ScrollUpGenericList(ListUi
);
1248 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1249 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1251 ScrollPageDownGenericList(ListUi
);
1253 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1254 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1256 ScrollPageUpGenericList(ListUi
);
1258 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1259 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1261 if (ConfirmQuit(Ir
))
1264 RedrawGenericList(ListUi
);
1266 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1267 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1269 RestoreGenericListState(ListUi
->List
);
1270 return nextPage
; // Use some "prevPage;" instead?
1272 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1276 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1279 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1286 * Displays the ComputerSettingsPage.
1289 * DeviceSettingsPage
1293 * Number of the next page.
1296 ComputerSettingsPage(PINPUT_RECORD Ir
)
1298 GENERIC_LIST_UI ListUi
;
1299 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1301 InitGenericListUi(&ListUi
, ComputerList
);
1302 DrawGenericList(&ListUi
,
1308 SaveGenericListState(ComputerList
);
1310 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1315 * Displays the DisplaySettingsPage.
1318 * DeviceSettingsPage
1322 * Number of the next page.
1325 DisplaySettingsPage(PINPUT_RECORD Ir
)
1327 GENERIC_LIST_UI ListUi
;
1328 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1330 InitGenericListUi(&ListUi
, DisplayList
);
1331 DrawGenericList(&ListUi
,
1337 SaveGenericListState(DisplayList
);
1339 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1344 * Displays the KeyboardSettingsPage.
1347 * DeviceSettingsPage
1351 * Number of the next page.
1354 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1356 GENERIC_LIST_UI ListUi
;
1357 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1359 InitGenericListUi(&ListUi
, KeyboardList
);
1360 DrawGenericList(&ListUi
,
1366 SaveGenericListState(KeyboardList
);
1368 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1373 * Displays the LayoutSettingsPage.
1376 * DeviceSettingsPage
1380 * Number of the next page.
1383 LayoutSettingsPage(PINPUT_RECORD Ir
)
1385 GENERIC_LIST_UI ListUi
;
1386 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1388 InitGenericListUi(&ListUi
, LayoutList
);
1389 DrawGenericList(&ListUi
,
1395 SaveGenericListState(LayoutList
);
1397 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1402 IsDiskSizeValid(PPARTENTRY PartEntry
)
1406 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1407 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1409 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1411 /* Partition is too small so ask for another one */
1412 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1423 * Displays the SelectPartitionPage.
1426 * SelectFileSystemPage (At once if unattended)
1427 * SelectFileSystemPage (Default if free space is selected)
1428 * CreatePrimaryPartitionPage
1429 * CreateExtendedPartitionPage
1430 * CreateLogicalPartitionPage
1431 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1432 * DeletePartitionPage
1436 * Set InstallShortcut (only if not unattended + free space is selected)
1439 * Number of the next page.
1442 SelectPartitionPage(PINPUT_RECORD Ir
)
1447 if (PartitionList
== NULL
)
1449 PartitionList
= CreatePartitionList();
1450 if (PartitionList
== NULL
)
1452 /* FIXME: show an error dialog */
1453 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1456 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1458 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1462 TempPartition
= NULL
;
1463 FormatState
= Start
;
1466 if (RepairUpdateFlag
)
1468 /* Determine the selected installation disk & partition */
1469 if (!SelectPartition(PartitionList
,
1470 CurrentInstallation
->DiskNumber
,
1471 CurrentInstallation
->PartitionNumber
))
1473 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1477 return SELECT_FILE_SYSTEM_PAGE
;
1480 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1482 InitPartitionListUi(&ListUi
, PartitionList
,
1487 DrawPartitionList(&ListUi
);
1489 if (IsUnattendedSetup
)
1491 if (!SelectPartition(PartitionList
,
1492 USetupData
.DestinationDiskNumber
,
1493 USetupData
.DestinationPartitionNumber
))
1495 if (USetupData
.AutoPartition
)
1497 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1499 CreateLogicalPartition(PartitionList
,
1500 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1505 CreatePrimaryPartition(PartitionList
,
1506 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1510 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1511 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1513 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1514 USetupData
.RequiredPartitionDiskSpace
);
1515 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1518 return SELECT_FILE_SYSTEM_PAGE
;
1523 DrawPartitionList(&ListUi
);
1525 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1526 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1528 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1529 USetupData
.RequiredPartitionDiskSpace
);
1530 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1533 return SELECT_FILE_SYSTEM_PAGE
;
1539 /* Update status text */
1540 if (PartitionList
->CurrentPartition
== NULL
)
1542 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1544 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1546 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1548 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1552 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1557 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1559 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1561 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1565 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1570 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1574 CONSOLE_ConInKey(Ir
);
1576 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1577 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1579 if (ConfirmQuit(Ir
))
1581 DestroyPartitionList(PartitionList
);
1582 PartitionList
= NULL
;
1588 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1589 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1591 ScrollDownPartitionList(&ListUi
);
1593 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1594 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1596 ScrollUpPartitionList(&ListUi
);
1598 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1600 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1601 continue; // return SELECT_PARTITION_PAGE;
1603 if (PartitionList
->CurrentPartition
== NULL
||
1604 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1606 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1608 CreateLogicalPartition(PartitionList
,
1614 CreatePrimaryPartition(PartitionList
,
1620 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1622 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1623 USetupData
.RequiredPartitionDiskSpace
);
1624 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1627 return SELECT_FILE_SYSTEM_PAGE
;
1629 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1631 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1633 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1634 if (Error
!= NOT_AN_ERROR
)
1636 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1637 return SELECT_PARTITION_PAGE
;
1640 return CREATE_PRIMARY_PARTITION_PAGE
;
1643 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1645 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1647 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1648 if (Error
!= NOT_AN_ERROR
)
1650 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1651 return SELECT_PARTITION_PAGE
;
1654 return CREATE_EXTENDED_PARTITION_PAGE
;
1657 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1659 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1661 Error
= LogicalPartitionCreationChecks(PartitionList
);
1662 if (Error
!= NOT_AN_ERROR
)
1664 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1665 return SELECT_PARTITION_PAGE
;
1668 return CREATE_LOGICAL_PARTITION_PAGE
;
1671 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1673 WCHAR PathBuffer
[MAX_PATH
];
1674 UNICODE_STRING CurrentPartition
;
1676 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1678 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1679 return SELECT_PARTITION_PAGE
;
1682 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1683 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1684 PartitionList
->CurrentDisk
->DiskNumber
,
1685 PartitionList
->CurrentPartition
->PartitionNumber
);
1686 RtlInitUnicodeString(&CurrentPartition
, PathBuffer
);
1689 * Check whether the user attempts to delete the partition on which
1690 * the installation source is present. If so, fail with an error.
1692 // &USetupData.SourceRootPath
1693 if (RtlPrefixUnicodeString(&CurrentPartition
, &USetupData
.SourcePath
, TRUE
))
1695 PopupError("You cannot delete the partition containing the installation source!",
1696 MUIGetString(STRING_CONTINUE
),
1697 Ir
, POPUP_WAIT_ENTER
);
1698 return SELECT_PARTITION_PAGE
;
1701 if (PartitionList
->CurrentPartition
->BootIndicator
||
1702 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1704 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1707 return DELETE_PARTITION_PAGE
;
1711 return SELECT_PARTITION_PAGE
;
1715 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1716 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1717 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1720 ShowPartitionSizeInputBox(SHORT Left
,
1744 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1749 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1750 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1753 WriteConsoleOutputCharacterA(StdOutput
,
1759 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1760 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1762 WriteConsoleOutputCharacterA(StdOutput
,
1768 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1769 Length
= wcslen(InputBuffer
);
1771 CONSOLE_SetInputTextXY(iLeft
,
1773 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1775 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1776 CONSOLE_SetCursorType(TRUE
, TRUE
);
1780 CONSOLE_ConInKey(&Ir
);
1782 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1783 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1788 InputBuffer
[0] = UNICODE_NULL
;
1789 CONSOLE_SetCursorType(TRUE
, FALSE
);
1792 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1794 CONSOLE_SetCursorType(TRUE
, FALSE
);
1797 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1802 InputBuffer
[0] = UNICODE_NULL
;
1803 CONSOLE_SetCursorType(TRUE
, FALSE
);
1806 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1807 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1810 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1812 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1813 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1816 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1818 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1819 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1824 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1827 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1828 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1833 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1836 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1837 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1841 memmove(&InputBuffer
[Pos
],
1842 &InputBuffer
[Pos
+ 1],
1843 (Length
- Pos
- 1) * sizeof(WCHAR
));
1844 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1847 CONSOLE_SetInputTextXY(iLeft
,
1849 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1851 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1854 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1859 memmove(&InputBuffer
[Pos
- 1],
1861 (Length
- Pos
) * sizeof(WCHAR
));
1862 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1866 CONSOLE_SetInputTextXY(iLeft
,
1868 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1870 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1873 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1875 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1877 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1879 if ((ch
>= L
'0') && (ch
<= L
'9'))
1882 memmove(&InputBuffer
[Pos
+ 1],
1884 (Length
- Pos
) * sizeof(WCHAR
));
1885 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1886 InputBuffer
[Pos
] = ch
;
1890 CONSOLE_SetInputTextXY(iLeft
,
1892 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1894 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1903 * Displays the CreatePrimaryPartitionPage.
1906 * SelectPartitionPage
1907 * SelectFileSystemPage (default)
1911 * Number of the next page.
1914 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1916 PDISKENTRY DiskEntry
;
1917 PPARTENTRY PartEntry
;
1920 WCHAR InputBuffer
[50];
1924 ULONGLONG SectorCount
;
1927 if (PartitionList
== NULL
||
1928 PartitionList
->CurrentDisk
== NULL
||
1929 PartitionList
->CurrentPartition
== NULL
)
1931 /* FIXME: show an error dialog */
1935 DiskEntry
= PartitionList
->CurrentDisk
;
1936 PartEntry
= PartitionList
->CurrentPartition
;
1938 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1940 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1942 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1944 if (DiskSize
>= 10 * GB
) /* 10 GB */
1946 DiskSize
= DiskSize
/ GB
;
1947 Unit
= MUIGetString(STRING_GB
);
1952 DiskSize
= DiskSize
/ MB
;
1956 Unit
= MUIGetString(STRING_MB
);
1959 if (DiskEntry
->DriverName
.Length
> 0)
1961 CONSOLE_PrintTextXY(6, 10,
1962 MUIGetString(STRING_HDINFOPARTCREATE_1
),
1965 DiskEntry
->DiskNumber
,
1969 &DiskEntry
->DriverName
,
1970 DiskEntry
->NoMbr
? "GPT" : "MBR");
1974 CONSOLE_PrintTextXY(6, 10,
1975 MUIGetString(STRING_HDINFOPARTCREATE_2
),
1978 DiskEntry
->DiskNumber
,
1982 DiskEntry
->NoMbr
? "GPT" : "MBR");
1985 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
1988 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1989 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
1992 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
1994 PartEntry
= PartitionList
->CurrentPartition
;
1997 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
1999 if (MaxSize
> PARTITION_MAXSIZE
)
2000 MaxSize
= PARTITION_MAXSIZE
;
2002 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2003 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2007 if (ConfirmQuit(Ir
))
2014 return SELECT_PARTITION_PAGE
;
2018 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2026 if (PartSize
> MaxSize
)
2032 /* Convert to bytes */
2033 if (PartSize
== MaxSize
)
2035 /* Use all of the unpartitioned disk space */
2036 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2040 /* Calculate the sector count from the size in MB */
2041 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2043 /* But never get larger than the unpartitioned disk space */
2044 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2045 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2048 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2050 CreatePrimaryPartition(PartitionList
,
2054 return SELECT_PARTITION_PAGE
;
2058 return CREATE_PRIMARY_PARTITION_PAGE
;
2063 * Displays the CreateExtendedPartitionPage.
2066 * SelectPartitionPage (default)
2070 * Number of the next page.
2073 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2075 PDISKENTRY DiskEntry
;
2076 PPARTENTRY PartEntry
;
2079 WCHAR InputBuffer
[50];
2083 ULONGLONG SectorCount
;
2086 if (PartitionList
== NULL
||
2087 PartitionList
->CurrentDisk
== NULL
||
2088 PartitionList
->CurrentPartition
== NULL
)
2090 /* FIXME: show an error dialog */
2094 DiskEntry
= PartitionList
->CurrentDisk
;
2095 PartEntry
= PartitionList
->CurrentPartition
;
2097 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2099 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2101 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2103 if (DiskSize
>= 10 * GB
) /* 10 GB */
2105 DiskSize
= DiskSize
/ GB
;
2106 Unit
= MUIGetString(STRING_GB
);
2111 DiskSize
= DiskSize
/ MB
;
2115 Unit
= MUIGetString(STRING_MB
);
2118 if (DiskEntry
->DriverName
.Length
> 0)
2120 CONSOLE_PrintTextXY(6, 10,
2121 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2124 DiskEntry
->DiskNumber
,
2128 &DiskEntry
->DriverName
,
2129 DiskEntry
->NoMbr
? "GPT" : "MBR");
2133 CONSOLE_PrintTextXY(6, 10,
2134 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2137 DiskEntry
->DiskNumber
,
2141 DiskEntry
->NoMbr
? "GPT" : "MBR");
2144 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2147 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2148 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2151 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2153 PartEntry
= PartitionList
->CurrentPartition
;
2156 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2158 if (MaxSize
> PARTITION_MAXSIZE
)
2159 MaxSize
= PARTITION_MAXSIZE
;
2161 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2162 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2166 if (ConfirmQuit(Ir
))
2173 return SELECT_PARTITION_PAGE
;
2177 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2185 if (PartSize
> MaxSize
)
2191 /* Convert to bytes */
2192 if (PartSize
== MaxSize
)
2194 /* Use all of the unpartitioned disk space */
2195 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2199 /* Calculate the sector count from the size in MB */
2200 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2202 /* But never get larger than the unpartitioned disk space */
2203 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2204 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2207 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2209 CreateExtendedPartition(PartitionList
,
2212 return SELECT_PARTITION_PAGE
;
2216 return CREATE_EXTENDED_PARTITION_PAGE
;
2221 * Displays the CreateLogicalPartitionPage.
2224 * SelectFileSystemPage (default)
2228 * Number of the next page.
2231 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2233 PDISKENTRY DiskEntry
;
2234 PPARTENTRY PartEntry
;
2237 WCHAR InputBuffer
[50];
2241 ULONGLONG SectorCount
;
2244 if (PartitionList
== NULL
||
2245 PartitionList
->CurrentDisk
== NULL
||
2246 PartitionList
->CurrentPartition
== NULL
)
2248 /* FIXME: show an error dialog */
2252 DiskEntry
= PartitionList
->CurrentDisk
;
2253 PartEntry
= PartitionList
->CurrentPartition
;
2255 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2257 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2259 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2261 if (DiskSize
>= 10 * GB
) /* 10 GB */
2263 DiskSize
= DiskSize
/ GB
;
2264 Unit
= MUIGetString(STRING_GB
);
2269 DiskSize
= DiskSize
/ MB
;
2273 Unit
= MUIGetString(STRING_MB
);
2276 if (DiskEntry
->DriverName
.Length
> 0)
2278 CONSOLE_PrintTextXY(6, 10,
2279 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2282 DiskEntry
->DiskNumber
,
2286 &DiskEntry
->DriverName
,
2287 DiskEntry
->NoMbr
? "GPT" : "MBR");
2291 CONSOLE_PrintTextXY(6, 10,
2292 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2295 DiskEntry
->DiskNumber
,
2299 DiskEntry
->NoMbr
? "GPT" : "MBR");
2302 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2305 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2306 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2309 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2311 PartEntry
= PartitionList
->CurrentPartition
;
2314 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2316 if (MaxSize
> PARTITION_MAXSIZE
)
2317 MaxSize
= PARTITION_MAXSIZE
;
2319 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2320 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2324 if (ConfirmQuit(Ir
))
2331 return SELECT_PARTITION_PAGE
;
2335 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2343 if (PartSize
> MaxSize
)
2349 /* Convert to bytes */
2350 if (PartSize
== MaxSize
)
2352 /* Use all of the unpartitioned disk space */
2353 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2357 /* Calculate the sector count from the size in MB */
2358 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2360 /* But never get larger than the unpartitioned disk space */
2361 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2362 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2365 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2367 CreateLogicalPartition(PartitionList
,
2371 return SELECT_PARTITION_PAGE
;
2375 return CREATE_LOGICAL_PARTITION_PAGE
;
2380 * Displays the ConfirmDeleteSystemPartitionPage.
2383 * DeletePartitionPage (default)
2384 * SelectPartitionPage
2387 * Number of the next page.
2390 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2392 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2396 CONSOLE_ConInKey(Ir
);
2398 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2399 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2401 if (ConfirmQuit(Ir
))
2406 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2408 return DELETE_PARTITION_PAGE
;
2410 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2412 return SELECT_PARTITION_PAGE
;
2416 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2421 * Displays the DeletePartitionPage.
2424 * SelectPartitionPage (default)
2428 * Number of the next page.
2431 DeletePartitionPage(PINPUT_RECORD Ir
)
2433 PDISKENTRY DiskEntry
;
2434 PPARTENTRY PartEntry
;
2438 CHAR PartTypeString
[32];
2440 if (PartitionList
== NULL
||
2441 PartitionList
->CurrentDisk
== NULL
||
2442 PartitionList
->CurrentPartition
== NULL
)
2444 /* FIXME: show an error dialog */
2448 DiskEntry
= PartitionList
->CurrentDisk
;
2449 PartEntry
= PartitionList
->CurrentPartition
;
2451 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2453 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2455 ARRAYSIZE(PartTypeString
));
2457 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2459 if (PartSize
>= 10 * GB
) /* 10 GB */
2461 PartSize
= PartSize
/ GB
;
2462 Unit
= MUIGetString(STRING_GB
);
2466 if (PartSize
>= 10 * MB
) /* 10 MB */
2468 PartSize
= PartSize
/ MB
;
2469 Unit
= MUIGetString(STRING_MB
);
2473 PartSize
= PartSize
/ KB
;
2474 Unit
= MUIGetString(STRING_KB
);
2477 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2479 CONSOLE_PrintTextXY(6, 10,
2480 MUIGetString(STRING_HDDINFOUNK2
),
2481 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2482 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2483 PartEntry
->PartitionType
,
2489 CONSOLE_PrintTextXY(6, 10,
2490 " %c%c %s %I64u %s",
2491 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2492 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2498 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2500 if (DiskSize
>= 10 * GB
) /* 10 GB */
2502 DiskSize
= DiskSize
/ GB
;
2503 Unit
= MUIGetString(STRING_GB
);
2508 DiskSize
= DiskSize
/ MB
;
2512 Unit
= MUIGetString(STRING_MB
);
2515 if (DiskEntry
->DriverName
.Length
> 0)
2517 CONSOLE_PrintTextXY(6, 12,
2518 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2521 DiskEntry
->DiskNumber
,
2525 &DiskEntry
->DriverName
,
2526 DiskEntry
->NoMbr
? "GPT" : "MBR");
2530 CONSOLE_PrintTextXY(6, 12,
2531 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2534 DiskEntry
->DiskNumber
,
2538 DiskEntry
->NoMbr
? "GPT" : "MBR");
2543 CONSOLE_ConInKey(Ir
);
2545 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2546 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2548 if (ConfirmQuit(Ir
))
2553 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2555 return SELECT_PARTITION_PAGE
;
2557 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2559 DeleteCurrentPartition(PartitionList
);
2561 return SELECT_PARTITION_PAGE
;
2565 return DELETE_PARTITION_PAGE
;
2570 * Displays the SelectFileSystemPage.
2573 * CheckFileSystemPage (At once if RepairUpdate is selected)
2574 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2575 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2576 * SelectPartitionPage (If the user aborts)
2577 * FormatPartitionPage (Default)
2581 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2582 * Calls CheckActiveSystemPartition()
2585 * Number of the next page.
2588 SelectFileSystemPage(PINPUT_RECORD Ir
)
2590 PDISKENTRY DiskEntry
;
2591 PPARTENTRY PartEntry
;
2596 CHAR PartTypeString
[32];
2597 FORMATMACHINESTATE PreviousFormatState
;
2599 DPRINT("SelectFileSystemPage()\n");
2601 if (PartitionList
== NULL
||
2602 PartitionList
->CurrentDisk
== NULL
||
2603 PartitionList
->CurrentPartition
== NULL
)
2605 /* FIXME: show an error dialog */
2609 /* Find or set the active system partition */
2610 CheckActiveSystemPartition(PartitionList
);
2611 if (PartitionList
->SystemPartition
== NULL
)
2613 /* FIXME: show an error dialog */
2615 // Error dialog should say that we cannot find a suitable
2616 // system partition and create one on the system. At this point,
2617 // it may be nice to ask the user whether he wants to continue,
2618 // or use an external drive as the system drive/partition
2619 // (e.g. floppy, USB drive, etc...)
2624 PreviousFormatState
= FormatState
;
2625 switch (FormatState
)
2629 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2631 TempPartition
= PartitionList
->SystemPartition
;
2632 TempPartition
->NeedsCheck
= TRUE
;
2634 FormatState
= FormatSystemPartition
;
2635 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2639 TempPartition
= PartitionList
->CurrentPartition
;
2640 TempPartition
->NeedsCheck
= TRUE
;
2642 FormatState
= FormatInstallPartition
;
2643 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2648 case FormatSystemPartition
:
2650 TempPartition
= PartitionList
->CurrentPartition
;
2651 TempPartition
->NeedsCheck
= TRUE
;
2653 FormatState
= FormatInstallPartition
;
2654 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2658 case FormatInstallPartition
:
2660 if (GetNextUnformattedPartition(PartitionList
,
2664 FormatState
= FormatOtherPartition
;
2665 TempPartition
->NeedsCheck
= TRUE
;
2666 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2670 FormatState
= FormatDone
;
2671 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2672 return CHECK_FILE_SYSTEM_PAGE
;
2677 case FormatOtherPartition
:
2679 if (GetNextUnformattedPartition(PartitionList
,
2683 FormatState
= FormatOtherPartition
;
2684 TempPartition
->NeedsCheck
= TRUE
;
2685 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2689 FormatState
= FormatDone
;
2690 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2691 return CHECK_FILE_SYSTEM_PAGE
;
2698 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2699 /* FIXME: show an error dialog */
2704 PartEntry
= TempPartition
;
2705 DiskEntry
= PartEntry
->DiskEntry
;
2707 /* Adjust disk size */
2708 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2709 if (DiskSize
>= 10 * GB
) /* 10 GB */
2711 DiskSize
= DiskSize
/ GB
;
2712 DiskUnit
= MUIGetString(STRING_GB
);
2716 DiskSize
= DiskSize
/ MB
;
2717 DiskUnit
= MUIGetString(STRING_MB
);
2720 /* Adjust partition size */
2721 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2722 if (PartSize
>= 10 * GB
) /* 10 GB */
2724 PartSize
= PartSize
/ GB
;
2725 PartUnit
= MUIGetString(STRING_GB
);
2729 PartSize
= PartSize
/ MB
;
2730 PartUnit
= MUIGetString(STRING_MB
);
2733 /* Adjust partition type */
2734 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2736 ARRAYSIZE(PartTypeString
));
2738 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2740 if (PartEntry
->AutoCreate
)
2742 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2745 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2746 PartEntry
->PartitionNumber
,
2752 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2753 DiskEntry
->DiskNumber
,
2759 &DiskEntry
->DriverName
,
2760 DiskEntry
->NoMbr
? "GPT" : "MBR");
2762 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2764 PartEntry
->AutoCreate
= FALSE
;
2766 else if (PartEntry
->New
)
2768 switch (FormatState
)
2770 case FormatSystemPartition
:
2771 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2774 case FormatInstallPartition
:
2775 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2778 case FormatOtherPartition
:
2779 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2786 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2790 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2792 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2794 CONSOLE_PrintTextXY(8, 10,
2795 MUIGetString(STRING_HDDINFOUNK4
),
2796 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2797 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2798 PartEntry
->PartitionType
,
2804 CONSOLE_PrintTextXY(8, 10,
2806 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2807 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2813 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2814 DiskEntry
->DiskNumber
,
2820 &DiskEntry
->DriverName
,
2821 DiskEntry
->NoMbr
? "GPT" : "MBR");
2824 if (FileSystemList
== NULL
)
2826 /* Create the file system list, and by default select the "FAT" file system */
2827 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2828 if (FileSystemList
== NULL
)
2830 /* FIXME: show an error dialog */
2835 if (RepairUpdateFlag
)
2837 return CHECK_FILE_SYSTEM_PAGE
;
2838 //return SELECT_PARTITION_PAGE;
2841 if (IsUnattendedSetup
)
2843 if (USetupData
.FormatPartition
)
2846 * We use whatever currently selected file system we have
2847 * (by default, this is "FAT", as per the initialization
2848 * performed above). Note that it may be interesting to specify
2849 * which file system to use in unattended installations, in the
2850 * txtsetup.sif file.
2852 return FORMAT_PARTITION_PAGE
;
2855 return CHECK_FILE_SYSTEM_PAGE
;
2858 DrawFileSystemList(FileSystemList
);
2862 CONSOLE_ConInKey(Ir
);
2864 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2865 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2867 if (ConfirmQuit(Ir
))
2872 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2873 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2875 FormatState
= Start
;
2876 return SELECT_PARTITION_PAGE
;
2878 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2879 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2881 ScrollDownFileSystemList(FileSystemList
);
2883 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2884 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2886 ScrollUpFileSystemList(FileSystemList
);
2888 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2890 if (!FileSystemList
->Selected
->FileSystem
)
2891 return SELECT_FILE_SYSTEM_PAGE
;
2893 return FORMAT_PARTITION_PAGE
;
2897 FormatState
= PreviousFormatState
;
2899 return SELECT_FILE_SYSTEM_PAGE
;
2904 * Displays the FormatPartitionPage.
2907 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2908 * SelectPartitionPage (At once)
2912 * Sets PartitionList->CurrentPartition->FormatState
2913 * Sets USetupData.DestinationRootPath
2916 * Number of the next page.
2919 FormatPartitionPage(PINPUT_RECORD Ir
)
2921 UNICODE_STRING PartitionRootPath
;
2922 WCHAR PathBuffer
[MAX_PATH
];
2923 PDISKENTRY DiskEntry
;
2924 PPARTENTRY PartEntry
;
2925 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2931 PPARTITION_INFORMATION PartitionInfo
;
2934 DPRINT("FormatPartitionPage()\n");
2936 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2938 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2940 /* FIXME: show an error dialog */
2944 PartEntry
= TempPartition
;
2945 DiskEntry
= PartEntry
->DiskEntry
;
2947 SelectedFileSystem
= FileSystemList
->Selected
;
2951 if (!IsUnattendedSetup
)
2953 CONSOLE_ConInKey(Ir
);
2956 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2957 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2959 if (ConfirmQuit(Ir
))
2964 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
2966 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2968 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
2970 /* FIXME: show an error dialog */
2975 CONSOLE_PrintTextXY(6, 12,
2976 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2977 DiskEntry
->Cylinders
,
2978 DiskEntry
->TracksPerCylinder
,
2979 DiskEntry
->SectorsPerTrack
,
2980 DiskEntry
->BytesPerSector
,
2981 DiskEntry
->Dirty
? '*' : ' ');
2985 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
2987 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
2989 CONSOLE_PrintTextXY(6, Line
,
2990 "%2u: %2lu %c %12I64u %12I64u %02x",
2992 PartitionInfo
->PartitionNumber
,
2993 PartitionInfo
->BootIndicator
? 'A' : '-',
2994 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
2995 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
2996 PartitionInfo
->PartitionType
);
3001 /* Commit the partition changes to the disk */
3002 if (!WritePartitionsToDisk(PartitionList
))
3004 DPRINT("WritePartitionsToDisk() failed\n");
3005 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3009 /* Set PartitionRootPath */
3010 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3011 L
"\\Device\\Harddisk%lu\\Partition%lu",
3012 DiskEntry
->DiskNumber
,
3013 PartEntry
->PartitionNumber
);
3014 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3015 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3017 /* Format the partition */
3018 if (SelectedFileSystem
->FileSystem
)
3020 Status
= FormatPartition(&PartitionRootPath
,
3021 SelectedFileSystem
);
3022 if (!NT_SUCCESS(Status
))
3024 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3025 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3029 PartEntry
->FormatState
= Formatted
;
3030 // PartEntry->FileSystem = FileSystem;
3031 PartEntry
->New
= FALSE
;
3035 CONSOLE_SetStatusText(" Done. Press any key ...");
3036 CONSOLE_ConInKey(Ir
);
3039 return SELECT_FILE_SYSTEM_PAGE
;
3043 return FORMAT_PARTITION_PAGE
;
3048 * Displays the CheckFileSystemPage.
3051 * InstallDirectoryPage (At once)
3055 * Inits or reloads FileSystemList
3058 * Number of the next page.
3061 CheckFileSystemPage(PINPUT_RECORD Ir
)
3063 PFILE_SYSTEM CurrentFileSystem
;
3064 UNICODE_STRING PartitionRootPath
;
3065 WCHAR PathBuffer
[MAX_PATH
];
3066 CHAR Buffer
[MAX_PATH
];
3067 PDISKENTRY DiskEntry
;
3068 PPARTENTRY PartEntry
;
3071 if (PartitionList
== NULL
)
3073 /* FIXME: show an error dialog */
3077 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3079 return INSTALL_DIRECTORY_PAGE
;
3082 /* Set PartitionRootPath */
3083 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3084 L
"\\Device\\Harddisk%lu\\Partition%lu",
3085 DiskEntry
->DiskNumber
,
3086 PartEntry
->PartitionNumber
);
3087 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3088 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3090 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3092 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3094 CurrentFileSystem
= PartEntry
->FileSystem
;
3095 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3096 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3098 /* HACK: Do not try to check a partition with an unknown filesystem */
3099 if (CurrentFileSystem
== NULL
)
3101 PartEntry
->NeedsCheck
= FALSE
;
3102 return CHECK_FILE_SYSTEM_PAGE
;
3105 if (CurrentFileSystem
->ChkdskFunc
== NULL
)
3108 "Setup is currently unable to check a partition formatted in %S.\n"
3110 " \x07 Press ENTER to continue Setup.\n"
3111 " \x07 Press F3 to quit Setup.",
3112 CurrentFileSystem
->FileSystemName
);
3115 MUIGetString(STRING_QUITCONTINUE
),
3116 NULL
, POPUP_WAIT_NONE
);
3120 CONSOLE_ConInKey(Ir
);
3122 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3123 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3125 if (ConfirmQuit(Ir
))
3128 return CHECK_FILE_SYSTEM_PAGE
;
3130 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3132 PartEntry
->NeedsCheck
= FALSE
;
3133 return CHECK_FILE_SYSTEM_PAGE
;
3139 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3140 if (!NT_SUCCESS(Status
))
3142 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3143 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3144 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3145 "(Status 0x%08lx).\n", Status
);
3147 // MUIGetString(STRING_REBOOTCOMPUTER),
3148 MUIGetString(STRING_CONTINUE
),
3149 Ir
, POPUP_WAIT_ENTER
);
3151 // return QUIT_PAGE;
3154 PartEntry
->NeedsCheck
= FALSE
;
3155 return CHECK_FILE_SYSTEM_PAGE
;
3161 BuildInstallPaths(PWSTR InstallDir
,
3162 PDISKENTRY DiskEntry
,
3163 PPARTENTRY PartEntry
)
3165 WCHAR PathBuffer
[MAX_PATH
];
3167 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3168 /* Create 'InstallPath' string */
3169 RtlFreeUnicodeString(&InstallPath
);
3170 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3172 /* Create 'USetupData.DestinationRootPath' string */
3173 RtlFreeUnicodeString(&USetupData
.DestinationRootPath
);
3174 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3175 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3176 DiskEntry
->DiskNumber
,
3177 PartEntry
->PartitionNumber
);
3178 RtlCreateUnicodeString(&USetupData
.DestinationRootPath
, PathBuffer
);
3179 DPRINT("DestinationRootPath: %wZ\n", &USetupData
.DestinationRootPath
);
3181 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3182 /* Create 'USetupData.DestinationPath' string */
3183 RtlFreeUnicodeString(&USetupData
.DestinationPath
);
3184 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3185 USetupData
.DestinationRootPath
.Buffer
, InstallDir
);
3186 RtlCreateUnicodeString(&USetupData
.DestinationPath
, PathBuffer
);
3188 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3189 /* Create 'USetupData.DestinationArcPath' */
3190 RtlFreeUnicodeString(&USetupData
.DestinationArcPath
);
3191 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3192 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3193 DiskEntry
->BiosDiskNumber
,
3194 PartEntry
->PartitionNumber
);
3195 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3196 RtlCreateUnicodeString(&USetupData
.DestinationArcPath
, PathBuffer
);
3198 /* Initialize DestinationDriveLetter */
3199 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3204 * Displays the InstallDirectoryPage.
3211 * Number of the next page.
3214 InstallDirectoryPage(PINPUT_RECORD Ir
)
3216 PDISKENTRY DiskEntry
;
3217 PPARTENTRY PartEntry
;
3218 WCHAR InstallDir
[MAX_PATH
];
3222 /* We do not need the filesystem list anymore */
3223 if (FileSystemList
!= NULL
)
3225 DestroyFileSystemList(FileSystemList
);
3226 FileSystemList
= NULL
;
3229 if (PartitionList
== NULL
||
3230 PartitionList
->CurrentDisk
== NULL
||
3231 PartitionList
->CurrentPartition
== NULL
)
3233 /* FIXME: show an error dialog */
3237 DiskEntry
= PartitionList
->CurrentDisk
;
3238 PartEntry
= PartitionList
->CurrentPartition
;
3240 // if (IsUnattendedSetup)
3241 if (RepairUpdateFlag
)
3242 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3243 else if (USetupData
.InstallationDirectory
[0])
3244 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3246 wcscpy(InstallDir
, L
"\\ReactOS");
3249 * Check the validity of the predefined 'InstallDir'. If we are either
3250 * in unattended setup or in update/repair mode, and the installation path
3251 * is valid, just perform the installation. Otherwise (either in the case
3252 * of an invalid path, or we are in regular setup), display the UI and allow
3253 * the user to specify a new installation path.
3255 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3257 BuildInstallPaths(InstallDir
,
3262 * Check whether the user attempts to install ReactOS within the
3263 * installation source directory, or in a subdirectory thereof.
3264 * If so, fail with an error.
3266 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3268 PopupError("You cannot install ReactOS within the installation source directory!",
3269 MUIGetString(STRING_CONTINUE
),
3270 Ir
, POPUP_WAIT_ENTER
);
3271 return INSTALL_DIRECTORY_PAGE
;
3274 return PREPARE_COPY_PAGE
;
3277 Length
= wcslen(InstallDir
);
3280 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3281 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3282 CONSOLE_SetCursorXY(8 + Pos
, 11);
3283 CONSOLE_SetCursorType(TRUE
, TRUE
);
3287 CONSOLE_ConInKey(Ir
);
3289 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3290 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3292 CONSOLE_SetCursorType(TRUE
, FALSE
);
3294 if (ConfirmQuit(Ir
))
3297 CONSOLE_SetCursorType(TRUE
, TRUE
);
3300 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3301 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3305 memmove(&InstallDir
[Pos
],
3306 &InstallDir
[Pos
+ 1],
3307 (Length
- Pos
- 1) * sizeof(WCHAR
));
3308 InstallDir
[Length
- 1] = UNICODE_NULL
;
3311 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3312 CONSOLE_SetCursorXY(8 + Pos
, 11);
3315 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3316 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3319 CONSOLE_SetCursorXY(8 + Pos
, 11);
3321 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3322 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3325 CONSOLE_SetCursorXY(8 + Pos
, 11);
3327 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3328 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3333 CONSOLE_SetCursorXY(8 + Pos
, 11);
3336 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3337 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3342 CONSOLE_SetCursorXY(8 + Pos
, 11);
3345 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3347 CONSOLE_SetCursorType(TRUE
, FALSE
);
3350 * Check for the validity of the installation directory and pop up
3351 * an error if it is not the case. Then the user can fix its input.
3353 if (!IsValidPath(InstallDir
))
3355 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3356 return INSTALL_DIRECTORY_PAGE
;
3359 BuildInstallPaths(InstallDir
,
3364 * Check whether the user attempts to install ReactOS within the
3365 * installation source directory, or in a subdirectory thereof.
3366 * If so, fail with an error.
3368 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3370 PopupError("You cannot install ReactOS within the installation source directory!",
3371 MUIGetString(STRING_CONTINUE
),
3372 Ir
, POPUP_WAIT_ENTER
);
3373 return INSTALL_DIRECTORY_PAGE
;
3376 return PREPARE_COPY_PAGE
;
3378 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3383 memmove(&InstallDir
[Pos
- 1],
3385 (Length
- Pos
) * sizeof(WCHAR
));
3386 InstallDir
[Length
- 1] = UNICODE_NULL
;
3390 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3391 CONSOLE_SetCursorXY(8 + Pos
, 11);
3394 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3398 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3399 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3402 memmove(&InstallDir
[Pos
+ 1],
3404 (Length
- Pos
) * sizeof(WCHAR
));
3405 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3406 InstallDir
[Pos
] = c
;
3410 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3411 CONSOLE_SetCursorXY(8 + Pos
, 11);
3417 return INSTALL_DIRECTORY_PAGE
;
3422 AddSectionToCopyQueueCab(HINF InfFile
,
3424 PWCHAR SourceCabinet
,
3425 PCUNICODE_STRING DestinationPath
,
3428 INFCONTEXT FilesContext
;
3429 INFCONTEXT DirContext
;
3431 PWCHAR FileKeyValue
;
3433 PWCHAR TargetFileName
;
3436 * This code enumerates the list of files in reactos.dff / reactos.inf
3437 * that need to be extracted from reactos.cab and be installed in their
3438 * respective directories.
3441 /* Search for the SectionName section */
3442 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3445 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3446 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3451 * Enumerate the files in the section and add them to the file queue.
3455 /* Get source file name and target directory id */
3456 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3458 /* FIXME: Handle error! */
3459 DPRINT1("INF_GetData() failed\n");
3463 /* Get optional target file name */
3464 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3465 TargetFileName
= NULL
;
3467 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3469 /* Lookup target directory */
3470 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3472 /* FIXME: Handle error! */
3473 DPRINT1("SetupFindFirstLine() failed\n");
3474 INF_FreeData(FileKeyName
);
3475 INF_FreeData(FileKeyValue
);
3476 INF_FreeData(TargetFileName
);
3480 INF_FreeData(FileKeyValue
);
3482 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3484 /* FIXME: Handle error! */
3485 DPRINT1("INF_GetData() failed\n");
3486 INF_FreeData(FileKeyName
);
3487 INF_FreeData(TargetFileName
);
3491 if (!SetupQueueCopy(SetupFileQueue
,
3493 USetupData
.SourceRootPath
.Buffer
,
3494 USetupData
.SourceRootDir
.Buffer
,
3499 /* FIXME: Handle error! */
3500 DPRINT1("SetupQueueCopy() failed\n");
3503 INF_FreeData(FileKeyName
);
3504 INF_FreeData(TargetFileName
);
3505 INF_FreeData(DirKeyValue
);
3506 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3513 AddSectionToCopyQueue(HINF InfFile
,
3515 PWCHAR SourceCabinet
,
3516 PCUNICODE_STRING DestinationPath
,
3519 INFCONTEXT FilesContext
;
3520 INFCONTEXT DirContext
;
3522 PWCHAR FileKeyValue
;
3524 PWCHAR TargetFileName
;
3525 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3528 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3531 * This code enumerates the list of files in txtsetup.sif
3532 * that need to be installed in their respective directories.
3535 /* Search for the SectionName section */
3536 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3539 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3540 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3545 * Enumerate the files in the section and add them to the file queue.
3549 /* Get source file name */
3550 if (!INF_GetDataField(&FilesContext
, 0, &FileKeyName
))
3552 /* FIXME: Handle error! */
3553 DPRINT1("INF_GetData() failed\n");
3557 /* Get target directory id */
3558 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3560 /* FIXME: Handle error! */
3561 DPRINT1("INF_GetData() failed\n");
3562 INF_FreeData(FileKeyName
);
3566 /* Get optional target file name */
3567 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3568 TargetFileName
= NULL
;
3569 else if (!*TargetFileName
)
3570 TargetFileName
= NULL
;
3572 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3574 /* Lookup target directory */
3575 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3577 /* FIXME: Handle error! */
3578 DPRINT1("SetupFindFirstLine() failed\n");
3579 INF_FreeData(FileKeyName
);
3580 INF_FreeData(FileKeyValue
);
3581 INF_FreeData(TargetFileName
);
3585 INF_FreeData(FileKeyValue
);
3587 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3589 /* FIXME: Handle error! */
3590 DPRINT1("INF_GetData() failed\n");
3591 INF_FreeData(FileKeyName
);
3592 INF_FreeData(TargetFileName
);
3596 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3598 /* Installation path */
3599 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3601 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3602 USetupData
.SourceRootDir
.Buffer
);
3604 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3606 else if (DirKeyValue
[0] == L
'\\')
3609 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3611 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3614 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3616 else // if (DirKeyValue[0] != L'\\')
3618 /* Path relative to the installation path */
3619 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3621 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3622 USetupData
.SourceRootDir
.Buffer
, DirKeyValue
);
3624 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3627 if (!SetupQueueCopy(SetupFileQueue
,
3629 USetupData
.SourceRootPath
.Buffer
,
3630 CompleteOrigDirName
,
3635 /* FIXME: Handle error! */
3636 DPRINT1("SetupQueueCopy() failed\n");
3639 INF_FreeData(FileKeyName
);
3640 INF_FreeData(TargetFileName
);
3641 INF_FreeData(DirKeyValue
);
3642 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3649 PrepareCopyPageInfFile(HINF InfFile
,
3650 PWCHAR SourceCabinet
,
3654 INFCONTEXT DirContext
;
3655 PWCHAR AdditionalSectionName
= NULL
;
3657 WCHAR PathBuffer
[MAX_PATH
];
3659 /* Add common files */
3660 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3663 /* Add specific files depending of computer type */
3664 if (SourceCabinet
== NULL
)
3666 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3669 if (AdditionalSectionName
)
3671 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3676 /* Create directories */
3680 * Copying files to USetupData.DestinationRootPath should be done from within
3681 * the SystemPartitionFiles section.
3682 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3683 * For installing to USetupData.DestinationPath specify just '\' .
3686 /* Get destination path */
3687 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), USetupData
.DestinationPath
.Buffer
);
3689 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3691 /* Create the install directory */
3692 Status
= SetupCreateDirectory(PathBuffer
);
3693 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3695 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3696 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3700 /* Search for the 'Directories' section */
3701 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3705 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3709 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3715 /* Enumerate the directory values and create the subdirectories */
3718 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3724 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3726 /* Installation path */
3727 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3729 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3730 USetupData
.DestinationPath
.Buffer
);
3732 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3734 else if (DirKeyValue
[0] == L
'\\')
3737 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3739 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3740 USetupData
.DestinationRootPath
.Buffer
, DirKeyValue
);
3742 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3744 Status
= SetupCreateDirectory(PathBuffer
);
3745 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3747 INF_FreeData(DirKeyValue
);
3748 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3749 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3753 else // if (DirKeyValue[0] != L'\\')
3755 /* Path relative to the installation path */
3756 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3758 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3759 USetupData
.DestinationPath
.Buffer
, DirKeyValue
);
3761 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3763 Status
= SetupCreateDirectory(PathBuffer
);
3764 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3766 INF_FreeData(DirKeyValue
);
3767 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3768 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3773 INF_FreeData(DirKeyValue
);
3774 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3781 * Displays the PrepareCopyPage.
3784 * FileCopyPage(At once)
3788 * Inits SetupFileQueue
3789 * Calls PrepareCopyPageInfFile
3792 * Number of the next page.
3795 PrepareCopyPage(PINPUT_RECORD Ir
)
3798 WCHAR PathBuffer
[MAX_PATH
];
3799 INFCONTEXT CabinetsContext
;
3805 MUIDisplayPage(PREPARE_COPY_PAGE
);
3807 /* Create the file queue */
3808 SetupFileQueue
= SetupOpenFileQueue();
3809 if (SetupFileQueue
== NULL
)
3811 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3815 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3817 /* FIXME: show an error dialog */
3821 /* Search for the 'Cabinets' section */
3822 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3824 return FILE_COPY_PAGE
;
3828 * Enumerate the directory values in the 'Cabinets'
3829 * section and parse their inf files.
3833 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3836 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3837 USetupData
.SourcePath
.Buffer
, KeyValue
);
3839 CabinetInitialize();
3840 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3841 CabinetSetCabinetName(PathBuffer
);
3843 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3845 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3847 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3848 if (InfFileData
== NULL
)
3850 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3856 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3857 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3861 InfHandle
= INF_OpenBufferedFileA((PSTR
)InfFileData
,
3865 USetupData
.LanguageId
,
3868 if (InfHandle
== INVALID_HANDLE_VALUE
)
3870 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3876 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3878 /* FIXME: show an error dialog */
3881 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3883 return FILE_COPY_PAGE
;
3889 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3892 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3894 /* Get the memory information from the system */
3895 NtQuerySystemInformation(SystemPerformanceInformation
,
3900 /* Check if this is initial setup */
3903 /* Set maximum limits to be total RAM pages */
3904 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3905 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3906 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3909 /* Set current values */
3910 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3911 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3912 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3918 FileCopyCallback(PVOID Context
,
3923 PCOPYCONTEXT CopyContext
;
3925 CopyContext
= (PCOPYCONTEXT
)Context
;
3927 switch (Notification
)
3929 case SPFILENOTIFY_STARTSUBQUEUE
:
3930 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3931 ProgressSetStepCount(CopyContext
->ProgressBar
,
3932 CopyContext
->TotalOperations
);
3933 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3936 case SPFILENOTIFY_STARTCOPY
:
3937 /* Display copy message */
3938 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3939 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3942 case SPFILENOTIFY_ENDCOPY
:
3943 CopyContext
->CompletedOperations
++;
3945 /* SYSREG checkpoint */
3946 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3947 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3949 ProgressNextStep(CopyContext
->ProgressBar
);
3950 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3959 * Displays the FileCopyPage.
3962 * RegistryPage(At once)
3965 * Calls SetupCommitFileQueueW
3966 * Calls SetupCloseFileQueue
3969 * Number of the next page.
3972 FileCopyPage(PINPUT_RECORD Ir
)
3974 COPYCONTEXT CopyContext
;
3975 unsigned int mem_bar_width
;
3977 MUIDisplayPage(FILE_COPY_PAGE
);
3979 /* Create context for the copy process */
3980 CopyContext
.DestinationRootPath
= USetupData
.DestinationRootPath
.Buffer
;
3981 CopyContext
.InstallPath
= InstallPath
.Buffer
;
3982 CopyContext
.TotalOperations
= 0;
3983 CopyContext
.CompletedOperations
= 0;
3985 /* Create the progress bar as well */
3986 CopyContext
.ProgressBar
= CreateProgressBar(13,
3993 MUIGetString(STRING_SETUPCOPYINGFILES
));
3995 // fit memory bars to screen width, distribute them uniform
3996 mem_bar_width
= (xScreen
- 26) / 5;
3997 mem_bar_width
-= mem_bar_width
% 2; // make even
3998 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3999 /* Create the paged pool progress bar */
4000 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4009 /* Create the non paged pool progress bar */
4010 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4012 (xScreen
/ 2) + (mem_bar_width
/ 2),
4014 (xScreen
/ 2)- (mem_bar_width
/ 2),
4019 /* Create the global memory progress bar */
4020 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4024 xScreen
- 13 - mem_bar_width
,
4029 /* Do the file copying */
4030 SetupCommitFileQueueW(NULL
,
4035 /* If we get here, we're done, so cleanup the queue and progress bar */
4036 SetupCloseFileQueue(SetupFileQueue
);
4037 DestroyProgressBar(CopyContext
.ProgressBar
);
4038 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4039 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4040 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4042 /* Create the $winnt$.inf file */
4043 InstallSetupInfFile(&USetupData
);
4045 /* Go display the next page */
4046 return REGISTRY_PAGE
;
4051 * Displays the RegistryPage.
4054 * SuccessPage (if RepairUpdate)
4055 * BootLoaderPage (default)
4059 * Calls RegInitializeRegistry
4060 * Calls ImportRegistryFile
4061 * Calls SetDefaultPagefile
4062 * Calls SetMountedDeviceValues
4065 * Number of the next page.
4068 RegistryPage(PINPUT_RECORD Ir
)
4071 INFCONTEXT InfContext
;
4076 BOOLEAN ShouldRepairRegistry
= FALSE
;
4079 MUIDisplayPage(REGISTRY_PAGE
);
4081 if (RepairUpdateFlag
)
4083 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
4085 /* Verify the registry hives and check whether we need to update or repair any of them */
4086 Status
= VerifyRegistryHives(&USetupData
.DestinationPath
, &ShouldRepairRegistry
);
4087 if (!NT_SUCCESS(Status
))
4089 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status
);
4090 ShouldRepairRegistry
= FALSE
;
4092 if (!ShouldRepairRegistry
)
4093 DPRINT1("No need to repair the registry\n");
4097 /* Update the registry */
4098 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE
));
4100 /* Initialize the registry and setup the registry hives */
4101 Status
= RegInitializeRegistry(&USetupData
.DestinationPath
);
4102 if (!NT_SUCCESS(Status
))
4104 DPRINT1("RegInitializeRegistry() failed\n");
4105 /********** HACK!!!!!!!!!!! **********/
4106 if (Status
== STATUS_NOT_IMPLEMENTED
)
4108 /* The hack was called, display its corresponding error */
4109 MUIDisplayError(ERROR_INITIALIZE_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4112 /*************************************/
4114 /* Something else failed */
4115 MUIDisplayError(ERROR_CREATE_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4120 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
4123 * We fully setup the hives, in case we are doing a fresh installation
4124 * (RepairUpdateFlag == FALSE), or in case we are doing an update
4125 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
4126 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
4129 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Fresh", NULL
, &InfContext
); // Windows-compatible
4131 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
); // ReactOS-specific
4135 DPRINT1("SetupFindFirstLine() failed\n");
4136 MUIDisplayError(ERROR_FIND_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4140 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
4143 * In case we are doing an update (RepairUpdateFlag == TRUE) and
4144 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
4145 * we only update the hives.
4148 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Upgrade", NULL
, &InfContext
);
4151 /* Nothing to do for update! */
4152 DPRINT1("No update needed for the registry!\n");
4159 INF_GetDataField(&InfContext
, 0, &Action
);
4160 INF_GetDataField(&InfContext
, 1, &File
);
4161 INF_GetDataField(&InfContext
, 2, &Section
);
4163 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
4167 INF_FreeData(Action
);
4169 INF_FreeData(Section
);
4173 if (!_wcsicmp(Action
, L
"AddReg"))
4175 else if (!_wcsicmp(Action
, L
"DelReg"))
4179 DPRINT1("Unrecognized registry INF action '%S'\n", Action
);
4180 INF_FreeData(Action
);
4182 INF_FreeData(Section
);
4186 INF_FreeData(Action
);
4188 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE
), File
);
4190 if (!ImportRegistryFile(USetupData
.SourcePath
.Buffer
, File
, Section
, USetupData
.LanguageId
, Delete
))
4192 DPRINT1("Importing %S failed\n", File
);
4194 INF_FreeData(Section
);
4195 MUIDisplayError(ERROR_IMPORT_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4198 } while (SetupFindNextLine(&InfContext
, &InfContext
));
4200 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
4202 /* See the explanation for this test above */
4204 /* Update display registry settings */
4205 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYSETTINGSUPDATE
));
4206 if (!ProcessDisplayRegistry(SetupInf
, DisplayList
))
4208 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4212 /* Set the locale */
4213 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE
));
4214 if (!ProcessLocaleRegistry(LanguageList
))
4216 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4220 /* Add keyboard layouts */
4221 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS
));
4222 if (!AddKeyboardLayouts(SelectedLanguageId
))
4224 MUIDisplayError(ERROR_ADDING_KBLAYOUTS
, Ir
, POPUP_WAIT_ENTER
);
4229 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId
)))
4231 MUIDisplayError(ERROR_UPDATE_GEOID
, Ir
, POPUP_WAIT_ENTER
);
4235 if (!IsUnattendedSetup
)
4237 /* Update keyboard layout settings */
4238 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE
));
4239 if (!ProcessKeyboardLayoutRegistry(LayoutList
, SelectedLanguageId
))
4241 MUIDisplayError(ERROR_UPDATE_KBSETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4246 /* Add codepage information to registry */
4247 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE
));
4248 if (!AddCodePage(SelectedLanguageId
))
4250 MUIDisplayError(ERROR_ADDING_CODEPAGE
, Ir
, POPUP_WAIT_ENTER
);
4254 /* Set the default pagefile entry */
4255 SetDefaultPagefile(DestinationDriveLetter
);
4257 /* Update the mounted devices list */
4258 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
4259 SetMountedDeviceValues(PartitionList
);
4264 // TODO: Unload all the registry stuff, perform cleanup,
4265 // and copy the created hive files into .sav files.
4267 RegCleanupRegistry(&USetupData
.DestinationPath
);
4270 * Check whether we were in update/repair mode but we were actually
4271 * repairing the registry hives. If so, we have finished repairing them,
4272 * and we now reset the flag and run the proper registry update.
4273 * Otherwise we have finished the registry update!
4275 if (RepairUpdateFlag
&& ShouldRepairRegistry
)
4277 ShouldRepairRegistry
= FALSE
;
4281 if (NT_SUCCESS(Status
))
4283 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4284 return BOOT_LOADER_PAGE
;
4294 * Displays the BootLoaderPage.
4297 * SuccessPage (if RepairUpdate)
4298 * BootLoaderHarddiskMbrPage
4299 * BootLoaderHarddiskVbrPage
4300 * BootLoaderFloppyPage
4305 * Calls RegInitializeRegistry
4306 * Calls ImportRegistryFile
4307 * Calls SetDefaultPagefile
4308 * Calls SetMountedDeviceValues
4311 * Number of the next page.
4314 BootLoaderPage(PINPUT_RECORD Ir
)
4316 UCHAR PartitionType
;
4317 BOOLEAN InstallOnFloppy
;
4319 WCHAR PathBuffer
[MAX_PATH
];
4321 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4323 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4324 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4325 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4326 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4327 PartitionList
->SystemPartition
->PartitionNumber
);
4328 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4329 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4331 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4333 /* For unattended setup, skip MBR installation or install on floppy if needed */
4334 if (IsUnattendedSetup
)
4336 if ((USetupData
.MBRInstallType
== 0) ||
4337 (USetupData
.MBRInstallType
== 1))
4344 * We may install an MBR or VBR, but before that, check whether
4345 * we need to actually install the VBR on floppy.
4347 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4349 DPRINT("Error: system partition invalid (unused)\n");
4350 InstallOnFloppy
= TRUE
;
4352 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4354 /* OS/2 boot manager partition */
4355 DPRINT("Found OS/2 boot manager partition\n");
4356 InstallOnFloppy
= TRUE
;
4358 else if (PartitionType
== PARTITION_EXT2
)
4360 /* Linux EXT2 partition */
4361 DPRINT("Found Linux EXT2 partition\n");
4362 InstallOnFloppy
= FALSE
;
4364 else if (PartitionType
== PARTITION_IFS
)
4366 /* NTFS partition */
4367 DPRINT("Found NTFS partition\n");
4369 // FIXME: Make it FALSE when we'll support NTFS installation!
4370 InstallOnFloppy
= TRUE
;
4372 else if ((PartitionType
== PARTITION_FAT_12
) ||
4373 (PartitionType
== PARTITION_FAT_16
) ||
4374 (PartitionType
== PARTITION_HUGE
) ||
4375 (PartitionType
== PARTITION_XINT13
) ||
4376 (PartitionType
== PARTITION_FAT32
) ||
4377 (PartitionType
== PARTITION_FAT32_XINT13
))
4379 DPRINT("Found FAT partition\n");
4380 InstallOnFloppy
= FALSE
;
4384 /* Unknown partition */
4385 DPRINT("Unknown partition found\n");
4386 InstallOnFloppy
= TRUE
;
4389 /* We should install on floppy */
4390 if (InstallOnFloppy
)
4392 USetupData
.MBRInstallType
= 1;
4396 /* Is it an unattended install on hdd? */
4397 if (IsUnattendedSetup
)
4399 if ((USetupData
.MBRInstallType
== 2) ||
4400 (USetupData
.MBRInstallType
== 3))
4406 MUIDisplayPage(BOOT_LOADER_PAGE
);
4407 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4411 CONSOLE_ConInKey(Ir
);
4413 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4414 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4416 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4425 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4427 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4428 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4430 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4439 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4441 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4442 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4444 if (ConfirmQuit(Ir
))
4449 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4453 /* Install on both MBR and VBR */
4454 USetupData
.MBRInstallType
= 2;
4457 else if (Line
== 13)
4459 /* Install on VBR only */
4460 USetupData
.MBRInstallType
= 3;
4463 else if (Line
== 14)
4465 /* Install on floppy */
4466 USetupData
.MBRInstallType
= 1;
4469 else if (Line
== 15)
4471 /* Skip MBR installation */
4472 USetupData
.MBRInstallType
= 0;
4476 return BOOT_LOADER_PAGE
;
4481 switch (USetupData
.MBRInstallType
)
4483 /* Skip MBR installation */
4485 return SUCCESS_PAGE
;
4487 /* Install on floppy */
4489 return BOOT_LOADER_FLOPPY_PAGE
;
4491 /* Install on both MBR and VBR */
4493 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4495 /* Install on VBR only */
4497 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4500 return BOOT_LOADER_PAGE
;
4505 * Displays the BootLoaderFloppyPage.
4508 * SuccessPage (At once)
4512 * Calls InstallFatBootcodeToFloppy()
4515 * Number of the next page.
4518 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4522 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4524 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4528 CONSOLE_ConInKey(Ir
);
4530 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4531 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4533 if (ConfirmQuit(Ir
))
4538 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4540 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4541 &USetupData
.DestinationArcPath
);
4542 if (!NT_SUCCESS(Status
))
4544 if (Status
== STATUS_DEVICE_NOT_READY
)
4545 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4547 /* TODO: Print error message */
4548 return BOOT_LOADER_FLOPPY_PAGE
;
4551 return SUCCESS_PAGE
;
4555 return BOOT_LOADER_FLOPPY_PAGE
;
4560 * Displays the BootLoaderHarddiskVbrPage.
4563 * SuccessPage (At once)
4567 * Calls InstallVBRToPartition()
4570 * Number of the next page.
4573 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4577 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4578 &USetupData
.SourceRootPath
,
4579 &USetupData
.DestinationArcPath
,
4580 PartitionList
->SystemPartition
->PartitionType
);
4581 if (!NT_SUCCESS(Status
))
4583 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4587 return SUCCESS_PAGE
;
4592 * Displays the BootLoaderHarddiskMbrPage.
4595 * SuccessPage (At once)
4599 * Calls InstallVBRToPartition()
4600 * Calls InstallMbrBootCodeToDisk()
4603 * Number of the next page.
4606 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4609 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4611 /* Step 1: Write the VBR */
4612 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4613 &USetupData
.SourceRootPath
,
4614 &USetupData
.DestinationArcPath
,
4615 PartitionList
->SystemPartition
->PartitionType
);
4616 if (!NT_SUCCESS(Status
))
4618 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4622 /* Step 2: Write the MBR */
4623 StringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4624 L
"\\Device\\Harddisk%d\\Partition0",
4625 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4626 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4627 &USetupData
.SourceRootPath
,
4628 DestinationDevicePathBuffer
);
4629 if (!NT_SUCCESS(Status
))
4631 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4632 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4636 return SUCCESS_PAGE
;
4641 * @name ProgressTimeOutStringHandler
4643 * Handles the generation (displaying) of the timeout
4644 * countdown to the screen dynamically.
4647 * A pointer to a progress bar.
4649 * @param AlwaysUpdate
4650 * Constantly update the progress bar (boolean type).
4653 * A pointer to a string buffer.
4655 * @param cchBufferSize
4656 * The buffer's size in number of characters.
4659 * TRUE or FALSE on function termination.
4664 ProgressTimeOutStringHandler(
4665 IN PPROGRESSBAR Bar
,
4666 IN BOOLEAN AlwaysUpdate
,
4668 IN SIZE_T cchBufferSize
)
4670 ULONG OldProgress
= Bar
->Progress
;
4672 if (Bar
->StepCount
== 0)
4678 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4681 /* Build the progress string if it has changed */
4682 if (Bar
->ProgressFormatText
&&
4683 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4685 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4686 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4695 * @name ProgressCountdown
4697 * Displays and draws a red-coloured progress bar with a countdown.
4698 * When the timeout is reached, the flush page is displayed for reboot.
4701 * A pointer to an input keyboard record.
4704 * Initial countdown value in seconds.
4712 IN PINPUT_RECORD Ir
,
4716 ULONG StartTime
, BarWidth
, TimerDiv
;
4718 LONG TimerValue
, OldTimerValue
;
4719 LARGE_INTEGER Timeout
;
4720 PPROGRESSBAR ProgressBar
;
4721 BOOLEAN RefreshProgress
= TRUE
;
4723 /* Bail out if the timeout is already zero */
4727 /* Create the timeout progress bar and set it up */
4728 ProgressBar
= CreateProgressBarEx(13,
4735 FOREGROUND_RED
| BACKGROUND_BLUE
,
4738 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4739 ProgressTimeOutStringHandler
);
4741 BarWidth
= max(1, ProgressBar
->Width
);
4742 TimerValue
= TimeOut
* BarWidth
;
4743 ProgressSetStepCount(ProgressBar
, TimerValue
);
4745 StartTime
= NtGetTickCount();
4748 TimerDiv
= 1000 / BarWidth
;
4749 TimerDiv
= max(1, TimerDiv
);
4750 OldTimerValue
= TimerValue
;
4753 /* Decrease the timer */
4756 * Compute how much time the previous operations took.
4757 * This allows us in particular to take account for any time
4758 * elapsed if something slowed down.
4760 TimeElapsed
= NtGetTickCount() - StartTime
;
4761 if (TimeElapsed
>= TimerDiv
)
4763 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4764 TimeElapsed
/= TimerDiv
;
4765 StartTime
+= (TimerDiv
* TimeElapsed
);
4767 if (TimeElapsed
<= TimerValue
)
4768 TimerValue
-= TimeElapsed
;
4772 RefreshProgress
= TRUE
;
4775 if (RefreshProgress
)
4777 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4778 RefreshProgress
= FALSE
;
4781 /* Stop when the timer reaches zero */
4782 if (TimerValue
<= 0)
4785 /* Check for user key presses */
4788 * If the timer is used, use a passive wait of maximum 1 second
4789 * while monitoring for incoming console input events, so that
4790 * we are still able to display the timing count.
4793 /* Wait a maximum of 1 second for input events */
4794 TimeElapsed
= NtGetTickCount() - StartTime
;
4795 if (TimeElapsed
< TimerDiv
)
4797 /* Convert the time to NT Format */
4798 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4799 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4803 Status
= STATUS_TIMEOUT
;
4806 /* Check whether the input event has been signaled, or a timeout happened */
4807 if (Status
== STATUS_TIMEOUT
)
4811 if (Status
!= STATUS_WAIT_0
)
4813 /* An error happened, bail out */
4814 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4818 /* Check for an ENTER key press */
4819 while (CONSOLE_ConInKeyPeek(Ir
))
4821 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4823 /* Found it, stop waiting */
4830 /* Destroy the progress bar and quit */
4831 DestroyProgressBar(ProgressBar
);
4836 * Displays the QuitPage.
4839 * FlushPage (At once)
4845 * Number of the next page.
4848 QuitPage(PINPUT_RECORD Ir
)
4850 MUIDisplayPage(QUIT_PAGE
);
4852 /* Destroy the NTOS installations list */
4853 if (NtOsInstallsList
!= NULL
)
4855 DestroyGenericList(NtOsInstallsList
, TRUE
);
4856 NtOsInstallsList
= NULL
;
4859 /* Destroy the partition list */
4860 if (PartitionList
!= NULL
)
4862 DestroyPartitionList(PartitionList
);
4863 PartitionList
= NULL
;
4865 TempPartition
= NULL
;
4866 FormatState
= Start
;
4868 /* Destroy the filesystem list */
4869 if (FileSystemList
!= NULL
)
4871 DestroyFileSystemList(FileSystemList
);
4872 FileSystemList
= NULL
;
4875 /* Destroy the computer settings list */
4876 if (ComputerList
!= NULL
)
4878 DestroyGenericList(ComputerList
, TRUE
);
4879 ComputerList
= NULL
;
4882 /* Destroy the display settings list */
4883 if (DisplayList
!= NULL
)
4885 DestroyGenericList(DisplayList
, TRUE
);
4889 /* Destroy the keyboard settings list */
4890 if (KeyboardList
!= NULL
)
4892 DestroyGenericList(KeyboardList
, TRUE
);
4893 KeyboardList
= NULL
;
4896 /* Destroy the keyboard layout list */
4897 if (LayoutList
!= NULL
)
4899 DestroyGenericList(LayoutList
, TRUE
);
4903 /* Destroy the languages list */
4904 if (LanguageList
!= NULL
)
4906 DestroyGenericList(LanguageList
, FALSE
);
4907 LanguageList
= NULL
;
4910 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4912 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4913 ProgressCountdown(Ir
, 15);
4919 * Displays the SuccessPage.
4922 * FlushPage (At once)
4928 * Number of the next page.
4931 SuccessPage(PINPUT_RECORD Ir
)
4933 MUIDisplayPage(SUCCESS_PAGE
);
4935 if (IsUnattendedSetup
)
4938 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4939 ProgressCountdown(Ir
, 15);
4945 * Displays the FlushPage.
4948 * RebootPage (At once)
4951 * Number of the next page.
4954 FlushPage(PINPUT_RECORD Ir
)
4956 MUIDisplayPage(FLUSH_PAGE
);
4962 PnpEventThread(IN LPVOID lpParameter
);
4966 * The start routine and page management
4976 InfSetHeap(ProcessHeap
);
4978 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4979 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4980 if (!NT_SUCCESS(Status
))
4981 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4983 /* Create the PnP thread in suspended state */
4984 Status
= RtlCreateUserThread(NtCurrentProcess(),
4994 if (!NT_SUCCESS(Status
))
4997 if (!CONSOLE_Init())
4999 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
5000 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
5001 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
5003 /* We failed to initialize the video, just quit the installer */
5004 return STATUS_APP_INIT_FAILURE
;
5007 /* Initialize global unicode strings */
5008 RtlInitUnicodeString(&USetupData
.SourcePath
, NULL
);
5009 RtlInitUnicodeString(&USetupData
.SourceRootPath
, NULL
);
5010 RtlInitUnicodeString(&USetupData
.SourceRootDir
, NULL
);
5011 RtlInitUnicodeString(&InstallPath
, NULL
);
5012 RtlInitUnicodeString(&USetupData
.DestinationPath
, NULL
);
5013 RtlInitUnicodeString(&USetupData
.DestinationArcPath
, NULL
);
5014 RtlInitUnicodeString(&USetupData
.DestinationRootPath
, NULL
);
5015 RtlInitUnicodeString(&USetupData
.SystemRootPath
, NULL
);
5017 /* Hide the cursor */
5018 CONSOLE_SetCursorType(TRUE
, FALSE
);
5020 /* Global Initialization page */
5021 CONSOLE_ClearScreen();
5023 Page
= SetupStartPage(&Ir
);
5025 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
5027 CONSOLE_ClearScreen();
5030 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
5037 Page
= LanguagePage(&Ir
);
5042 Page
= WelcomePage(&Ir
);
5047 Page
= LicensePage(&Ir
);
5051 case INSTALL_INTRO_PAGE
:
5052 Page
= InstallIntroPage(&Ir
);
5056 case SCSI_CONTROLLER_PAGE
:
5057 Page
= ScsiControllerPage(&Ir
);
5060 case OEM_DRIVER_PAGE
:
5061 Page
= OemDriverPage(&Ir
);
5065 case DEVICE_SETTINGS_PAGE
:
5066 Page
= DeviceSettingsPage(&Ir
);
5069 case COMPUTER_SETTINGS_PAGE
:
5070 Page
= ComputerSettingsPage(&Ir
);
5073 case DISPLAY_SETTINGS_PAGE
:
5074 Page
= DisplaySettingsPage(&Ir
);
5077 case KEYBOARD_SETTINGS_PAGE
:
5078 Page
= KeyboardSettingsPage(&Ir
);
5081 case LAYOUT_SETTINGS_PAGE
:
5082 Page
= LayoutSettingsPage(&Ir
);
5085 case SELECT_PARTITION_PAGE
:
5086 Page
= SelectPartitionPage(&Ir
);
5089 case CREATE_PRIMARY_PARTITION_PAGE
:
5090 Page
= CreatePrimaryPartitionPage(&Ir
);
5093 case CREATE_EXTENDED_PARTITION_PAGE
:
5094 Page
= CreateExtendedPartitionPage(&Ir
);
5097 case CREATE_LOGICAL_PARTITION_PAGE
:
5098 Page
= CreateLogicalPartitionPage(&Ir
);
5101 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5102 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5105 case DELETE_PARTITION_PAGE
:
5106 Page
= DeletePartitionPage(&Ir
);
5109 case SELECT_FILE_SYSTEM_PAGE
:
5110 Page
= SelectFileSystemPage(&Ir
);
5113 case FORMAT_PARTITION_PAGE
:
5114 Page
= FormatPartitionPage(&Ir
);
5117 case CHECK_FILE_SYSTEM_PAGE
:
5118 Page
= CheckFileSystemPage(&Ir
);
5121 case INSTALL_DIRECTORY_PAGE
:
5122 Page
= InstallDirectoryPage(&Ir
);
5125 case PREPARE_COPY_PAGE
:
5126 Page
= PrepareCopyPage(&Ir
);
5129 case FILE_COPY_PAGE
:
5130 Page
= FileCopyPage(&Ir
);
5134 Page
= RegistryPage(&Ir
);
5137 case BOOT_LOADER_PAGE
:
5138 Page
= BootLoaderPage(&Ir
);
5141 case BOOT_LOADER_FLOPPY_PAGE
:
5142 Page
= BootLoaderFloppyPage(&Ir
);
5145 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5146 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5149 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5150 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5154 case REPAIR_INTRO_PAGE
:
5155 Page
= RepairIntroPage(&Ir
);
5158 case UPGRADE_REPAIR_PAGE
:
5159 Page
= UpgradeRepairPage(&Ir
);
5163 Page
= SuccessPage(&Ir
);
5167 Page
= FlushPage(&Ir
);
5171 Page
= QuitPage(&Ir
);
5180 SetupCloseInfFile(SetupInf
);
5182 if (Page
== RECOVERY_PAGE
)
5188 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5189 NtShutdownSystem(ShutdownReboot
);
5190 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5192 return STATUS_SUCCESS
;
5197 NtProcessStartup(PPEB Peb
)
5202 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5204 ProcessHeap
= Peb
->ProcessHeap
;
5206 NtQuerySystemTime(&Time
);
5208 Status
= RunUSetup();
5210 if (NT_SUCCESS(Status
))
5213 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5214 * a protective waiting.
5215 * This wait is needed because, since we are started as SMSS.EXE,
5216 * the NT kernel explicitly waits 5 seconds for the initial process
5217 * SMSS.EXE to initialize (as a protective measure), and otherwise
5218 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5220 Time
.QuadPart
+= 50000000;
5221 NtDelayExecution(FALSE
, &Time
);
5225 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5226 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5227 0, 0, NULL
, 0, NULL
);
5230 NtTerminateProcess(NtCurrentProcess(), Status
);