3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
45 /* GLOBALS ******************************************************************/
48 static UNICODE_STRING SourceRootPath
;
49 static UNICODE_STRING SourceRootDir
;
50 /* static */ UNICODE_STRING SourcePath
;
51 BOOLEAN IsUnattendedSetup
= FALSE
;
52 LONG UnattendDestinationDiskNumber
;
53 LONG UnattendDestinationPartitionNumber
;
54 LONG UnattendMBRInstallType
= -1;
55 LONG UnattendFormatPartition
= 0;
56 LONG AutoPartition
= 0;
57 WCHAR UnattendInstallationDirectory
[MAX_PATH
];
58 PWCHAR SelectedLanguageId
;
60 WCHAR DefaultLanguage
[20];
61 WCHAR DefaultKBLayout
[20];
62 BOOLEAN RepairUpdateFlag
= FALSE
;
63 HANDLE hPnpThread
= INVALID_HANDLE_VALUE
;
65 PPARTLIST PartitionList
= NULL
;
66 PPARTENTRY TempPartition
= NULL
;
67 FORMATMACHINESTATE FormatState
= Start
;
70 /* LOCALS *******************************************************************/
72 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
74 static UNICODE_STRING InstallPath
;
77 * Path to the system partition, where the boot manager resides.
78 * On x86 PCs, this is usually the active partition.
79 * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
81 * For more information, see:
82 * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
83 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
84 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
85 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
86 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
87 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
89 static UNICODE_STRING SystemRootPath
;
91 /* Path to the install directory inside the ReactOS boot partition */
92 static UNICODE_STRING DestinationPath
;
93 static UNICODE_STRING DestinationArcPath
;
94 static UNICODE_STRING DestinationRootPath
;
96 static WCHAR DestinationDriveLetter
; // FIXME: Is it really useful??
100 static HSPFILEQ SetupFileQueue
= NULL
;
102 static PGENERIC_LIST ComputerList
= NULL
;
103 static PGENERIC_LIST DisplayList
= NULL
;
104 static PGENERIC_LIST KeyboardList
= NULL
;
105 static PGENERIC_LIST LayoutList
= NULL
;
106 static PGENERIC_LIST LanguageList
= NULL
;
108 static LANGID LanguageId
= 0;
110 static ULONG RequiredPartitionDiskSpace
= ~0;
112 /* FUNCTIONS ****************************************************************/
115 PrintString(char* fmt
,...)
119 UNICODE_STRING UnicodeString
;
120 ANSI_STRING AnsiString
;
123 vsprintf(buffer
, fmt
, ap
);
126 RtlInitAnsiString(&AnsiString
, buffer
);
127 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
128 NtDisplayString(&UnicodeString
);
129 RtlFreeUnicodeString(&UnicodeString
);
134 DrawBox(IN SHORT xLeft
,
142 /* draw upper left corner */
145 FillConsoleOutputCharacterA(StdOutput
,
151 /* draw upper edge */
154 FillConsoleOutputCharacterA(StdOutput
,
160 /* draw upper right corner */
161 coPos
.X
= xLeft
+ Width
- 1;
163 FillConsoleOutputCharacterA(StdOutput
,
169 /* Draw right edge, inner space and left edge */
170 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
173 FillConsoleOutputCharacterA(StdOutput
,
180 FillConsoleOutputCharacterA(StdOutput
,
186 coPos
.X
= xLeft
+ Width
- 1;
187 FillConsoleOutputCharacterA(StdOutput
,
194 /* draw lower left corner */
196 coPos
.Y
= yTop
+ Height
- 1;
197 FillConsoleOutputCharacterA(StdOutput
,
203 /* draw lower edge */
205 coPos
.Y
= yTop
+ Height
- 1;
206 FillConsoleOutputCharacterA(StdOutput
,
212 /* draw lower right corner */
213 coPos
.X
= xLeft
+ Width
- 1;
214 coPos
.Y
= yTop
+ Height
- 1;
215 FillConsoleOutputCharacterA(StdOutput
,
224 PopupError(PCCH Text
,
242 /* Count text lines and longest line */
249 p
= strchr(pnext
, '\n');
253 Length
= strlen(pnext
);
258 Length
= (ULONG
)(p
- pnext
);
264 if (Length
> MaxLength
)
267 if (LastLine
!= FALSE
)
273 /* Check length of status line */
276 Length
= strlen(Status
);
278 if (Length
> MaxLength
)
282 Width
= MaxLength
+ 4;
288 yTop
= (yScreen
- Height
) / 2;
289 xLeft
= (xScreen
- Width
) / 2;
292 /* Set screen attributes */
294 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
296 FillConsoleOutputAttribute(StdOutput
,
297 FOREGROUND_RED
| BACKGROUND_WHITE
,
303 DrawBox(xLeft
, yTop
, Width
, Height
);
305 /* Print message text */
310 p
= strchr(pnext
, '\n');
314 Length
= strlen(pnext
);
319 Length
= (ULONG
)(p
- pnext
);
326 WriteConsoleOutputCharacterA(StdOutput
,
333 if (LastLine
!= FALSE
)
340 /* Print separator line and status text */
343 coPos
.Y
= yTop
+ Height
- 3;
345 FillConsoleOutputCharacterA(StdOutput
,
352 FillConsoleOutputCharacterA(StdOutput
,
358 coPos
.X
= xLeft
+ Width
- 1;
359 FillConsoleOutputCharacterA(StdOutput
,
367 WriteConsoleOutputCharacterA(StdOutput
,
369 min(strlen(Status
), (SIZE_T
)Width
- 4),
374 if (WaitEvent
== POPUP_WAIT_NONE
)
379 CONSOLE_ConInKey(Ir
);
381 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
382 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
394 * FALSE: Don't quit setup.
397 ConfirmQuit(PINPUT_RECORD Ir
)
400 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
404 CONSOLE_ConInKey(Ir
);
406 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
407 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
412 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
424 CheckUnattendedSetup(VOID
)
426 WCHAR UnattendInfPath
[MAX_PATH
];
433 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2, SourcePath
.Buffer
, L
"unattend.inf");
435 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
437 DPRINT("Does not exist: %S\n", UnattendInfPath
);
441 /* Load 'unattend.inf' from install media. */
442 UnattendInf
= SetupOpenInfFileW(UnattendInfPath
,
448 if (UnattendInf
== INVALID_HANDLE_VALUE
)
450 DPRINT("SetupOpenInfFileW() failed\n");
454 /* Open 'Unattend' section */
455 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
457 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
458 SetupCloseInfFile(UnattendInf
);
462 /* Get pointer 'Signature' key */
463 if (!INF_GetData(&Context
, NULL
, &Value
))
465 DPRINT("INF_GetData() failed for key 'Signature'\n");
466 SetupCloseInfFile(UnattendInf
);
470 /* Check 'Signature' string */
471 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
473 DPRINT("Signature not $ReactOS$\n");
474 SetupCloseInfFile(UnattendInf
);
478 /* Check if Unattend setup is enabled */
479 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
481 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
482 SetupCloseInfFile(UnattendInf
);
486 if (!INF_GetData(&Context
, NULL
, &Value
))
488 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
489 SetupCloseInfFile(UnattendInf
);
493 if (_wcsicmp(Value
, L
"yes") != 0)
495 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
496 SetupCloseInfFile(UnattendInf
);
500 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
501 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
503 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
504 SetupCloseInfFile(UnattendInf
);
508 if (!SetupGetIntField(&Context
, 1, &IntValue
))
510 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
511 SetupCloseInfFile(UnattendInf
);
515 UnattendDestinationDiskNumber
= (LONG
)IntValue
;
517 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
518 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
520 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
521 SetupCloseInfFile(UnattendInf
);
525 if (!SetupGetIntField(&Context
, 1, &IntValue
))
527 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
528 SetupCloseInfFile(UnattendInf
);
532 UnattendDestinationPartitionNumber
= (LONG
)IntValue
;
534 /* Search for 'InstallationDirectory' in the 'Unattend' section */
535 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
537 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
538 SetupCloseInfFile(UnattendInf
);
542 /* Get pointer 'InstallationDirectory' key */
543 if (!INF_GetData(&Context
, NULL
, &Value
))
545 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
546 SetupCloseInfFile(UnattendInf
);
550 wcscpy(UnattendInstallationDirectory
, Value
);
552 IsUnattendedSetup
= TRUE
;
554 /* Search for 'MBRInstallType' in the 'Unattend' section */
555 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
557 if (SetupGetIntField(&Context
, 1, &IntValue
))
559 UnattendMBRInstallType
= IntValue
;
563 /* Search for 'FormatPartition' in the 'Unattend' section */
564 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
566 if (SetupGetIntField(&Context
, 1, &IntValue
))
568 UnattendFormatPartition
= IntValue
;
572 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
574 if (SetupGetIntField(&Context
, 1, &IntValue
))
576 AutoPartition
= IntValue
;
580 /* search for LocaleID in the 'Unattend' section*/
581 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
583 if (INF_GetData(&Context
, NULL
, &Value
))
585 LONG Id
= wcstol(Value
, NULL
, 16);
586 swprintf(LocaleID
, L
"%08lx", Id
);
590 SetupCloseInfFile(UnattendInf
);
592 DPRINT("Running unattended setup\n");
599 PGENERIC_LIST_ENTRY ListEntry
;
600 LPCWSTR pszNewLayout
;
602 pszNewLayout
= MUIDefaultKeyboardLayout();
604 if (LayoutList
== NULL
)
606 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
607 if (LayoutList
== NULL
)
609 /* FIXME: Handle error! */
614 ListEntry
= GetFirstListEntry(LayoutList
);
616 /* Search for default layout (if provided) */
617 if (pszNewLayout
!= NULL
)
619 while (ListEntry
!= NULL
)
621 if (!wcscmp(pszNewLayout
, GetListEntryUserData(ListEntry
)))
623 SetCurrentListEntry(LayoutList
, ListEntry
);
627 ListEntry
= GetNextListEntry(ListEntry
);
634 * Displays the LanguagePage.
636 * Next pages: WelcomePage, QuitPage
639 * Init SelectedLanguageId
643 * Number of the next page.
646 LanguagePage(PINPUT_RECORD Ir
)
648 GENERIC_LIST_UI ListUi
;
649 PWCHAR NewLanguageId
;
650 BOOL RefreshPage
= FALSE
;
652 /* Initialize the computer settings list */
653 if (LanguageList
== NULL
)
655 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
656 if (LanguageList
== NULL
)
658 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
664 SelectedLanguageId
= DefaultLanguage
;
665 SetConsoleCodePage();
668 /* If there's just a single language in the list skip
669 * the language selection process altogether! */
670 if (GenericListHasSingleEntry(LanguageList
))
672 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
676 InitGenericListUi(&ListUi
, LanguageList
);
677 DrawGenericList(&ListUi
,
683 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
685 MUIDisplayPage(LANGUAGE_PAGE
);
689 CONSOLE_ConInKey(Ir
);
691 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
692 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
694 ScrollDownGenericList(&ListUi
);
697 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
698 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
700 ScrollUpGenericList(&ListUi
);
703 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
704 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
706 ScrollPageDownGenericList(&ListUi
);
709 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
710 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
712 ScrollPageUpGenericList(&ListUi
);
715 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
716 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
718 if (ConfirmQuit(Ir
) != FALSE
)
721 RedrawGenericList(&ListUi
);
723 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
725 SelectedLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
727 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
729 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
735 SetConsoleCodePage();
739 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
742 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
748 NewLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
750 if (SelectedLanguageId
!= NewLanguageId
)
752 /* Clear the language page */
753 MUIClearPage(LANGUAGE_PAGE
);
755 SelectedLanguageId
= NewLanguageId
;
758 SetConsoleCodePage();
760 /* Redraw language selection page in native language */
761 MUIDisplayPage(LANGUAGE_PAGE
);
776 * LanguagePage (at once, default)
777 * InstallIntroPage (at once, if unattended)
783 * Init SourceRootPath
786 * Init RequiredPartitionDiskSpace
787 * Init IsUnattendedSetup
788 * If unattended, init *List and sets the Codepage
789 * If unattended, init SelectedLanguageId
790 * If unattended, init LanguageId
793 * Number of the next page.
796 SetupStartPage(PINPUT_RECORD Ir
)
799 WCHAR FileNameBuffer
[MAX_PATH
];
803 PGENERIC_LIST_ENTRY ListEntry
;
806 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
808 /* Get the source path and source root path */
809 Status
= GetSourcePaths(&SourcePath
,
812 if (!NT_SUCCESS(Status
))
814 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
815 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
818 DPRINT1("SourcePath: '%wZ'", &SourcePath
);
819 DPRINT1("SourceRootPath: '%wZ'", &SourceRootPath
);
820 DPRINT1("SourceRootDir: '%wZ'", &SourceRootDir
);
822 /* Load txtsetup.sif from install media. */
823 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2, SourcePath
.Buffer
, L
"txtsetup.sif");
824 SetupInf
= SetupOpenInfFileW(FileNameBuffer
,
830 if (SetupInf
== INVALID_HANDLE_VALUE
)
832 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
836 /* Open 'Version' section */
837 if (!SetupFindFirstLineW(SetupInf
, L
"Version", L
"Signature", &Context
))
839 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
843 /* Get pointer 'Signature' key */
844 if (!INF_GetData(&Context
, NULL
, &Value
))
846 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
850 /* Check 'Signature' string */
851 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
853 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
857 /* Open 'DiskSpaceRequirements' section */
858 if (!SetupFindFirstLineW(SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
860 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
864 /* Get the 'FreeSysPartDiskSpace' value */
865 if (!SetupGetIntField(&Context
, 1, &IntValue
))
867 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
871 RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
873 /* Start the PnP thread */
874 if (hPnpThread
!= INVALID_HANDLE_VALUE
)
876 NtResumeThread(hPnpThread
, NULL
);
877 hPnpThread
= INVALID_HANDLE_VALUE
;
880 CheckUnattendedSetup();
882 if (IsUnattendedSetup
)
884 // TODO: Read options from inf
885 ComputerList
= CreateComputerTypeList(SetupInf
);
886 DisplayList
= CreateDisplayDriverList(SetupInf
);
887 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
888 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
889 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
892 wcscpy(SelectedLanguageId
, LocaleID
);
893 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
895 /* first we hack LanguageList */
896 ListEntry
= GetFirstListEntry(LanguageList
);
897 while (ListEntry
!= NULL
)
899 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
901 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry
));
902 SetCurrentListEntry(LanguageList
, ListEntry
);
906 ListEntry
= GetNextListEntry(ListEntry
);
910 ListEntry
= GetFirstListEntry(LayoutList
);
911 while (ListEntry
!= NULL
)
913 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
915 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry
));
916 SetCurrentListEntry(LayoutList
, ListEntry
);
920 ListEntry
= GetNextListEntry(ListEntry
);
923 SetConsoleCodePage();
925 return INSTALL_INTRO_PAGE
;
928 return LANGUAGE_PAGE
;
933 * Displays the WelcomePage.
936 * InstallIntroPage (default)
942 * Number of the next page.
945 WelcomePage(PINPUT_RECORD Ir
)
947 MUIDisplayPage(WELCOME_PAGE
);
951 CONSOLE_ConInKey(Ir
);
953 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
954 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
956 if (ConfirmQuit(Ir
) != FALSE
)
961 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
963 return INSTALL_INTRO_PAGE
;
965 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
967 return REPAIR_INTRO_PAGE
;
969 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
980 * Displays the License page.
983 * WelcomePage (default)
986 * Number of the next page.
989 LicensePage(PINPUT_RECORD Ir
)
991 MUIDisplayPage(LICENSE_PAGE
);
995 CONSOLE_ConInKey(Ir
);
997 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1003 return LICENSE_PAGE
;
1008 * Displays the RepairIntroPage.
1011 * RebootPage (default)
1017 * Number of the next page.
1020 RepairIntroPage(PINPUT_RECORD Ir
)
1022 MUIDisplayPage(REPAIR_INTRO_PAGE
);
1026 CONSOLE_ConInKey(Ir
);
1028 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1032 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
1034 RepairUpdateFlag
= TRUE
;
1035 return INSTALL_INTRO_PAGE
;
1037 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
1039 return RECOVERY_PAGE
;
1041 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1042 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1044 return WELCOME_PAGE
;
1048 return REPAIR_INTRO_PAGE
;
1052 * Displays the InstallIntroPage.
1055 * DeviceSettingsPage (At once if repair or update is selected)
1056 * SelectPartitionPage (At once if unattended setup)
1057 * DeviceSettingsPage (default)
1061 * Number of the next page.
1064 InstallIntroPage(PINPUT_RECORD Ir
)
1066 if (RepairUpdateFlag
)
1068 //return SELECT_PARTITION_PAGE;
1069 return DEVICE_SETTINGS_PAGE
;
1072 if (IsUnattendedSetup
)
1073 return SELECT_PARTITION_PAGE
;
1075 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1079 CONSOLE_ConInKey(Ir
);
1081 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1082 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1084 if (ConfirmQuit(Ir
) != FALSE
)
1089 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1091 return DEVICE_SETTINGS_PAGE
;
1092 // return SCSI_CONTROLLER_PAGE;
1096 return INSTALL_INTRO_PAGE
;
1102 ScsiControllerPage(PINPUT_RECORD Ir
)
1104 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1106 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1108 /* FIXME: print loaded mass storage driver descriptions */
1110 CONSOLE_SetTextXY(8, 10, "TEST device");
1113 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1117 CONSOLE_ConInKey(Ir
);
1119 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1120 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1122 if (ConfirmQuit(Ir
) != FALSE
)
1127 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1129 return DEVICE_SETTINGS_PAGE
;
1133 return SCSI_CONTROLLER_PAGE
;
1137 OemDriverPage(PINPUT_RECORD Ir
)
1139 // MUIDisplayPage(OEM_DRIVER_PAGE);
1141 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1143 /* FIXME: Implement!! */
1145 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1149 CONSOLE_ConInKey(Ir
);
1151 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1152 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1154 if (ConfirmQuit(Ir
) == TRUE
)
1159 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1161 return DEVICE_SETTINGS_PAGE
;
1165 return OEM_DRIVER_PAGE
;
1171 * Displays the DeviceSettingsPage.
1174 * SelectPartitionPage (At once if repair or update is selected)
1175 * ComputerSettingsPage
1176 * DisplaySettingsPage
1177 * KeyboardSettingsPage
1178 * LayoutsettingsPage
1179 * SelectPartitionPage
1189 * Number of the next page.
1192 DeviceSettingsPage(PINPUT_RECORD Ir
)
1194 static ULONG Line
= 16;
1196 /* Initialize the computer settings list */
1197 if (ComputerList
== NULL
)
1199 ComputerList
= CreateComputerTypeList(SetupInf
);
1200 if (ComputerList
== NULL
)
1202 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1207 /* Initialize the display settings list */
1208 if (DisplayList
== NULL
)
1210 DisplayList
= CreateDisplayDriverList(SetupInf
);
1211 if (DisplayList
== NULL
)
1213 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1218 /* Initialize the keyboard settings list */
1219 if (KeyboardList
== NULL
)
1221 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1222 if (KeyboardList
== NULL
)
1224 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1229 /* Initialize the keyboard layout list */
1230 if (LayoutList
== NULL
)
1232 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
1233 if (LayoutList
== NULL
)
1235 /* FIXME: report error */
1236 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1241 if (RepairUpdateFlag
)
1242 return SELECT_PARTITION_PAGE
;
1244 // if (IsUnattendedSetup)
1245 // return SELECT_PARTITION_PAGE;
1247 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1249 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList
)));
1250 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList
)));
1251 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList
)));
1252 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList
)));
1254 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1258 CONSOLE_ConInKey(Ir
);
1260 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1261 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1263 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1267 else if (Line
== 16)
1272 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1274 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1275 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1277 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1281 else if (Line
== 16)
1286 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1288 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1289 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1291 if (ConfirmQuit(Ir
) != FALSE
)
1296 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1299 return COMPUTER_SETTINGS_PAGE
;
1300 else if (Line
== 12)
1301 return DISPLAY_SETTINGS_PAGE
;
1302 else if (Line
== 13)
1303 return KEYBOARD_SETTINGS_PAGE
;
1304 else if (Line
== 14)
1305 return LAYOUT_SETTINGS_PAGE
;
1306 else if (Line
== 16)
1307 return SELECT_PARTITION_PAGE
;
1311 return DEVICE_SETTINGS_PAGE
;
1316 * Handles generic selection lists.
1319 * GenericList: The list to handle.
1320 * nextPage: The page it needs to jump to after this page.
1321 * Ir: The PINPUT_RECORD
1324 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1325 PAGE_NUMBER nextPage
,
1330 CONSOLE_ConInKey(Ir
);
1332 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1333 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1335 ScrollDownGenericList(ListUi
);
1337 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1338 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1340 ScrollUpGenericList(ListUi
);
1342 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1343 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1345 ScrollPageDownGenericList(ListUi
);
1347 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1348 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1350 ScrollPageUpGenericList(ListUi
);
1352 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1353 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1355 if (ConfirmQuit(Ir
) != FALSE
)
1358 RedrawGenericList(ListUi
);
1360 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1361 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1363 RestoreGenericListState(ListUi
->List
);
1364 return nextPage
; // Use some "prevPage;" instead?
1366 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1370 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1373 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1380 * Displays the ComputerSettingsPage.
1383 * DeviceSettingsPage
1387 * Number of the next page.
1390 ComputerSettingsPage(PINPUT_RECORD Ir
)
1392 GENERIC_LIST_UI ListUi
;
1393 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1395 InitGenericListUi(&ListUi
, ComputerList
);
1396 DrawGenericList(&ListUi
,
1402 SaveGenericListState(ComputerList
);
1404 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1409 * Displays the DisplaySettingsPage.
1412 * DeviceSettingsPage
1416 * Number of the next page.
1419 DisplaySettingsPage(PINPUT_RECORD Ir
)
1421 GENERIC_LIST_UI ListUi
;
1422 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1424 InitGenericListUi(&ListUi
, DisplayList
);
1425 DrawGenericList(&ListUi
,
1431 SaveGenericListState(DisplayList
);
1433 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1438 * Displays the KeyboardSettingsPage.
1441 * DeviceSettingsPage
1445 * Number of the next page.
1448 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1450 GENERIC_LIST_UI ListUi
;
1451 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1453 InitGenericListUi(&ListUi
, KeyboardList
);
1454 DrawGenericList(&ListUi
,
1460 SaveGenericListState(KeyboardList
);
1462 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1467 * Displays the LayoutSettingsPage.
1470 * DeviceSettingsPage
1474 * Number of the next page.
1477 LayoutSettingsPage(PINPUT_RECORD Ir
)
1479 GENERIC_LIST_UI ListUi
;
1480 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1482 InitGenericListUi(&ListUi
, LayoutList
);
1483 DrawGenericList(&ListUi
,
1489 SaveGenericListState(LayoutList
);
1491 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1496 IsDiskSizeValid(PPARTENTRY PartEntry
)
1500 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1501 size
= (size
+ 524288) / 1048576; /* in MBytes */
1503 if (size
< RequiredPartitionDiskSpace
)
1505 /* partition is too small so ask for another partition */
1506 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, RequiredPartitionDiskSpace
);
1517 * Displays the SelectPartitionPage.
1520 * SelectFileSystemPage (At once if unattended)
1521 * SelectFileSystemPage (Default if free space is selected)
1522 * CreatePrimaryPartitionPage
1523 * CreateExtendedPartitionPage
1524 * CreateLogicalPartitionPage
1525 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1526 * DeletePartitionPage
1530 * Init DestinationDriveLetter (only if unattended or not free space is selected)
1531 * Set InstallShortcut (only if not unattended + free space is selected)
1534 * Number of the next page.
1537 SelectPartitionPage(PINPUT_RECORD Ir
)
1542 if (PartitionList
== NULL
)
1544 PartitionList
= CreatePartitionList();
1545 if (PartitionList
== NULL
)
1547 /* FIXME: show an error dialog */
1548 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1551 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1553 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1557 TempPartition
= NULL
;
1558 FormatState
= Start
;
1561 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1563 InitPartitionListUi(&ListUi
, PartitionList
,
1568 DrawPartitionList(&ListUi
);
1570 if (IsUnattendedSetup
)
1572 if (!SelectPartition(PartitionList
, UnattendDestinationDiskNumber
, UnattendDestinationPartitionNumber
))
1576 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1578 CreateLogicalPartition(PartitionList
,
1579 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1584 CreatePrimaryPartition(PartitionList
,
1585 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1589 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1590 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1592 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1593 RequiredPartitionDiskSpace
);
1594 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1597 DestinationDriveLetter
= (WCHAR
)PartitionList
->CurrentPartition
->DriveLetter
;
1599 return SELECT_FILE_SYSTEM_PAGE
;
1604 DrawPartitionList(&ListUi
);
1606 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1607 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1609 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1610 RequiredPartitionDiskSpace
);
1611 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1614 DestinationDriveLetter
= (WCHAR
)PartitionList
->CurrentPartition
->DriveLetter
;
1616 return SELECT_FILE_SYSTEM_PAGE
;
1622 /* Update status text */
1623 if (PartitionList
->CurrentPartition
== NULL
)
1625 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1627 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1629 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1631 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1635 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1640 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1642 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1644 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1648 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1653 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1657 CONSOLE_ConInKey(Ir
);
1659 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1660 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1662 if (ConfirmQuit(Ir
) != FALSE
)
1664 DestroyPartitionList(PartitionList
);
1665 PartitionList
= NULL
;
1671 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1672 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1674 ScrollDownPartitionList(&ListUi
);
1676 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1677 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1679 ScrollUpPartitionList(&ListUi
);
1681 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1683 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1684 continue; // return SELECT_PARTITION_PAGE;
1686 if (PartitionList
->CurrentPartition
== NULL
||
1687 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1689 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1691 CreateLogicalPartition(PartitionList
,
1697 CreatePrimaryPartition(PartitionList
,
1703 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1705 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1706 RequiredPartitionDiskSpace
);
1707 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1710 DestinationDriveLetter
= (WCHAR
)PartitionList
->CurrentPartition
->DriveLetter
;
1712 return SELECT_FILE_SYSTEM_PAGE
;
1714 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1716 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1718 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1719 if (Error
!= NOT_AN_ERROR
)
1721 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1722 return SELECT_PARTITION_PAGE
;
1725 return CREATE_PRIMARY_PARTITION_PAGE
;
1728 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1730 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1732 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1733 if (Error
!= NOT_AN_ERROR
)
1735 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1736 return SELECT_PARTITION_PAGE
;
1739 return CREATE_EXTENDED_PARTITION_PAGE
;
1742 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1744 if (PartitionList
->CurrentPartition
->LogicalPartition
!= FALSE
)
1746 Error
= LogicalPartitionCreationChecks(PartitionList
);
1747 if (Error
!= NOT_AN_ERROR
)
1749 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1750 return SELECT_PARTITION_PAGE
;
1753 return CREATE_LOGICAL_PARTITION_PAGE
;
1756 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1758 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1760 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1761 return SELECT_PARTITION_PAGE
;
1764 if (PartitionList
->CurrentPartition
->BootIndicator
||
1765 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1767 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1770 return DELETE_PARTITION_PAGE
;
1774 return SELECT_PARTITION_PAGE
;
1778 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1779 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1780 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1783 ShowPartitionSizeInputBox(SHORT Left
,
1807 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1812 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1813 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1816 WriteConsoleOutputCharacterA(StdOutput
,
1822 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1823 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1825 WriteConsoleOutputCharacterA(StdOutput
,
1831 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1832 Length
= wcslen(InputBuffer
);
1834 CONSOLE_SetInputTextXY(iLeft
,
1836 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1838 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1839 CONSOLE_SetCursorType(TRUE
, TRUE
);
1843 CONSOLE_ConInKey(&Ir
);
1845 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1846 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1851 InputBuffer
[0] = UNICODE_NULL
;
1852 CONSOLE_SetCursorType(TRUE
, FALSE
);
1855 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1857 CONSOLE_SetCursorType(TRUE
, FALSE
);
1860 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1865 InputBuffer
[0] = UNICODE_NULL
;
1866 CONSOLE_SetCursorType(TRUE
, FALSE
);
1869 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1870 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1873 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1875 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1876 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1879 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1881 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1882 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1887 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1890 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1891 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1896 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1899 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1900 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1904 memmove(&InputBuffer
[Pos
],
1905 &InputBuffer
[Pos
+ 1],
1906 (Length
- Pos
- 1) * sizeof(WCHAR
));
1907 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1910 CONSOLE_SetInputTextXY(iLeft
,
1912 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1914 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1917 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1922 memmove(&InputBuffer
[Pos
- 1],
1924 (Length
- Pos
) * sizeof(WCHAR
));
1925 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1929 CONSOLE_SetInputTextXY(iLeft
,
1931 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1933 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1936 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1938 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1940 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1942 if ((ch
>= L
'0') && (ch
<= L
'9'))
1945 memmove(&InputBuffer
[Pos
+ 1],
1947 (Length
- Pos
) * sizeof(WCHAR
));
1948 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1949 InputBuffer
[Pos
] = ch
;
1953 CONSOLE_SetInputTextXY(iLeft
,
1955 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1957 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1966 * Displays the CreatePrimaryPartitionPage.
1969 * SelectPartitionPage
1970 * SelectFileSystemPage (default)
1974 * Number of the next page.
1977 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1979 PDISKENTRY DiskEntry
;
1980 PPARTENTRY PartEntry
;
1983 WCHAR InputBuffer
[50];
1987 ULONGLONG SectorCount
;
1990 if (PartitionList
== NULL
||
1991 PartitionList
->CurrentDisk
== NULL
||
1992 PartitionList
->CurrentPartition
== NULL
)
1994 /* FIXME: show an error dialog */
1998 DiskEntry
= PartitionList
->CurrentDisk
;
1999 PartEntry
= PartitionList
->CurrentPartition
;
2001 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2003 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
2005 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2007 if (DiskSize
>= 10737418240) /* 10 GB */
2009 DiskSize
= DiskSize
/ 1073741824;
2010 Unit
= MUIGetString(STRING_GB
);
2015 DiskSize
= DiskSize
/ 1048576;
2019 Unit
= MUIGetString(STRING_MB
);
2022 if (DiskEntry
->DriverName
.Length
> 0)
2024 CONSOLE_PrintTextXY(6, 10,
2025 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2028 DiskEntry
->DiskNumber
,
2032 &DiskEntry
->DriverName
,
2033 DiskEntry
->NoMbr
? "GPT" : "MBR");
2037 CONSOLE_PrintTextXY(6, 10,
2038 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2041 DiskEntry
->DiskNumber
,
2045 DiskEntry
->NoMbr
? "GPT" : "MBR");
2048 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2051 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2052 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2055 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2057 PartEntry
= PartitionList
->CurrentPartition
;
2060 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2062 if (MaxSize
> PARTITION_MAXSIZE
)
2063 MaxSize
= PARTITION_MAXSIZE
;
2065 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2066 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2070 if (ConfirmQuit(Ir
) != FALSE
)
2075 else if (Cancel
!= FALSE
)
2077 return SELECT_PARTITION_PAGE
;
2081 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2089 if (PartSize
> MaxSize
)
2095 /* Convert to bytes */
2096 if (PartSize
== MaxSize
)
2098 /* Use all of the unpartitioned disk space */
2099 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2103 /* Calculate the sector count from the size in MB */
2104 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2106 /* But never get larger than the unpartitioned disk space */
2107 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2108 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2111 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2113 CreatePrimaryPartition(PartitionList
,
2117 return SELECT_PARTITION_PAGE
;
2121 return CREATE_PRIMARY_PARTITION_PAGE
;
2126 * Displays the CreateExtendedPartitionPage.
2129 * SelectPartitionPage (default)
2133 * Number of the next page.
2136 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2138 PDISKENTRY DiskEntry
;
2139 PPARTENTRY PartEntry
;
2142 WCHAR InputBuffer
[50];
2146 ULONGLONG SectorCount
;
2149 if (PartitionList
== NULL
||
2150 PartitionList
->CurrentDisk
== NULL
||
2151 PartitionList
->CurrentPartition
== NULL
)
2153 /* FIXME: show an error dialog */
2157 DiskEntry
= PartitionList
->CurrentDisk
;
2158 PartEntry
= PartitionList
->CurrentPartition
;
2160 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2162 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2164 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2166 if (DiskSize
>= 10737418240) /* 10 GB */
2168 DiskSize
= DiskSize
/ 1073741824;
2169 Unit
= MUIGetString(STRING_GB
);
2174 DiskSize
= DiskSize
/ 1048576;
2178 Unit
= MUIGetString(STRING_MB
);
2181 if (DiskEntry
->DriverName
.Length
> 0)
2183 CONSOLE_PrintTextXY(6, 10,
2184 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2187 DiskEntry
->DiskNumber
,
2191 &DiskEntry
->DriverName
,
2192 DiskEntry
->NoMbr
? "GPT" : "MBR");
2196 CONSOLE_PrintTextXY(6, 10,
2197 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2200 DiskEntry
->DiskNumber
,
2204 DiskEntry
->NoMbr
? "GPT" : "MBR");
2207 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2210 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2211 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2214 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2216 PartEntry
= PartitionList
->CurrentPartition
;
2219 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2221 if (MaxSize
> PARTITION_MAXSIZE
)
2222 MaxSize
= PARTITION_MAXSIZE
;
2224 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2225 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2229 if (ConfirmQuit(Ir
) != FALSE
)
2234 else if (Cancel
!= FALSE
)
2236 return SELECT_PARTITION_PAGE
;
2240 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2248 if (PartSize
> MaxSize
)
2254 /* Convert to bytes */
2255 if (PartSize
== MaxSize
)
2257 /* Use all of the unpartitioned disk space */
2258 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2262 /* Calculate the sector count from the size in MB */
2263 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2265 /* But never get larger than the unpartitioned disk space */
2266 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2267 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2270 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2272 CreateExtendedPartition(PartitionList
,
2275 return SELECT_PARTITION_PAGE
;
2279 return CREATE_EXTENDED_PARTITION_PAGE
;
2284 * Displays the CreateLogicalPartitionPage.
2287 * SelectFileSystemPage (default)
2291 * Number of the next page.
2294 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2296 PDISKENTRY DiskEntry
;
2297 PPARTENTRY PartEntry
;
2300 WCHAR InputBuffer
[50];
2304 ULONGLONG SectorCount
;
2307 if (PartitionList
== NULL
||
2308 PartitionList
->CurrentDisk
== NULL
||
2309 PartitionList
->CurrentPartition
== NULL
)
2311 /* FIXME: show an error dialog */
2315 DiskEntry
= PartitionList
->CurrentDisk
;
2316 PartEntry
= PartitionList
->CurrentPartition
;
2318 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2320 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2322 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2324 if (DiskSize
>= 10737418240) /* 10 GB */
2326 DiskSize
= DiskSize
/ 1073741824;
2327 Unit
= MUIGetString(STRING_GB
);
2332 DiskSize
= DiskSize
/ 1048576;
2336 Unit
= MUIGetString(STRING_MB
);
2339 if (DiskEntry
->DriverName
.Length
> 0)
2341 CONSOLE_PrintTextXY(6, 10,
2342 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2345 DiskEntry
->DiskNumber
,
2349 &DiskEntry
->DriverName
,
2350 DiskEntry
->NoMbr
? "GPT" : "MBR");
2354 CONSOLE_PrintTextXY(6, 10,
2355 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2358 DiskEntry
->DiskNumber
,
2362 DiskEntry
->NoMbr
? "GPT" : "MBR");
2365 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2368 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2369 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2372 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2374 PartEntry
= PartitionList
->CurrentPartition
;
2377 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2379 if (MaxSize
> PARTITION_MAXSIZE
)
2380 MaxSize
= PARTITION_MAXSIZE
;
2382 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2383 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2387 if (ConfirmQuit(Ir
) != FALSE
)
2392 else if (Cancel
!= FALSE
)
2394 return SELECT_PARTITION_PAGE
;
2398 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2406 if (PartSize
> MaxSize
)
2412 /* Convert to bytes */
2413 if (PartSize
== MaxSize
)
2415 /* Use all of the unpartitioned disk space */
2416 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2420 /* Calculate the sector count from the size in MB */
2421 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2423 /* But never get larger than the unpartitioned disk space */
2424 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2425 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2428 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2430 CreateLogicalPartition(PartitionList
,
2434 return SELECT_PARTITION_PAGE
;
2438 return CREATE_LOGICAL_PARTITION_PAGE
;
2443 * Displays the ConfirmDeleteSystemPartitionPage.
2446 * DeletePartitionPage (default)
2447 * SelectPartitionPage
2450 * Number of the next page.
2453 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2455 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2459 CONSOLE_ConInKey(Ir
);
2461 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2462 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2464 if (ConfirmQuit(Ir
) == TRUE
)
2469 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2471 return DELETE_PARTITION_PAGE
;
2473 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2475 return SELECT_PARTITION_PAGE
;
2479 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2484 * Displays the DeletePartitionPage.
2487 * SelectPartitionPage (default)
2491 * Number of the next page.
2494 DeletePartitionPage(PINPUT_RECORD Ir
)
2496 PDISKENTRY DiskEntry
;
2497 PPARTENTRY PartEntry
;
2501 CHAR PartTypeString
[32];
2503 if (PartitionList
== NULL
||
2504 PartitionList
->CurrentDisk
== NULL
||
2505 PartitionList
->CurrentPartition
== NULL
)
2507 /* FIXME: show an error dialog */
2511 DiskEntry
= PartitionList
->CurrentDisk
;
2512 PartEntry
= PartitionList
->CurrentPartition
;
2514 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2516 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2518 ARRAYSIZE(PartTypeString
));
2520 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2522 if (PartSize
>= 10737418240) /* 10 GB */
2524 PartSize
= PartSize
/ 1073741824;
2525 Unit
= MUIGetString(STRING_GB
);
2529 if (PartSize
>= 10485760) /* 10 MB */
2531 PartSize
= PartSize
/ 1048576;
2532 Unit
= MUIGetString(STRING_MB
);
2536 PartSize
= PartSize
/ 1024;
2537 Unit
= MUIGetString(STRING_KB
);
2540 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2542 CONSOLE_PrintTextXY(6, 10,
2543 MUIGetString(STRING_HDDINFOUNK2
),
2544 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2545 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2546 PartEntry
->PartitionType
,
2552 CONSOLE_PrintTextXY(6, 10,
2553 " %c%c %s %I64u %s",
2554 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2555 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2561 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2563 if (DiskSize
>= 10737418240) /* 10 GB */
2565 DiskSize
= DiskSize
/ 1073741824;
2566 Unit
= MUIGetString(STRING_GB
);
2571 DiskSize
= DiskSize
/ 1048576;
2575 Unit
= MUIGetString(STRING_MB
);
2578 if (DiskEntry
->DriverName
.Length
> 0)
2580 CONSOLE_PrintTextXY(6, 12,
2581 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2584 DiskEntry
->DiskNumber
,
2588 &DiskEntry
->DriverName
,
2589 DiskEntry
->NoMbr
? "GPT" : "MBR");
2593 CONSOLE_PrintTextXY(6, 12,
2594 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2597 DiskEntry
->DiskNumber
,
2601 DiskEntry
->NoMbr
? "GPT" : "MBR");
2606 CONSOLE_ConInKey(Ir
);
2608 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2609 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2611 if (ConfirmQuit(Ir
) != FALSE
)
2616 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2618 return SELECT_PARTITION_PAGE
;
2620 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2622 DeleteCurrentPartition(PartitionList
);
2624 return SELECT_PARTITION_PAGE
;
2628 return DELETE_PARTITION_PAGE
;
2633 * Displays the SelectFileSystemPage.
2636 * CheckFileSystemPage (At once if RepairUpdate is selected)
2637 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2638 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2639 * SelectPartitionPage (If the user aborts)
2640 * FormatPartitionPage (Default)
2644 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2645 * Calls CheckActiveSystemPartition()
2648 * Number of the next page.
2651 SelectFileSystemPage(PINPUT_RECORD Ir
)
2653 PDISKENTRY DiskEntry
;
2654 PPARTENTRY PartEntry
;
2659 CHAR PartTypeString
[32];
2660 FORMATMACHINESTATE PreviousFormatState
;
2662 DPRINT("SelectFileSystemPage()\n");
2664 if (PartitionList
== NULL
||
2665 PartitionList
->CurrentDisk
== NULL
||
2666 PartitionList
->CurrentPartition
== NULL
)
2668 /* FIXME: show an error dialog */
2672 /* Find or set the active system partition */
2673 CheckActiveSystemPartition(PartitionList
);
2674 if (PartitionList
->SystemPartition
== NULL
)
2676 /* FIXME: show an error dialog */
2678 // Error dialog should say that we cannot find a suitable
2679 // system partition and create one on the system. At this point,
2680 // it may be nice to ask the user whether he wants to continue,
2681 // or use an external drive as the system drive/partition
2682 // (e.g. floppy, USB drive, etc...)
2687 PreviousFormatState
= FormatState
;
2688 switch (FormatState
)
2692 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2694 TempPartition
= PartitionList
->SystemPartition
;
2695 TempPartition
->NeedsCheck
= TRUE
;
2697 FormatState
= FormatSystemPartition
;
2698 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2702 TempPartition
= PartitionList
->CurrentPartition
;
2703 TempPartition
->NeedsCheck
= TRUE
;
2705 FormatState
= FormatInstallPartition
;
2706 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2711 case FormatSystemPartition
:
2713 TempPartition
= PartitionList
->CurrentPartition
;
2714 TempPartition
->NeedsCheck
= TRUE
;
2716 FormatState
= FormatInstallPartition
;
2717 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2721 case FormatInstallPartition
:
2723 if (GetNextUnformattedPartition(PartitionList
,
2727 FormatState
= FormatOtherPartition
;
2728 TempPartition
->NeedsCheck
= TRUE
;
2729 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2733 FormatState
= FormatDone
;
2734 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2735 return CHECK_FILE_SYSTEM_PAGE
;
2740 case FormatOtherPartition
:
2742 if (GetNextUnformattedPartition(PartitionList
,
2746 FormatState
= FormatOtherPartition
;
2747 TempPartition
->NeedsCheck
= TRUE
;
2748 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2752 FormatState
= FormatDone
;
2753 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2754 return CHECK_FILE_SYSTEM_PAGE
;
2761 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2762 /* FIXME: show an error dialog */
2767 PartEntry
= TempPartition
;
2768 DiskEntry
= PartEntry
->DiskEntry
;
2770 /* Adjust disk size */
2771 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2772 if (DiskSize
>= 10737418240) /* 10 GB */
2774 DiskSize
= DiskSize
/ 1073741824;
2775 DiskUnit
= MUIGetString(STRING_GB
);
2779 DiskSize
= DiskSize
/ 1048576;
2780 DiskUnit
= MUIGetString(STRING_MB
);
2783 /* Adjust partition size */
2784 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2785 if (PartSize
>= 10737418240) /* 10 GB */
2787 PartSize
= PartSize
/ 1073741824;
2788 PartUnit
= MUIGetString(STRING_GB
);
2792 PartSize
= PartSize
/ 1048576;
2793 PartUnit
= MUIGetString(STRING_MB
);
2796 /* Adjust partition type */
2797 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2799 ARRAYSIZE(PartTypeString
));
2801 if (PartEntry
->AutoCreate
!= FALSE
)
2803 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2806 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2807 PartEntry
->PartitionNumber
,
2813 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2814 DiskEntry
->DiskNumber
,
2820 &DiskEntry
->DriverName
,
2821 DiskEntry
->NoMbr
? "GPT" : "MBR");
2823 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2825 PartEntry
->AutoCreate
= FALSE
;
2827 else if (PartEntry
->New
!= FALSE
)
2829 switch (FormatState
)
2831 case FormatSystemPartition
:
2832 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2835 case FormatInstallPartition
:
2836 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2839 case FormatOtherPartition
:
2840 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2847 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2851 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2853 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2855 CONSOLE_PrintTextXY(8, 10,
2856 MUIGetString(STRING_HDDINFOUNK4
),
2857 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2858 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2859 PartEntry
->PartitionType
,
2865 CONSOLE_PrintTextXY(8, 10,
2867 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2868 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2874 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2875 DiskEntry
->DiskNumber
,
2881 &DiskEntry
->DriverName
,
2882 DiskEntry
->NoMbr
? "GPT" : "MBR");
2885 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2887 if (FileSystemList
== NULL
)
2889 /* Create the file system list, and by default select the "FAT" file system */
2890 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2891 if (FileSystemList
== NULL
)
2893 /* FIXME: show an error dialog */
2898 if (RepairUpdateFlag
)
2900 return CHECK_FILE_SYSTEM_PAGE
;
2901 //return SELECT_PARTITION_PAGE;
2904 if (IsUnattendedSetup
)
2906 if (UnattendFormatPartition
)
2909 * We use whatever currently selected file system we have
2910 * (by default, this is "FAT", as per the initialization
2911 * performed above). Note that it may be interesting to specify
2912 * which file system to use in unattended installations, in the
2913 * txtsetup.sif file.
2915 return FORMAT_PARTITION_PAGE
;
2918 return CHECK_FILE_SYSTEM_PAGE
;
2921 DrawFileSystemList(FileSystemList
);
2925 CONSOLE_ConInKey(Ir
);
2927 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2928 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2930 if (ConfirmQuit(Ir
) != FALSE
)
2935 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2936 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2938 FormatState
= Start
;
2939 return SELECT_PARTITION_PAGE
;
2941 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2942 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2944 ScrollDownFileSystemList(FileSystemList
);
2946 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2947 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2949 ScrollUpFileSystemList(FileSystemList
);
2951 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2953 if (!FileSystemList
->Selected
->FileSystem
)
2954 return SELECT_FILE_SYSTEM_PAGE
;
2956 return FORMAT_PARTITION_PAGE
;
2960 FormatState
= PreviousFormatState
;
2962 return SELECT_FILE_SYSTEM_PAGE
;
2967 * Displays the FormatPartitionPage.
2970 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2971 * SelectPartitionPage (At once)
2975 * Sets PartitionList->CurrentPartition->FormatState
2976 * Sets DestinationRootPath
2979 * Number of the next page.
2982 FormatPartitionPage(PINPUT_RECORD Ir
)
2984 UNICODE_STRING PartitionRootPath
;
2985 WCHAR PathBuffer
[MAX_PATH
];
2986 PDISKENTRY DiskEntry
;
2987 PPARTENTRY PartEntry
;
2988 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2994 PPARTITION_INFORMATION PartitionInfo
;
2997 DPRINT("FormatPartitionPage()\n");
2999 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
3001 if (PartitionList
== NULL
|| TempPartition
== NULL
)
3003 /* FIXME: show an error dialog */
3007 PartEntry
= TempPartition
;
3008 DiskEntry
= PartEntry
->DiskEntry
;
3010 SelectedFileSystem
= FileSystemList
->Selected
;
3014 if (!IsUnattendedSetup
)
3016 CONSOLE_ConInKey(Ir
);
3019 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3020 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3022 if (ConfirmQuit(Ir
) != FALSE
)
3027 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3029 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3031 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3033 /* FIXME: show an error dialog */
3038 CONSOLE_PrintTextXY(6, 12,
3039 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3040 DiskEntry
->Cylinders
,
3041 DiskEntry
->TracksPerCylinder
,
3042 DiskEntry
->SectorsPerTrack
,
3043 DiskEntry
->BytesPerSector
,
3044 DiskEntry
->Dirty
? '*' : ' ');
3048 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3050 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3052 CONSOLE_PrintTextXY(6, Line
,
3053 "%2u: %2lu %c %12I64u %12I64u %02x",
3055 PartitionInfo
->PartitionNumber
,
3056 PartitionInfo
->BootIndicator
? 'A' : '-',
3057 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3058 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3059 PartitionInfo
->PartitionType
);
3064 /* Commit the partition changes to the disk */
3065 if (!WritePartitionsToDisk(PartitionList
))
3067 DPRINT("WritePartitionsToDisk() failed\n");
3068 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3072 /* Set PartitionRootPath */
3073 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3074 L
"\\Device\\Harddisk%lu\\Partition%lu",
3075 DiskEntry
->DiskNumber
,
3076 PartEntry
->PartitionNumber
);
3077 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3078 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3080 /* Format the partition */
3081 if (SelectedFileSystem
->FileSystem
)
3083 Status
= FormatPartition(&PartitionRootPath
,
3084 SelectedFileSystem
);
3085 if (!NT_SUCCESS(Status
))
3087 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3088 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3092 PartEntry
->FormatState
= Formatted
;
3093 // PartEntry->FileSystem = FileSystem;
3094 PartEntry
->New
= FALSE
;
3098 CONSOLE_SetStatusText(" Done. Press any key ...");
3099 CONSOLE_ConInKey(Ir
);
3102 return SELECT_FILE_SYSTEM_PAGE
;
3106 return FORMAT_PARTITION_PAGE
;
3111 * Displays the CheckFileSystemPage.
3114 * InstallDirectoryPage (At once)
3118 * Inits or reloads FileSystemList
3121 * Number of the next page.
3124 CheckFileSystemPage(PINPUT_RECORD Ir
)
3126 PFILE_SYSTEM CurrentFileSystem
;
3127 UNICODE_STRING PartitionRootPath
;
3128 WCHAR PathBuffer
[MAX_PATH
];
3129 CHAR Buffer
[MAX_PATH
];
3130 PDISKENTRY DiskEntry
;
3131 PPARTENTRY PartEntry
;
3134 if (PartitionList
== NULL
)
3136 /* FIXME: show an error dialog */
3140 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3142 return INSTALL_DIRECTORY_PAGE
;
3145 /* Set PartitionRootPath */
3146 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3147 L
"\\Device\\Harddisk%lu\\Partition%lu",
3148 DiskEntry
->DiskNumber
,
3149 PartEntry
->PartitionNumber
);
3150 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3151 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3153 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3155 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3157 CurrentFileSystem
= PartEntry
->FileSystem
;
3158 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3159 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3161 /* HACK: Do not try to check a partition with an unknown filesystem */
3162 if (CurrentFileSystem
== NULL
)
3164 PartEntry
->NeedsCheck
= FALSE
;
3165 return CHECK_FILE_SYSTEM_PAGE
;
3168 if (CurrentFileSystem
->ChkdskFunc
== NULL
)
3171 "Setup is currently unable to check a partition formatted in %S.\n"
3173 " \x07 Press ENTER to continue Setup.\n"
3174 " \x07 Press F3 to quit Setup.",
3175 CurrentFileSystem
->FileSystemName
);
3178 MUIGetString(STRING_QUITCONTINUE
),
3179 NULL
, POPUP_WAIT_NONE
);
3183 CONSOLE_ConInKey(Ir
);
3185 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3186 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3188 if (ConfirmQuit(Ir
))
3191 return CHECK_FILE_SYSTEM_PAGE
;
3193 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3195 PartEntry
->NeedsCheck
= FALSE
;
3196 return CHECK_FILE_SYSTEM_PAGE
;
3202 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3203 if (!NT_SUCCESS(Status
))
3205 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3206 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3207 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3208 "(Status 0x%08lx).\n", Status
);
3210 // MUIGetString(STRING_REBOOTCOMPUTER),
3211 MUIGetString(STRING_CONTINUE
),
3212 Ir
, POPUP_WAIT_ENTER
);
3214 // return QUIT_PAGE;
3217 PartEntry
->NeedsCheck
= FALSE
;
3218 return CHECK_FILE_SYSTEM_PAGE
;
3224 BuildInstallPaths(PWSTR InstallDir
,
3225 PDISKENTRY DiskEntry
,
3226 PPARTENTRY PartEntry
)
3228 WCHAR PathBuffer
[MAX_PATH
];
3230 /* Create 'InstallPath' string */
3231 RtlFreeUnicodeString(&InstallPath
);
3232 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3234 /* Create 'DestinationRootPath' string */
3235 RtlFreeUnicodeString(&DestinationRootPath
);
3236 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3237 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3238 DiskEntry
->DiskNumber
,
3239 PartEntry
->PartitionNumber
);
3240 RtlCreateUnicodeString(&DestinationRootPath
, PathBuffer
);
3241 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath
);
3243 /* Create 'DestinationPath' string */
3244 RtlFreeUnicodeString(&DestinationPath
);
3245 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3246 DestinationRootPath
.Buffer
, InstallDir
);
3247 RtlCreateUnicodeString(&DestinationPath
, PathBuffer
);
3249 /* Create 'DestinationArcPath' */
3250 RtlFreeUnicodeString(&DestinationArcPath
);
3251 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3252 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3253 DiskEntry
->BiosDiskNumber
,
3254 PartEntry
->PartitionNumber
);
3255 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3256 RtlCreateUnicodeString(&DestinationArcPath
, PathBuffer
);
3261 * Displays the InstallDirectoryPage.
3264 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3268 * Number of the next page.
3271 InstallDirectoryPage(PINPUT_RECORD Ir
)
3273 PDISKENTRY DiskEntry
;
3274 PPARTENTRY PartEntry
;
3275 WCHAR InstallDir
[51];
3279 /* We do not need the filesystem list any more */
3280 if (FileSystemList
!= NULL
)
3282 DestroyFileSystemList(FileSystemList
);
3283 FileSystemList
= NULL
;
3286 if (PartitionList
== NULL
||
3287 PartitionList
->CurrentDisk
== NULL
||
3288 PartitionList
->CurrentPartition
== NULL
)
3290 /* FIXME: show an error dialog */
3294 DiskEntry
= PartitionList
->CurrentDisk
;
3295 PartEntry
= PartitionList
->CurrentPartition
;
3297 if (IsUnattendedSetup
)
3299 if (!IsValidPath(UnattendInstallationDirectory
))
3301 /* FIXME: Log the error? */
3305 BuildInstallPaths(UnattendInstallationDirectory
,
3309 return PREPARE_COPY_PAGE
;
3312 wcscpy(InstallDir
, L
"\\ReactOS");
3314 Length
= wcslen(InstallDir
);
3316 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3317 CONSOLE_SetCursorXY(8 + Pos
, 11);
3318 CONSOLE_SetCursorType(TRUE
, TRUE
);
3319 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3323 CONSOLE_ConInKey(Ir
);
3325 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3326 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3328 CONSOLE_SetCursorType(TRUE
, FALSE
);
3330 if (ConfirmQuit(Ir
) != FALSE
)
3333 CONSOLE_SetCursorType(TRUE
, TRUE
);
3336 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3337 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3341 memmove(&InstallDir
[Pos
],
3342 &InstallDir
[Pos
+ 1],
3343 (Length
- Pos
- 1) * sizeof(WCHAR
));
3344 InstallDir
[Length
- 1] = UNICODE_NULL
;
3347 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3348 CONSOLE_SetCursorXY(8 + Pos
, 11);
3351 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3352 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3355 CONSOLE_SetCursorXY(8 + Pos
, 11);
3357 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3358 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3361 CONSOLE_SetCursorXY(8 + Pos
, 11);
3363 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3364 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3369 CONSOLE_SetCursorXY(8 + Pos
, 11);
3372 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3373 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3378 CONSOLE_SetCursorXY(8 + Pos
, 11);
3381 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3383 CONSOLE_SetCursorType(TRUE
, FALSE
);
3386 * Check for the validity of the installation directory and pop up
3387 * an error if it is not the case. Then the user can fix its input.
3389 if (!IsValidPath(InstallDir
))
3391 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3392 return INSTALL_DIRECTORY_PAGE
;
3395 BuildInstallPaths(InstallDir
,
3399 return PREPARE_COPY_PAGE
;
3401 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3406 memmove(&InstallDir
[Pos
- 1],
3408 (Length
- Pos
) * sizeof(WCHAR
));
3409 InstallDir
[Length
- 1] = UNICODE_NULL
;
3413 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3414 CONSOLE_SetCursorXY(8 + Pos
, 11);
3417 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3421 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3422 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3425 memmove(&InstallDir
[Pos
+ 1],
3427 (Length
- Pos
) * sizeof(WCHAR
));
3428 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3429 InstallDir
[Pos
] = c
;
3433 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3434 CONSOLE_SetCursorXY(8 + Pos
, 11);
3440 return INSTALL_DIRECTORY_PAGE
;
3445 AddSectionToCopyQueueCab(HINF InfFile
,
3447 PWCHAR SourceCabinet
,
3448 PCUNICODE_STRING DestinationPath
,
3451 INFCONTEXT FilesContext
;
3452 INFCONTEXT DirContext
;
3454 PWCHAR FileKeyValue
;
3456 PWCHAR TargetFileName
;
3459 * This code enumerates the list of files in reactos.dff / reactos.inf
3460 * that need to be extracted from reactos.cab and be installed in their
3461 * respective directories.
3464 /* Search for the SectionName section */
3465 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3468 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3469 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3474 * Enumerate the files in the section and add them to the file queue.
3478 /* Get source file name and target directory id */
3479 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3481 /* FIXME: Handle error! */
3482 DPRINT1("INF_GetData() failed\n");
3486 /* Get optional target file name */
3487 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3488 TargetFileName
= NULL
;
3490 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3492 /* Lookup target directory */
3493 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3495 /* FIXME: Handle error! */
3496 DPRINT1("SetupFindFirstLine() failed\n");
3500 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3502 /* FIXME: Handle error! */
3503 DPRINT1("INF_GetData() failed\n");
3507 if (!SetupQueueCopy(SetupFileQueue
,
3509 SourceRootPath
.Buffer
,
3510 SourceRootDir
.Buffer
,
3515 /* FIXME: Handle error! */
3516 DPRINT1("SetupQueueCopy() failed\n");
3518 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3525 AddSectionToCopyQueue(HINF InfFile
,
3527 PWCHAR SourceCabinet
,
3528 PCUNICODE_STRING DestinationPath
,
3531 INFCONTEXT FilesContext
;
3532 INFCONTEXT DirContext
;
3534 PWCHAR FileKeyValue
;
3536 PWCHAR TargetFileName
;
3537 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3540 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3543 * This code enumerates the list of files in txtsetup.sif
3544 * that need to be installed in their respective directories.
3547 /* Search for the SectionName section */
3548 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3551 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3552 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3557 * Enumerate the files in the section and add them to the file queue.
3561 /* Get source file name and target directory id */
3562 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3564 /* FIXME: Handle error! */
3565 DPRINT1("INF_GetData() failed\n");
3569 /* Get target directory id */
3570 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3572 /* FIXME: Handle error! */
3573 DPRINT1("INF_GetData() failed\n");
3577 /* Get optional target file name */
3578 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3579 TargetFileName
= NULL
;
3580 else if (!*TargetFileName
)
3581 TargetFileName
= NULL
;
3583 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3585 /* Lookup target directory */
3586 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3588 /* FIXME: Handle error! */
3589 DPRINT1("SetupFindFirstLine() failed\n");
3593 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3595 /* FIXME: Handle error! */
3596 DPRINT1("INF_GetData() failed\n");
3600 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3602 /* Installation path */
3603 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3605 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3606 SourceRootDir
.Buffer
);
3608 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3610 else if (DirKeyValue
[0] == L
'\\')
3613 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3615 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3618 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3620 else // if (DirKeyValue[0] != L'\\')
3622 /* Path relative to the installation path */
3623 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3625 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3626 SourceRootDir
.Buffer
, DirKeyValue
);
3628 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3631 if (!SetupQueueCopy(SetupFileQueue
,
3633 SourceRootPath
.Buffer
,
3634 CompleteOrigDirName
,
3639 /* FIXME: Handle error! */
3640 DPRINT1("SetupQueueCopy() failed\n");
3642 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3649 PrepareCopyPageInfFile(HINF InfFile
,
3650 PWCHAR SourceCabinet
,
3654 INFCONTEXT DirContext
;
3655 PWCHAR AdditionalSectionName
= NULL
;
3657 WCHAR PathBuffer
[MAX_PATH
];
3659 /* Add common files */
3660 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &DestinationPath
, Ir
))
3663 /* Add specific files depending of computer type */
3664 if (SourceCabinet
== NULL
)
3666 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3669 if (AdditionalSectionName
)
3671 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &DestinationPath
, Ir
))
3676 /* Create directories */
3680 * Copying files to DestinationRootPath should be done from within
3681 * the SystemPartitionFiles section.
3682 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3683 * For installing to DestinationPath specify just '\' .
3686 /* Get destination path */
3687 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), DestinationPath
.Buffer
);
3689 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3691 /* Create the install directory */
3692 Status
= SetupCreateDirectory(PathBuffer
);
3693 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3695 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3696 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3700 /* Search for the 'Directories' section */
3701 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3705 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3709 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3715 /* Enumerate the directory values and create the subdirectories */
3718 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3724 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3726 /* Installation path */
3727 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3729 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3730 DestinationPath
.Buffer
);
3732 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3734 else if (DirKeyValue
[0] == L
'\\')
3737 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3739 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3740 DestinationRootPath
.Buffer
, DirKeyValue
);
3742 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3744 Status
= SetupCreateDirectory(PathBuffer
);
3745 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3747 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3748 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3752 else // if (DirKeyValue[0] != L'\\')
3754 /* Path relative to the installation path */
3755 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3757 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3758 DestinationPath
.Buffer
, DirKeyValue
);
3760 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3762 Status
= SetupCreateDirectory(PathBuffer
);
3763 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3765 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3766 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3770 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3777 * Displays the PrepareCopyPage.
3780 * FileCopyPage(At once)
3784 * Inits SetupFileQueue
3785 * Calls PrepareCopyPageInfFile
3788 * Number of the next page.
3791 PrepareCopyPage(PINPUT_RECORD Ir
)
3794 WCHAR PathBuffer
[MAX_PATH
];
3795 INFCONTEXT CabinetsContext
;
3801 MUIDisplayPage(PREPARE_COPY_PAGE
);
3803 /* Create the file queue */
3804 SetupFileQueue
= SetupOpenFileQueue();
3805 if (SetupFileQueue
== NULL
)
3807 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3811 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3813 /* FIXME: show an error dialog */
3817 /* Search for the 'Cabinets' section */
3818 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3820 return FILE_COPY_PAGE
;
3824 * Enumerate the directory values in the 'Cabinets'
3825 * section and parse their inf files.
3829 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3832 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3833 SourcePath
.Buffer
, KeyValue
);
3835 CabinetInitialize();
3836 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3837 CabinetSetCabinetName(PathBuffer
);
3839 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3841 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3843 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3844 if (InfFileData
== NULL
)
3846 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3852 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3853 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3857 InfHandle
= INF_OpenBufferedFileA((CHAR
*) InfFileData
,
3864 if (InfHandle
== INVALID_HANDLE_VALUE
)
3866 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3872 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3874 /* FIXME: show an error dialog */
3877 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3879 return FILE_COPY_PAGE
;
3885 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3888 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3890 /* Get the memory information from the system */
3891 NtQuerySystemInformation(SystemPerformanceInformation
,
3896 /* Check if this is initial setup */
3899 /* Set maximum limits to be total RAM pages */
3900 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3901 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3902 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3905 /* Set current values */
3906 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3907 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3908 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3914 FileCopyCallback(PVOID Context
,
3919 PCOPYCONTEXT CopyContext
;
3921 CopyContext
= (PCOPYCONTEXT
)Context
;
3923 switch (Notification
)
3925 case SPFILENOTIFY_STARTSUBQUEUE
:
3926 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3927 ProgressSetStepCount(CopyContext
->ProgressBar
,
3928 CopyContext
->TotalOperations
);
3929 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3932 case SPFILENOTIFY_STARTCOPY
:
3933 /* Display copy message */
3934 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3935 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3938 case SPFILENOTIFY_ENDCOPY
:
3939 CopyContext
->CompletedOperations
++;
3941 /* SYSREG checkpoint */
3942 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3943 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3945 ProgressNextStep(CopyContext
->ProgressBar
);
3946 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3955 * Displays the FileCopyPage.
3958 * RegistryPage(At once)
3961 * Calls SetupCommitFileQueueW
3962 * Calls SetupCloseFileQueue
3965 * Number of the next page.
3968 FileCopyPage(PINPUT_RECORD Ir
)
3970 COPYCONTEXT CopyContext
;
3971 unsigned int mem_bar_width
;
3973 MUIDisplayPage(FILE_COPY_PAGE
);
3975 /* Create context for the copy process */
3976 CopyContext
.DestinationRootPath
= DestinationRootPath
.Buffer
;
3977 CopyContext
.InstallPath
= InstallPath
.Buffer
;
3978 CopyContext
.TotalOperations
= 0;
3979 CopyContext
.CompletedOperations
= 0;
3981 /* Create the progress bar as well */
3982 CopyContext
.ProgressBar
= CreateProgressBar(13,
3989 MUIGetString(STRING_SETUPCOPYINGFILES
));
3991 // fit memory bars to screen width, distribute them uniform
3992 mem_bar_width
= (xScreen
- 26) / 5;
3993 mem_bar_width
-= mem_bar_width
% 2; // make even
3994 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3995 /* Create the paged pool progress bar */
3996 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4005 /* Create the non paged pool progress bar */
4006 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4008 (xScreen
/ 2) + (mem_bar_width
/ 2),
4010 (xScreen
/ 2)- (mem_bar_width
/ 2),
4015 /* Create the global memory progress bar */
4016 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4020 xScreen
- 13 - mem_bar_width
,
4025 /* Do the file copying */
4026 SetupCommitFileQueueW(NULL
,
4031 /* If we get here, we're done, so cleanup the queue and progress bar */
4032 SetupCloseFileQueue(SetupFileQueue
);
4033 DestroyProgressBar(CopyContext
.ProgressBar
);
4034 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4035 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4036 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4038 /* Go display the next page */
4039 return REGISTRY_PAGE
;
4044 * Displays the RegistryPage.
4047 * SuccessPage (if RepairUpdate)
4048 * BootLoaderPage (default)
4052 * Calls SetInstallPathValue
4053 * Calls NtInitializeRegistry
4054 * Calls ImportRegistryFile
4055 * Calls SetDefaultPagefile
4056 * Calls SetMountedDeviceValues
4059 * Number of the next page.
4062 RegistryPage(PINPUT_RECORD Ir
)
4064 INFCONTEXT InfContext
;
4071 MUIDisplayPage(REGISTRY_PAGE
);
4073 if (RepairUpdateFlag
)
4076 DPRINT1("FIXME: Updating / repairing the registry is NOT implemented yet!\n");
4077 return SUCCESS_PAGE
;
4080 /************************ HACK!!!!!!!!!!! *********************************/
4081 if (!SetInstallPathValue(&DestinationPath
))
4083 DPRINT1("SetInstallPathValue() failed\n");
4084 MUIDisplayError(ERROR_INITIALIZE_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4087 /************************ HACK!!!!!!!!!!! *********************************/
4089 /* Create the default hives */
4090 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4091 if (!NT_SUCCESS(Status
))
4093 DPRINT1("NtInitializeRegistry() failed (Status %lx)\n", Status
);
4094 MUIDisplayError(ERROR_CREATE_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4098 /* Update registry */
4099 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE
));
4101 if (!SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
))
4103 DPRINT1("SetupFindFirstLine() failed\n");
4104 MUIDisplayError(ERROR_FIND_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4110 INF_GetDataField(&InfContext
, 0, &Action
);
4111 INF_GetDataField(&InfContext
, 1, &File
);
4112 INF_GetDataField(&InfContext
, 2, &Section
);
4114 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
4119 if (!_wcsicmp(Action
, L
"AddReg"))
4123 else if (!_wcsicmp(Action
, L
"DelReg"))
4132 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE
), File
);
4134 if (!ImportRegistryFile(File
, Section
, LanguageId
, Delete
))
4136 DPRINT1("Importing %S failed\n", File
);
4138 MUIDisplayError(ERROR_IMPORT_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4141 } while (SetupFindNextLine(&InfContext
, &InfContext
));
4143 /* Update display registry settings */
4144 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE
));
4145 if (!ProcessDisplayRegistry(SetupInf
, DisplayList
))
4147 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4151 /* Set the locale */
4152 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE
));
4153 if (!ProcessLocaleRegistry(LanguageList
))
4155 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4159 /* Add keyboard layouts */
4160 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS
));
4161 if (!AddKeyboardLayouts())
4163 MUIDisplayError(ERROR_ADDING_KBLAYOUTS
, Ir
, POPUP_WAIT_ENTER
);
4168 if (!SetGeoID(MUIGetGeoID()))
4170 MUIDisplayError(ERROR_UPDATE_GEOID
, Ir
, POPUP_WAIT_ENTER
);
4174 if (!IsUnattendedSetup
)
4176 /* Update keyboard layout settings */
4177 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE
));
4178 if (!ProcessKeyboardLayoutRegistry(LayoutList
))
4180 MUIDisplayError(ERROR_UPDATE_KBSETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4185 /* Add codepage information to registry */
4186 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE
));
4189 MUIDisplayError(ERROR_ADDING_CODEPAGE
, Ir
, POPUP_WAIT_ENTER
);
4193 /* Set the default pagefile entry */
4194 SetDefaultPagefile(DestinationDriveLetter
);
4196 /* Update the mounted devices list */
4197 SetMountedDeviceValues(PartitionList
);
4199 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4201 return BOOT_LOADER_PAGE
;
4206 * Displays the BootLoaderPage.
4209 * SuccessPage (if RepairUpdate)
4210 * BootLoaderHarddiskMbrPage
4211 * BootLoaderHarddiskVbrPage
4212 * BootLoaderFloppyPage
4217 * Calls SetInstallPathValue
4218 * Calls NtInitializeRegistry
4219 * Calls ImportRegistryFile
4220 * Calls SetDefaultPagefile
4221 * Calls SetMountedDeviceValues
4224 * Number of the next page.
4227 BootLoaderPage(PINPUT_RECORD Ir
)
4229 UCHAR PartitionType
;
4230 BOOLEAN InstallOnFloppy
;
4232 WCHAR PathBuffer
[MAX_PATH
];
4234 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4236 RtlFreeUnicodeString(&SystemRootPath
);
4237 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4238 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4239 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4240 PartitionList
->SystemPartition
->PartitionNumber
);
4241 RtlCreateUnicodeString(&SystemRootPath
, PathBuffer
);
4242 DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath
);
4244 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4246 if (IsUnattendedSetup
)
4248 if (UnattendMBRInstallType
== 0) /* skip MBR installation */
4250 return SUCCESS_PAGE
;
4252 else if (UnattendMBRInstallType
== 1) /* install on floppy */
4254 return BOOT_LOADER_FLOPPY_PAGE
;
4258 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4260 DPRINT("Error: system partition invalid (unused)\n");
4261 InstallOnFloppy
= TRUE
;
4263 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4265 /* OS/2 boot manager partition */
4266 DPRINT("Found OS/2 boot manager partition\n");
4267 InstallOnFloppy
= TRUE
;
4269 else if (PartitionType
== PARTITION_EXT2
)
4271 /* Linux EXT2 partition */
4272 DPRINT("Found Linux EXT2 partition\n");
4273 InstallOnFloppy
= FALSE
;
4275 else if (PartitionType
== PARTITION_IFS
)
4277 /* NTFS partition */
4278 DPRINT("Found NTFS partition\n");
4280 // FIXME: Make it FALSE when we'll support NTFS installation!
4281 InstallOnFloppy
= TRUE
;
4283 else if ((PartitionType
== PARTITION_FAT_12
) ||
4284 (PartitionType
== PARTITION_FAT_16
) ||
4285 (PartitionType
== PARTITION_HUGE
) ||
4286 (PartitionType
== PARTITION_XINT13
) ||
4287 (PartitionType
== PARTITION_FAT32
) ||
4288 (PartitionType
== PARTITION_FAT32_XINT13
))
4290 DPRINT("Found FAT partition\n");
4291 InstallOnFloppy
= FALSE
;
4295 /* Unknown partition */
4296 DPRINT("Unknown partition found\n");
4297 InstallOnFloppy
= TRUE
;
4300 if (InstallOnFloppy
!= FALSE
)
4302 return BOOT_LOADER_FLOPPY_PAGE
;
4305 /* Unattended install on hdd? */
4306 if (IsUnattendedSetup
&& UnattendMBRInstallType
== 2)
4308 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4311 MUIDisplayPage(BOOT_LOADER_PAGE
);
4312 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4316 CONSOLE_ConInKey(Ir
);
4318 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4319 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4321 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4330 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4332 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4333 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4335 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4344 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4346 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4347 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4349 if (ConfirmQuit(Ir
) != FALSE
)
4354 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4358 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4360 else if (Line
== 13)
4362 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4364 else if (Line
== 14)
4366 return BOOT_LOADER_FLOPPY_PAGE
;
4368 else if (Line
== 15)
4370 return SUCCESS_PAGE
;
4373 return BOOT_LOADER_PAGE
;
4377 return BOOT_LOADER_PAGE
;
4382 * Displays the BootLoaderFloppyPage.
4385 * SuccessPage (At once)
4389 * Calls InstallFatBootcodeToFloppy()
4392 * Number of the next page.
4395 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4399 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4401 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4405 CONSOLE_ConInKey(Ir
);
4407 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4408 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4410 if (ConfirmQuit(Ir
) != FALSE
)
4415 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4417 if (DoesPathExist(NULL
, L
"\\Device\\Floppy0\\") == FALSE
)
4419 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4420 return BOOT_LOADER_FLOPPY_PAGE
;
4423 Status
= InstallFatBootcodeToFloppy(&SourceRootPath
, &DestinationArcPath
);
4424 if (!NT_SUCCESS(Status
))
4426 /* Print error message */
4427 return BOOT_LOADER_FLOPPY_PAGE
;
4430 return SUCCESS_PAGE
;
4434 return BOOT_LOADER_FLOPPY_PAGE
;
4439 * Displays the BootLoaderHarddiskVbrPage.
4442 * SuccessPage (At once)
4446 * Calls InstallVBRToPartition()
4449 * Number of the next page.
4452 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4456 Status
= InstallVBRToPartition(&SystemRootPath
,
4458 &DestinationArcPath
,
4459 PartitionList
->SystemPartition
->PartitionType
);
4460 if (!NT_SUCCESS(Status
))
4462 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4466 return SUCCESS_PAGE
;
4471 * Displays the BootLoaderHarddiskMbrPage.
4474 * SuccessPage (At once)
4478 * Calls InstallVBRToPartition()
4479 * Calls InstallMbrBootCodeToDisk()
4482 * Number of the next page.
4485 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4488 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4489 WCHAR SourceMbrPathBuffer
[MAX_PATH
];
4490 WCHAR DstPath
[MAX_PATH
];
4492 /* Step 1: Write the VBR */
4493 Status
= InstallVBRToPartition(&SystemRootPath
,
4495 &DestinationArcPath
,
4496 PartitionList
->SystemPartition
->PartitionType
);
4497 if (!NT_SUCCESS(Status
))
4499 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4503 /* Step 2: Write the MBR */
4504 StringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4505 L
"\\Device\\Harddisk%d\\Partition0",
4506 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4508 CombinePaths(SourceMbrPathBuffer
, ARRAYSIZE(SourceMbrPathBuffer
), 2, SourceRootPath
.Buffer
, L
"\\loader\\dosmbr.bin");
4510 if (IsThereAValidBootSector(DestinationDevicePathBuffer
))
4512 /* Save current MBR */
4513 CombinePaths(DstPath
, ARRAYSIZE(DstPath
), 2, SystemRootPath
.Buffer
, L
"mbr.old");
4515 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer
, DstPath
);
4516 Status
= SaveBootSector(DestinationDevicePathBuffer
, DstPath
, sizeof(PARTITION_SECTOR
));
4517 if (!NT_SUCCESS(Status
))
4519 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status
);
4520 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4524 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4525 SourceMbrPathBuffer
, DestinationDevicePathBuffer
);
4526 Status
= InstallMbrBootCodeToDisk(SourceMbrPathBuffer
,
4527 DestinationDevicePathBuffer
);
4528 if (!NT_SUCCESS(Status
))
4530 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4532 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4536 return SUCCESS_PAGE
;
4541 * @name ProgressTimeOutStringHandler
4543 * Handles the generation (displaying) of the timeout
4544 * countdown to the screen dynamically.
4547 * A pointer to a progress bar.
4549 * @param AlwaysUpdate
4550 * Constantly update the progress bar (boolean type).
4553 * A pointer to a string buffer.
4555 * @param cchBufferSize
4556 * The buffer's size in number of characters.
4559 * TRUE or FALSE on function termination.
4564 ProgressTimeOutStringHandler(
4565 IN PPROGRESSBAR Bar
,
4566 IN BOOLEAN AlwaysUpdate
,
4568 IN SIZE_T cchBufferSize
)
4570 ULONG OldProgress
= Bar
->Progress
;
4572 if (Bar
->StepCount
== 0)
4578 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4581 /* Build the progress string if it has changed */
4582 if (Bar
->ProgressFormatText
&&
4583 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4585 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4586 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4595 * @name ProgressCountdown
4597 * Displays and draws a red-coloured progress bar with a countdown.
4598 * When the timeout is reached, the flush page is displayed for reboot.
4601 * A pointer to an input keyboard record.
4604 * Initial countdown value in seconds.
4612 IN PINPUT_RECORD Ir
,
4616 ULONG StartTime
, BarWidth
, TimerDiv
;
4618 LONG TimerValue
, OldTimerValue
;
4619 LARGE_INTEGER Timeout
;
4620 PPROGRESSBAR ProgressBar
;
4621 BOOLEAN RefreshProgress
= TRUE
;
4623 /* Bail out if the timeout is already zero */
4627 /* Create the timeout progress bar and set it up */
4628 ProgressBar
= CreateProgressBarEx(13,
4635 FOREGROUND_RED
| BACKGROUND_BLUE
,
4638 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4639 ProgressTimeOutStringHandler
);
4641 BarWidth
= max(1, ProgressBar
->Width
);
4642 TimerValue
= TimeOut
* BarWidth
;
4643 ProgressSetStepCount(ProgressBar
, TimerValue
);
4645 StartTime
= NtGetTickCount();
4648 TimerDiv
= 1000 / BarWidth
;
4649 TimerDiv
= max(1, TimerDiv
);
4650 OldTimerValue
= TimerValue
;
4653 /* Decrease the timer */
4656 * Compute how much time the previous operations took.
4657 * This allows us in particular to take account for any time
4658 * elapsed if something slowed down.
4660 TimeElapsed
= NtGetTickCount() - StartTime
;
4661 if (TimeElapsed
>= TimerDiv
)
4663 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4664 TimeElapsed
/= TimerDiv
;
4665 StartTime
+= (TimerDiv
* TimeElapsed
);
4667 if (TimeElapsed
<= TimerValue
)
4668 TimerValue
-= TimeElapsed
;
4672 RefreshProgress
= TRUE
;
4675 if (RefreshProgress
)
4677 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4678 RefreshProgress
= FALSE
;
4681 /* Stop when the timer reaches zero */
4682 if (TimerValue
<= 0)
4685 /* Check for user key presses */
4688 * If the timer is used, use a passive wait of maximum 1 second
4689 * while monitoring for incoming console input events, so that
4690 * we are still able to display the timing count.
4693 /* Wait a maximum of 1 second for input events */
4694 TimeElapsed
= NtGetTickCount() - StartTime
;
4695 if (TimeElapsed
< TimerDiv
)
4697 /* Convert the time to NT Format */
4698 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4699 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4703 Status
= STATUS_TIMEOUT
;
4706 /* Check whether the input event has been signaled, or a timeout happened */
4707 if (Status
== STATUS_TIMEOUT
)
4711 if (Status
!= STATUS_WAIT_0
)
4713 /* An error happened, bail out */
4714 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4718 /* Check for an ENTER key press */
4719 while (CONSOLE_ConInKeyPeek(Ir
))
4721 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4723 /* Found it, stop waiting */
4730 /* Destroy the progress bar and quit */
4731 DestroyProgressBar(ProgressBar
);
4736 * Displays the QuitPage.
4739 * FlushPage (At once)
4745 * Number of the next page.
4748 QuitPage(PINPUT_RECORD Ir
)
4750 MUIDisplayPage(QUIT_PAGE
);
4752 /* Destroy the partition list */
4753 if (PartitionList
!= NULL
)
4755 DestroyPartitionList(PartitionList
);
4756 PartitionList
= NULL
;
4758 TempPartition
= NULL
;
4759 FormatState
= Start
;
4761 /* Destroy the filesystem list */
4762 if (FileSystemList
!= NULL
)
4764 DestroyFileSystemList(FileSystemList
);
4765 FileSystemList
= NULL
;
4768 /* Destroy the computer settings list */
4769 if (ComputerList
!= NULL
)
4771 DestroyGenericList(ComputerList
, TRUE
);
4772 ComputerList
= NULL
;
4775 /* Destroy the display settings list */
4776 if (DisplayList
!= NULL
)
4778 DestroyGenericList(DisplayList
, TRUE
);
4782 /* Destroy the keyboard settings list */
4783 if (KeyboardList
!= NULL
)
4785 DestroyGenericList(KeyboardList
, TRUE
);
4786 KeyboardList
= NULL
;
4789 /* Destroy the keyboard layout list */
4790 if (LayoutList
!= NULL
)
4792 DestroyGenericList(LayoutList
, TRUE
);
4796 /* Destroy the languages list */
4797 if (LanguageList
!= NULL
)
4799 DestroyGenericList(LanguageList
, FALSE
);
4800 LanguageList
= NULL
;
4803 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4805 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4806 ProgressCountdown(Ir
, 15);
4812 * Displays the SuccessPage.
4815 * FlushPage (At once)
4821 * Number of the next page.
4824 SuccessPage(PINPUT_RECORD Ir
)
4826 MUIDisplayPage(SUCCESS_PAGE
);
4828 if (IsUnattendedSetup
)
4831 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4832 ProgressCountdown(Ir
, 15);
4838 * Displays the FlushPage.
4841 * RebootPage (At once)
4844 * Number of the next page.
4847 FlushPage(PINPUT_RECORD Ir
)
4849 MUIDisplayPage(FLUSH_PAGE
);
4855 PnpEventThread(IN LPVOID lpParameter
);
4859 * The start routine and page management
4870 NtQuerySystemTime(&Time
);
4872 /* Create the PnP thread in suspended state */
4873 Status
= RtlCreateUserThread(NtCurrentProcess(),
4883 if (!NT_SUCCESS(Status
))
4884 hPnpThread
= INVALID_HANDLE_VALUE
;
4886 if (!CONSOLE_Init())
4888 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4889 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4890 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4892 /* Raise a hard error (crash the system/BSOD) */
4893 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
4897 /* Initialize global unicode strings */
4898 RtlInitUnicodeString(&SourcePath
, NULL
);
4899 RtlInitUnicodeString(&SourceRootPath
, NULL
);
4900 RtlInitUnicodeString(&SourceRootDir
, NULL
);
4901 RtlInitUnicodeString(&InstallPath
, NULL
);
4902 RtlInitUnicodeString(&DestinationPath
, NULL
);
4903 RtlInitUnicodeString(&DestinationArcPath
, NULL
);
4904 RtlInitUnicodeString(&DestinationRootPath
, NULL
);
4905 RtlInitUnicodeString(&SystemRootPath
, NULL
);
4907 /* Hide the cursor */
4908 CONSOLE_SetCursorType(TRUE
, FALSE
);
4910 /* Global Initialization page */
4911 CONSOLE_ClearScreen();
4913 Page
= SetupStartPage(&Ir
);
4915 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4917 CONSOLE_ClearScreen();
4920 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4927 Page
= LanguagePage(&Ir
);
4932 Page
= WelcomePage(&Ir
);
4937 Page
= LicensePage(&Ir
);
4941 case INSTALL_INTRO_PAGE
:
4942 Page
= InstallIntroPage(&Ir
);
4946 case SCSI_CONTROLLER_PAGE
:
4947 Page
= ScsiControllerPage(&Ir
);
4950 case OEM_DRIVER_PAGE
:
4951 Page
= OemDriverPage(&Ir
);
4955 case DEVICE_SETTINGS_PAGE
:
4956 Page
= DeviceSettingsPage(&Ir
);
4959 case COMPUTER_SETTINGS_PAGE
:
4960 Page
= ComputerSettingsPage(&Ir
);
4963 case DISPLAY_SETTINGS_PAGE
:
4964 Page
= DisplaySettingsPage(&Ir
);
4967 case KEYBOARD_SETTINGS_PAGE
:
4968 Page
= KeyboardSettingsPage(&Ir
);
4971 case LAYOUT_SETTINGS_PAGE
:
4972 Page
= LayoutSettingsPage(&Ir
);
4975 case SELECT_PARTITION_PAGE
:
4976 Page
= SelectPartitionPage(&Ir
);
4979 case CREATE_PRIMARY_PARTITION_PAGE
:
4980 Page
= CreatePrimaryPartitionPage(&Ir
);
4983 case CREATE_EXTENDED_PARTITION_PAGE
:
4984 Page
= CreateExtendedPartitionPage(&Ir
);
4987 case CREATE_LOGICAL_PARTITION_PAGE
:
4988 Page
= CreateLogicalPartitionPage(&Ir
);
4991 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
4992 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
4995 case DELETE_PARTITION_PAGE
:
4996 Page
= DeletePartitionPage(&Ir
);
4999 case SELECT_FILE_SYSTEM_PAGE
:
5000 Page
= SelectFileSystemPage(&Ir
);
5003 case FORMAT_PARTITION_PAGE
:
5004 Page
= FormatPartitionPage(&Ir
);
5007 case CHECK_FILE_SYSTEM_PAGE
:
5008 Page
= CheckFileSystemPage(&Ir
);
5011 case INSTALL_DIRECTORY_PAGE
:
5012 Page
= InstallDirectoryPage(&Ir
);
5015 case PREPARE_COPY_PAGE
:
5016 Page
= PrepareCopyPage(&Ir
);
5019 case FILE_COPY_PAGE
:
5020 Page
= FileCopyPage(&Ir
);
5024 Page
= RegistryPage(&Ir
);
5027 case BOOT_LOADER_PAGE
:
5028 Page
= BootLoaderPage(&Ir
);
5031 case BOOT_LOADER_FLOPPY_PAGE
:
5032 Page
= BootLoaderFloppyPage(&Ir
);
5035 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5036 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5039 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5040 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5044 case REPAIR_INTRO_PAGE
:
5045 Page
= RepairIntroPage(&Ir
);
5049 Page
= SuccessPage(&Ir
);
5053 Page
= FlushPage(&Ir
);
5057 Page
= QuitPage(&Ir
);
5066 if (Page
== RECOVERY_PAGE
)
5071 /* Avoid bugcheck */
5072 Time
.QuadPart
+= 50000000;
5073 NtDelayExecution(FALSE
, &Time
);
5076 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5077 NtShutdownSystem(ShutdownReboot
);
5078 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5079 NtTerminateProcess(NtCurrentProcess(), 0);
5084 NtProcessStartup(PPEB Peb
)
5086 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5088 ProcessHeap
= Peb
->ProcessHeap
;
5089 InfSetHeap(ProcessHeap
);