3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
40 /* GLOBALS & LOCALS *********************************************************/
43 BOOLEAN IsUnattendedSetup
= FALSE
;
45 static USETUP_DATA USetupData
;
47 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
48 static WCHAR DestinationDriveLetter
;
53 PCWSTR SelectedLanguageId
;
54 static WCHAR DefaultLanguage
[20]; // Copy of string inside LanguageList
55 static WCHAR DefaultKBLayout
[20]; // Copy of string inside KeyboardList
57 static BOOLEAN RepairUpdateFlag
= FALSE
;
59 static HANDLE hPnpThread
= NULL
;
61 static PPARTLIST PartitionList
= NULL
;
62 static PPARTENTRY TempPartition
= NULL
;
63 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
64 static FORMATMACHINESTATE FormatState
= Start
;
66 /*****************************************************/
68 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
69 static PGENERIC_LIST NtOsInstallsList
= NULL
;
72 // HACK: Temporary compatibility code.
74 static CABINET_CONTEXT CabinetContext
;
75 #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
76 #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
77 #define CabinetSetCabinetName(a) (CabinetSetCabinetName(&CabinetContext,(a)))
78 #define CabinetOpen() (CabinetOpen(&CabinetContext))
79 #define CabinetGetCabinetName() (CabinetGetCabinetName(&CabinetContext))
80 #define CabinetGetCabinetReservedArea(a) (CabinetGetCabinetReservedArea(&CabinetContext,(a)))
81 #define CabinetCleanup() (CabinetCleanup(&CabinetContext))
85 /* FUNCTIONS ****************************************************************/
88 PrintString(char* fmt
,...)
92 UNICODE_STRING UnicodeString
;
93 ANSI_STRING AnsiString
;
96 vsprintf(buffer
, fmt
, ap
);
99 RtlInitAnsiString(&AnsiString
, buffer
);
100 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
101 NtDisplayString(&UnicodeString
);
102 RtlFreeUnicodeString(&UnicodeString
);
107 DrawBox(IN SHORT xLeft
,
115 /* Draw upper left corner */
118 FillConsoleOutputCharacterA(StdOutput
,
124 /* Draw upper edge */
127 FillConsoleOutputCharacterA(StdOutput
,
133 /* Draw upper right corner */
134 coPos
.X
= xLeft
+ Width
- 1;
136 FillConsoleOutputCharacterA(StdOutput
,
142 /* Draw right edge, inner space and left edge */
143 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
146 FillConsoleOutputCharacterA(StdOutput
,
153 FillConsoleOutputCharacterA(StdOutput
,
159 coPos
.X
= xLeft
+ Width
- 1;
160 FillConsoleOutputCharacterA(StdOutput
,
167 /* Draw lower left corner */
169 coPos
.Y
= yTop
+ Height
- 1;
170 FillConsoleOutputCharacterA(StdOutput
,
176 /* Draw lower edge */
178 coPos
.Y
= yTop
+ Height
- 1;
179 FillConsoleOutputCharacterA(StdOutput
,
185 /* Draw lower right corner */
186 coPos
.X
= xLeft
+ Width
- 1;
187 coPos
.Y
= yTop
+ Height
- 1;
188 FillConsoleOutputCharacterA(StdOutput
,
197 PopupError(PCCH Text
,
215 /* Count text lines and longest line */
222 p
= strchr(pnext
, '\n');
226 Length
= strlen(pnext
);
231 Length
= (ULONG
)(p
- pnext
);
237 if (Length
> MaxLength
)
246 /* Check length of status line */
249 Length
= strlen(Status
);
251 if (Length
> MaxLength
)
255 Width
= MaxLength
+ 4;
261 yTop
= (yScreen
- Height
) / 2;
262 xLeft
= (xScreen
- Width
) / 2;
265 /* Set screen attributes */
267 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
269 FillConsoleOutputAttribute(StdOutput
,
270 FOREGROUND_RED
| BACKGROUND_WHITE
,
276 DrawBox(xLeft
, yTop
, Width
, Height
);
278 /* Print message text */
283 p
= strchr(pnext
, '\n');
287 Length
= strlen(pnext
);
292 Length
= (ULONG
)(p
- pnext
);
299 WriteConsoleOutputCharacterA(StdOutput
,
313 /* Print separator line and status text */
316 coPos
.Y
= yTop
+ Height
- 3;
318 FillConsoleOutputCharacterA(StdOutput
,
325 FillConsoleOutputCharacterA(StdOutput
,
331 coPos
.X
= xLeft
+ Width
- 1;
332 FillConsoleOutputCharacterA(StdOutput
,
340 WriteConsoleOutputCharacterA(StdOutput
,
342 min(strlen(Status
), (SIZE_T
)Width
- 4),
347 if (WaitEvent
== POPUP_WAIT_NONE
)
352 CONSOLE_ConInKey(Ir
);
354 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
355 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
367 * FALSE: Don't quit setup.
370 ConfirmQuit(PINPUT_RECORD Ir
)
373 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
377 CONSOLE_ConInKey(Ir
);
379 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
380 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
385 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
399 PGENERIC_LIST_ENTRY ListEntry
;
402 pszNewLayout
= MUIDefaultKeyboardLayout(SelectedLanguageId
);
404 if (USetupData
.LayoutList
== NULL
)
406 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
407 if (USetupData
.LayoutList
== NULL
)
409 /* FIXME: Handle error! */
414 /* Search for default layout (if provided) */
415 if (pszNewLayout
!= NULL
)
417 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
418 ListEntry
= GetNextListEntry(ListEntry
))
420 if (!wcscmp(pszNewLayout
, ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
))
422 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
432 GetSettingDescription(
433 IN PGENERIC_LIST_ENTRY Entry
,
435 IN SIZE_T cchBufferSize
)
437 return RtlStringCchPrintfA(Buffer
, cchBufferSize
, "%S",
438 ((PGENENTRY
)GetListEntryData(Entry
))->Value
);
443 GetNTOSInstallationName(
444 IN PGENERIC_LIST_ENTRY Entry
,
446 IN SIZE_T cchBufferSize
)
448 PNTOS_INSTALLATION NtOsInstall
= (PNTOS_INSTALLATION
)GetListEntryData(Entry
);
449 PPARTENTRY PartEntry
= NtOsInstall
->PartEntry
;
451 if (PartEntry
&& PartEntry
->DriveLetter
)
453 /* We have retrieved a partition that is mounted */
454 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
456 PartEntry
->DriveLetter
,
457 NtOsInstall
->PathComponent
,
458 NtOsInstall
->InstallationName
);
462 /* We failed somewhere, just show the NT path */
463 return RtlStringCchPrintfA(Buffer
, cchBufferSize
,
465 &NtOsInstall
->SystemNtPath
,
466 NtOsInstall
->InstallationName
);
472 * Displays the LanguagePage.
474 * Next pages: WelcomePage, QuitPage
477 * Init SelectedLanguageId
478 * Init USetupData.LanguageId
481 * Number of the next page.
484 LanguagePage(PINPUT_RECORD Ir
)
486 GENERIC_LIST_UI ListUi
;
487 PCWSTR NewLanguageId
;
488 BOOL RefreshPage
= FALSE
;
490 /* Initialize the computer settings list */
491 if (USetupData
.LanguageList
== NULL
)
493 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
494 if (USetupData
.LanguageList
== NULL
)
496 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
501 SelectedLanguageId
= DefaultLanguage
;
502 USetupData
.LanguageId
= 0;
505 SetConsoleCodePage();
509 * If there is no language or just a single one in the list,
510 * skip the language selection process altogether.
512 if (GetNumberOfListEntries(USetupData
.LanguageList
) <= 1)
514 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
518 InitGenericListUi(&ListUi
, USetupData
.LanguageList
, GetSettingDescription
);
519 DrawGenericList(&ListUi
,
524 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
526 MUIDisplayPage(LANGUAGE_PAGE
);
530 CONSOLE_ConInKey(Ir
);
532 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
533 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
535 ScrollDownGenericList(&ListUi
);
538 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
539 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
541 ScrollUpGenericList(&ListUi
);
544 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
545 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
547 ScrollPageDownGenericList(&ListUi
);
550 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
551 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
553 ScrollPageUpGenericList(&ListUi
);
556 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
557 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
562 RedrawGenericList(&ListUi
);
564 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
566 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
569 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
571 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
573 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
579 SetConsoleCodePage();
583 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
586 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
592 ASSERT(GetNumberOfListEntries(USetupData
.LanguageList
) >= 1);
595 ((PGENENTRY
)GetListEntryData(GetCurrentListEntry(USetupData
.LanguageList
)))->Id
;
597 if (wcscmp(SelectedLanguageId
, NewLanguageId
))
599 /* Clear the language page */
600 MUIClearPage(LANGUAGE_PAGE
);
602 SelectedLanguageId
= NewLanguageId
;
605 SetConsoleCodePage();
607 /* Redraw language selection page in native language */
608 MUIDisplayPage(LANGUAGE_PAGE
);
623 * LanguagePage (at once, default)
624 * InstallIntroPage (at once, if unattended)
629 * Init USetupData.SourcePath
630 * Init USetupData.SourceRootPath
631 * Init USetupData.SourceRootDir
632 * Init USetupData.SetupInf
633 * Init USetupData.RequiredPartitionDiskSpace
634 * Init IsUnattendedSetup
635 * If unattended, init *List and sets the Codepage
636 * If unattended, init SelectedLanguageId
637 * If unattended, init USetupData.LanguageId
640 * Number of the next page.
643 SetupStartPage(PINPUT_RECORD Ir
)
646 PGENERIC_LIST_ENTRY ListEntry
;
649 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
651 /* Initialize Setup, phase 1 */
652 Error
= InitializeSetup(&USetupData
, 1);
653 if (Error
!= ERROR_SUCCESS
)
655 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
659 /* Start the PnP thread */
660 if (hPnpThread
!= NULL
)
662 NtResumeThread(hPnpThread
, NULL
);
666 CheckUnattendedSetup(&USetupData
);
668 if (IsUnattendedSetup
)
670 // TODO: Read options from inf
671 /* Load the hardware, language and keyboard layout lists */
673 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
674 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
675 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
677 USetupData
.LanguageList
= CreateLanguageList(USetupData
.SetupInf
, DefaultLanguage
);
680 SelectedLanguageId
= DefaultLanguage
;
681 wcscpy(DefaultLanguage
, USetupData
.LocaleID
);
682 USetupData
.LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
684 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
686 /* first we hack LanguageList */
687 for (ListEntry
= GetFirstListEntry(USetupData
.LanguageList
); ListEntry
;
688 ListEntry
= GetNextListEntry(ListEntry
))
690 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
691 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
693 DPRINT("found %S in LanguageList\n", LocaleId
);
694 SetCurrentListEntry(USetupData
.LanguageList
, ListEntry
);
700 for (ListEntry
= GetFirstListEntry(USetupData
.LayoutList
); ListEntry
;
701 ListEntry
= GetNextListEntry(ListEntry
))
703 LocaleId
= ((PGENENTRY
)GetListEntryData(ListEntry
))->Id
;
704 if (!wcsicmp(USetupData
.LocaleID
, LocaleId
))
706 DPRINT("found %S in LayoutList\n", LocaleId
);
707 SetCurrentListEntry(USetupData
.LayoutList
, ListEntry
);
712 SetConsoleCodePage();
714 return INSTALL_INTRO_PAGE
;
717 return LANGUAGE_PAGE
;
722 * Displays the WelcomePage.
725 * InstallIntroPage (default)
732 * Number of the next page.
735 WelcomePage(PINPUT_RECORD Ir
)
737 MUIDisplayPage(WELCOME_PAGE
);
741 CONSOLE_ConInKey(Ir
);
743 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
744 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
751 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
753 return INSTALL_INTRO_PAGE
;
755 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
757 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
759 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
770 * Displays the License page.
773 * WelcomePage (default)
776 * Number of the next page.
779 LicensePage(PINPUT_RECORD Ir
)
781 MUIDisplayPage(LICENSE_PAGE
);
785 CONSOLE_ConInKey(Ir
);
787 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
798 * Displays the RepairIntroPage.
801 * RebootPage (default)
807 * Number of the next page.
810 RepairIntroPage(PINPUT_RECORD Ir
)
812 MUIDisplayPage(REPAIR_INTRO_PAGE
);
816 CONSOLE_ConInKey(Ir
);
818 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
822 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
824 RepairUpdateFlag
= TRUE
;
825 return INSTALL_INTRO_PAGE
;
827 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
829 return RECOVERY_PAGE
;
831 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
832 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
838 return REPAIR_INTRO_PAGE
;
842 * Displays the UpgradeRepairPage.
845 * RebootPage (default)
851 * Number of the next page.
854 UpgradeRepairPage(PINPUT_RECORD Ir
)
856 GENERIC_LIST_UI ListUi
;
859 if (PartitionList
== NULL
)
861 PartitionList
= CreatePartitionList();
862 if (PartitionList
== NULL
)
864 /* FIXME: show an error dialog */
865 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
868 else if (IsListEmpty(&PartitionList
->DiskListHead
))
870 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
874 TempPartition
= NULL
;
879 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
880 if (!NtOsInstallsList
)
881 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
884 * If there is no available installation (or just a single one??) that can
885 * be updated in the list, just continue with the regular installation.
887 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
889 RepairUpdateFlag
= FALSE
;
891 // return INSTALL_INTRO_PAGE;
892 return DEVICE_SETTINGS_PAGE
;
893 // return SCSI_CONTROLLER_PAGE;
896 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
898 InitGenericListUi(&ListUi
, NtOsInstallsList
, GetNTOSInstallationName
);
899 DrawGenericList(&ListUi
,
904 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
907 CONSOLE_ConInKey(Ir
);
909 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
911 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
913 case VK_DOWN
: /* DOWN */
914 ScrollDownGenericList(&ListUi
);
917 ScrollUpGenericList(&ListUi
);
919 case VK_NEXT
: /* PAGE DOWN */
920 ScrollPageDownGenericList(&ListUi
);
922 case VK_PRIOR
: /* PAGE UP */
923 ScrollPageUpGenericList(&ListUi
);
930 RedrawGenericList(&ListUi
);
933 case VK_ESCAPE
: /* ESC */
935 RestoreGenericListUiState(&ListUi
);
936 // return nextPage; // prevPage;
938 // return INSTALL_INTRO_PAGE;
939 return DEVICE_SETTINGS_PAGE
;
940 // return SCSI_CONTROLLER_PAGE;
946 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
947 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
948 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
950 /* Retrieve the current installation */
951 ASSERT(GetNumberOfListEntries(NtOsInstallsList
) >= 1);
953 CurrentInstallation
=
954 (PNTOS_INSTALLATION
)GetListEntryData(GetCurrentListEntry(NtOsInstallsList
));
956 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
957 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
959 RepairUpdateFlag
= TRUE
;
962 /***/return INSTALL_INTRO_PAGE
;/***/
964 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
965 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
967 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
972 return UPGRADE_REPAIR_PAGE
;
977 * Displays the InstallIntroPage.
980 * DeviceSettingsPage (At once if repair or update is selected)
981 * SelectPartitionPage (At once if unattended setup)
982 * DeviceSettingsPage (default)
986 * Number of the next page.
989 InstallIntroPage(PINPUT_RECORD Ir
)
991 if (RepairUpdateFlag
)
993 #if 1 /* Old code that looks good */
995 // return SELECT_PARTITION_PAGE;
996 return DEVICE_SETTINGS_PAGE
;
998 #else /* Possible new code? */
1000 return DEVICE_SETTINGS_PAGE
;
1001 // return SCSI_CONTROLLER_PAGE;
1006 if (IsUnattendedSetup
)
1007 return SELECT_PARTITION_PAGE
;
1009 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1013 CONSOLE_ConInKey(Ir
);
1015 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1016 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1018 if (ConfirmQuit(Ir
))
1023 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1025 return UPGRADE_REPAIR_PAGE
;
1029 return INSTALL_INTRO_PAGE
;
1035 ScsiControllerPage(PINPUT_RECORD Ir
)
1037 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1039 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1041 /* FIXME: print loaded mass storage driver descriptions */
1043 CONSOLE_SetTextXY(8, 10, "TEST device");
1046 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1050 CONSOLE_ConInKey(Ir
);
1052 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1053 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1055 if (ConfirmQuit(Ir
))
1060 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1062 return DEVICE_SETTINGS_PAGE
;
1066 return SCSI_CONTROLLER_PAGE
;
1070 OemDriverPage(PINPUT_RECORD Ir
)
1072 // MUIDisplayPage(OEM_DRIVER_PAGE);
1074 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1076 /* FIXME: Implement!! */
1078 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1082 CONSOLE_ConInKey(Ir
);
1084 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1085 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1087 if (ConfirmQuit(Ir
))
1092 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1094 return DEVICE_SETTINGS_PAGE
;
1098 return OEM_DRIVER_PAGE
;
1104 * Displays the DeviceSettingsPage.
1107 * SelectPartitionPage (At once if repair or update is selected)
1108 * ComputerSettingsPage
1109 * DisplaySettingsPage
1110 * KeyboardSettingsPage
1111 * LayoutsettingsPage
1112 * SelectPartitionPage
1116 * Init USetupData.ComputerList
1117 * Init USetupData.DisplayList
1118 * Init USetupData.KeyboardList
1119 * Init USetupData.LayoutList
1122 * Number of the next page.
1125 DeviceSettingsPage(PINPUT_RECORD Ir
)
1127 static ULONG Line
= 16;
1129 /* Initialize the computer settings list */
1130 if (USetupData
.ComputerList
== NULL
)
1132 USetupData
.ComputerList
= CreateComputerTypeList(USetupData
.SetupInf
);
1133 if (USetupData
.ComputerList
== NULL
)
1135 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1140 /* Initialize the display settings list */
1141 if (USetupData
.DisplayList
== NULL
)
1143 USetupData
.DisplayList
= CreateDisplayDriverList(USetupData
.SetupInf
);
1144 if (USetupData
.DisplayList
== NULL
)
1146 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1151 /* Initialize the keyboard settings list */
1152 if (USetupData
.KeyboardList
== NULL
)
1154 USetupData
.KeyboardList
= CreateKeyboardDriverList(USetupData
.SetupInf
);
1155 if (USetupData
.KeyboardList
== NULL
)
1157 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1162 /* Initialize the keyboard layout list */
1163 if (USetupData
.LayoutList
== NULL
)
1165 USetupData
.LayoutList
= CreateKeyboardLayoutList(USetupData
.SetupInf
, SelectedLanguageId
, DefaultKBLayout
);
1166 if (USetupData
.LayoutList
== NULL
)
1168 /* FIXME: report error */
1169 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1174 if (RepairUpdateFlag
)
1175 return SELECT_PARTITION_PAGE
;
1177 // if (IsUnattendedSetup)
1178 // return SELECT_PARTITION_PAGE;
1180 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1182 DrawGenericListCurrentItem(USetupData
.ComputerList
, GetSettingDescription
, 25, 11);
1183 DrawGenericListCurrentItem(USetupData
.DisplayList
, GetSettingDescription
, 25, 12);
1184 DrawGenericListCurrentItem(USetupData
.KeyboardList
, GetSettingDescription
, 25, 13);
1185 DrawGenericListCurrentItem(USetupData
.LayoutList
, GetSettingDescription
, 25, 14);
1187 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1191 CONSOLE_ConInKey(Ir
);
1193 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1194 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1196 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1200 else if (Line
== 16)
1205 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1207 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1208 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1210 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1214 else if (Line
== 16)
1219 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1221 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1222 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1224 if (ConfirmQuit(Ir
))
1229 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1232 return COMPUTER_SETTINGS_PAGE
;
1233 else if (Line
== 12)
1234 return DISPLAY_SETTINGS_PAGE
;
1235 else if (Line
== 13)
1236 return KEYBOARD_SETTINGS_PAGE
;
1237 else if (Line
== 14)
1238 return LAYOUT_SETTINGS_PAGE
;
1239 else if (Line
== 16)
1240 return SELECT_PARTITION_PAGE
;
1244 return DEVICE_SETTINGS_PAGE
;
1249 * Handles generic selection lists.
1252 * GenericList: The list to handle.
1253 * nextPage: The page it needs to jump to after this page.
1254 * Ir: The PINPUT_RECORD
1257 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1258 PAGE_NUMBER nextPage
,
1263 CONSOLE_ConInKey(Ir
);
1265 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1266 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1268 ScrollDownGenericList(ListUi
);
1270 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1271 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1273 ScrollUpGenericList(ListUi
);
1275 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1276 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1278 ScrollPageDownGenericList(ListUi
);
1280 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1281 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1283 ScrollPageUpGenericList(ListUi
);
1285 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1286 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1288 if (ConfirmQuit(Ir
))
1291 RedrawGenericList(ListUi
);
1293 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1294 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1296 RestoreGenericListUiState(ListUi
);
1297 return nextPage
; // Use some "prevPage;" instead?
1299 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1303 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1306 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1313 * Displays the ComputerSettingsPage.
1316 * DeviceSettingsPage
1320 * Number of the next page.
1323 ComputerSettingsPage(PINPUT_RECORD Ir
)
1325 GENERIC_LIST_UI ListUi
;
1326 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1328 InitGenericListUi(&ListUi
, USetupData
.ComputerList
, GetSettingDescription
);
1329 DrawGenericList(&ListUi
,
1334 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1339 * Displays the DisplaySettingsPage.
1342 * DeviceSettingsPage
1346 * Number of the next page.
1349 DisplaySettingsPage(PINPUT_RECORD Ir
)
1351 GENERIC_LIST_UI ListUi
;
1352 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1354 InitGenericListUi(&ListUi
, USetupData
.DisplayList
, GetSettingDescription
);
1355 DrawGenericList(&ListUi
,
1360 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1365 * Displays the KeyboardSettingsPage.
1368 * DeviceSettingsPage
1372 * Number of the next page.
1375 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1377 GENERIC_LIST_UI ListUi
;
1378 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1380 InitGenericListUi(&ListUi
, USetupData
.KeyboardList
, GetSettingDescription
);
1381 DrawGenericList(&ListUi
,
1386 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1391 * Displays the LayoutSettingsPage.
1394 * DeviceSettingsPage
1398 * Number of the next page.
1401 LayoutSettingsPage(PINPUT_RECORD Ir
)
1403 GENERIC_LIST_UI ListUi
;
1404 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1406 InitGenericListUi(&ListUi
, USetupData
.LayoutList
, GetSettingDescription
);
1407 DrawGenericList(&ListUi
,
1412 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1417 IsDiskSizeValid(PPARTENTRY PartEntry
)
1421 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1422 size
= (size
+ (512 * KB
)) / MB
; /* in MBytes */
1424 if (size
< USetupData
.RequiredPartitionDiskSpace
)
1426 /* Partition is too small so ask for another one */
1427 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, USetupData
.RequiredPartitionDiskSpace
);
1438 * Displays the SelectPartitionPage.
1441 * SelectFileSystemPage (At once if unattended)
1442 * SelectFileSystemPage (Default if free space is selected)
1443 * CreatePrimaryPartitionPage
1444 * CreateExtendedPartitionPage
1445 * CreateLogicalPartitionPage
1446 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1447 * DeletePartitionPage
1451 * Set InstallShortcut (only if not unattended + free space is selected)
1454 * Number of the next page.
1457 SelectPartitionPage(PINPUT_RECORD Ir
)
1462 if (PartitionList
== NULL
)
1464 PartitionList
= CreatePartitionList();
1465 if (PartitionList
== NULL
)
1467 /* FIXME: show an error dialog */
1468 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1471 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1473 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1477 TempPartition
= NULL
;
1478 FormatState
= Start
;
1481 if (RepairUpdateFlag
)
1483 /* Determine the selected installation disk & partition */
1484 if (!SelectPartition(PartitionList
,
1485 CurrentInstallation
->DiskNumber
,
1486 CurrentInstallation
->PartitionNumber
))
1488 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1492 return SELECT_FILE_SYSTEM_PAGE
;
1495 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1497 InitPartitionListUi(&ListUi
, PartitionList
,
1502 DrawPartitionList(&ListUi
);
1504 if (IsUnattendedSetup
)
1506 if (!SelectPartition(PartitionList
,
1507 USetupData
.DestinationDiskNumber
,
1508 USetupData
.DestinationPartitionNumber
))
1510 if (USetupData
.AutoPartition
)
1512 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1514 CreateLogicalPartition(PartitionList
,
1515 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1520 CreatePrimaryPartition(PartitionList
,
1521 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
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
;
1538 DrawPartitionList(&ListUi
);
1540 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1541 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1543 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1544 USetupData
.RequiredPartitionDiskSpace
);
1545 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1548 return SELECT_FILE_SYSTEM_PAGE
;
1554 /* Update status text */
1555 if (PartitionList
->CurrentPartition
== NULL
)
1557 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1559 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1561 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1563 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1567 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1572 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1574 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1576 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1580 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1585 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1589 CONSOLE_ConInKey(Ir
);
1591 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1592 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1594 if (ConfirmQuit(Ir
))
1596 DestroyPartitionList(PartitionList
);
1597 PartitionList
= NULL
;
1603 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1604 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1606 ScrollDownPartitionList(&ListUi
);
1608 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1609 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1611 ScrollUpPartitionList(&ListUi
);
1613 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1615 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1616 continue; // return SELECT_PARTITION_PAGE;
1618 if (PartitionList
->CurrentPartition
== NULL
||
1619 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1621 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1623 CreateLogicalPartition(PartitionList
,
1629 CreatePrimaryPartition(PartitionList
,
1635 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1637 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1638 USetupData
.RequiredPartitionDiskSpace
);
1639 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1642 return SELECT_FILE_SYSTEM_PAGE
;
1644 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1646 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1648 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1649 if (Error
!= NOT_AN_ERROR
)
1651 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1652 return SELECT_PARTITION_PAGE
;
1655 return CREATE_PRIMARY_PARTITION_PAGE
;
1658 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1660 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1662 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1663 if (Error
!= NOT_AN_ERROR
)
1665 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1666 return SELECT_PARTITION_PAGE
;
1669 return CREATE_EXTENDED_PARTITION_PAGE
;
1672 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1674 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1676 Error
= LogicalPartitionCreationChecks(PartitionList
);
1677 if (Error
!= NOT_AN_ERROR
)
1679 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1680 return SELECT_PARTITION_PAGE
;
1683 return CREATE_LOGICAL_PARTITION_PAGE
;
1686 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1688 WCHAR PathBuffer
[MAX_PATH
];
1689 UNICODE_STRING CurrentPartition
;
1691 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1693 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1694 return SELECT_PARTITION_PAGE
;
1697 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
1698 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
1699 PartitionList
->CurrentDisk
->DiskNumber
,
1700 PartitionList
->CurrentPartition
->PartitionNumber
);
1701 RtlInitUnicodeString(&CurrentPartition
, PathBuffer
);
1704 * Check whether the user attempts to delete the partition on which
1705 * the installation source is present. If so, fail with an error.
1707 // &USetupData.SourceRootPath
1708 if (RtlPrefixUnicodeString(&CurrentPartition
, &USetupData
.SourcePath
, TRUE
))
1710 PopupError("You cannot delete the partition containing the installation source!",
1711 MUIGetString(STRING_CONTINUE
),
1712 Ir
, POPUP_WAIT_ENTER
);
1713 return SELECT_PARTITION_PAGE
;
1716 if (PartitionList
->CurrentPartition
->BootIndicator
||
1717 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1719 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1722 return DELETE_PARTITION_PAGE
;
1726 return SELECT_PARTITION_PAGE
;
1730 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1731 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1732 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1735 ShowPartitionSizeInputBox(SHORT Left
,
1759 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1764 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1765 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1768 WriteConsoleOutputCharacterA(StdOutput
,
1774 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1775 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1777 WriteConsoleOutputCharacterA(StdOutput
,
1783 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1784 Length
= wcslen(InputBuffer
);
1786 CONSOLE_SetInputTextXY(iLeft
,
1788 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1790 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1791 CONSOLE_SetCursorType(TRUE
, TRUE
);
1795 CONSOLE_ConInKey(&Ir
);
1797 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1798 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1803 InputBuffer
[0] = UNICODE_NULL
;
1804 CONSOLE_SetCursorType(TRUE
, FALSE
);
1807 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1809 CONSOLE_SetCursorType(TRUE
, FALSE
);
1812 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1817 InputBuffer
[0] = UNICODE_NULL
;
1818 CONSOLE_SetCursorType(TRUE
, FALSE
);
1821 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1822 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1825 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1827 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1828 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1831 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1833 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1834 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1839 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1842 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1843 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1848 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1851 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1852 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1856 memmove(&InputBuffer
[Pos
],
1857 &InputBuffer
[Pos
+ 1],
1858 (Length
- Pos
- 1) * sizeof(WCHAR
));
1859 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1862 CONSOLE_SetInputTextXY(iLeft
,
1864 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1866 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1869 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1874 memmove(&InputBuffer
[Pos
- 1],
1876 (Length
- Pos
) * sizeof(WCHAR
));
1877 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1881 CONSOLE_SetInputTextXY(iLeft
,
1883 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1885 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1888 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1890 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1892 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1894 if ((ch
>= L
'0') && (ch
<= L
'9'))
1897 memmove(&InputBuffer
[Pos
+ 1],
1899 (Length
- Pos
) * sizeof(WCHAR
));
1900 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1901 InputBuffer
[Pos
] = ch
;
1905 CONSOLE_SetInputTextXY(iLeft
,
1907 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1909 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1918 * Displays the CreatePrimaryPartitionPage.
1921 * SelectPartitionPage
1922 * SelectFileSystemPage (default)
1926 * Number of the next page.
1929 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1931 PDISKENTRY DiskEntry
;
1932 PPARTENTRY PartEntry
;
1935 WCHAR InputBuffer
[50];
1939 ULONGLONG SectorCount
;
1942 if (PartitionList
== NULL
||
1943 PartitionList
->CurrentDisk
== NULL
||
1944 PartitionList
->CurrentPartition
== NULL
)
1946 /* FIXME: show an error dialog */
1950 DiskEntry
= PartitionList
->CurrentDisk
;
1951 PartEntry
= PartitionList
->CurrentPartition
;
1953 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1955 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1957 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1959 if (DiskSize
>= 10 * GB
) /* 10 GB */
1961 DiskSize
= DiskSize
/ GB
;
1962 Unit
= MUIGetString(STRING_GB
);
1967 DiskSize
= DiskSize
/ MB
;
1971 Unit
= MUIGetString(STRING_MB
);
1974 if (DiskEntry
->DriverName
.Length
> 0)
1976 CONSOLE_PrintTextXY(6, 10,
1977 MUIGetString(STRING_HDINFOPARTCREATE_1
),
1980 DiskEntry
->DiskNumber
,
1984 &DiskEntry
->DriverName
,
1985 DiskEntry
->NoMbr
? "GPT" : "MBR");
1989 CONSOLE_PrintTextXY(6, 10,
1990 MUIGetString(STRING_HDINFOPARTCREATE_2
),
1993 DiskEntry
->DiskNumber
,
1997 DiskEntry
->NoMbr
? "GPT" : "MBR");
2000 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2003 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2004 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2007 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2009 PartEntry
= PartitionList
->CurrentPartition
;
2012 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2014 if (MaxSize
> PARTITION_MAXSIZE
)
2015 MaxSize
= PARTITION_MAXSIZE
;
2017 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2018 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2022 if (ConfirmQuit(Ir
))
2029 return SELECT_PARTITION_PAGE
;
2033 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2041 if (PartSize
> MaxSize
)
2047 /* Convert to bytes */
2048 if (PartSize
== MaxSize
)
2050 /* Use all of the unpartitioned disk space */
2051 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2055 /* Calculate the sector count from the size in MB */
2056 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2058 /* But never get larger than the unpartitioned disk space */
2059 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2060 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2063 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2065 CreatePrimaryPartition(PartitionList
,
2069 return SELECT_PARTITION_PAGE
;
2073 return CREATE_PRIMARY_PARTITION_PAGE
;
2078 * Displays the CreateExtendedPartitionPage.
2081 * SelectPartitionPage (default)
2085 * Number of the next page.
2088 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2090 PDISKENTRY DiskEntry
;
2091 PPARTENTRY PartEntry
;
2094 WCHAR InputBuffer
[50];
2098 ULONGLONG SectorCount
;
2101 if (PartitionList
== NULL
||
2102 PartitionList
->CurrentDisk
== NULL
||
2103 PartitionList
->CurrentPartition
== NULL
)
2105 /* FIXME: show an error dialog */
2109 DiskEntry
= PartitionList
->CurrentDisk
;
2110 PartEntry
= PartitionList
->CurrentPartition
;
2112 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2114 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2116 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2118 if (DiskSize
>= 10 * GB
) /* 10 GB */
2120 DiskSize
= DiskSize
/ GB
;
2121 Unit
= MUIGetString(STRING_GB
);
2126 DiskSize
= DiskSize
/ MB
;
2130 Unit
= MUIGetString(STRING_MB
);
2133 if (DiskEntry
->DriverName
.Length
> 0)
2135 CONSOLE_PrintTextXY(6, 10,
2136 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2139 DiskEntry
->DiskNumber
,
2143 &DiskEntry
->DriverName
,
2144 DiskEntry
->NoMbr
? "GPT" : "MBR");
2148 CONSOLE_PrintTextXY(6, 10,
2149 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2152 DiskEntry
->DiskNumber
,
2156 DiskEntry
->NoMbr
? "GPT" : "MBR");
2159 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2162 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2163 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2166 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2168 PartEntry
= PartitionList
->CurrentPartition
;
2171 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2173 if (MaxSize
> PARTITION_MAXSIZE
)
2174 MaxSize
= PARTITION_MAXSIZE
;
2176 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2177 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2181 if (ConfirmQuit(Ir
))
2188 return SELECT_PARTITION_PAGE
;
2192 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2200 if (PartSize
> MaxSize
)
2206 /* Convert to bytes */
2207 if (PartSize
== MaxSize
)
2209 /* Use all of the unpartitioned disk space */
2210 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2214 /* Calculate the sector count from the size in MB */
2215 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2217 /* But never get larger than the unpartitioned disk space */
2218 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2219 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2222 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2224 CreateExtendedPartition(PartitionList
,
2227 return SELECT_PARTITION_PAGE
;
2231 return CREATE_EXTENDED_PARTITION_PAGE
;
2236 * Displays the CreateLogicalPartitionPage.
2239 * SelectFileSystemPage (default)
2243 * Number of the next page.
2246 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2248 PDISKENTRY DiskEntry
;
2249 PPARTENTRY PartEntry
;
2252 WCHAR InputBuffer
[50];
2256 ULONGLONG SectorCount
;
2259 if (PartitionList
== NULL
||
2260 PartitionList
->CurrentDisk
== NULL
||
2261 PartitionList
->CurrentPartition
== NULL
)
2263 /* FIXME: show an error dialog */
2267 DiskEntry
= PartitionList
->CurrentDisk
;
2268 PartEntry
= PartitionList
->CurrentPartition
;
2270 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2272 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2274 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2276 if (DiskSize
>= 10 * GB
) /* 10 GB */
2278 DiskSize
= DiskSize
/ GB
;
2279 Unit
= MUIGetString(STRING_GB
);
2284 DiskSize
= DiskSize
/ MB
;
2288 Unit
= MUIGetString(STRING_MB
);
2291 if (DiskEntry
->DriverName
.Length
> 0)
2293 CONSOLE_PrintTextXY(6, 10,
2294 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2297 DiskEntry
->DiskNumber
,
2301 &DiskEntry
->DriverName
,
2302 DiskEntry
->NoMbr
? "GPT" : "MBR");
2306 CONSOLE_PrintTextXY(6, 10,
2307 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2310 DiskEntry
->DiskNumber
,
2314 DiskEntry
->NoMbr
? "GPT" : "MBR");
2317 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2320 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2321 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ MB
);
2324 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2326 PartEntry
= PartitionList
->CurrentPartition
;
2329 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / MB
; /* in MBytes (rounded) */
2331 if (MaxSize
> PARTITION_MAXSIZE
)
2332 MaxSize
= PARTITION_MAXSIZE
;
2334 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2335 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2339 if (ConfirmQuit(Ir
))
2346 return SELECT_PARTITION_PAGE
;
2350 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2358 if (PartSize
> MaxSize
)
2364 /* Convert to bytes */
2365 if (PartSize
== MaxSize
)
2367 /* Use all of the unpartitioned disk space */
2368 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2372 /* Calculate the sector count from the size in MB */
2373 SectorCount
= PartSize
* MB
/ DiskEntry
->BytesPerSector
;
2375 /* But never get larger than the unpartitioned disk space */
2376 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2377 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2380 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2382 CreateLogicalPartition(PartitionList
,
2386 return SELECT_PARTITION_PAGE
;
2390 return CREATE_LOGICAL_PARTITION_PAGE
;
2395 * Displays the ConfirmDeleteSystemPartitionPage.
2398 * DeletePartitionPage (default)
2399 * SelectPartitionPage
2402 * Number of the next page.
2405 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2407 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2411 CONSOLE_ConInKey(Ir
);
2413 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2414 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2416 if (ConfirmQuit(Ir
))
2421 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2423 return DELETE_PARTITION_PAGE
;
2425 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2427 return SELECT_PARTITION_PAGE
;
2431 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2436 * Displays the DeletePartitionPage.
2439 * SelectPartitionPage (default)
2443 * Number of the next page.
2446 DeletePartitionPage(PINPUT_RECORD Ir
)
2448 PDISKENTRY DiskEntry
;
2449 PPARTENTRY PartEntry
;
2453 CHAR PartTypeString
[32];
2455 if (PartitionList
== NULL
||
2456 PartitionList
->CurrentDisk
== NULL
||
2457 PartitionList
->CurrentPartition
== NULL
)
2459 /* FIXME: show an error dialog */
2463 DiskEntry
= PartitionList
->CurrentDisk
;
2464 PartEntry
= PartitionList
->CurrentPartition
;
2466 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2468 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2470 ARRAYSIZE(PartTypeString
));
2472 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2474 if (PartSize
>= 10 * GB
) /* 10 GB */
2476 PartSize
= PartSize
/ GB
;
2477 Unit
= MUIGetString(STRING_GB
);
2481 if (PartSize
>= 10 * MB
) /* 10 MB */
2483 PartSize
= PartSize
/ MB
;
2484 Unit
= MUIGetString(STRING_MB
);
2488 PartSize
= PartSize
/ KB
;
2489 Unit
= MUIGetString(STRING_KB
);
2492 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2494 CONSOLE_PrintTextXY(6, 10,
2495 MUIGetString(STRING_HDDINFOUNK2
),
2496 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2497 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2498 PartEntry
->PartitionType
,
2504 CONSOLE_PrintTextXY(6, 10,
2505 " %c%c %s %I64u %s",
2506 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2507 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2513 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2515 if (DiskSize
>= 10 * GB
) /* 10 GB */
2517 DiskSize
= DiskSize
/ GB
;
2518 Unit
= MUIGetString(STRING_GB
);
2523 DiskSize
= DiskSize
/ MB
;
2527 Unit
= MUIGetString(STRING_MB
);
2530 if (DiskEntry
->DriverName
.Length
> 0)
2532 CONSOLE_PrintTextXY(6, 12,
2533 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2536 DiskEntry
->DiskNumber
,
2540 &DiskEntry
->DriverName
,
2541 DiskEntry
->NoMbr
? "GPT" : "MBR");
2545 CONSOLE_PrintTextXY(6, 12,
2546 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2549 DiskEntry
->DiskNumber
,
2553 DiskEntry
->NoMbr
? "GPT" : "MBR");
2558 CONSOLE_ConInKey(Ir
);
2560 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2561 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2563 if (ConfirmQuit(Ir
))
2568 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2570 return SELECT_PARTITION_PAGE
;
2572 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2574 DeleteCurrentPartition(PartitionList
);
2576 return SELECT_PARTITION_PAGE
;
2580 return DELETE_PARTITION_PAGE
;
2585 * Displays the SelectFileSystemPage.
2588 * CheckFileSystemPage (At once if RepairUpdate is selected)
2589 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2590 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2591 * SelectPartitionPage (If the user aborts)
2592 * FormatPartitionPage (Default)
2596 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2597 * Calls CheckActiveSystemPartition()
2600 * Number of the next page.
2603 SelectFileSystemPage(PINPUT_RECORD Ir
)
2605 PDISKENTRY DiskEntry
;
2606 PPARTENTRY PartEntry
;
2611 CHAR PartTypeString
[32];
2612 FORMATMACHINESTATE PreviousFormatState
;
2614 DPRINT("SelectFileSystemPage()\n");
2616 if (PartitionList
== NULL
||
2617 PartitionList
->CurrentDisk
== NULL
||
2618 PartitionList
->CurrentPartition
== NULL
)
2620 /* FIXME: show an error dialog */
2624 /* Find or set the active system partition */
2625 CheckActiveSystemPartition(PartitionList
);
2626 if (PartitionList
->SystemPartition
== NULL
)
2628 /* FIXME: show an error dialog */
2630 // Error dialog should say that we cannot find a suitable
2631 // system partition and create one on the system. At this point,
2632 // it may be nice to ask the user whether he wants to continue,
2633 // or use an external drive as the system drive/partition
2634 // (e.g. floppy, USB drive, etc...)
2639 PreviousFormatState
= FormatState
;
2640 switch (FormatState
)
2644 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2646 TempPartition
= PartitionList
->SystemPartition
;
2647 TempPartition
->NeedsCheck
= TRUE
;
2649 FormatState
= FormatSystemPartition
;
2650 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2654 TempPartition
= PartitionList
->CurrentPartition
;
2655 TempPartition
->NeedsCheck
= TRUE
;
2657 FormatState
= FormatInstallPartition
;
2658 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2663 case FormatSystemPartition
:
2665 TempPartition
= PartitionList
->CurrentPartition
;
2666 TempPartition
->NeedsCheck
= TRUE
;
2668 FormatState
= FormatInstallPartition
;
2669 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2673 case FormatInstallPartition
:
2675 if (GetNextUnformattedPartition(PartitionList
,
2679 FormatState
= FormatOtherPartition
;
2680 TempPartition
->NeedsCheck
= TRUE
;
2681 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2685 FormatState
= FormatDone
;
2686 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2687 return CHECK_FILE_SYSTEM_PAGE
;
2692 case FormatOtherPartition
:
2694 if (GetNextUnformattedPartition(PartitionList
,
2698 FormatState
= FormatOtherPartition
;
2699 TempPartition
->NeedsCheck
= TRUE
;
2700 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2704 FormatState
= FormatDone
;
2705 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2706 return CHECK_FILE_SYSTEM_PAGE
;
2713 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2714 /* FIXME: show an error dialog */
2719 PartEntry
= TempPartition
;
2720 DiskEntry
= PartEntry
->DiskEntry
;
2722 /* Adjust disk size */
2723 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2724 if (DiskSize
>= 10 * GB
) /* 10 GB */
2726 DiskSize
= DiskSize
/ GB
;
2727 DiskUnit
= MUIGetString(STRING_GB
);
2731 DiskSize
= DiskSize
/ MB
;
2732 DiskUnit
= MUIGetString(STRING_MB
);
2735 /* Adjust partition size */
2736 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2737 if (PartSize
>= 10 * GB
) /* 10 GB */
2739 PartSize
= PartSize
/ GB
;
2740 PartUnit
= MUIGetString(STRING_GB
);
2744 PartSize
= PartSize
/ MB
;
2745 PartUnit
= MUIGetString(STRING_MB
);
2748 /* Adjust partition type */
2749 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2751 ARRAYSIZE(PartTypeString
));
2753 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2755 if (PartEntry
->AutoCreate
)
2757 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2760 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2761 PartEntry
->PartitionNumber
,
2767 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2768 DiskEntry
->DiskNumber
,
2774 &DiskEntry
->DriverName
,
2775 DiskEntry
->NoMbr
? "GPT" : "MBR");
2777 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2779 PartEntry
->AutoCreate
= FALSE
;
2781 else if (PartEntry
->New
)
2783 switch (FormatState
)
2785 case FormatSystemPartition
:
2786 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2789 case FormatInstallPartition
:
2790 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2793 case FormatOtherPartition
:
2794 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2801 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2805 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2807 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2809 CONSOLE_PrintTextXY(8, 10,
2810 MUIGetString(STRING_HDDINFOUNK4
),
2811 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2812 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2813 PartEntry
->PartitionType
,
2819 CONSOLE_PrintTextXY(8, 10,
2821 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2822 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2828 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2829 DiskEntry
->DiskNumber
,
2835 &DiskEntry
->DriverName
,
2836 DiskEntry
->NoMbr
? "GPT" : "MBR");
2839 if (FileSystemList
== NULL
)
2841 /* Create the file system list, and by default select the "FAT" file system */
2842 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2843 if (FileSystemList
== NULL
)
2845 /* FIXME: show an error dialog */
2850 if (RepairUpdateFlag
)
2852 return CHECK_FILE_SYSTEM_PAGE
;
2853 //return SELECT_PARTITION_PAGE;
2856 if (IsUnattendedSetup
)
2858 if (USetupData
.FormatPartition
)
2861 * We use whatever currently selected file system we have
2862 * (by default, this is "FAT", as per the initialization
2863 * performed above). Note that it may be interesting to specify
2864 * which file system to use in unattended installations, in the
2865 * txtsetup.sif file.
2867 return FORMAT_PARTITION_PAGE
;
2870 return CHECK_FILE_SYSTEM_PAGE
;
2873 DrawFileSystemList(FileSystemList
);
2877 CONSOLE_ConInKey(Ir
);
2879 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2880 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2882 if (ConfirmQuit(Ir
))
2887 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2888 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2890 FormatState
= Start
;
2891 return SELECT_PARTITION_PAGE
;
2893 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2894 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2896 ScrollDownFileSystemList(FileSystemList
);
2898 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2899 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2901 ScrollUpFileSystemList(FileSystemList
);
2903 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2905 if (!FileSystemList
->Selected
->FileSystem
)
2906 return SELECT_FILE_SYSTEM_PAGE
;
2908 return FORMAT_PARTITION_PAGE
;
2912 FormatState
= PreviousFormatState
;
2914 return SELECT_FILE_SYSTEM_PAGE
;
2919 * Displays the FormatPartitionPage.
2922 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2923 * SelectPartitionPage (At once)
2927 * Sets PartitionList->CurrentPartition->FormatState
2928 * Sets USetupData.DestinationRootPath
2931 * Number of the next page.
2934 FormatPartitionPage(PINPUT_RECORD Ir
)
2937 PDISKENTRY DiskEntry
;
2938 PPARTENTRY PartEntry
;
2939 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2940 UNICODE_STRING PartitionRootPath
;
2941 WCHAR PathBuffer
[MAX_PATH
];
2942 CHAR Buffer
[MAX_PATH
];
2947 PPARTITION_INFORMATION PartitionInfo
;
2950 DPRINT("FormatPartitionPage()\n");
2952 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2954 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2956 /* FIXME: show an error dialog */
2960 PartEntry
= TempPartition
;
2961 DiskEntry
= PartEntry
->DiskEntry
;
2963 SelectedFileSystem
= FileSystemList
->Selected
;
2967 if (!IsUnattendedSetup
)
2969 CONSOLE_ConInKey(Ir
);
2972 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2973 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2975 if (ConfirmQuit(Ir
))
2980 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
2982 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2984 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
2986 /* FIXME: show an error dialog */
2991 CONSOLE_PrintTextXY(6, 12,
2992 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2993 DiskEntry
->Cylinders
,
2994 DiskEntry
->TracksPerCylinder
,
2995 DiskEntry
->SectorsPerTrack
,
2996 DiskEntry
->BytesPerSector
,
2997 DiskEntry
->Dirty
? '*' : ' ');
3001 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3003 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3005 CONSOLE_PrintTextXY(6, Line
,
3006 "%2u: %2lu %c %12I64u %12I64u %02x",
3008 PartitionInfo
->PartitionNumber
,
3009 PartitionInfo
->BootIndicator
? 'A' : '-',
3010 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3011 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3012 PartitionInfo
->PartitionType
);
3017 /* Commit the partition changes to the disk */
3018 if (!WritePartitionsToDisk(PartitionList
))
3020 DPRINT("WritePartitionsToDisk() failed\n");
3021 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3025 /* Set PartitionRootPath */
3026 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3027 L
"\\Device\\Harddisk%lu\\Partition%lu",
3028 DiskEntry
->DiskNumber
,
3029 PartEntry
->PartitionNumber
);
3030 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3031 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3033 /* Format the partition */
3034 if (SelectedFileSystem
->FileSystem
)
3036 Status
= FormatPartition(&PartitionRootPath
,
3037 SelectedFileSystem
);
3038 if (Status
== STATUS_NOT_SUPPORTED
)
3041 "Setup is currently unable to format a partition in %S.\n"
3043 " \x07 Press ENTER to continue Setup.\n"
3044 " \x07 Press F3 to quit Setup.",
3045 SelectedFileSystem
->FileSystem
->FileSystemName
);
3048 MUIGetString(STRING_QUITCONTINUE
),
3049 NULL
, POPUP_WAIT_NONE
);
3053 CONSOLE_ConInKey(Ir
);
3055 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3056 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3058 if (ConfirmQuit(Ir
))
3061 return SELECT_FILE_SYSTEM_PAGE
;
3063 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3065 return SELECT_FILE_SYSTEM_PAGE
;
3069 else if (!NT_SUCCESS(Status
))
3071 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3072 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3076 PartEntry
->FormatState
= Formatted
;
3077 // PartEntry->FileSystem = FileSystem;
3078 PartEntry
->New
= FALSE
;
3082 CONSOLE_SetStatusText(" Done. Press any key ...");
3083 CONSOLE_ConInKey(Ir
);
3086 return SELECT_FILE_SYSTEM_PAGE
;
3090 return FORMAT_PARTITION_PAGE
;
3095 * Displays the CheckFileSystemPage.
3098 * InstallDirectoryPage (At once)
3102 * Inits or reloads FileSystemList
3105 * Number of the next page.
3108 CheckFileSystemPage(PINPUT_RECORD Ir
)
3111 PDISKENTRY DiskEntry
;
3112 PPARTENTRY PartEntry
;
3113 PFILE_SYSTEM CurrentFileSystem
;
3114 UNICODE_STRING PartitionRootPath
;
3115 WCHAR PathBuffer
[MAX_PATH
];
3116 CHAR Buffer
[MAX_PATH
];
3118 if (PartitionList
== NULL
)
3120 /* FIXME: show an error dialog */
3124 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3126 return INSTALL_DIRECTORY_PAGE
;
3129 /* Set PartitionRootPath */
3130 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3131 L
"\\Device\\Harddisk%lu\\Partition%lu",
3132 DiskEntry
->DiskNumber
,
3133 PartEntry
->PartitionNumber
);
3134 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3135 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3137 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3139 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3141 CurrentFileSystem
= PartEntry
->FileSystem
;
3142 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3143 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3145 /* HACK: Do not try to check a partition with an unknown filesystem */
3146 if (CurrentFileSystem
== NULL
)
3148 PartEntry
->NeedsCheck
= FALSE
;
3149 return CHECK_FILE_SYSTEM_PAGE
;
3152 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3153 if (Status
== STATUS_NOT_SUPPORTED
)
3156 "Setup is currently unable to check a partition formatted in %S.\n"
3158 " \x07 Press ENTER to continue Setup.\n"
3159 " \x07 Press F3 to quit Setup.",
3160 CurrentFileSystem
->FileSystemName
);
3163 MUIGetString(STRING_QUITCONTINUE
),
3164 NULL
, POPUP_WAIT_NONE
);
3168 CONSOLE_ConInKey(Ir
);
3170 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3171 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3173 if (ConfirmQuit(Ir
))
3176 return CHECK_FILE_SYSTEM_PAGE
;
3178 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3180 PartEntry
->NeedsCheck
= FALSE
;
3181 return CHECK_FILE_SYSTEM_PAGE
;
3185 else if (!NT_SUCCESS(Status
))
3187 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3188 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3189 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3190 "(Status 0x%08lx).\n", Status
);
3192 // MUIGetString(STRING_REBOOTCOMPUTER),
3193 MUIGetString(STRING_CONTINUE
),
3194 Ir
, POPUP_WAIT_ENTER
);
3196 // return QUIT_PAGE;
3199 PartEntry
->NeedsCheck
= FALSE
;
3200 return CHECK_FILE_SYSTEM_PAGE
;
3205 BuildInstallPaths(PWSTR InstallDir
,
3206 PDISKENTRY DiskEntry
,
3207 PPARTENTRY PartEntry
)
3211 Status
= InitDestinationPaths(&USetupData
, InstallDir
, DiskEntry
, PartEntry
);
3212 // TODO: Check Status
3213 UNREFERENCED_PARAMETER(Status
);
3215 /* Initialize DestinationDriveLetter */
3216 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3222 IN PCWSTR InstallDir
)
3226 Length
= wcslen(InstallDir
);
3228 // TODO: Add check for 8.3 too.
3230 /* Path must be at least 2 characters long */
3234 /* Path must start with a backslash */
3235 // if (InstallDir[0] != L'\\')
3238 /* Path must not end with a backslash */
3239 if (InstallDir
[Length
- 1] == L
'\\')
3242 /* Path must not contain whitespace characters */
3243 for (i
= 0; i
< Length
; i
++)
3245 if (iswspace(InstallDir
[i
]))
3249 /* Path component must not end with a dot */
3250 for (i
= 0; i
< Length
; i
++)
3252 if (InstallDir
[i
] == L
'\\' && i
> 0)
3254 if (InstallDir
[i
- 1] == L
'.')
3259 if (InstallDir
[Length
- 1] == L
'.')
3267 * Displays the InstallDirectoryPage.
3274 * Number of the next page.
3277 InstallDirectoryPage(PINPUT_RECORD Ir
)
3279 PDISKENTRY DiskEntry
;
3280 PPARTENTRY PartEntry
;
3281 WCHAR InstallDir
[MAX_PATH
];
3285 /* We do not need the filesystem list anymore */
3286 if (FileSystemList
!= NULL
)
3288 DestroyFileSystemList(FileSystemList
);
3289 FileSystemList
= NULL
;
3292 if (PartitionList
== NULL
||
3293 PartitionList
->CurrentDisk
== NULL
||
3294 PartitionList
->CurrentPartition
== NULL
)
3296 /* FIXME: show an error dialog */
3300 DiskEntry
= PartitionList
->CurrentDisk
;
3301 PartEntry
= PartitionList
->CurrentPartition
;
3303 // if (IsUnattendedSetup)
3304 if (RepairUpdateFlag
)
3305 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3306 else if (USetupData
.InstallationDirectory
[0])
3307 wcscpy(InstallDir
, USetupData
.InstallationDirectory
);
3309 wcscpy(InstallDir
, L
"\\ReactOS");
3312 * Check the validity of the predefined 'InstallDir'. If we are either
3313 * in unattended setup or in update/repair mode, and the installation path
3314 * is valid, just perform the installation. Otherwise (either in the case
3315 * of an invalid path, or we are in regular setup), display the UI and allow
3316 * the user to specify a new installation path.
3318 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3320 BuildInstallPaths(InstallDir
,
3325 * Check whether the user attempts to install ReactOS within the
3326 * installation source directory, or in a subdirectory thereof.
3327 * If so, fail with an error.
3329 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3331 PopupError("You cannot install ReactOS within the installation source directory!",
3332 MUIGetString(STRING_CONTINUE
),
3333 Ir
, POPUP_WAIT_ENTER
);
3334 return INSTALL_DIRECTORY_PAGE
;
3337 return PREPARE_COPY_PAGE
;
3340 Length
= wcslen(InstallDir
);
3343 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3344 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3345 CONSOLE_SetCursorXY(8 + Pos
, 11);
3346 CONSOLE_SetCursorType(TRUE
, TRUE
);
3350 CONSOLE_ConInKey(Ir
);
3352 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3353 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3355 CONSOLE_SetCursorType(TRUE
, FALSE
);
3357 if (ConfirmQuit(Ir
))
3360 CONSOLE_SetCursorType(TRUE
, TRUE
);
3363 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3364 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3368 memmove(&InstallDir
[Pos
],
3369 &InstallDir
[Pos
+ 1],
3370 (Length
- Pos
- 1) * sizeof(WCHAR
));
3371 InstallDir
[Length
- 1] = UNICODE_NULL
;
3374 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3375 CONSOLE_SetCursorXY(8 + Pos
, 11);
3378 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3379 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3382 CONSOLE_SetCursorXY(8 + Pos
, 11);
3384 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3385 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3388 CONSOLE_SetCursorXY(8 + Pos
, 11);
3390 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3391 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3396 CONSOLE_SetCursorXY(8 + Pos
, 11);
3399 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3400 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3405 CONSOLE_SetCursorXY(8 + Pos
, 11);
3408 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3410 CONSOLE_SetCursorType(TRUE
, FALSE
);
3413 * Check for the validity of the installation directory and pop up
3414 * an error if it is not the case. Then the user can fix its input.
3416 if (!IsValidPath(InstallDir
))
3418 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3419 return INSTALL_DIRECTORY_PAGE
;
3422 BuildInstallPaths(InstallDir
,
3427 * Check whether the user attempts to install ReactOS within the
3428 * installation source directory, or in a subdirectory thereof.
3429 * If so, fail with an error.
3431 if (RtlPrefixUnicodeString(&USetupData
.SourcePath
, &USetupData
.DestinationPath
, TRUE
))
3433 PopupError("You cannot install ReactOS within the installation source directory!",
3434 MUIGetString(STRING_CONTINUE
),
3435 Ir
, POPUP_WAIT_ENTER
);
3436 return INSTALL_DIRECTORY_PAGE
;
3439 return PREPARE_COPY_PAGE
;
3441 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3446 memmove(&InstallDir
[Pos
- 1],
3448 (Length
- Pos
) * sizeof(WCHAR
));
3449 InstallDir
[Length
- 1] = UNICODE_NULL
;
3453 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3454 CONSOLE_SetCursorXY(8 + Pos
, 11);
3457 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3461 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3462 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3465 memmove(&InstallDir
[Pos
+ 1],
3467 (Length
- Pos
) * sizeof(WCHAR
));
3468 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3469 InstallDir
[Pos
] = c
;
3473 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3474 CONSOLE_SetCursorXY(8 + Pos
, 11);
3480 return INSTALL_DIRECTORY_PAGE
;
3485 AddSectionToCopyQueueCab(HINF InfFile
,
3487 PCWSTR SourceCabinet
,
3488 PCUNICODE_STRING DestinationPath
,
3491 INFCONTEXT FilesContext
;
3492 INFCONTEXT DirContext
;
3494 PCWSTR FileKeyValue
;
3496 PCWSTR TargetFileName
;
3497 WCHAR FileDstPath
[MAX_PATH
];
3500 * This code enumerates the list of files in reactos.dff / reactos.inf
3501 * that need to be extracted from reactos.cab and be installed in their
3502 * respective directories.
3505 /* Search for the SectionName section */
3506 if (!SpInfFindFirstLine(InfFile
, SectionName
, NULL
, &FilesContext
))
3508 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3513 * Enumerate the files in the section and add them to the file queue.
3517 /* Get source file name and target directory id */
3518 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3520 /* FIXME: Handle error! */
3521 DPRINT1("INF_GetData() failed\n");
3525 /* Get optional target file name */
3526 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3527 TargetFileName
= NULL
;
3529 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3531 /* Lookup target directory */
3532 if (!SpInfFindFirstLine(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3534 /* FIXME: Handle error! */
3535 DPRINT1("SetupFindFirstLine() failed\n");
3536 INF_FreeData(FileKeyName
);
3537 INF_FreeData(FileKeyValue
);
3538 INF_FreeData(TargetFileName
);
3542 INF_FreeData(FileKeyValue
);
3544 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3546 /* FIXME: Handle error! */
3547 DPRINT1("INF_GetData() failed\n");
3548 INF_FreeData(FileKeyName
);
3549 INF_FreeData(TargetFileName
);
3553 #if 1 // HACK moved! (r66604)
3555 ULONG Length
= wcslen(DirKeyValue
);
3556 if ((Length
> 0) && (DirKeyValue
[Length
- 1] == L
'\\'))
3558 *((PWSTR
)DirKeyValue
+ Length
) = UNICODE_NULL
;
3561 /* Build the full target path */
3562 RtlStringCchCopyW(FileDstPath
, ARRAYSIZE(FileDstPath
),
3563 USetupData
.DestinationRootPath
.Buffer
);
3564 if (DirKeyValue
[0] == UNICODE_NULL
)
3566 /* Installation path */
3568 /* Add the installation path */
3569 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, USetupData
.InstallPath
.Buffer
);
3571 else if (DirKeyValue
[0] == L
'\\')
3574 // if (DirKeyValue[1] != UNICODE_NULL)
3575 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, DirKeyValue
);
3577 else // if (DirKeyValue[0] != L'\\')
3579 /* Path relative to the installation path */
3581 /* Add the installation path */
3582 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 2,
3583 USetupData
.InstallPath
.Buffer
, DirKeyValue
);
3587 if (!SpFileQueueCopy((HSPFILEQ
)USetupData
.SetupFileQueue
,
3588 USetupData
.SourceRootPath
.Buffer
,
3589 USetupData
.SourceRootDir
.Buffer
,
3598 /* FIXME: Handle error! */
3599 DPRINT1("SpFileQueueCopy() failed\n");
3602 INF_FreeData(FileKeyName
);
3603 INF_FreeData(TargetFileName
);
3604 INF_FreeData(DirKeyValue
);
3605 } while (SpInfFindNextLine(&FilesContext
, &FilesContext
));
3612 AddSectionToCopyQueue(HINF InfFile
,
3614 PCWSTR SourceCabinet
,
3615 PCUNICODE_STRING DestinationPath
,
3618 INFCONTEXT FilesContext
;
3619 INFCONTEXT DirContext
;
3621 PCWSTR FileKeyValue
;
3623 PCWSTR TargetFileName
;
3624 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3625 WCHAR FileDstPath
[MAX_PATH
];
3628 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3631 * This code enumerates the list of files in txtsetup.sif
3632 * that need to be installed in their respective directories.
3635 /* Search for the SectionName section */
3636 if (!SpInfFindFirstLine(InfFile
, SectionName
, NULL
, &FilesContext
))
3638 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, SectionName
);
3643 * Enumerate the files in the section and add them to the file queue.
3647 /* Get source file name */
3648 if (!INF_GetDataField(&FilesContext
, 0, &FileKeyName
))
3650 /* FIXME: Handle error! */
3651 DPRINT1("INF_GetData() failed\n");
3655 /* Get target directory id */
3656 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3658 /* FIXME: Handle error! */
3659 DPRINT1("INF_GetData() failed\n");
3660 INF_FreeData(FileKeyName
);
3664 /* Get optional target file name */
3665 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3666 TargetFileName
= NULL
;
3667 else if (!*TargetFileName
)
3668 TargetFileName
= NULL
;
3670 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3672 /* Lookup target directory */
3673 if (!SpInfFindFirstLine(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3675 /* FIXME: Handle error! */
3676 DPRINT1("SetupFindFirstLine() failed\n");
3677 INF_FreeData(FileKeyName
);
3678 INF_FreeData(FileKeyValue
);
3679 INF_FreeData(TargetFileName
);
3683 INF_FreeData(FileKeyValue
);
3685 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3687 /* FIXME: Handle error! */
3688 DPRINT1("INF_GetData() failed\n");
3689 INF_FreeData(FileKeyName
);
3690 INF_FreeData(TargetFileName
);
3694 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3696 /* Installation path */
3697 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3699 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3700 USetupData
.SourceRootDir
.Buffer
);
3702 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3704 else if (DirKeyValue
[0] == L
'\\')
3707 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3709 RtlStringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3712 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3714 else // if (DirKeyValue[0] != L'\\')
3716 /* Path relative to the installation path */
3717 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3719 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3720 USetupData
.SourceRootDir
.Buffer
, DirKeyValue
);
3722 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3725 #if 1 // HACK moved! (r66604)
3727 ULONG Length
= wcslen(DirKeyValue
);
3728 if ((Length
> 0) && (DirKeyValue
[Length
- 1] == L
'\\'))
3730 *((PWSTR
)DirKeyValue
+ Length
) = UNICODE_NULL
;
3733 /* Build the full target path */
3734 RtlStringCchCopyW(FileDstPath
, ARRAYSIZE(FileDstPath
),
3735 USetupData
.DestinationRootPath
.Buffer
);
3736 if (DirKeyValue
[0] == UNICODE_NULL
)
3738 /* Installation path */
3740 /* Add the installation path */
3741 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, USetupData
.InstallPath
.Buffer
);
3743 else if (DirKeyValue
[0] == L
'\\')
3746 // if (DirKeyValue[1] != UNICODE_NULL)
3747 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, DirKeyValue
);
3749 else // if (DirKeyValue[0] != L'\\')
3751 /* Path relative to the installation path */
3753 /* Add the installation path */
3754 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 2,
3755 USetupData
.InstallPath
.Buffer
, DirKeyValue
);
3759 if (!SpFileQueueCopy((HSPFILEQ
)USetupData
.SetupFileQueue
,
3760 USetupData
.SourceRootPath
.Buffer
,
3761 CompleteOrigDirName
,
3770 /* FIXME: Handle error! */
3771 DPRINT1("SpFileQueueCopy() failed\n");
3774 INF_FreeData(FileKeyName
);
3775 INF_FreeData(TargetFileName
);
3776 INF_FreeData(DirKeyValue
);
3777 } while (SpInfFindNextLine(&FilesContext
, &FilesContext
));
3784 PrepareCopyPageInfFile(HINF InfFile
,
3785 PCWSTR SourceCabinet
,
3789 INFCONTEXT DirContext
;
3790 PWCHAR AdditionalSectionName
= NULL
;
3792 WCHAR PathBuffer
[MAX_PATH
];
3794 /* Add common files */
3795 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3798 /* Add specific files depending of computer type */
3799 if (SourceCabinet
== NULL
)
3801 if (!ProcessComputerFiles(InfFile
, USetupData
.ComputerList
, &AdditionalSectionName
))
3804 if (AdditionalSectionName
)
3806 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &USetupData
.DestinationPath
, Ir
))
3811 /* Create directories */
3815 * Copying files to USetupData.DestinationRootPath should be done from within
3816 * the SystemPartitionFiles section.
3817 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3818 * For installing to USetupData.DestinationPath specify just '\' .
3821 /* Get destination path */
3822 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), USetupData
.DestinationPath
.Buffer
);
3824 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3826 /* Create the install directory */
3827 Status
= SetupCreateDirectory(PathBuffer
);
3828 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3830 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3831 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3835 /* Search for the 'Directories' section */
3836 if (!SpInfFindFirstLine(InfFile
, L
"Directories", NULL
, &DirContext
))
3839 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3841 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
, L
"Directories");
3846 /* Enumerate the directory values and create the subdirectories */
3849 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3855 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3857 /* Installation path */
3858 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3860 RtlStringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3861 USetupData
.DestinationPath
.Buffer
);
3863 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3865 else if (DirKeyValue
[0] == L
'\\')
3868 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3870 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3871 USetupData
.DestinationRootPath
.Buffer
, DirKeyValue
);
3873 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3875 Status
= SetupCreateDirectory(PathBuffer
);
3876 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3878 INF_FreeData(DirKeyValue
);
3879 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3880 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3884 else // if (DirKeyValue[0] != L'\\')
3886 /* Path relative to the installation path */
3887 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3889 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3890 USetupData
.DestinationPath
.Buffer
, DirKeyValue
);
3892 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3894 Status
= SetupCreateDirectory(PathBuffer
);
3895 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3897 INF_FreeData(DirKeyValue
);
3898 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3899 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3904 INF_FreeData(DirKeyValue
);
3905 } while (SpInfFindNextLine(&DirContext
, &DirContext
));
3912 * Displays the PrepareCopyPage.
3915 * FileCopyPage(At once)
3919 * Inits SetupFileQueue
3920 * Calls PrepareCopyPageInfFile
3923 * Number of the next page.
3926 PrepareCopyPage(PINPUT_RECORD Ir
)
3929 WCHAR PathBuffer
[MAX_PATH
];
3930 INFCONTEXT CabinetsContext
;
3936 MUIDisplayPage(PREPARE_COPY_PAGE
);
3938 /* Create the file queue */
3939 USetupData
.SetupFileQueue
= SpFileQueueOpen();
3940 if (USetupData
.SetupFileQueue
== NULL
)
3942 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3946 if (!PrepareCopyPageInfFile(USetupData
.SetupInf
, NULL
, Ir
))
3948 /* FIXME: show an error dialog */
3952 /* Search for the 'Cabinets' section */
3953 if (!SpInfFindFirstLine(USetupData
.SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3955 return FILE_COPY_PAGE
;
3959 * Enumerate the directory values in the 'Cabinets'
3960 * section and parse their inf files.
3964 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3967 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3968 USetupData
.SourcePath
.Buffer
, KeyValue
);
3970 CabinetInitialize();
3971 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3972 CabinetSetCabinetName(PathBuffer
);
3974 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3976 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3978 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3979 if (InfFileData
== NULL
)
3981 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3987 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3988 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3992 InfHandle
= INF_OpenBufferedFileA((PSTR
)InfFileData
,
3996 USetupData
.LanguageId
,
3999 if (InfHandle
== INVALID_HANDLE_VALUE
)
4001 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
4007 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
4009 /* FIXME: show an error dialog */
4012 } while (SpInfFindNextLine(&CabinetsContext
, &CabinetsContext
));
4014 return FILE_COPY_PAGE
;
4017 typedef struct _COPYCONTEXT
4019 ULONG TotalOperations
;
4020 ULONG CompletedOperations
;
4021 PPROGRESSBAR ProgressBar
;
4022 PPROGRESSBAR MemoryBars
[4];
4023 } COPYCONTEXT
, *PCOPYCONTEXT
;
4026 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
4029 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
4031 /* Get the memory information from the system */
4032 NtQuerySystemInformation(SystemPerformanceInformation
,
4037 /* Check if this is initial setup */
4040 /* Set maximum limits to be total RAM pages */
4041 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
4042 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
4043 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
4046 /* Set current values */
4047 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
4048 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
4049 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
4054 FileCopyCallback(PVOID Context
,
4059 PCOPYCONTEXT CopyContext
= (PCOPYCONTEXT
)Context
;
4060 PFILEPATHS_W FilePathInfo
;
4061 PCWSTR SrcFileName
, DstFileName
;
4063 switch (Notification
)
4065 case SPFILENOTIFY_STARTSUBQUEUE
:
4067 CopyContext
->TotalOperations
= (ULONG
)Param2
;
4068 CopyContext
->CompletedOperations
= 0;
4069 ProgressSetStepCount(CopyContext
->ProgressBar
,
4070 CopyContext
->TotalOperations
);
4071 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
4075 case SPFILENOTIFY_STARTDELETE
:
4076 case SPFILENOTIFY_STARTRENAME
:
4077 case SPFILENOTIFY_STARTCOPY
:
4079 FilePathInfo
= (PFILEPATHS_W
)Param1
;
4081 if (Notification
== SPFILENOTIFY_STARTDELETE
)
4083 /* Display delete message */
4084 ASSERT(Param2
== FILEOP_DELETE
);
4086 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
4087 if (DstFileName
) ++DstFileName
;
4088 else DstFileName
= FilePathInfo
->Target
;
4090 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING
),
4093 else if (Notification
== SPFILENOTIFY_STARTRENAME
)
4095 /* Display move/rename message */
4096 ASSERT(Param2
== FILEOP_RENAME
);
4098 SrcFileName
= wcsrchr(FilePathInfo
->Source
, L
'\\');
4099 if (SrcFileName
) ++SrcFileName
;
4100 else SrcFileName
= FilePathInfo
->Source
;
4102 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
4103 if (DstFileName
) ++DstFileName
;
4104 else DstFileName
= FilePathInfo
->Target
;
4106 if (!wcsicmp(SrcFileName
, DstFileName
))
4107 Param2
= STRING_MOVING
;
4109 Param2
= STRING_RENAMING
;
4111 CONSOLE_SetStatusText(MUIGetString(Param2
),
4112 SrcFileName
, DstFileName
);
4114 else if (Notification
== SPFILENOTIFY_STARTCOPY
)
4116 /* Display copy message */
4117 ASSERT(Param2
== FILEOP_COPY
);
4119 /* NOTE: When extracting from CABs the Source is the CAB name */
4120 DstFileName
= wcsrchr(FilePathInfo
->Target
, L
'\\');
4121 if (DstFileName
) ++DstFileName
;
4122 else DstFileName
= FilePathInfo
->Target
;
4124 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
),
4128 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4132 case SPFILENOTIFY_COPYERROR
:
4134 FilePathInfo
= (PFILEPATHS_W
)Param1
;
4136 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
4137 FilePathInfo
->Target
, FilePathInfo
->Win32Error
);
4141 case SPFILENOTIFY_ENDDELETE
:
4142 case SPFILENOTIFY_ENDRENAME
:
4143 case SPFILENOTIFY_ENDCOPY
:
4145 CopyContext
->CompletedOperations
++;
4147 /* SYSREG checkpoint */
4148 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
4149 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4151 ProgressNextStep(CopyContext
->ProgressBar
);
4152 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4162 * Displays the FileCopyPage.
4165 * RegistryPage(At once)
4168 * Calls SetupCommitFileQueueW
4169 * Calls SpFileQueueClose
4172 * Number of the next page.
4175 FileCopyPage(PINPUT_RECORD Ir
)
4177 COPYCONTEXT CopyContext
;
4180 MUIDisplayPage(FILE_COPY_PAGE
);
4182 /* Create context for the copy process */
4183 CopyContext
.TotalOperations
= 0;
4184 CopyContext
.CompletedOperations
= 0;
4186 /* Create the progress bar as well */
4187 CopyContext
.ProgressBar
= CreateProgressBar(13,
4194 MUIGetString(STRING_SETUPCOPYINGFILES
));
4196 // fit memory bars to screen width, distribute them uniform
4197 MemBarWidth
= (xScreen
- 26) / 5;
4198 MemBarWidth
-= MemBarWidth
% 2; // make even
4199 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4200 /* Create the paged pool progress bar */
4201 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4210 /* Create the non paged pool progress bar */
4211 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (MemBarWidth
/ 2),
4213 (xScreen
/ 2) + (MemBarWidth
/ 2),
4215 (xScreen
/ 2)- (MemBarWidth
/ 2),
4220 /* Create the global memory progress bar */
4221 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - MemBarWidth
,
4225 xScreen
- 13 - MemBarWidth
,
4230 /* Do the file copying */
4231 SpFileQueueCommit(NULL
,
4232 USetupData
.SetupFileQueue
,
4236 /* If we get here, we're done, so cleanup the queue and progress bar */
4237 SpFileQueueClose(USetupData
.SetupFileQueue
);
4238 DestroyProgressBar(CopyContext
.ProgressBar
);
4239 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4240 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4241 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4243 /* Create the $winnt$.inf file */
4244 InstallSetupInfFile(&USetupData
);
4246 /* Go display the next page */
4247 return REGISTRY_PAGE
;
4253 RegistryStatus(IN REGISTRY_STATUS RegStatus
, ...)
4255 /* WARNING: Please keep this lookup table in sync with the resources! */
4256 static const UINT StringIDs
[] =
4258 STRING_DONE
, /* Success */
4259 STRING_REGHIVEUPDATE
, /* RegHiveUpdate */
4260 STRING_IMPORTFILE
, /* ImportRegHive */
4261 STRING_DISPLAYSETTINGSUPDATE
, /* DisplaySettingsUpdate */
4262 STRING_LOCALESETTINGSUPDATE
, /* LocaleSettingsUpdate */
4263 STRING_ADDKBLAYOUTS
, /* KeybLayouts */
4264 STRING_KEYBOARDSETTINGSUPDATE
, /* KeybSettingsUpdate */
4265 STRING_CODEPAGEINFOUPDATE
, /* CodePageInfoUpdate */
4270 if (RegStatus
< ARRAYSIZE(StringIDs
))
4272 va_start(args
, RegStatus
);
4273 CONSOLE_SetStatusTextV(MUIGetString(StringIDs
[RegStatus
]), args
);
4278 CONSOLE_SetStatusText("Unknown status %d", RegStatus
);
4283 * Displays the RegistryPage.
4286 * SuccessPage (if RepairUpdate)
4287 * BootLoaderPage (default)
4291 * Calls UpdateRegistry
4294 * Number of the next page.
4297 RegistryPage(PINPUT_RECORD Ir
)
4301 MUIDisplayPage(REGISTRY_PAGE
);
4303 Error
= UpdateRegistry(&USetupData
,
4306 DestinationDriveLetter
,
4309 if (Error
!= ERROR_SUCCESS
)
4311 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ENTER
);
4316 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4317 return BOOT_LOADER_PAGE
;
4323 * Displays the BootLoaderPage.
4326 * SuccessPage (if RepairUpdate)
4327 * BootLoaderHarddiskMbrPage
4328 * BootLoaderHarddiskVbrPage
4329 * BootLoaderFloppyPage
4334 * Calls RegInitializeRegistry
4335 * Calls ImportRegistryFile
4336 * Calls SetDefaultPagefile
4337 * Calls SetMountedDeviceValues
4340 * Number of the next page.
4343 BootLoaderPage(PINPUT_RECORD Ir
)
4345 UCHAR PartitionType
;
4346 BOOLEAN InstallOnFloppy
;
4348 WCHAR PathBuffer
[MAX_PATH
];
4350 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4352 RtlFreeUnicodeString(&USetupData
.SystemRootPath
);
4353 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4354 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4355 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4356 PartitionList
->SystemPartition
->PartitionNumber
);
4357 RtlCreateUnicodeString(&USetupData
.SystemRootPath
, PathBuffer
);
4358 DPRINT1("SystemRootPath: %wZ\n", &USetupData
.SystemRootPath
);
4360 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4362 /* For unattended setup, skip MBR installation or install on floppy if needed */
4363 if (IsUnattendedSetup
)
4365 if ((USetupData
.MBRInstallType
== 0) ||
4366 (USetupData
.MBRInstallType
== 1))
4373 * We may install an MBR or VBR, but before that, check whether
4374 * we need to actually install the VBR on floppy.
4376 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4378 DPRINT("Error: system partition invalid (unused)\n");
4379 InstallOnFloppy
= TRUE
;
4381 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4383 /* OS/2 boot manager partition */
4384 DPRINT("Found OS/2 boot manager partition\n");
4385 InstallOnFloppy
= TRUE
;
4387 else if (PartitionType
== PARTITION_EXT2
)
4389 /* Linux EXT2 partition */
4390 DPRINT("Found Linux EXT2 partition\n");
4391 InstallOnFloppy
= FALSE
;
4393 else if (PartitionType
== PARTITION_IFS
)
4395 /* NTFS partition */
4396 DPRINT("Found NTFS partition\n");
4398 // FIXME: Make it FALSE when we'll support NTFS installation!
4399 InstallOnFloppy
= TRUE
;
4401 else if ((PartitionType
== PARTITION_FAT_12
) ||
4402 (PartitionType
== PARTITION_FAT_16
) ||
4403 (PartitionType
== PARTITION_HUGE
) ||
4404 (PartitionType
== PARTITION_XINT13
) ||
4405 (PartitionType
== PARTITION_FAT32
) ||
4406 (PartitionType
== PARTITION_FAT32_XINT13
))
4408 DPRINT("Found FAT partition\n");
4409 InstallOnFloppy
= FALSE
;
4413 /* Unknown partition */
4414 DPRINT("Unknown partition found\n");
4415 InstallOnFloppy
= TRUE
;
4418 /* We should install on floppy */
4419 if (InstallOnFloppy
)
4421 USetupData
.MBRInstallType
= 1;
4425 /* Is it an unattended install on hdd? */
4426 if (IsUnattendedSetup
)
4428 if ((USetupData
.MBRInstallType
== 2) ||
4429 (USetupData
.MBRInstallType
== 3))
4435 MUIDisplayPage(BOOT_LOADER_PAGE
);
4436 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4440 CONSOLE_ConInKey(Ir
);
4442 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4443 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4445 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4454 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4456 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4457 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4459 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4468 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4470 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4471 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4473 if (ConfirmQuit(Ir
))
4478 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4482 /* Install on both MBR and VBR */
4483 USetupData
.MBRInstallType
= 2;
4486 else if (Line
== 13)
4488 /* Install on VBR only */
4489 USetupData
.MBRInstallType
= 3;
4492 else if (Line
== 14)
4494 /* Install on floppy */
4495 USetupData
.MBRInstallType
= 1;
4498 else if (Line
== 15)
4500 /* Skip MBR installation */
4501 USetupData
.MBRInstallType
= 0;
4505 return BOOT_LOADER_PAGE
;
4510 switch (USetupData
.MBRInstallType
)
4512 /* Skip MBR installation */
4514 return SUCCESS_PAGE
;
4516 /* Install on floppy */
4518 return BOOT_LOADER_FLOPPY_PAGE
;
4520 /* Install on both MBR and VBR */
4522 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4524 /* Install on VBR only */
4526 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4529 return BOOT_LOADER_PAGE
;
4534 * Displays the BootLoaderFloppyPage.
4537 * SuccessPage (At once)
4541 * Calls InstallFatBootcodeToFloppy()
4544 * Number of the next page.
4547 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4551 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4553 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4557 CONSOLE_ConInKey(Ir
);
4559 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4560 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4562 if (ConfirmQuit(Ir
))
4567 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4569 Status
= InstallFatBootcodeToFloppy(&USetupData
.SourceRootPath
,
4570 &USetupData
.DestinationArcPath
);
4571 if (!NT_SUCCESS(Status
))
4573 if (Status
== STATUS_DEVICE_NOT_READY
)
4574 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4576 /* TODO: Print error message */
4577 return BOOT_LOADER_FLOPPY_PAGE
;
4580 return SUCCESS_PAGE
;
4584 return BOOT_LOADER_FLOPPY_PAGE
;
4589 * Displays the BootLoaderHarddiskVbrPage.
4592 * SuccessPage (At once)
4596 * Calls InstallVBRToPartition()
4599 * Number of the next page.
4602 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4606 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4607 &USetupData
.SourceRootPath
,
4608 &USetupData
.DestinationArcPath
,
4609 PartitionList
->SystemPartition
->PartitionType
);
4610 if (!NT_SUCCESS(Status
))
4612 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4616 return SUCCESS_PAGE
;
4621 * Displays the BootLoaderHarddiskMbrPage.
4624 * SuccessPage (At once)
4628 * Calls InstallVBRToPartition()
4629 * Calls InstallMbrBootCodeToDisk()
4632 * Number of the next page.
4635 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4638 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4640 /* Step 1: Write the VBR */
4641 Status
= InstallVBRToPartition(&USetupData
.SystemRootPath
,
4642 &USetupData
.SourceRootPath
,
4643 &USetupData
.DestinationArcPath
,
4644 PartitionList
->SystemPartition
->PartitionType
);
4645 if (!NT_SUCCESS(Status
))
4647 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4651 /* Step 2: Write the MBR */
4652 RtlStringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4653 L
"\\Device\\Harddisk%d\\Partition0",
4654 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4655 Status
= InstallMbrBootCodeToDisk(&USetupData
.SystemRootPath
,
4656 &USetupData
.SourceRootPath
,
4657 DestinationDevicePathBuffer
);
4658 if (!NT_SUCCESS(Status
))
4660 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status
);
4661 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4665 return SUCCESS_PAGE
;
4670 * @name ProgressTimeOutStringHandler
4672 * Handles the generation (displaying) of the timeout
4673 * countdown to the screen dynamically.
4676 * A pointer to a progress bar.
4678 * @param AlwaysUpdate
4679 * Constantly update the progress bar (boolean type).
4682 * A pointer to a string buffer.
4684 * @param cchBufferSize
4685 * The buffer's size in number of characters.
4688 * TRUE or FALSE on function termination.
4693 ProgressTimeOutStringHandler(
4694 IN PPROGRESSBAR Bar
,
4695 IN BOOLEAN AlwaysUpdate
,
4697 IN SIZE_T cchBufferSize
)
4699 ULONG OldProgress
= Bar
->Progress
;
4701 if (Bar
->StepCount
== 0)
4707 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4710 /* Build the progress string if it has changed */
4711 if (Bar
->ProgressFormatText
&&
4712 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4714 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4715 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4724 * @name ProgressCountdown
4726 * Displays and draws a red-coloured progress bar with a countdown.
4727 * When the timeout is reached, the flush page is displayed for reboot.
4730 * A pointer to an input keyboard record.
4733 * Initial countdown value in seconds.
4741 IN PINPUT_RECORD Ir
,
4745 ULONG StartTime
, BarWidth
, TimerDiv
;
4747 LONG TimerValue
, OldTimerValue
;
4748 LARGE_INTEGER Timeout
;
4749 PPROGRESSBAR ProgressBar
;
4750 BOOLEAN RefreshProgress
= TRUE
;
4752 /* Bail out if the timeout is already zero */
4756 /* Create the timeout progress bar and set it up */
4757 ProgressBar
= CreateProgressBarEx(13,
4764 FOREGROUND_RED
| BACKGROUND_BLUE
,
4767 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4768 ProgressTimeOutStringHandler
);
4770 BarWidth
= max(1, ProgressBar
->Width
);
4771 TimerValue
= TimeOut
* BarWidth
;
4772 ProgressSetStepCount(ProgressBar
, TimerValue
);
4774 StartTime
= NtGetTickCount();
4777 TimerDiv
= 1000 / BarWidth
;
4778 TimerDiv
= max(1, TimerDiv
);
4779 OldTimerValue
= TimerValue
;
4782 /* Decrease the timer */
4785 * Compute how much time the previous operations took.
4786 * This allows us in particular to take account for any time
4787 * elapsed if something slowed down.
4789 TimeElapsed
= NtGetTickCount() - StartTime
;
4790 if (TimeElapsed
>= TimerDiv
)
4792 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4793 TimeElapsed
/= TimerDiv
;
4794 StartTime
+= (TimerDiv
* TimeElapsed
);
4796 if (TimeElapsed
<= TimerValue
)
4797 TimerValue
-= TimeElapsed
;
4801 RefreshProgress
= TRUE
;
4804 if (RefreshProgress
)
4806 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4807 RefreshProgress
= FALSE
;
4810 /* Stop when the timer reaches zero */
4811 if (TimerValue
<= 0)
4814 /* Check for user key presses */
4817 * If the timer is used, use a passive wait of maximum 1 second
4818 * while monitoring for incoming console input events, so that
4819 * we are still able to display the timing count.
4822 /* Wait a maximum of 1 second for input events */
4823 TimeElapsed
= NtGetTickCount() - StartTime
;
4824 if (TimeElapsed
< TimerDiv
)
4826 /* Convert the time to NT Format */
4827 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4828 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4832 Status
= STATUS_TIMEOUT
;
4835 /* Check whether the input event has been signaled, or a timeout happened */
4836 if (Status
== STATUS_TIMEOUT
)
4840 if (Status
!= STATUS_WAIT_0
)
4842 /* An error happened, bail out */
4843 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4847 /* Check for an ENTER key press */
4848 while (CONSOLE_ConInKeyPeek(Ir
))
4850 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4852 /* Found it, stop waiting */
4859 /* Destroy the progress bar and quit */
4860 DestroyProgressBar(ProgressBar
);
4865 * Displays the QuitPage.
4868 * FlushPage (At once)
4874 * Number of the next page.
4877 QuitPage(PINPUT_RECORD Ir
)
4879 MUIDisplayPage(QUIT_PAGE
);
4881 /* Destroy the NTOS installations list */
4882 if (NtOsInstallsList
!= NULL
)
4884 DestroyGenericList(NtOsInstallsList
, TRUE
);
4885 NtOsInstallsList
= NULL
;
4888 /* Destroy the partition list */
4889 if (PartitionList
!= NULL
)
4891 DestroyPartitionList(PartitionList
);
4892 PartitionList
= NULL
;
4895 TempPartition
= NULL
;
4896 FormatState
= Start
;
4898 /* Destroy the filesystem list */
4899 if (FileSystemList
!= NULL
)
4901 DestroyFileSystemList(FileSystemList
);
4902 FileSystemList
= NULL
;
4905 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4907 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4908 ProgressCountdown(Ir
, 15);
4914 * Displays the SuccessPage.
4917 * FlushPage (At once)
4923 * Number of the next page.
4926 SuccessPage(PINPUT_RECORD Ir
)
4928 MUIDisplayPage(SUCCESS_PAGE
);
4930 if (IsUnattendedSetup
)
4933 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4934 ProgressCountdown(Ir
, 15);
4940 * Displays the FlushPage.
4943 * RebootPage (At once)
4946 * Number of the next page.
4949 FlushPage(PINPUT_RECORD Ir
)
4951 MUIDisplayPage(FLUSH_PAGE
);
4957 PnpEventThread(IN LPVOID lpParameter
);
4961 * The start routine and page management
4971 InfSetHeap(ProcessHeap
);
4973 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4974 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4975 if (!NT_SUCCESS(Status
))
4976 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4978 /* Create the PnP thread in suspended state */
4979 Status
= RtlCreateUserThread(NtCurrentProcess(),
4986 &USetupData
.SetupInf
,
4989 if (!NT_SUCCESS(Status
))
4992 if (!CONSOLE_Init())
4994 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4995 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4996 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4998 /* We failed to initialize the video, just quit the installer */
4999 return STATUS_APP_INIT_FAILURE
;
5002 /* Initialize Setup, phase 0 */
5003 InitializeSetup(&USetupData
, 0);
5005 /* Hide the cursor */
5006 CONSOLE_SetCursorType(TRUE
, FALSE
);
5008 /* Global Initialization page */
5009 CONSOLE_ClearScreen();
5011 Page
= SetupStartPage(&Ir
);
5013 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
5015 CONSOLE_ClearScreen();
5018 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
5025 Page
= LanguagePage(&Ir
);
5030 Page
= WelcomePage(&Ir
);
5035 Page
= LicensePage(&Ir
);
5039 case INSTALL_INTRO_PAGE
:
5040 Page
= InstallIntroPage(&Ir
);
5044 case SCSI_CONTROLLER_PAGE
:
5045 Page
= ScsiControllerPage(&Ir
);
5048 case OEM_DRIVER_PAGE
:
5049 Page
= OemDriverPage(&Ir
);
5053 case DEVICE_SETTINGS_PAGE
:
5054 Page
= DeviceSettingsPage(&Ir
);
5057 case COMPUTER_SETTINGS_PAGE
:
5058 Page
= ComputerSettingsPage(&Ir
);
5061 case DISPLAY_SETTINGS_PAGE
:
5062 Page
= DisplaySettingsPage(&Ir
);
5065 case KEYBOARD_SETTINGS_PAGE
:
5066 Page
= KeyboardSettingsPage(&Ir
);
5069 case LAYOUT_SETTINGS_PAGE
:
5070 Page
= LayoutSettingsPage(&Ir
);
5073 case SELECT_PARTITION_PAGE
:
5074 Page
= SelectPartitionPage(&Ir
);
5077 case CREATE_PRIMARY_PARTITION_PAGE
:
5078 Page
= CreatePrimaryPartitionPage(&Ir
);
5081 case CREATE_EXTENDED_PARTITION_PAGE
:
5082 Page
= CreateExtendedPartitionPage(&Ir
);
5085 case CREATE_LOGICAL_PARTITION_PAGE
:
5086 Page
= CreateLogicalPartitionPage(&Ir
);
5089 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5090 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5093 case DELETE_PARTITION_PAGE
:
5094 Page
= DeletePartitionPage(&Ir
);
5097 case SELECT_FILE_SYSTEM_PAGE
:
5098 Page
= SelectFileSystemPage(&Ir
);
5101 case FORMAT_PARTITION_PAGE
:
5102 Page
= FormatPartitionPage(&Ir
);
5105 case CHECK_FILE_SYSTEM_PAGE
:
5106 Page
= CheckFileSystemPage(&Ir
);
5109 case INSTALL_DIRECTORY_PAGE
:
5110 Page
= InstallDirectoryPage(&Ir
);
5113 case PREPARE_COPY_PAGE
:
5114 Page
= PrepareCopyPage(&Ir
);
5117 case FILE_COPY_PAGE
:
5118 Page
= FileCopyPage(&Ir
);
5122 Page
= RegistryPage(&Ir
);
5125 case BOOT_LOADER_PAGE
:
5126 Page
= BootLoaderPage(&Ir
);
5129 case BOOT_LOADER_FLOPPY_PAGE
:
5130 Page
= BootLoaderFloppyPage(&Ir
);
5133 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5134 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5137 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5138 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5142 case REPAIR_INTRO_PAGE
:
5143 Page
= RepairIntroPage(&Ir
);
5146 case UPGRADE_REPAIR_PAGE
:
5147 Page
= UpgradeRepairPage(&Ir
);
5151 Page
= SuccessPage(&Ir
);
5155 Page
= FlushPage(&Ir
);
5159 Page
= QuitPage(&Ir
);
5168 /* Setup has finished */
5169 FinishSetup(&USetupData
);
5171 if (Page
== RECOVERY_PAGE
)
5177 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5178 NtShutdownSystem(ShutdownReboot
);
5179 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5181 return STATUS_SUCCESS
;
5186 NtProcessStartup(PPEB Peb
)
5191 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5193 ProcessHeap
= Peb
->ProcessHeap
;
5195 NtQuerySystemTime(&Time
);
5197 Status
= RunUSetup();
5199 if (NT_SUCCESS(Status
))
5202 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5203 * a protective waiting.
5204 * This wait is needed because, since we are started as SMSS.EXE,
5205 * the NT kernel explicitly waits 5 seconds for the initial process
5206 * SMSS.EXE to initialize (as a protective measure), and otherwise
5207 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5209 Time
.QuadPart
+= 50000000;
5210 NtDelayExecution(FALSE
, &Time
);
5214 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5215 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5216 0, 0, NULL
, 0, NULL
);
5219 NtTerminateProcess(NtCurrentProcess(), Status
);