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 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
97 static WCHAR DestinationDriveLetter
;
101 static HSPFILEQ SetupFileQueue
= NULL
;
103 static PGENERIC_LIST ComputerList
= NULL
;
104 static PGENERIC_LIST DisplayList
= NULL
;
105 static PGENERIC_LIST KeyboardList
= NULL
;
106 static PGENERIC_LIST LayoutList
= NULL
;
107 static PGENERIC_LIST LanguageList
= NULL
;
109 static LANGID LanguageId
= 0;
111 static ULONG RequiredPartitionDiskSpace
= ~0;
113 /* FUNCTIONS ****************************************************************/
116 PrintString(char* fmt
,...)
120 UNICODE_STRING UnicodeString
;
121 ANSI_STRING AnsiString
;
124 vsprintf(buffer
, fmt
, ap
);
127 RtlInitAnsiString(&AnsiString
, buffer
);
128 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
129 NtDisplayString(&UnicodeString
);
130 RtlFreeUnicodeString(&UnicodeString
);
135 DrawBox(IN SHORT xLeft
,
143 /* draw upper left corner */
146 FillConsoleOutputCharacterA(StdOutput
,
152 /* draw upper edge */
155 FillConsoleOutputCharacterA(StdOutput
,
161 /* draw upper right corner */
162 coPos
.X
= xLeft
+ Width
- 1;
164 FillConsoleOutputCharacterA(StdOutput
,
170 /* Draw right edge, inner space and left edge */
171 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
174 FillConsoleOutputCharacterA(StdOutput
,
181 FillConsoleOutputCharacterA(StdOutput
,
187 coPos
.X
= xLeft
+ Width
- 1;
188 FillConsoleOutputCharacterA(StdOutput
,
195 /* draw lower left corner */
197 coPos
.Y
= yTop
+ Height
- 1;
198 FillConsoleOutputCharacterA(StdOutput
,
204 /* draw lower edge */
206 coPos
.Y
= yTop
+ Height
- 1;
207 FillConsoleOutputCharacterA(StdOutput
,
213 /* draw lower right corner */
214 coPos
.X
= xLeft
+ Width
- 1;
215 coPos
.Y
= yTop
+ Height
- 1;
216 FillConsoleOutputCharacterA(StdOutput
,
225 PopupError(PCCH Text
,
243 /* Count text lines and longest line */
250 p
= strchr(pnext
, '\n');
254 Length
= strlen(pnext
);
259 Length
= (ULONG
)(p
- pnext
);
265 if (Length
> MaxLength
)
268 if (LastLine
!= FALSE
)
274 /* Check length of status line */
277 Length
= strlen(Status
);
279 if (Length
> MaxLength
)
283 Width
= MaxLength
+ 4;
289 yTop
= (yScreen
- Height
) / 2;
290 xLeft
= (xScreen
- Width
) / 2;
293 /* Set screen attributes */
295 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
297 FillConsoleOutputAttribute(StdOutput
,
298 FOREGROUND_RED
| BACKGROUND_WHITE
,
304 DrawBox(xLeft
, yTop
, Width
, Height
);
306 /* Print message text */
311 p
= strchr(pnext
, '\n');
315 Length
= strlen(pnext
);
320 Length
= (ULONG
)(p
- pnext
);
327 WriteConsoleOutputCharacterA(StdOutput
,
334 if (LastLine
!= FALSE
)
341 /* Print separator line and status text */
344 coPos
.Y
= yTop
+ Height
- 3;
346 FillConsoleOutputCharacterA(StdOutput
,
353 FillConsoleOutputCharacterA(StdOutput
,
359 coPos
.X
= xLeft
+ Width
- 1;
360 FillConsoleOutputCharacterA(StdOutput
,
368 WriteConsoleOutputCharacterA(StdOutput
,
370 min(strlen(Status
), (SIZE_T
)Width
- 4),
375 if (WaitEvent
== POPUP_WAIT_NONE
)
380 CONSOLE_ConInKey(Ir
);
382 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
383 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
395 * FALSE: Don't quit setup.
398 ConfirmQuit(PINPUT_RECORD Ir
)
401 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
405 CONSOLE_ConInKey(Ir
);
407 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
408 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
413 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
425 CheckUnattendedSetup(VOID
)
427 WCHAR UnattendInfPath
[MAX_PATH
];
434 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2, SourcePath
.Buffer
, L
"unattend.inf");
436 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
438 DPRINT("Does not exist: %S\n", UnattendInfPath
);
442 /* Load 'unattend.inf' from install media. */
443 UnattendInf
= SetupOpenInfFileW(UnattendInfPath
,
449 if (UnattendInf
== INVALID_HANDLE_VALUE
)
451 DPRINT("SetupOpenInfFileW() failed\n");
455 /* Open 'Unattend' section */
456 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
458 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
459 SetupCloseInfFile(UnattendInf
);
463 /* Get pointer 'Signature' key */
464 if (!INF_GetData(&Context
, NULL
, &Value
))
466 DPRINT("INF_GetData() failed for key 'Signature'\n");
467 SetupCloseInfFile(UnattendInf
);
471 /* Check 'Signature' string */
472 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
474 DPRINT("Signature not $ReactOS$\n");
475 SetupCloseInfFile(UnattendInf
);
479 /* Check if Unattend setup is enabled */
480 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
482 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
483 SetupCloseInfFile(UnattendInf
);
487 if (!INF_GetData(&Context
, NULL
, &Value
))
489 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
490 SetupCloseInfFile(UnattendInf
);
494 if (_wcsicmp(Value
, L
"yes") != 0)
496 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
497 SetupCloseInfFile(UnattendInf
);
501 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
502 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
504 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
505 SetupCloseInfFile(UnattendInf
);
509 if (!SetupGetIntField(&Context
, 1, &IntValue
))
511 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
512 SetupCloseInfFile(UnattendInf
);
516 UnattendDestinationDiskNumber
= (LONG
)IntValue
;
518 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
519 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
521 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
522 SetupCloseInfFile(UnattendInf
);
526 if (!SetupGetIntField(&Context
, 1, &IntValue
))
528 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
529 SetupCloseInfFile(UnattendInf
);
533 UnattendDestinationPartitionNumber
= (LONG
)IntValue
;
535 /* Search for 'InstallationDirectory' in the 'Unattend' section */
536 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
538 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
539 SetupCloseInfFile(UnattendInf
);
543 /* Get pointer 'InstallationDirectory' key */
544 if (!INF_GetData(&Context
, NULL
, &Value
))
546 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
547 SetupCloseInfFile(UnattendInf
);
551 wcscpy(UnattendInstallationDirectory
, Value
);
553 IsUnattendedSetup
= TRUE
;
555 /* Search for 'MBRInstallType' in the 'Unattend' section */
556 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
558 if (SetupGetIntField(&Context
, 1, &IntValue
))
560 UnattendMBRInstallType
= IntValue
;
564 /* Search for 'FormatPartition' in the 'Unattend' section */
565 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
567 if (SetupGetIntField(&Context
, 1, &IntValue
))
569 UnattendFormatPartition
= IntValue
;
573 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
575 if (SetupGetIntField(&Context
, 1, &IntValue
))
577 AutoPartition
= IntValue
;
581 /* search for LocaleID in the 'Unattend' section*/
582 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
584 if (INF_GetData(&Context
, NULL
, &Value
))
586 LONG Id
= wcstol(Value
, NULL
, 16);
587 swprintf(LocaleID
, L
"%08lx", Id
);
591 SetupCloseInfFile(UnattendInf
);
593 DPRINT("Running unattended setup\n");
600 PGENERIC_LIST_ENTRY ListEntry
;
601 LPCWSTR pszNewLayout
;
603 pszNewLayout
= MUIDefaultKeyboardLayout();
605 if (LayoutList
== NULL
)
607 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
608 if (LayoutList
== NULL
)
610 /* FIXME: Handle error! */
615 ListEntry
= GetFirstListEntry(LayoutList
);
617 /* Search for default layout (if provided) */
618 if (pszNewLayout
!= NULL
)
620 while (ListEntry
!= NULL
)
622 if (!wcscmp(pszNewLayout
, GetListEntryUserData(ListEntry
)))
624 SetCurrentListEntry(LayoutList
, ListEntry
);
628 ListEntry
= GetNextListEntry(ListEntry
);
635 * Displays the LanguagePage.
637 * Next pages: WelcomePage, QuitPage
640 * Init SelectedLanguageId
644 * Number of the next page.
647 LanguagePage(PINPUT_RECORD Ir
)
649 GENERIC_LIST_UI ListUi
;
650 PWCHAR NewLanguageId
;
651 BOOL RefreshPage
= FALSE
;
653 /* Initialize the computer settings list */
654 if (LanguageList
== NULL
)
656 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
657 if (LanguageList
== NULL
)
659 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
665 SelectedLanguageId
= DefaultLanguage
;
666 SetConsoleCodePage();
669 /* If there's just a single language in the list skip
670 * the language selection process altogether! */
671 if (GenericListHasSingleEntry(LanguageList
))
673 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
677 InitGenericListUi(&ListUi
, LanguageList
);
678 DrawGenericList(&ListUi
,
684 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
686 MUIDisplayPage(LANGUAGE_PAGE
);
690 CONSOLE_ConInKey(Ir
);
692 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
693 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
695 ScrollDownGenericList(&ListUi
);
698 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
699 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
701 ScrollUpGenericList(&ListUi
);
704 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
705 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
707 ScrollPageDownGenericList(&ListUi
);
710 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
711 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
713 ScrollPageUpGenericList(&ListUi
);
716 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
717 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
719 if (ConfirmQuit(Ir
) != FALSE
)
722 RedrawGenericList(&ListUi
);
724 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
726 SelectedLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
728 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
730 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
736 SetConsoleCodePage();
740 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
743 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
749 NewLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
751 if (SelectedLanguageId
!= NewLanguageId
)
753 /* Clear the language page */
754 MUIClearPage(LANGUAGE_PAGE
);
756 SelectedLanguageId
= NewLanguageId
;
759 SetConsoleCodePage();
761 /* Redraw language selection page in native language */
762 MUIDisplayPage(LANGUAGE_PAGE
);
777 * LanguagePage (at once, default)
778 * InstallIntroPage (at once, if unattended)
784 * Init SourceRootPath
787 * Init RequiredPartitionDiskSpace
788 * Init IsUnattendedSetup
789 * If unattended, init *List and sets the Codepage
790 * If unattended, init SelectedLanguageId
791 * If unattended, init LanguageId
794 * Number of the next page.
797 SetupStartPage(PINPUT_RECORD Ir
)
800 WCHAR FileNameBuffer
[MAX_PATH
];
804 PGENERIC_LIST_ENTRY ListEntry
;
807 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
809 /* Get the source path and source root path */
810 Status
= GetSourcePaths(&SourcePath
,
813 if (!NT_SUCCESS(Status
))
815 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
816 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
819 DPRINT1("SourcePath: '%wZ'\n", &SourcePath
);
820 DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath
);
821 DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir
);
823 /* Load txtsetup.sif from install media. */
824 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2, SourcePath
.Buffer
, L
"txtsetup.sif");
825 SetupInf
= SetupOpenInfFileW(FileNameBuffer
,
831 if (SetupInf
== INVALID_HANDLE_VALUE
)
833 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
837 /* Open 'Version' section */
838 if (!SetupFindFirstLineW(SetupInf
, L
"Version", L
"Signature", &Context
))
840 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
844 /* Get pointer 'Signature' key */
845 if (!INF_GetData(&Context
, NULL
, &Value
))
847 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
851 /* Check 'Signature' string */
852 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
854 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
858 /* Open 'DiskSpaceRequirements' section */
859 if (!SetupFindFirstLineW(SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
861 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
865 /* Get the 'FreeSysPartDiskSpace' value */
866 if (!SetupGetIntField(&Context
, 1, &IntValue
))
868 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
872 RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
874 /* Start the PnP thread */
875 if (hPnpThread
!= INVALID_HANDLE_VALUE
)
877 NtResumeThread(hPnpThread
, NULL
);
878 hPnpThread
= INVALID_HANDLE_VALUE
;
881 CheckUnattendedSetup();
883 if (IsUnattendedSetup
)
885 // TODO: Read options from inf
886 ComputerList
= CreateComputerTypeList(SetupInf
);
887 DisplayList
= CreateDisplayDriverList(SetupInf
);
888 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
889 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
890 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
893 wcscpy(SelectedLanguageId
, LocaleID
);
894 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
896 /* first we hack LanguageList */
897 ListEntry
= GetFirstListEntry(LanguageList
);
898 while (ListEntry
!= NULL
)
900 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
902 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry
));
903 SetCurrentListEntry(LanguageList
, ListEntry
);
907 ListEntry
= GetNextListEntry(ListEntry
);
911 ListEntry
= GetFirstListEntry(LayoutList
);
912 while (ListEntry
!= NULL
)
914 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
916 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry
));
917 SetCurrentListEntry(LayoutList
, ListEntry
);
921 ListEntry
= GetNextListEntry(ListEntry
);
924 SetConsoleCodePage();
926 return INSTALL_INTRO_PAGE
;
929 return LANGUAGE_PAGE
;
934 * Displays the WelcomePage.
937 * InstallIntroPage (default)
943 * Number of the next page.
946 WelcomePage(PINPUT_RECORD Ir
)
948 MUIDisplayPage(WELCOME_PAGE
);
952 CONSOLE_ConInKey(Ir
);
954 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
955 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
957 if (ConfirmQuit(Ir
) != FALSE
)
962 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
964 return INSTALL_INTRO_PAGE
;
966 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
968 return REPAIR_INTRO_PAGE
;
970 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
981 * Displays the License page.
984 * WelcomePage (default)
987 * Number of the next page.
990 LicensePage(PINPUT_RECORD Ir
)
992 MUIDisplayPage(LICENSE_PAGE
);
996 CONSOLE_ConInKey(Ir
);
998 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1000 return WELCOME_PAGE
;
1004 return LICENSE_PAGE
;
1009 * Displays the RepairIntroPage.
1012 * RebootPage (default)
1018 * Number of the next page.
1021 RepairIntroPage(PINPUT_RECORD Ir
)
1023 MUIDisplayPage(REPAIR_INTRO_PAGE
);
1027 CONSOLE_ConInKey(Ir
);
1029 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1033 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
1035 RepairUpdateFlag
= TRUE
;
1036 return INSTALL_INTRO_PAGE
;
1038 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
1040 return RECOVERY_PAGE
;
1042 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1043 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1045 return WELCOME_PAGE
;
1049 return REPAIR_INTRO_PAGE
;
1053 * Displays the InstallIntroPage.
1056 * DeviceSettingsPage (At once if repair or update is selected)
1057 * SelectPartitionPage (At once if unattended setup)
1058 * DeviceSettingsPage (default)
1062 * Number of the next page.
1065 InstallIntroPage(PINPUT_RECORD Ir
)
1067 if (RepairUpdateFlag
)
1069 //return SELECT_PARTITION_PAGE;
1070 return DEVICE_SETTINGS_PAGE
;
1073 if (IsUnattendedSetup
)
1074 return SELECT_PARTITION_PAGE
;
1076 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1080 CONSOLE_ConInKey(Ir
);
1082 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1083 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1085 if (ConfirmQuit(Ir
) != FALSE
)
1090 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1092 return DEVICE_SETTINGS_PAGE
;
1093 // return SCSI_CONTROLLER_PAGE;
1097 return INSTALL_INTRO_PAGE
;
1103 ScsiControllerPage(PINPUT_RECORD Ir
)
1105 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1107 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1109 /* FIXME: print loaded mass storage driver descriptions */
1111 CONSOLE_SetTextXY(8, 10, "TEST device");
1114 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1118 CONSOLE_ConInKey(Ir
);
1120 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1121 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1123 if (ConfirmQuit(Ir
) != FALSE
)
1128 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1130 return DEVICE_SETTINGS_PAGE
;
1134 return SCSI_CONTROLLER_PAGE
;
1138 OemDriverPage(PINPUT_RECORD Ir
)
1140 // MUIDisplayPage(OEM_DRIVER_PAGE);
1142 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1144 /* FIXME: Implement!! */
1146 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1150 CONSOLE_ConInKey(Ir
);
1152 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1153 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1155 if (ConfirmQuit(Ir
) == TRUE
)
1160 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1162 return DEVICE_SETTINGS_PAGE
;
1166 return OEM_DRIVER_PAGE
;
1172 * Displays the DeviceSettingsPage.
1175 * SelectPartitionPage (At once if repair or update is selected)
1176 * ComputerSettingsPage
1177 * DisplaySettingsPage
1178 * KeyboardSettingsPage
1179 * LayoutsettingsPage
1180 * SelectPartitionPage
1190 * Number of the next page.
1193 DeviceSettingsPage(PINPUT_RECORD Ir
)
1195 static ULONG Line
= 16;
1197 /* Initialize the computer settings list */
1198 if (ComputerList
== NULL
)
1200 ComputerList
= CreateComputerTypeList(SetupInf
);
1201 if (ComputerList
== NULL
)
1203 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1208 /* Initialize the display settings list */
1209 if (DisplayList
== NULL
)
1211 DisplayList
= CreateDisplayDriverList(SetupInf
);
1212 if (DisplayList
== NULL
)
1214 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1219 /* Initialize the keyboard settings list */
1220 if (KeyboardList
== NULL
)
1222 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1223 if (KeyboardList
== NULL
)
1225 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1230 /* Initialize the keyboard layout list */
1231 if (LayoutList
== NULL
)
1233 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
1234 if (LayoutList
== NULL
)
1236 /* FIXME: report error */
1237 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1242 if (RepairUpdateFlag
)
1243 return SELECT_PARTITION_PAGE
;
1245 // if (IsUnattendedSetup)
1246 // return SELECT_PARTITION_PAGE;
1248 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1250 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList
)));
1251 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList
)));
1252 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList
)));
1253 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList
)));
1255 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1259 CONSOLE_ConInKey(Ir
);
1261 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1262 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1264 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1268 else if (Line
== 16)
1273 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1275 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1276 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1278 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1282 else if (Line
== 16)
1287 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1289 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1290 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1292 if (ConfirmQuit(Ir
) != FALSE
)
1297 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1300 return COMPUTER_SETTINGS_PAGE
;
1301 else if (Line
== 12)
1302 return DISPLAY_SETTINGS_PAGE
;
1303 else if (Line
== 13)
1304 return KEYBOARD_SETTINGS_PAGE
;
1305 else if (Line
== 14)
1306 return LAYOUT_SETTINGS_PAGE
;
1307 else if (Line
== 16)
1308 return SELECT_PARTITION_PAGE
;
1312 return DEVICE_SETTINGS_PAGE
;
1317 * Handles generic selection lists.
1320 * GenericList: The list to handle.
1321 * nextPage: The page it needs to jump to after this page.
1322 * Ir: The PINPUT_RECORD
1325 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1326 PAGE_NUMBER nextPage
,
1331 CONSOLE_ConInKey(Ir
);
1333 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1334 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1336 ScrollDownGenericList(ListUi
);
1338 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1339 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1341 ScrollUpGenericList(ListUi
);
1343 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1344 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1346 ScrollPageDownGenericList(ListUi
);
1348 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1349 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1351 ScrollPageUpGenericList(ListUi
);
1353 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1354 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1356 if (ConfirmQuit(Ir
) != FALSE
)
1359 RedrawGenericList(ListUi
);
1361 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1362 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1364 RestoreGenericListState(ListUi
->List
);
1365 return nextPage
; // Use some "prevPage;" instead?
1367 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1371 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1374 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1381 * Displays the ComputerSettingsPage.
1384 * DeviceSettingsPage
1388 * Number of the next page.
1391 ComputerSettingsPage(PINPUT_RECORD Ir
)
1393 GENERIC_LIST_UI ListUi
;
1394 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1396 InitGenericListUi(&ListUi
, ComputerList
);
1397 DrawGenericList(&ListUi
,
1403 SaveGenericListState(ComputerList
);
1405 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1410 * Displays the DisplaySettingsPage.
1413 * DeviceSettingsPage
1417 * Number of the next page.
1420 DisplaySettingsPage(PINPUT_RECORD Ir
)
1422 GENERIC_LIST_UI ListUi
;
1423 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1425 InitGenericListUi(&ListUi
, DisplayList
);
1426 DrawGenericList(&ListUi
,
1432 SaveGenericListState(DisplayList
);
1434 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1439 * Displays the KeyboardSettingsPage.
1442 * DeviceSettingsPage
1446 * Number of the next page.
1449 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1451 GENERIC_LIST_UI ListUi
;
1452 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1454 InitGenericListUi(&ListUi
, KeyboardList
);
1455 DrawGenericList(&ListUi
,
1461 SaveGenericListState(KeyboardList
);
1463 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1468 * Displays the LayoutSettingsPage.
1471 * DeviceSettingsPage
1475 * Number of the next page.
1478 LayoutSettingsPage(PINPUT_RECORD Ir
)
1480 GENERIC_LIST_UI ListUi
;
1481 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1483 InitGenericListUi(&ListUi
, LayoutList
);
1484 DrawGenericList(&ListUi
,
1490 SaveGenericListState(LayoutList
);
1492 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1497 IsDiskSizeValid(PPARTENTRY PartEntry
)
1501 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1502 size
= (size
+ 524288) / 1048576; /* in MBytes */
1504 if (size
< RequiredPartitionDiskSpace
)
1506 /* partition is too small so ask for another partition */
1507 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, RequiredPartitionDiskSpace
);
1518 * Displays the SelectPartitionPage.
1521 * SelectFileSystemPage (At once if unattended)
1522 * SelectFileSystemPage (Default if free space is selected)
1523 * CreatePrimaryPartitionPage
1524 * CreateExtendedPartitionPage
1525 * CreateLogicalPartitionPage
1526 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1527 * DeletePartitionPage
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 return SELECT_FILE_SYSTEM_PAGE
;
1602 DrawPartitionList(&ListUi
);
1604 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1605 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1607 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1608 RequiredPartitionDiskSpace
);
1609 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1612 return SELECT_FILE_SYSTEM_PAGE
;
1618 /* Update status text */
1619 if (PartitionList
->CurrentPartition
== NULL
)
1621 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1623 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1625 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1627 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1631 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1636 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1638 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1640 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1644 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1649 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1653 CONSOLE_ConInKey(Ir
);
1655 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1656 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1658 if (ConfirmQuit(Ir
) != FALSE
)
1660 DestroyPartitionList(PartitionList
);
1661 PartitionList
= NULL
;
1667 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1668 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1670 ScrollDownPartitionList(&ListUi
);
1672 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1673 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1675 ScrollUpPartitionList(&ListUi
);
1677 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1679 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1680 continue; // return SELECT_PARTITION_PAGE;
1682 if (PartitionList
->CurrentPartition
== NULL
||
1683 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1685 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1687 CreateLogicalPartition(PartitionList
,
1693 CreatePrimaryPartition(PartitionList
,
1699 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1701 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1702 RequiredPartitionDiskSpace
);
1703 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1706 return SELECT_FILE_SYSTEM_PAGE
;
1708 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1710 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1712 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1713 if (Error
!= NOT_AN_ERROR
)
1715 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1716 return SELECT_PARTITION_PAGE
;
1719 return CREATE_PRIMARY_PARTITION_PAGE
;
1722 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1724 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1726 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1727 if (Error
!= NOT_AN_ERROR
)
1729 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1730 return SELECT_PARTITION_PAGE
;
1733 return CREATE_EXTENDED_PARTITION_PAGE
;
1736 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1738 if (PartitionList
->CurrentPartition
->LogicalPartition
!= FALSE
)
1740 Error
= LogicalPartitionCreationChecks(PartitionList
);
1741 if (Error
!= NOT_AN_ERROR
)
1743 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1744 return SELECT_PARTITION_PAGE
;
1747 return CREATE_LOGICAL_PARTITION_PAGE
;
1750 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1752 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1754 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1755 return SELECT_PARTITION_PAGE
;
1758 if (PartitionList
->CurrentPartition
->BootIndicator
||
1759 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1761 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1764 return DELETE_PARTITION_PAGE
;
1768 return SELECT_PARTITION_PAGE
;
1772 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1773 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1774 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1777 ShowPartitionSizeInputBox(SHORT Left
,
1801 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1806 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1807 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1810 WriteConsoleOutputCharacterA(StdOutput
,
1816 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1817 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1819 WriteConsoleOutputCharacterA(StdOutput
,
1825 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1826 Length
= wcslen(InputBuffer
);
1828 CONSOLE_SetInputTextXY(iLeft
,
1830 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1832 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1833 CONSOLE_SetCursorType(TRUE
, TRUE
);
1837 CONSOLE_ConInKey(&Ir
);
1839 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1840 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1845 InputBuffer
[0] = UNICODE_NULL
;
1846 CONSOLE_SetCursorType(TRUE
, FALSE
);
1849 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1851 CONSOLE_SetCursorType(TRUE
, FALSE
);
1854 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1859 InputBuffer
[0] = UNICODE_NULL
;
1860 CONSOLE_SetCursorType(TRUE
, FALSE
);
1863 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1864 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1867 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1869 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1870 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1873 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1875 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1876 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1881 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1884 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1885 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1890 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1893 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1894 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1898 memmove(&InputBuffer
[Pos
],
1899 &InputBuffer
[Pos
+ 1],
1900 (Length
- Pos
- 1) * sizeof(WCHAR
));
1901 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1904 CONSOLE_SetInputTextXY(iLeft
,
1906 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1908 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1911 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1916 memmove(&InputBuffer
[Pos
- 1],
1918 (Length
- Pos
) * sizeof(WCHAR
));
1919 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1923 CONSOLE_SetInputTextXY(iLeft
,
1925 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1927 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1930 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1932 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1934 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1936 if ((ch
>= L
'0') && (ch
<= L
'9'))
1939 memmove(&InputBuffer
[Pos
+ 1],
1941 (Length
- Pos
) * sizeof(WCHAR
));
1942 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1943 InputBuffer
[Pos
] = ch
;
1947 CONSOLE_SetInputTextXY(iLeft
,
1949 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1951 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1960 * Displays the CreatePrimaryPartitionPage.
1963 * SelectPartitionPage
1964 * SelectFileSystemPage (default)
1968 * Number of the next page.
1971 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1973 PDISKENTRY DiskEntry
;
1974 PPARTENTRY PartEntry
;
1977 WCHAR InputBuffer
[50];
1981 ULONGLONG SectorCount
;
1984 if (PartitionList
== NULL
||
1985 PartitionList
->CurrentDisk
== NULL
||
1986 PartitionList
->CurrentPartition
== NULL
)
1988 /* FIXME: show an error dialog */
1992 DiskEntry
= PartitionList
->CurrentDisk
;
1993 PartEntry
= PartitionList
->CurrentPartition
;
1995 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1997 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
1999 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2001 if (DiskSize
>= 10737418240) /* 10 GB */
2003 DiskSize
= DiskSize
/ 1073741824;
2004 Unit
= MUIGetString(STRING_GB
);
2009 DiskSize
= DiskSize
/ 1048576;
2013 Unit
= MUIGetString(STRING_MB
);
2016 if (DiskEntry
->DriverName
.Length
> 0)
2018 CONSOLE_PrintTextXY(6, 10,
2019 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2022 DiskEntry
->DiskNumber
,
2026 &DiskEntry
->DriverName
,
2027 DiskEntry
->NoMbr
? "GPT" : "MBR");
2031 CONSOLE_PrintTextXY(6, 10,
2032 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2035 DiskEntry
->DiskNumber
,
2039 DiskEntry
->NoMbr
? "GPT" : "MBR");
2042 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2045 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2046 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2049 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2051 PartEntry
= PartitionList
->CurrentPartition
;
2054 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2056 if (MaxSize
> PARTITION_MAXSIZE
)
2057 MaxSize
= PARTITION_MAXSIZE
;
2059 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2060 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2064 if (ConfirmQuit(Ir
) != FALSE
)
2069 else if (Cancel
!= FALSE
)
2071 return SELECT_PARTITION_PAGE
;
2075 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2083 if (PartSize
> MaxSize
)
2089 /* Convert to bytes */
2090 if (PartSize
== MaxSize
)
2092 /* Use all of the unpartitioned disk space */
2093 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2097 /* Calculate the sector count from the size in MB */
2098 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2100 /* But never get larger than the unpartitioned disk space */
2101 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2102 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2105 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2107 CreatePrimaryPartition(PartitionList
,
2111 return SELECT_PARTITION_PAGE
;
2115 return CREATE_PRIMARY_PARTITION_PAGE
;
2120 * Displays the CreateExtendedPartitionPage.
2123 * SelectPartitionPage (default)
2127 * Number of the next page.
2130 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2132 PDISKENTRY DiskEntry
;
2133 PPARTENTRY PartEntry
;
2136 WCHAR InputBuffer
[50];
2140 ULONGLONG SectorCount
;
2143 if (PartitionList
== NULL
||
2144 PartitionList
->CurrentDisk
== NULL
||
2145 PartitionList
->CurrentPartition
== NULL
)
2147 /* FIXME: show an error dialog */
2151 DiskEntry
= PartitionList
->CurrentDisk
;
2152 PartEntry
= PartitionList
->CurrentPartition
;
2154 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2156 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2158 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2160 if (DiskSize
>= 10737418240) /* 10 GB */
2162 DiskSize
= DiskSize
/ 1073741824;
2163 Unit
= MUIGetString(STRING_GB
);
2168 DiskSize
= DiskSize
/ 1048576;
2172 Unit
= MUIGetString(STRING_MB
);
2175 if (DiskEntry
->DriverName
.Length
> 0)
2177 CONSOLE_PrintTextXY(6, 10,
2178 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2181 DiskEntry
->DiskNumber
,
2185 &DiskEntry
->DriverName
,
2186 DiskEntry
->NoMbr
? "GPT" : "MBR");
2190 CONSOLE_PrintTextXY(6, 10,
2191 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2194 DiskEntry
->DiskNumber
,
2198 DiskEntry
->NoMbr
? "GPT" : "MBR");
2201 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2204 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2205 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2208 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2210 PartEntry
= PartitionList
->CurrentPartition
;
2213 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2215 if (MaxSize
> PARTITION_MAXSIZE
)
2216 MaxSize
= PARTITION_MAXSIZE
;
2218 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2219 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2223 if (ConfirmQuit(Ir
) != FALSE
)
2228 else if (Cancel
!= FALSE
)
2230 return SELECT_PARTITION_PAGE
;
2234 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2242 if (PartSize
> MaxSize
)
2248 /* Convert to bytes */
2249 if (PartSize
== MaxSize
)
2251 /* Use all of the unpartitioned disk space */
2252 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2256 /* Calculate the sector count from the size in MB */
2257 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2259 /* But never get larger than the unpartitioned disk space */
2260 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2261 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2264 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2266 CreateExtendedPartition(PartitionList
,
2269 return SELECT_PARTITION_PAGE
;
2273 return CREATE_EXTENDED_PARTITION_PAGE
;
2278 * Displays the CreateLogicalPartitionPage.
2281 * SelectFileSystemPage (default)
2285 * Number of the next page.
2288 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2290 PDISKENTRY DiskEntry
;
2291 PPARTENTRY PartEntry
;
2294 WCHAR InputBuffer
[50];
2298 ULONGLONG SectorCount
;
2301 if (PartitionList
== NULL
||
2302 PartitionList
->CurrentDisk
== NULL
||
2303 PartitionList
->CurrentPartition
== NULL
)
2305 /* FIXME: show an error dialog */
2309 DiskEntry
= PartitionList
->CurrentDisk
;
2310 PartEntry
= PartitionList
->CurrentPartition
;
2312 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2314 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2316 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2318 if (DiskSize
>= 10737418240) /* 10 GB */
2320 DiskSize
= DiskSize
/ 1073741824;
2321 Unit
= MUIGetString(STRING_GB
);
2326 DiskSize
= DiskSize
/ 1048576;
2330 Unit
= MUIGetString(STRING_MB
);
2333 if (DiskEntry
->DriverName
.Length
> 0)
2335 CONSOLE_PrintTextXY(6, 10,
2336 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2339 DiskEntry
->DiskNumber
,
2343 &DiskEntry
->DriverName
,
2344 DiskEntry
->NoMbr
? "GPT" : "MBR");
2348 CONSOLE_PrintTextXY(6, 10,
2349 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2352 DiskEntry
->DiskNumber
,
2356 DiskEntry
->NoMbr
? "GPT" : "MBR");
2359 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2362 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2363 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2366 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2368 PartEntry
= PartitionList
->CurrentPartition
;
2371 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2373 if (MaxSize
> PARTITION_MAXSIZE
)
2374 MaxSize
= PARTITION_MAXSIZE
;
2376 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2377 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2381 if (ConfirmQuit(Ir
) != FALSE
)
2386 else if (Cancel
!= FALSE
)
2388 return SELECT_PARTITION_PAGE
;
2392 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2400 if (PartSize
> MaxSize
)
2406 /* Convert to bytes */
2407 if (PartSize
== MaxSize
)
2409 /* Use all of the unpartitioned disk space */
2410 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2414 /* Calculate the sector count from the size in MB */
2415 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2417 /* But never get larger than the unpartitioned disk space */
2418 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2419 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2422 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2424 CreateLogicalPartition(PartitionList
,
2428 return SELECT_PARTITION_PAGE
;
2432 return CREATE_LOGICAL_PARTITION_PAGE
;
2437 * Displays the ConfirmDeleteSystemPartitionPage.
2440 * DeletePartitionPage (default)
2441 * SelectPartitionPage
2444 * Number of the next page.
2447 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2449 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2453 CONSOLE_ConInKey(Ir
);
2455 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2456 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2458 if (ConfirmQuit(Ir
) == TRUE
)
2463 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2465 return DELETE_PARTITION_PAGE
;
2467 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2469 return SELECT_PARTITION_PAGE
;
2473 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2478 * Displays the DeletePartitionPage.
2481 * SelectPartitionPage (default)
2485 * Number of the next page.
2488 DeletePartitionPage(PINPUT_RECORD Ir
)
2490 PDISKENTRY DiskEntry
;
2491 PPARTENTRY PartEntry
;
2495 CHAR PartTypeString
[32];
2497 if (PartitionList
== NULL
||
2498 PartitionList
->CurrentDisk
== NULL
||
2499 PartitionList
->CurrentPartition
== NULL
)
2501 /* FIXME: show an error dialog */
2505 DiskEntry
= PartitionList
->CurrentDisk
;
2506 PartEntry
= PartitionList
->CurrentPartition
;
2508 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2510 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2512 ARRAYSIZE(PartTypeString
));
2514 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2516 if (PartSize
>= 10737418240) /* 10 GB */
2518 PartSize
= PartSize
/ 1073741824;
2519 Unit
= MUIGetString(STRING_GB
);
2523 if (PartSize
>= 10485760) /* 10 MB */
2525 PartSize
= PartSize
/ 1048576;
2526 Unit
= MUIGetString(STRING_MB
);
2530 PartSize
= PartSize
/ 1024;
2531 Unit
= MUIGetString(STRING_KB
);
2534 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2536 CONSOLE_PrintTextXY(6, 10,
2537 MUIGetString(STRING_HDDINFOUNK2
),
2538 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2539 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2540 PartEntry
->PartitionType
,
2546 CONSOLE_PrintTextXY(6, 10,
2547 " %c%c %s %I64u %s",
2548 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2549 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2555 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2557 if (DiskSize
>= 10737418240) /* 10 GB */
2559 DiskSize
= DiskSize
/ 1073741824;
2560 Unit
= MUIGetString(STRING_GB
);
2565 DiskSize
= DiskSize
/ 1048576;
2569 Unit
= MUIGetString(STRING_MB
);
2572 if (DiskEntry
->DriverName
.Length
> 0)
2574 CONSOLE_PrintTextXY(6, 12,
2575 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2578 DiskEntry
->DiskNumber
,
2582 &DiskEntry
->DriverName
,
2583 DiskEntry
->NoMbr
? "GPT" : "MBR");
2587 CONSOLE_PrintTextXY(6, 12,
2588 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2591 DiskEntry
->DiskNumber
,
2595 DiskEntry
->NoMbr
? "GPT" : "MBR");
2600 CONSOLE_ConInKey(Ir
);
2602 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2603 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2605 if (ConfirmQuit(Ir
) != FALSE
)
2610 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2612 return SELECT_PARTITION_PAGE
;
2614 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2616 DeleteCurrentPartition(PartitionList
);
2618 return SELECT_PARTITION_PAGE
;
2622 return DELETE_PARTITION_PAGE
;
2627 * Displays the SelectFileSystemPage.
2630 * CheckFileSystemPage (At once if RepairUpdate is selected)
2631 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2632 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2633 * SelectPartitionPage (If the user aborts)
2634 * FormatPartitionPage (Default)
2638 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2639 * Calls CheckActiveSystemPartition()
2642 * Number of the next page.
2645 SelectFileSystemPage(PINPUT_RECORD Ir
)
2647 PDISKENTRY DiskEntry
;
2648 PPARTENTRY PartEntry
;
2653 CHAR PartTypeString
[32];
2654 FORMATMACHINESTATE PreviousFormatState
;
2656 DPRINT("SelectFileSystemPage()\n");
2658 if (PartitionList
== NULL
||
2659 PartitionList
->CurrentDisk
== NULL
||
2660 PartitionList
->CurrentPartition
== NULL
)
2662 /* FIXME: show an error dialog */
2666 /* Find or set the active system partition */
2667 CheckActiveSystemPartition(PartitionList
);
2668 if (PartitionList
->SystemPartition
== NULL
)
2670 /* FIXME: show an error dialog */
2672 // Error dialog should say that we cannot find a suitable
2673 // system partition and create one on the system. At this point,
2674 // it may be nice to ask the user whether he wants to continue,
2675 // or use an external drive as the system drive/partition
2676 // (e.g. floppy, USB drive, etc...)
2681 PreviousFormatState
= FormatState
;
2682 switch (FormatState
)
2686 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2688 TempPartition
= PartitionList
->SystemPartition
;
2689 TempPartition
->NeedsCheck
= TRUE
;
2691 FormatState
= FormatSystemPartition
;
2692 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2696 TempPartition
= PartitionList
->CurrentPartition
;
2697 TempPartition
->NeedsCheck
= TRUE
;
2699 FormatState
= FormatInstallPartition
;
2700 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2705 case FormatSystemPartition
:
2707 TempPartition
= PartitionList
->CurrentPartition
;
2708 TempPartition
->NeedsCheck
= TRUE
;
2710 FormatState
= FormatInstallPartition
;
2711 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2715 case FormatInstallPartition
:
2717 if (GetNextUnformattedPartition(PartitionList
,
2721 FormatState
= FormatOtherPartition
;
2722 TempPartition
->NeedsCheck
= TRUE
;
2723 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2727 FormatState
= FormatDone
;
2728 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2729 return CHECK_FILE_SYSTEM_PAGE
;
2734 case FormatOtherPartition
:
2736 if (GetNextUnformattedPartition(PartitionList
,
2740 FormatState
= FormatOtherPartition
;
2741 TempPartition
->NeedsCheck
= TRUE
;
2742 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2746 FormatState
= FormatDone
;
2747 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2748 return CHECK_FILE_SYSTEM_PAGE
;
2755 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2756 /* FIXME: show an error dialog */
2761 PartEntry
= TempPartition
;
2762 DiskEntry
= PartEntry
->DiskEntry
;
2764 /* Adjust disk size */
2765 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2766 if (DiskSize
>= 10737418240) /* 10 GB */
2768 DiskSize
= DiskSize
/ 1073741824;
2769 DiskUnit
= MUIGetString(STRING_GB
);
2773 DiskSize
= DiskSize
/ 1048576;
2774 DiskUnit
= MUIGetString(STRING_MB
);
2777 /* Adjust partition size */
2778 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2779 if (PartSize
>= 10737418240) /* 10 GB */
2781 PartSize
= PartSize
/ 1073741824;
2782 PartUnit
= MUIGetString(STRING_GB
);
2786 PartSize
= PartSize
/ 1048576;
2787 PartUnit
= MUIGetString(STRING_MB
);
2790 /* Adjust partition type */
2791 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2793 ARRAYSIZE(PartTypeString
));
2795 if (PartEntry
->AutoCreate
!= FALSE
)
2797 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2800 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2801 PartEntry
->PartitionNumber
,
2807 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2808 DiskEntry
->DiskNumber
,
2814 &DiskEntry
->DriverName
,
2815 DiskEntry
->NoMbr
? "GPT" : "MBR");
2817 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2819 PartEntry
->AutoCreate
= FALSE
;
2821 else if (PartEntry
->New
!= FALSE
)
2823 switch (FormatState
)
2825 case FormatSystemPartition
:
2826 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2829 case FormatInstallPartition
:
2830 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2833 case FormatOtherPartition
:
2834 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2841 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2845 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2847 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2849 CONSOLE_PrintTextXY(8, 10,
2850 MUIGetString(STRING_HDDINFOUNK4
),
2851 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2852 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2853 PartEntry
->PartitionType
,
2859 CONSOLE_PrintTextXY(8, 10,
2861 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2862 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2868 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2869 DiskEntry
->DiskNumber
,
2875 &DiskEntry
->DriverName
,
2876 DiskEntry
->NoMbr
? "GPT" : "MBR");
2879 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2881 if (FileSystemList
== NULL
)
2883 /* Create the file system list, and by default select the "FAT" file system */
2884 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2885 if (FileSystemList
== NULL
)
2887 /* FIXME: show an error dialog */
2892 if (RepairUpdateFlag
)
2894 return CHECK_FILE_SYSTEM_PAGE
;
2895 //return SELECT_PARTITION_PAGE;
2898 if (IsUnattendedSetup
)
2900 if (UnattendFormatPartition
)
2903 * We use whatever currently selected file system we have
2904 * (by default, this is "FAT", as per the initialization
2905 * performed above). Note that it may be interesting to specify
2906 * which file system to use in unattended installations, in the
2907 * txtsetup.sif file.
2909 return FORMAT_PARTITION_PAGE
;
2912 return CHECK_FILE_SYSTEM_PAGE
;
2915 DrawFileSystemList(FileSystemList
);
2919 CONSOLE_ConInKey(Ir
);
2921 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2922 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2924 if (ConfirmQuit(Ir
) != FALSE
)
2929 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2930 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2932 FormatState
= Start
;
2933 return SELECT_PARTITION_PAGE
;
2935 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2936 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2938 ScrollDownFileSystemList(FileSystemList
);
2940 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2941 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2943 ScrollUpFileSystemList(FileSystemList
);
2945 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2947 if (!FileSystemList
->Selected
->FileSystem
)
2948 return SELECT_FILE_SYSTEM_PAGE
;
2950 return FORMAT_PARTITION_PAGE
;
2954 FormatState
= PreviousFormatState
;
2956 return SELECT_FILE_SYSTEM_PAGE
;
2961 * Displays the FormatPartitionPage.
2964 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2965 * SelectPartitionPage (At once)
2969 * Sets PartitionList->CurrentPartition->FormatState
2970 * Sets DestinationRootPath
2973 * Number of the next page.
2976 FormatPartitionPage(PINPUT_RECORD Ir
)
2978 UNICODE_STRING PartitionRootPath
;
2979 WCHAR PathBuffer
[MAX_PATH
];
2980 PDISKENTRY DiskEntry
;
2981 PPARTENTRY PartEntry
;
2982 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2988 PPARTITION_INFORMATION PartitionInfo
;
2991 DPRINT("FormatPartitionPage()\n");
2993 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2995 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2997 /* FIXME: show an error dialog */
3001 PartEntry
= TempPartition
;
3002 DiskEntry
= PartEntry
->DiskEntry
;
3004 SelectedFileSystem
= FileSystemList
->Selected
;
3008 if (!IsUnattendedSetup
)
3010 CONSOLE_ConInKey(Ir
);
3013 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3014 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3016 if (ConfirmQuit(Ir
) != FALSE
)
3021 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3023 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3025 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3027 /* FIXME: show an error dialog */
3032 CONSOLE_PrintTextXY(6, 12,
3033 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3034 DiskEntry
->Cylinders
,
3035 DiskEntry
->TracksPerCylinder
,
3036 DiskEntry
->SectorsPerTrack
,
3037 DiskEntry
->BytesPerSector
,
3038 DiskEntry
->Dirty
? '*' : ' ');
3042 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3044 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3046 CONSOLE_PrintTextXY(6, Line
,
3047 "%2u: %2lu %c %12I64u %12I64u %02x",
3049 PartitionInfo
->PartitionNumber
,
3050 PartitionInfo
->BootIndicator
? 'A' : '-',
3051 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3052 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3053 PartitionInfo
->PartitionType
);
3058 /* Commit the partition changes to the disk */
3059 if (!WritePartitionsToDisk(PartitionList
))
3061 DPRINT("WritePartitionsToDisk() failed\n");
3062 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3066 /* Set PartitionRootPath */
3067 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3068 L
"\\Device\\Harddisk%lu\\Partition%lu",
3069 DiskEntry
->DiskNumber
,
3070 PartEntry
->PartitionNumber
);
3071 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3072 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3074 /* Format the partition */
3075 if (SelectedFileSystem
->FileSystem
)
3077 Status
= FormatPartition(&PartitionRootPath
,
3078 SelectedFileSystem
);
3079 if (!NT_SUCCESS(Status
))
3081 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3082 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3086 PartEntry
->FormatState
= Formatted
;
3087 // PartEntry->FileSystem = FileSystem;
3088 PartEntry
->New
= FALSE
;
3092 CONSOLE_SetStatusText(" Done. Press any key ...");
3093 CONSOLE_ConInKey(Ir
);
3096 return SELECT_FILE_SYSTEM_PAGE
;
3100 return FORMAT_PARTITION_PAGE
;
3105 * Displays the CheckFileSystemPage.
3108 * InstallDirectoryPage (At once)
3112 * Inits or reloads FileSystemList
3115 * Number of the next page.
3118 CheckFileSystemPage(PINPUT_RECORD Ir
)
3120 PFILE_SYSTEM CurrentFileSystem
;
3121 UNICODE_STRING PartitionRootPath
;
3122 WCHAR PathBuffer
[MAX_PATH
];
3123 CHAR Buffer
[MAX_PATH
];
3124 PDISKENTRY DiskEntry
;
3125 PPARTENTRY PartEntry
;
3128 if (PartitionList
== NULL
)
3130 /* FIXME: show an error dialog */
3134 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3136 return INSTALL_DIRECTORY_PAGE
;
3139 /* Set PartitionRootPath */
3140 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3141 L
"\\Device\\Harddisk%lu\\Partition%lu",
3142 DiskEntry
->DiskNumber
,
3143 PartEntry
->PartitionNumber
);
3144 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3145 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3147 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3149 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3151 CurrentFileSystem
= PartEntry
->FileSystem
;
3152 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3153 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3155 /* HACK: Do not try to check a partition with an unknown filesystem */
3156 if (CurrentFileSystem
== NULL
)
3158 PartEntry
->NeedsCheck
= FALSE
;
3159 return CHECK_FILE_SYSTEM_PAGE
;
3162 if (CurrentFileSystem
->ChkdskFunc
== NULL
)
3165 "Setup is currently unable to check a partition formatted in %S.\n"
3167 " \x07 Press ENTER to continue Setup.\n"
3168 " \x07 Press F3 to quit Setup.",
3169 CurrentFileSystem
->FileSystemName
);
3172 MUIGetString(STRING_QUITCONTINUE
),
3173 NULL
, POPUP_WAIT_NONE
);
3177 CONSOLE_ConInKey(Ir
);
3179 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3180 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3182 if (ConfirmQuit(Ir
))
3185 return CHECK_FILE_SYSTEM_PAGE
;
3187 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3189 PartEntry
->NeedsCheck
= FALSE
;
3190 return CHECK_FILE_SYSTEM_PAGE
;
3196 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3197 if (!NT_SUCCESS(Status
))
3199 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3200 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3201 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3202 "(Status 0x%08lx).\n", Status
);
3204 // MUIGetString(STRING_REBOOTCOMPUTER),
3205 MUIGetString(STRING_CONTINUE
),
3206 Ir
, POPUP_WAIT_ENTER
);
3208 // return QUIT_PAGE;
3211 PartEntry
->NeedsCheck
= FALSE
;
3212 return CHECK_FILE_SYSTEM_PAGE
;
3218 BuildInstallPaths(PWSTR InstallDir
,
3219 PDISKENTRY DiskEntry
,
3220 PPARTENTRY PartEntry
)
3222 WCHAR PathBuffer
[MAX_PATH
];
3224 /* Create 'InstallPath' string */
3225 RtlFreeUnicodeString(&InstallPath
);
3226 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3228 /* Create 'DestinationRootPath' string */
3229 RtlFreeUnicodeString(&DestinationRootPath
);
3230 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3231 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3232 DiskEntry
->DiskNumber
,
3233 PartEntry
->PartitionNumber
);
3234 RtlCreateUnicodeString(&DestinationRootPath
, PathBuffer
);
3235 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath
);
3237 /* Create 'DestinationPath' string */
3238 RtlFreeUnicodeString(&DestinationPath
);
3239 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3240 DestinationRootPath
.Buffer
, InstallDir
);
3241 RtlCreateUnicodeString(&DestinationPath
, PathBuffer
);
3243 /* Create 'DestinationArcPath' */
3244 RtlFreeUnicodeString(&DestinationArcPath
);
3245 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3246 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3247 DiskEntry
->BiosDiskNumber
,
3248 PartEntry
->PartitionNumber
);
3249 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3250 RtlCreateUnicodeString(&DestinationArcPath
, PathBuffer
);
3252 /* Initialize DestinationDriveLetter */
3253 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3258 * Displays the InstallDirectoryPage.
3261 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3265 * Number of the next page.
3268 InstallDirectoryPage(PINPUT_RECORD Ir
)
3270 PDISKENTRY DiskEntry
;
3271 PPARTENTRY PartEntry
;
3272 WCHAR InstallDir
[51];
3276 /* We do not need the filesystem list any more */
3277 if (FileSystemList
!= NULL
)
3279 DestroyFileSystemList(FileSystemList
);
3280 FileSystemList
= NULL
;
3283 if (PartitionList
== NULL
||
3284 PartitionList
->CurrentDisk
== NULL
||
3285 PartitionList
->CurrentPartition
== NULL
)
3287 /* FIXME: show an error dialog */
3291 DiskEntry
= PartitionList
->CurrentDisk
;
3292 PartEntry
= PartitionList
->CurrentPartition
;
3294 if (IsUnattendedSetup
)
3296 if (!IsValidPath(UnattendInstallationDirectory
))
3298 /* FIXME: Log the error? */
3302 BuildInstallPaths(UnattendInstallationDirectory
,
3306 return PREPARE_COPY_PAGE
;
3309 wcscpy(InstallDir
, L
"\\ReactOS");
3311 Length
= wcslen(InstallDir
);
3313 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3314 CONSOLE_SetCursorXY(8 + Pos
, 11);
3315 CONSOLE_SetCursorType(TRUE
, TRUE
);
3316 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3320 CONSOLE_ConInKey(Ir
);
3322 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3323 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3325 CONSOLE_SetCursorType(TRUE
, FALSE
);
3327 if (ConfirmQuit(Ir
) != FALSE
)
3330 CONSOLE_SetCursorType(TRUE
, TRUE
);
3333 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3334 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3338 memmove(&InstallDir
[Pos
],
3339 &InstallDir
[Pos
+ 1],
3340 (Length
- Pos
- 1) * sizeof(WCHAR
));
3341 InstallDir
[Length
- 1] = UNICODE_NULL
;
3344 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3345 CONSOLE_SetCursorXY(8 + Pos
, 11);
3348 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3349 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3352 CONSOLE_SetCursorXY(8 + Pos
, 11);
3354 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3355 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3358 CONSOLE_SetCursorXY(8 + Pos
, 11);
3360 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3361 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3366 CONSOLE_SetCursorXY(8 + Pos
, 11);
3369 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3370 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3375 CONSOLE_SetCursorXY(8 + Pos
, 11);
3378 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3380 CONSOLE_SetCursorType(TRUE
, FALSE
);
3383 * Check for the validity of the installation directory and pop up
3384 * an error if it is not the case. Then the user can fix its input.
3386 if (!IsValidPath(InstallDir
))
3388 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3389 return INSTALL_DIRECTORY_PAGE
;
3392 BuildInstallPaths(InstallDir
,
3396 return PREPARE_COPY_PAGE
;
3398 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3403 memmove(&InstallDir
[Pos
- 1],
3405 (Length
- Pos
) * sizeof(WCHAR
));
3406 InstallDir
[Length
- 1] = UNICODE_NULL
;
3410 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3411 CONSOLE_SetCursorXY(8 + Pos
, 11);
3414 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3418 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3419 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3422 memmove(&InstallDir
[Pos
+ 1],
3424 (Length
- Pos
) * sizeof(WCHAR
));
3425 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3426 InstallDir
[Pos
] = c
;
3430 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3431 CONSOLE_SetCursorXY(8 + Pos
, 11);
3437 return INSTALL_DIRECTORY_PAGE
;
3442 AddSectionToCopyQueueCab(HINF InfFile
,
3444 PWCHAR SourceCabinet
,
3445 PCUNICODE_STRING DestinationPath
,
3448 INFCONTEXT FilesContext
;
3449 INFCONTEXT DirContext
;
3451 PWCHAR FileKeyValue
;
3453 PWCHAR TargetFileName
;
3456 * This code enumerates the list of files in reactos.dff / reactos.inf
3457 * that need to be extracted from reactos.cab and be installed in their
3458 * respective directories.
3461 /* Search for the SectionName section */
3462 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3465 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3466 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3471 * Enumerate the files in the section and add them to the file queue.
3475 /* Get source file name and target directory id */
3476 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3478 /* FIXME: Handle error! */
3479 DPRINT1("INF_GetData() failed\n");
3483 /* Get optional target file name */
3484 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3485 TargetFileName
= NULL
;
3487 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3489 /* Lookup target directory */
3490 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3492 /* FIXME: Handle error! */
3493 DPRINT1("SetupFindFirstLine() failed\n");
3497 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3499 /* FIXME: Handle error! */
3500 DPRINT1("INF_GetData() failed\n");
3504 if (!SetupQueueCopy(SetupFileQueue
,
3506 SourceRootPath
.Buffer
,
3507 SourceRootDir
.Buffer
,
3512 /* FIXME: Handle error! */
3513 DPRINT1("SetupQueueCopy() failed\n");
3515 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3522 AddSectionToCopyQueue(HINF InfFile
,
3524 PWCHAR SourceCabinet
,
3525 PCUNICODE_STRING DestinationPath
,
3528 INFCONTEXT FilesContext
;
3529 INFCONTEXT DirContext
;
3531 PWCHAR FileKeyValue
;
3533 PWCHAR TargetFileName
;
3534 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3537 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3540 * This code enumerates the list of files in txtsetup.sif
3541 * that need to be installed in their respective directories.
3544 /* Search for the SectionName section */
3545 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3548 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3549 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3554 * Enumerate the files in the section and add them to the file queue.
3558 /* Get source file name and target directory id */
3559 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3561 /* FIXME: Handle error! */
3562 DPRINT1("INF_GetData() failed\n");
3566 /* Get target directory id */
3567 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3569 /* FIXME: Handle error! */
3570 DPRINT1("INF_GetData() failed\n");
3574 /* Get optional target file name */
3575 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3576 TargetFileName
= NULL
;
3577 else if (!*TargetFileName
)
3578 TargetFileName
= NULL
;
3580 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3582 /* Lookup target directory */
3583 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3585 /* FIXME: Handle error! */
3586 DPRINT1("SetupFindFirstLine() failed\n");
3590 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3592 /* FIXME: Handle error! */
3593 DPRINT1("INF_GetData() failed\n");
3597 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3599 /* Installation path */
3600 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3602 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3603 SourceRootDir
.Buffer
);
3605 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3607 else if (DirKeyValue
[0] == L
'\\')
3610 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3612 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3615 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3617 else // if (DirKeyValue[0] != L'\\')
3619 /* Path relative to the installation path */
3620 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3622 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3623 SourceRootDir
.Buffer
, DirKeyValue
);
3625 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3628 if (!SetupQueueCopy(SetupFileQueue
,
3630 SourceRootPath
.Buffer
,
3631 CompleteOrigDirName
,
3636 /* FIXME: Handle error! */
3637 DPRINT1("SetupQueueCopy() failed\n");
3639 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3646 PrepareCopyPageInfFile(HINF InfFile
,
3647 PWCHAR SourceCabinet
,
3651 INFCONTEXT DirContext
;
3652 PWCHAR AdditionalSectionName
= NULL
;
3654 WCHAR PathBuffer
[MAX_PATH
];
3656 /* Add common files */
3657 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &DestinationPath
, Ir
))
3660 /* Add specific files depending of computer type */
3661 if (SourceCabinet
== NULL
)
3663 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3666 if (AdditionalSectionName
)
3668 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &DestinationPath
, Ir
))
3673 /* Create directories */
3677 * Copying files to DestinationRootPath should be done from within
3678 * the SystemPartitionFiles section.
3679 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3680 * For installing to DestinationPath specify just '\' .
3683 /* Get destination path */
3684 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), DestinationPath
.Buffer
);
3686 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3688 /* Create the install directory */
3689 Status
= SetupCreateDirectory(PathBuffer
);
3690 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3692 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3693 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3697 /* Search for the 'Directories' section */
3698 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3702 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3706 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3712 /* Enumerate the directory values and create the subdirectories */
3715 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3721 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3723 /* Installation path */
3724 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3726 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3727 DestinationPath
.Buffer
);
3729 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3731 else if (DirKeyValue
[0] == L
'\\')
3734 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3736 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3737 DestinationRootPath
.Buffer
, DirKeyValue
);
3739 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3741 Status
= SetupCreateDirectory(PathBuffer
);
3742 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3744 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3745 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3749 else // if (DirKeyValue[0] != L'\\')
3751 /* Path relative to the installation path */
3752 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3754 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3755 DestinationPath
.Buffer
, DirKeyValue
);
3757 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3759 Status
= SetupCreateDirectory(PathBuffer
);
3760 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3762 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3763 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3767 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3774 * Displays the PrepareCopyPage.
3777 * FileCopyPage(At once)
3781 * Inits SetupFileQueue
3782 * Calls PrepareCopyPageInfFile
3785 * Number of the next page.
3788 PrepareCopyPage(PINPUT_RECORD Ir
)
3791 WCHAR PathBuffer
[MAX_PATH
];
3792 INFCONTEXT CabinetsContext
;
3798 MUIDisplayPage(PREPARE_COPY_PAGE
);
3800 /* Create the file queue */
3801 SetupFileQueue
= SetupOpenFileQueue();
3802 if (SetupFileQueue
== NULL
)
3804 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3808 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3810 /* FIXME: show an error dialog */
3814 /* Search for the 'Cabinets' section */
3815 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3817 return FILE_COPY_PAGE
;
3821 * Enumerate the directory values in the 'Cabinets'
3822 * section and parse their inf files.
3826 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3829 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3830 SourcePath
.Buffer
, KeyValue
);
3832 CabinetInitialize();
3833 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3834 CabinetSetCabinetName(PathBuffer
);
3836 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3838 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3840 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3841 if (InfFileData
== NULL
)
3843 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3849 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3850 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3854 InfHandle
= INF_OpenBufferedFileA((CHAR
*) InfFileData
,
3861 if (InfHandle
== INVALID_HANDLE_VALUE
)
3863 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3869 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3871 /* FIXME: show an error dialog */
3874 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3876 return FILE_COPY_PAGE
;
3882 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3885 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3887 /* Get the memory information from the system */
3888 NtQuerySystemInformation(SystemPerformanceInformation
,
3893 /* Check if this is initial setup */
3896 /* Set maximum limits to be total RAM pages */
3897 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3898 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3899 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3902 /* Set current values */
3903 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3904 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3905 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3911 FileCopyCallback(PVOID Context
,
3916 PCOPYCONTEXT CopyContext
;
3918 CopyContext
= (PCOPYCONTEXT
)Context
;
3920 switch (Notification
)
3922 case SPFILENOTIFY_STARTSUBQUEUE
:
3923 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3924 ProgressSetStepCount(CopyContext
->ProgressBar
,
3925 CopyContext
->TotalOperations
);
3926 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3929 case SPFILENOTIFY_STARTCOPY
:
3930 /* Display copy message */
3931 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3932 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3935 case SPFILENOTIFY_ENDCOPY
:
3936 CopyContext
->CompletedOperations
++;
3938 /* SYSREG checkpoint */
3939 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3940 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3942 ProgressNextStep(CopyContext
->ProgressBar
);
3943 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3952 * Displays the FileCopyPage.
3955 * RegistryPage(At once)
3958 * Calls SetupCommitFileQueueW
3959 * Calls SetupCloseFileQueue
3962 * Number of the next page.
3965 FileCopyPage(PINPUT_RECORD Ir
)
3967 COPYCONTEXT CopyContext
;
3968 unsigned int mem_bar_width
;
3970 MUIDisplayPage(FILE_COPY_PAGE
);
3972 /* Create context for the copy process */
3973 CopyContext
.DestinationRootPath
= DestinationRootPath
.Buffer
;
3974 CopyContext
.InstallPath
= InstallPath
.Buffer
;
3975 CopyContext
.TotalOperations
= 0;
3976 CopyContext
.CompletedOperations
= 0;
3978 /* Create the progress bar as well */
3979 CopyContext
.ProgressBar
= CreateProgressBar(13,
3986 MUIGetString(STRING_SETUPCOPYINGFILES
));
3988 // fit memory bars to screen width, distribute them uniform
3989 mem_bar_width
= (xScreen
- 26) / 5;
3990 mem_bar_width
-= mem_bar_width
% 2; // make even
3991 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3992 /* Create the paged pool progress bar */
3993 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4002 /* Create the non paged pool progress bar */
4003 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4005 (xScreen
/ 2) + (mem_bar_width
/ 2),
4007 (xScreen
/ 2)- (mem_bar_width
/ 2),
4012 /* Create the global memory progress bar */
4013 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4017 xScreen
- 13 - mem_bar_width
,
4022 /* Do the file copying */
4023 SetupCommitFileQueueW(NULL
,
4028 /* If we get here, we're done, so cleanup the queue and progress bar */
4029 SetupCloseFileQueue(SetupFileQueue
);
4030 DestroyProgressBar(CopyContext
.ProgressBar
);
4031 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4032 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4033 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4035 /* Go display the next page */
4036 return REGISTRY_PAGE
;
4041 * Displays the RegistryPage.
4044 * SuccessPage (if RepairUpdate)
4045 * BootLoaderPage (default)
4049 * Calls RegInitializeRegistry
4050 * Calls ImportRegistryFile
4051 * Calls SetDefaultPagefile
4052 * Calls SetMountedDeviceValues
4055 * Number of the next page.
4058 RegistryPage(PINPUT_RECORD Ir
)
4060 INFCONTEXT InfContext
;
4067 MUIDisplayPage(REGISTRY_PAGE
);
4069 if (RepairUpdateFlag
)
4072 DPRINT1("FIXME: Updating / repairing the registry is NOT implemented yet!\n");
4073 return SUCCESS_PAGE
;
4076 /* Initialize the registry and setup the default installation hives */
4077 Status
= RegInitializeRegistry(&DestinationPath
);
4078 if (!NT_SUCCESS(Status
))
4080 DPRINT1("RegInitializeRegistry() failed\n");
4081 /********** HACK!!!!!!!!!!! **********/
4082 if (Status
== STATUS_NOT_IMPLEMENTED
)
4084 /* The hack was called, display its corresponding error */
4085 MUIDisplayError(ERROR_INITIALIZE_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4088 /*************************************/
4090 /* Something else (correct) failed */
4091 MUIDisplayError(ERROR_CREATE_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4096 /* Update registry */
4097 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE
));
4099 if (!SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
))
4101 DPRINT1("SetupFindFirstLine() failed\n");
4102 RegCleanupRegistry();
4103 MUIDisplayError(ERROR_FIND_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4109 INF_GetDataField(&InfContext
, 0, &Action
);
4110 INF_GetDataField(&InfContext
, 1, &File
);
4111 INF_GetDataField(&InfContext
, 2, &Section
);
4113 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
4118 if (!_wcsicmp(Action
, L
"AddReg"))
4122 else if (!_wcsicmp(Action
, L
"DelReg"))
4131 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE
), File
);
4133 if (!ImportRegistryFile(File
, Section
, LanguageId
, Delete
))
4135 DPRINT1("Importing %S failed\n", File
);
4137 RegCleanupRegistry();
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 RegCleanupRegistry();
4148 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4152 /* Set the locale */
4153 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE
));
4154 if (!ProcessLocaleRegistry(LanguageList
))
4156 RegCleanupRegistry();
4157 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4161 /* Add keyboard layouts */
4162 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS
));
4163 if (!AddKeyboardLayouts())
4165 RegCleanupRegistry();
4166 MUIDisplayError(ERROR_ADDING_KBLAYOUTS
, Ir
, POPUP_WAIT_ENTER
);
4171 if (!SetGeoID(MUIGetGeoID()))
4173 RegCleanupRegistry();
4174 MUIDisplayError(ERROR_UPDATE_GEOID
, Ir
, POPUP_WAIT_ENTER
);
4178 if (!IsUnattendedSetup
)
4180 /* Update keyboard layout settings */
4181 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE
));
4182 if (!ProcessKeyboardLayoutRegistry(LayoutList
))
4184 RegCleanupRegistry();
4185 MUIDisplayError(ERROR_UPDATE_KBSETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4190 /* Add codepage information to registry */
4191 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE
));
4194 RegCleanupRegistry();
4195 MUIDisplayError(ERROR_ADDING_CODEPAGE
, Ir
, POPUP_WAIT_ENTER
);
4199 /* Set the default pagefile entry */
4200 SetDefaultPagefile(DestinationDriveLetter
);
4202 /* Update the mounted devices list */
4203 SetMountedDeviceValues(PartitionList
);
4206 // TODO: Unload all the registry stuff, perform cleanup,
4207 // and copy the created hive files into .sav ones.
4209 RegCleanupRegistry();
4211 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4213 return BOOT_LOADER_PAGE
;
4218 * Displays the BootLoaderPage.
4221 * SuccessPage (if RepairUpdate)
4222 * BootLoaderHarddiskMbrPage
4223 * BootLoaderHarddiskVbrPage
4224 * BootLoaderFloppyPage
4229 * Calls RegInitializeRegistry
4230 * Calls ImportRegistryFile
4231 * Calls SetDefaultPagefile
4232 * Calls SetMountedDeviceValues
4235 * Number of the next page.
4238 BootLoaderPage(PINPUT_RECORD Ir
)
4240 UCHAR PartitionType
;
4241 BOOLEAN InstallOnFloppy
;
4243 WCHAR PathBuffer
[MAX_PATH
];
4245 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4247 RtlFreeUnicodeString(&SystemRootPath
);
4248 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4249 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4250 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4251 PartitionList
->SystemPartition
->PartitionNumber
);
4252 RtlCreateUnicodeString(&SystemRootPath
, PathBuffer
);
4253 DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath
);
4255 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4257 if (IsUnattendedSetup
)
4259 if (UnattendMBRInstallType
== 0) /* skip MBR installation */
4261 return SUCCESS_PAGE
;
4263 else if (UnattendMBRInstallType
== 1) /* install on floppy */
4265 return BOOT_LOADER_FLOPPY_PAGE
;
4269 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4271 DPRINT("Error: system partition invalid (unused)\n");
4272 InstallOnFloppy
= TRUE
;
4274 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4276 /* OS/2 boot manager partition */
4277 DPRINT("Found OS/2 boot manager partition\n");
4278 InstallOnFloppy
= TRUE
;
4280 else if (PartitionType
== PARTITION_EXT2
)
4282 /* Linux EXT2 partition */
4283 DPRINT("Found Linux EXT2 partition\n");
4284 InstallOnFloppy
= FALSE
;
4286 else if (PartitionType
== PARTITION_IFS
)
4288 /* NTFS partition */
4289 DPRINT("Found NTFS partition\n");
4291 // FIXME: Make it FALSE when we'll support NTFS installation!
4292 InstallOnFloppy
= TRUE
;
4294 else if ((PartitionType
== PARTITION_FAT_12
) ||
4295 (PartitionType
== PARTITION_FAT_16
) ||
4296 (PartitionType
== PARTITION_HUGE
) ||
4297 (PartitionType
== PARTITION_XINT13
) ||
4298 (PartitionType
== PARTITION_FAT32
) ||
4299 (PartitionType
== PARTITION_FAT32_XINT13
))
4301 DPRINT("Found FAT partition\n");
4302 InstallOnFloppy
= FALSE
;
4306 /* Unknown partition */
4307 DPRINT("Unknown partition found\n");
4308 InstallOnFloppy
= TRUE
;
4311 if (InstallOnFloppy
!= FALSE
)
4313 return BOOT_LOADER_FLOPPY_PAGE
;
4316 /* Unattended install on hdd? */
4317 if (IsUnattendedSetup
&& UnattendMBRInstallType
== 2)
4319 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4322 MUIDisplayPage(BOOT_LOADER_PAGE
);
4323 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4327 CONSOLE_ConInKey(Ir
);
4329 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4330 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4332 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4341 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4343 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4344 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4346 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4355 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4357 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4358 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4360 if (ConfirmQuit(Ir
) != FALSE
)
4365 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4369 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4371 else if (Line
== 13)
4373 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4375 else if (Line
== 14)
4377 return BOOT_LOADER_FLOPPY_PAGE
;
4379 else if (Line
== 15)
4381 return SUCCESS_PAGE
;
4384 return BOOT_LOADER_PAGE
;
4388 return BOOT_LOADER_PAGE
;
4393 * Displays the BootLoaderFloppyPage.
4396 * SuccessPage (At once)
4400 * Calls InstallFatBootcodeToFloppy()
4403 * Number of the next page.
4406 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4410 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4412 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4416 CONSOLE_ConInKey(Ir
);
4418 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4419 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4421 if (ConfirmQuit(Ir
) != FALSE
)
4426 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4428 if (DoesPathExist(NULL
, L
"\\Device\\Floppy0\\") == FALSE
)
4430 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4431 return BOOT_LOADER_FLOPPY_PAGE
;
4434 Status
= InstallFatBootcodeToFloppy(&SourceRootPath
, &DestinationArcPath
);
4435 if (!NT_SUCCESS(Status
))
4437 /* Print error message */
4438 return BOOT_LOADER_FLOPPY_PAGE
;
4441 return SUCCESS_PAGE
;
4445 return BOOT_LOADER_FLOPPY_PAGE
;
4450 * Displays the BootLoaderHarddiskVbrPage.
4453 * SuccessPage (At once)
4457 * Calls InstallVBRToPartition()
4460 * Number of the next page.
4463 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4467 Status
= InstallVBRToPartition(&SystemRootPath
,
4469 &DestinationArcPath
,
4470 PartitionList
->SystemPartition
->PartitionType
);
4471 if (!NT_SUCCESS(Status
))
4473 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4477 return SUCCESS_PAGE
;
4482 * Displays the BootLoaderHarddiskMbrPage.
4485 * SuccessPage (At once)
4489 * Calls InstallVBRToPartition()
4490 * Calls InstallMbrBootCodeToDisk()
4493 * Number of the next page.
4496 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4499 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4500 WCHAR SourceMbrPathBuffer
[MAX_PATH
];
4501 WCHAR DstPath
[MAX_PATH
];
4503 /* Step 1: Write the VBR */
4504 Status
= InstallVBRToPartition(&SystemRootPath
,
4506 &DestinationArcPath
,
4507 PartitionList
->SystemPartition
->PartitionType
);
4508 if (!NT_SUCCESS(Status
))
4510 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4514 /* Step 2: Write the MBR */
4515 StringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4516 L
"\\Device\\Harddisk%d\\Partition0",
4517 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4519 CombinePaths(SourceMbrPathBuffer
, ARRAYSIZE(SourceMbrPathBuffer
), 2, SourceRootPath
.Buffer
, L
"\\loader\\dosmbr.bin");
4521 if (IsThereAValidBootSector(DestinationDevicePathBuffer
))
4523 /* Save current MBR */
4524 CombinePaths(DstPath
, ARRAYSIZE(DstPath
), 2, SystemRootPath
.Buffer
, L
"mbr.old");
4526 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer
, DstPath
);
4527 Status
= SaveBootSector(DestinationDevicePathBuffer
, DstPath
, sizeof(PARTITION_SECTOR
));
4528 if (!NT_SUCCESS(Status
))
4530 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status
);
4531 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4535 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4536 SourceMbrPathBuffer
, DestinationDevicePathBuffer
);
4537 Status
= InstallMbrBootCodeToDisk(SourceMbrPathBuffer
,
4538 DestinationDevicePathBuffer
);
4539 if (!NT_SUCCESS(Status
))
4541 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4543 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4547 return SUCCESS_PAGE
;
4552 * @name ProgressTimeOutStringHandler
4554 * Handles the generation (displaying) of the timeout
4555 * countdown to the screen dynamically.
4558 * A pointer to a progress bar.
4560 * @param AlwaysUpdate
4561 * Constantly update the progress bar (boolean type).
4564 * A pointer to a string buffer.
4566 * @param cchBufferSize
4567 * The buffer's size in number of characters.
4570 * TRUE or FALSE on function termination.
4575 ProgressTimeOutStringHandler(
4576 IN PPROGRESSBAR Bar
,
4577 IN BOOLEAN AlwaysUpdate
,
4579 IN SIZE_T cchBufferSize
)
4581 ULONG OldProgress
= Bar
->Progress
;
4583 if (Bar
->StepCount
== 0)
4589 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4592 /* Build the progress string if it has changed */
4593 if (Bar
->ProgressFormatText
&&
4594 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4596 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4597 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4606 * @name ProgressCountdown
4608 * Displays and draws a red-coloured progress bar with a countdown.
4609 * When the timeout is reached, the flush page is displayed for reboot.
4612 * A pointer to an input keyboard record.
4615 * Initial countdown value in seconds.
4623 IN PINPUT_RECORD Ir
,
4627 ULONG StartTime
, BarWidth
, TimerDiv
;
4629 LONG TimerValue
, OldTimerValue
;
4630 LARGE_INTEGER Timeout
;
4631 PPROGRESSBAR ProgressBar
;
4632 BOOLEAN RefreshProgress
= TRUE
;
4634 /* Bail out if the timeout is already zero */
4638 /* Create the timeout progress bar and set it up */
4639 ProgressBar
= CreateProgressBarEx(13,
4646 FOREGROUND_RED
| BACKGROUND_BLUE
,
4649 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4650 ProgressTimeOutStringHandler
);
4652 BarWidth
= max(1, ProgressBar
->Width
);
4653 TimerValue
= TimeOut
* BarWidth
;
4654 ProgressSetStepCount(ProgressBar
, TimerValue
);
4656 StartTime
= NtGetTickCount();
4659 TimerDiv
= 1000 / BarWidth
;
4660 TimerDiv
= max(1, TimerDiv
);
4661 OldTimerValue
= TimerValue
;
4664 /* Decrease the timer */
4667 * Compute how much time the previous operations took.
4668 * This allows us in particular to take account for any time
4669 * elapsed if something slowed down.
4671 TimeElapsed
= NtGetTickCount() - StartTime
;
4672 if (TimeElapsed
>= TimerDiv
)
4674 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4675 TimeElapsed
/= TimerDiv
;
4676 StartTime
+= (TimerDiv
* TimeElapsed
);
4678 if (TimeElapsed
<= TimerValue
)
4679 TimerValue
-= TimeElapsed
;
4683 RefreshProgress
= TRUE
;
4686 if (RefreshProgress
)
4688 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4689 RefreshProgress
= FALSE
;
4692 /* Stop when the timer reaches zero */
4693 if (TimerValue
<= 0)
4696 /* Check for user key presses */
4699 * If the timer is used, use a passive wait of maximum 1 second
4700 * while monitoring for incoming console input events, so that
4701 * we are still able to display the timing count.
4704 /* Wait a maximum of 1 second for input events */
4705 TimeElapsed
= NtGetTickCount() - StartTime
;
4706 if (TimeElapsed
< TimerDiv
)
4708 /* Convert the time to NT Format */
4709 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4710 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4714 Status
= STATUS_TIMEOUT
;
4717 /* Check whether the input event has been signaled, or a timeout happened */
4718 if (Status
== STATUS_TIMEOUT
)
4722 if (Status
!= STATUS_WAIT_0
)
4724 /* An error happened, bail out */
4725 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4729 /* Check for an ENTER key press */
4730 while (CONSOLE_ConInKeyPeek(Ir
))
4732 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4734 /* Found it, stop waiting */
4741 /* Destroy the progress bar and quit */
4742 DestroyProgressBar(ProgressBar
);
4747 * Displays the QuitPage.
4750 * FlushPage (At once)
4756 * Number of the next page.
4759 QuitPage(PINPUT_RECORD Ir
)
4761 MUIDisplayPage(QUIT_PAGE
);
4763 /* Destroy the partition list */
4764 if (PartitionList
!= NULL
)
4766 DestroyPartitionList(PartitionList
);
4767 PartitionList
= NULL
;
4769 TempPartition
= NULL
;
4770 FormatState
= Start
;
4772 /* Destroy the filesystem list */
4773 if (FileSystemList
!= NULL
)
4775 DestroyFileSystemList(FileSystemList
);
4776 FileSystemList
= NULL
;
4779 /* Destroy the computer settings list */
4780 if (ComputerList
!= NULL
)
4782 DestroyGenericList(ComputerList
, TRUE
);
4783 ComputerList
= NULL
;
4786 /* Destroy the display settings list */
4787 if (DisplayList
!= NULL
)
4789 DestroyGenericList(DisplayList
, TRUE
);
4793 /* Destroy the keyboard settings list */
4794 if (KeyboardList
!= NULL
)
4796 DestroyGenericList(KeyboardList
, TRUE
);
4797 KeyboardList
= NULL
;
4800 /* Destroy the keyboard layout list */
4801 if (LayoutList
!= NULL
)
4803 DestroyGenericList(LayoutList
, TRUE
);
4807 /* Destroy the languages list */
4808 if (LanguageList
!= NULL
)
4810 DestroyGenericList(LanguageList
, FALSE
);
4811 LanguageList
= NULL
;
4814 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4816 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4817 ProgressCountdown(Ir
, 15);
4823 * Displays the SuccessPage.
4826 * FlushPage (At once)
4832 * Number of the next page.
4835 SuccessPage(PINPUT_RECORD Ir
)
4837 MUIDisplayPage(SUCCESS_PAGE
);
4839 if (IsUnattendedSetup
)
4842 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4843 ProgressCountdown(Ir
, 15);
4849 * Displays the FlushPage.
4852 * RebootPage (At once)
4855 * Number of the next page.
4858 FlushPage(PINPUT_RECORD Ir
)
4860 MUIDisplayPage(FLUSH_PAGE
);
4866 PnpEventThread(IN LPVOID lpParameter
);
4870 * The start routine and page management
4880 InfSetHeap(ProcessHeap
);
4882 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4883 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4884 if (!NT_SUCCESS(Status
))
4885 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4887 /* Create the PnP thread in suspended state */
4888 Status
= RtlCreateUserThread(NtCurrentProcess(),
4898 if (!NT_SUCCESS(Status
))
4899 hPnpThread
= INVALID_HANDLE_VALUE
;
4901 if (!CONSOLE_Init())
4903 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4904 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4905 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4907 /* We failed to initialize the video, just quit the installer */
4908 return STATUS_APP_INIT_FAILURE
;
4911 /* Initialize global unicode strings */
4912 RtlInitUnicodeString(&SourcePath
, NULL
);
4913 RtlInitUnicodeString(&SourceRootPath
, NULL
);
4914 RtlInitUnicodeString(&SourceRootDir
, NULL
);
4915 RtlInitUnicodeString(&InstallPath
, NULL
);
4916 RtlInitUnicodeString(&DestinationPath
, NULL
);
4917 RtlInitUnicodeString(&DestinationArcPath
, NULL
);
4918 RtlInitUnicodeString(&DestinationRootPath
, NULL
);
4919 RtlInitUnicodeString(&SystemRootPath
, NULL
);
4921 /* Hide the cursor */
4922 CONSOLE_SetCursorType(TRUE
, FALSE
);
4924 /* Global Initialization page */
4925 CONSOLE_ClearScreen();
4927 Page
= SetupStartPage(&Ir
);
4929 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4931 CONSOLE_ClearScreen();
4934 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4941 Page
= LanguagePage(&Ir
);
4946 Page
= WelcomePage(&Ir
);
4951 Page
= LicensePage(&Ir
);
4955 case INSTALL_INTRO_PAGE
:
4956 Page
= InstallIntroPage(&Ir
);
4960 case SCSI_CONTROLLER_PAGE
:
4961 Page
= ScsiControllerPage(&Ir
);
4964 case OEM_DRIVER_PAGE
:
4965 Page
= OemDriverPage(&Ir
);
4969 case DEVICE_SETTINGS_PAGE
:
4970 Page
= DeviceSettingsPage(&Ir
);
4973 case COMPUTER_SETTINGS_PAGE
:
4974 Page
= ComputerSettingsPage(&Ir
);
4977 case DISPLAY_SETTINGS_PAGE
:
4978 Page
= DisplaySettingsPage(&Ir
);
4981 case KEYBOARD_SETTINGS_PAGE
:
4982 Page
= KeyboardSettingsPage(&Ir
);
4985 case LAYOUT_SETTINGS_PAGE
:
4986 Page
= LayoutSettingsPage(&Ir
);
4989 case SELECT_PARTITION_PAGE
:
4990 Page
= SelectPartitionPage(&Ir
);
4993 case CREATE_PRIMARY_PARTITION_PAGE
:
4994 Page
= CreatePrimaryPartitionPage(&Ir
);
4997 case CREATE_EXTENDED_PARTITION_PAGE
:
4998 Page
= CreateExtendedPartitionPage(&Ir
);
5001 case CREATE_LOGICAL_PARTITION_PAGE
:
5002 Page
= CreateLogicalPartitionPage(&Ir
);
5005 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5006 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5009 case DELETE_PARTITION_PAGE
:
5010 Page
= DeletePartitionPage(&Ir
);
5013 case SELECT_FILE_SYSTEM_PAGE
:
5014 Page
= SelectFileSystemPage(&Ir
);
5017 case FORMAT_PARTITION_PAGE
:
5018 Page
= FormatPartitionPage(&Ir
);
5021 case CHECK_FILE_SYSTEM_PAGE
:
5022 Page
= CheckFileSystemPage(&Ir
);
5025 case INSTALL_DIRECTORY_PAGE
:
5026 Page
= InstallDirectoryPage(&Ir
);
5029 case PREPARE_COPY_PAGE
:
5030 Page
= PrepareCopyPage(&Ir
);
5033 case FILE_COPY_PAGE
:
5034 Page
= FileCopyPage(&Ir
);
5038 Page
= RegistryPage(&Ir
);
5041 case BOOT_LOADER_PAGE
:
5042 Page
= BootLoaderPage(&Ir
);
5045 case BOOT_LOADER_FLOPPY_PAGE
:
5046 Page
= BootLoaderFloppyPage(&Ir
);
5049 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5050 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5053 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5054 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5058 case REPAIR_INTRO_PAGE
:
5059 Page
= RepairIntroPage(&Ir
);
5063 Page
= SuccessPage(&Ir
);
5067 Page
= FlushPage(&Ir
);
5071 Page
= QuitPage(&Ir
);
5080 if (Page
== RECOVERY_PAGE
)
5086 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5087 NtShutdownSystem(ShutdownReboot
);
5088 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5090 return STATUS_SUCCESS
;
5095 NtProcessStartup(PPEB Peb
)
5100 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5102 ProcessHeap
= Peb
->ProcessHeap
;
5104 NtQuerySystemTime(&Time
);
5106 Status
= RunUSetup();
5108 if (NT_SUCCESS(Status
))
5111 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5112 * a protective waiting.
5113 * This wait is needed because, since we are started as SMSS.EXE,
5114 * the NT kernel explicitly waits 5 seconds for the initial process
5115 * SMSS.EXE to initialize (as a protective measure), and otherwise
5116 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5118 Time
.QuadPart
+= 50000000;
5119 NtDelayExecution(FALSE
, &Time
);
5123 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5124 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5125 0, 0, NULL
, 0, NULL
);
5128 NtTerminateProcess(NtCurrentProcess(), Status
);