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 ******************************************************************/
49 static UNICODE_STRING SourceRootPath
;
50 static UNICODE_STRING SourceRootDir
;
51 /* static */ UNICODE_STRING SourcePath
;
53 BOOLEAN IsUnattendedSetup
= FALSE
;
54 LONG UnattendDestinationDiskNumber
;
55 LONG UnattendDestinationPartitionNumber
;
56 LONG UnattendMBRInstallType
= -1;
57 LONG UnattendFormatPartition
= 0;
58 LONG AutoPartition
= 0;
59 WCHAR UnattendInstallationDirectory
[MAX_PATH
];
60 PWCHAR SelectedLanguageId
;
62 WCHAR DefaultLanguage
[20];
63 WCHAR DefaultKBLayout
[20];
64 static BOOLEAN RepairUpdateFlag
= FALSE
;
65 static HANDLE hPnpThread
= INVALID_HANDLE_VALUE
;
67 static PPARTLIST PartitionList
= NULL
;
68 static PPARTENTRY TempPartition
= NULL
;
69 static FORMATMACHINESTATE FormatState
= Start
;
72 /* LOCALS *******************************************************************/
74 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
76 static UNICODE_STRING InstallPath
;
79 * Path to the system partition, where the boot manager resides.
80 * On x86 PCs, this is usually the active partition.
81 * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
83 * For more information, see:
84 * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
85 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
86 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
87 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
88 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
89 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
91 static UNICODE_STRING SystemRootPath
;
93 /* Path to the install directory inside the ReactOS boot partition */
94 static UNICODE_STRING DestinationPath
;
95 static UNICODE_STRING DestinationArcPath
;
96 static UNICODE_STRING DestinationRootPath
;
98 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
99 static WCHAR DestinationDriveLetter
;
101 static HINF SetupInf
;
103 static HSPFILEQ SetupFileQueue
= NULL
;
105 static PGENERIC_LIST ComputerList
= NULL
;
106 static PGENERIC_LIST DisplayList
= NULL
;
107 static PGENERIC_LIST KeyboardList
= NULL
;
108 static PGENERIC_LIST LayoutList
= NULL
;
109 static PGENERIC_LIST LanguageList
= NULL
;
111 static LANGID LanguageId
= 0;
113 static ULONG RequiredPartitionDiskSpace
= ~0;
115 /* FUNCTIONS ****************************************************************/
118 PrintString(char* fmt
,...)
122 UNICODE_STRING UnicodeString
;
123 ANSI_STRING AnsiString
;
126 vsprintf(buffer
, fmt
, ap
);
129 RtlInitAnsiString(&AnsiString
, buffer
);
130 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
131 NtDisplayString(&UnicodeString
);
132 RtlFreeUnicodeString(&UnicodeString
);
137 DrawBox(IN SHORT xLeft
,
145 /* draw upper left corner */
148 FillConsoleOutputCharacterA(StdOutput
,
154 /* draw upper edge */
157 FillConsoleOutputCharacterA(StdOutput
,
163 /* draw upper right corner */
164 coPos
.X
= xLeft
+ Width
- 1;
166 FillConsoleOutputCharacterA(StdOutput
,
172 /* Draw right edge, inner space and left edge */
173 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
176 FillConsoleOutputCharacterA(StdOutput
,
183 FillConsoleOutputCharacterA(StdOutput
,
189 coPos
.X
= xLeft
+ Width
- 1;
190 FillConsoleOutputCharacterA(StdOutput
,
197 /* draw lower left corner */
199 coPos
.Y
= yTop
+ Height
- 1;
200 FillConsoleOutputCharacterA(StdOutput
,
206 /* draw lower edge */
208 coPos
.Y
= yTop
+ Height
- 1;
209 FillConsoleOutputCharacterA(StdOutput
,
215 /* draw lower right corner */
216 coPos
.X
= xLeft
+ Width
- 1;
217 coPos
.Y
= yTop
+ Height
- 1;
218 FillConsoleOutputCharacterA(StdOutput
,
227 PopupError(PCCH Text
,
245 /* Count text lines and longest line */
252 p
= strchr(pnext
, '\n');
256 Length
= strlen(pnext
);
261 Length
= (ULONG
)(p
- pnext
);
267 if (Length
> MaxLength
)
270 if (LastLine
!= FALSE
)
276 /* Check length of status line */
279 Length
= strlen(Status
);
281 if (Length
> MaxLength
)
285 Width
= MaxLength
+ 4;
291 yTop
= (yScreen
- Height
) / 2;
292 xLeft
= (xScreen
- Width
) / 2;
295 /* Set screen attributes */
297 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
299 FillConsoleOutputAttribute(StdOutput
,
300 FOREGROUND_RED
| BACKGROUND_WHITE
,
306 DrawBox(xLeft
, yTop
, Width
, Height
);
308 /* Print message text */
313 p
= strchr(pnext
, '\n');
317 Length
= strlen(pnext
);
322 Length
= (ULONG
)(p
- pnext
);
329 WriteConsoleOutputCharacterA(StdOutput
,
336 if (LastLine
!= FALSE
)
343 /* Print separator line and status text */
346 coPos
.Y
= yTop
+ Height
- 3;
348 FillConsoleOutputCharacterA(StdOutput
,
355 FillConsoleOutputCharacterA(StdOutput
,
361 coPos
.X
= xLeft
+ Width
- 1;
362 FillConsoleOutputCharacterA(StdOutput
,
370 WriteConsoleOutputCharacterA(StdOutput
,
372 min(strlen(Status
), (SIZE_T
)Width
- 4),
377 if (WaitEvent
== POPUP_WAIT_NONE
)
382 CONSOLE_ConInKey(Ir
);
384 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
385 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
397 * FALSE: Don't quit setup.
400 ConfirmQuit(PINPUT_RECORD Ir
)
403 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
407 CONSOLE_ConInKey(Ir
);
409 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
410 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
415 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
427 CheckUnattendedSetup(VOID
)
429 WCHAR UnattendInfPath
[MAX_PATH
];
436 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2, SourcePath
.Buffer
, L
"unattend.inf");
438 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
440 DPRINT("Does not exist: %S\n", UnattendInfPath
);
444 /* Load 'unattend.inf' from install media. */
445 UnattendInf
= SetupOpenInfFileW(UnattendInfPath
,
451 if (UnattendInf
== INVALID_HANDLE_VALUE
)
453 DPRINT("SetupOpenInfFileW() failed\n");
457 /* Open 'Unattend' section */
458 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
460 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
461 SetupCloseInfFile(UnattendInf
);
465 /* Get pointer 'Signature' key */
466 if (!INF_GetData(&Context
, NULL
, &Value
))
468 DPRINT("INF_GetData() failed for key 'Signature'\n");
469 SetupCloseInfFile(UnattendInf
);
473 /* Check 'Signature' string */
474 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
476 DPRINT("Signature not $ReactOS$\n");
477 SetupCloseInfFile(UnattendInf
);
481 /* Check if Unattend setup is enabled */
482 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
484 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
485 SetupCloseInfFile(UnattendInf
);
489 if (!INF_GetData(&Context
, NULL
, &Value
))
491 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
492 SetupCloseInfFile(UnattendInf
);
496 if (_wcsicmp(Value
, L
"yes") != 0)
498 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
499 SetupCloseInfFile(UnattendInf
);
503 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
504 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
506 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
507 SetupCloseInfFile(UnattendInf
);
511 if (!SetupGetIntField(&Context
, 1, &IntValue
))
513 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
514 SetupCloseInfFile(UnattendInf
);
518 UnattendDestinationDiskNumber
= (LONG
)IntValue
;
520 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
521 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
523 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
524 SetupCloseInfFile(UnattendInf
);
528 if (!SetupGetIntField(&Context
, 1, &IntValue
))
530 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
531 SetupCloseInfFile(UnattendInf
);
535 UnattendDestinationPartitionNumber
= (LONG
)IntValue
;
537 /* Search for 'InstallationDirectory' in the 'Unattend' section */
538 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
540 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
541 SetupCloseInfFile(UnattendInf
);
545 /* Get pointer 'InstallationDirectory' key */
546 if (!INF_GetData(&Context
, NULL
, &Value
))
548 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
549 SetupCloseInfFile(UnattendInf
);
553 wcscpy(UnattendInstallationDirectory
, Value
);
555 IsUnattendedSetup
= TRUE
;
556 DPRINT("Running unattended setup\n");
558 /* Search for 'MBRInstallType' in the 'Unattend' section */
559 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
561 if (SetupGetIntField(&Context
, 1, &IntValue
))
563 UnattendMBRInstallType
= IntValue
;
567 /* Search for 'FormatPartition' in the 'Unattend' section */
568 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
570 if (SetupGetIntField(&Context
, 1, &IntValue
))
572 UnattendFormatPartition
= IntValue
;
576 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
578 if (SetupGetIntField(&Context
, 1, &IntValue
))
580 AutoPartition
= IntValue
;
584 /* search for LocaleID in the 'Unattend' section*/
585 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
587 if (INF_GetData(&Context
, NULL
, &Value
))
589 LONG Id
= wcstol(Value
, NULL
, 16);
590 swprintf(LocaleID
, L
"%08lx", Id
);
594 SetupCloseInfFile(UnattendInf
);
601 PGENERIC_LIST_ENTRY ListEntry
;
602 LPCWSTR pszNewLayout
;
604 pszNewLayout
= MUIDefaultKeyboardLayout();
606 if (LayoutList
== NULL
)
608 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
609 if (LayoutList
== NULL
)
611 /* FIXME: Handle error! */
616 ListEntry
= GetFirstListEntry(LayoutList
);
618 /* Search for default layout (if provided) */
619 if (pszNewLayout
!= NULL
)
621 while (ListEntry
!= NULL
)
623 if (!wcscmp(pszNewLayout
, GetListEntryUserData(ListEntry
)))
625 SetCurrentListEntry(LayoutList
, ListEntry
);
629 ListEntry
= GetNextListEntry(ListEntry
);
636 * Displays the LanguagePage.
638 * Next pages: WelcomePage, QuitPage
641 * Init SelectedLanguageId
645 * Number of the next page.
648 LanguagePage(PINPUT_RECORD Ir
)
650 GENERIC_LIST_UI ListUi
;
651 PWCHAR NewLanguageId
;
652 BOOL RefreshPage
= FALSE
;
654 /* Initialize the computer settings list */
655 if (LanguageList
== NULL
)
657 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
658 if (LanguageList
== NULL
)
660 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
666 SelectedLanguageId
= DefaultLanguage
;
667 SetConsoleCodePage();
670 /* If there's just a single language in the list skip
671 * the language selection process altogether! */
672 if (GenericListHasSingleEntry(LanguageList
))
674 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
678 InitGenericListUi(&ListUi
, LanguageList
);
679 DrawGenericList(&ListUi
,
685 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
687 MUIDisplayPage(LANGUAGE_PAGE
);
691 CONSOLE_ConInKey(Ir
);
693 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
694 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
696 ScrollDownGenericList(&ListUi
);
699 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
700 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
702 ScrollUpGenericList(&ListUi
);
705 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
706 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
708 ScrollPageDownGenericList(&ListUi
);
711 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
712 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
714 ScrollPageUpGenericList(&ListUi
);
717 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
718 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
720 if (ConfirmQuit(Ir
) != FALSE
)
723 RedrawGenericList(&ListUi
);
725 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
727 SelectedLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
729 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
731 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
737 SetConsoleCodePage();
741 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
744 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
750 NewLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
752 if (SelectedLanguageId
!= NewLanguageId
)
754 /* Clear the language page */
755 MUIClearPage(LANGUAGE_PAGE
);
757 SelectedLanguageId
= NewLanguageId
;
760 SetConsoleCodePage();
762 /* Redraw language selection page in native language */
763 MUIDisplayPage(LANGUAGE_PAGE
);
778 * LanguagePage (at once, default)
779 * InstallIntroPage (at once, if unattended)
785 * Init SourceRootPath
788 * Init RequiredPartitionDiskSpace
789 * Init IsUnattendedSetup
790 * If unattended, init *List and sets the Codepage
791 * If unattended, init SelectedLanguageId
792 * If unattended, init LanguageId
795 * Number of the next page.
798 SetupStartPage(PINPUT_RECORD Ir
)
801 WCHAR FileNameBuffer
[MAX_PATH
];
805 PGENERIC_LIST_ENTRY ListEntry
;
808 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
810 /* Get the source path and source root path */
811 Status
= GetSourcePaths(&SourcePath
,
814 if (!NT_SUCCESS(Status
))
816 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
817 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
820 DPRINT1("SourcePath: '%wZ'\n", &SourcePath
);
821 DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath
);
822 DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir
);
824 /* Load txtsetup.sif from install media. */
825 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2, SourcePath
.Buffer
, L
"txtsetup.sif");
826 SetupInf
= SetupOpenInfFileW(FileNameBuffer
,
832 if (SetupInf
== INVALID_HANDLE_VALUE
)
834 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
838 /* Open 'Version' section */
839 if (!SetupFindFirstLineW(SetupInf
, L
"Version", L
"Signature", &Context
))
841 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
845 /* Get pointer 'Signature' key */
846 if (!INF_GetData(&Context
, NULL
, &Value
))
848 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
852 /* Check 'Signature' string */
853 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
855 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
859 /* Open 'DiskSpaceRequirements' section */
860 if (!SetupFindFirstLineW(SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
862 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
866 /* Get the 'FreeSysPartDiskSpace' value */
867 if (!SetupGetIntField(&Context
, 1, &IntValue
))
869 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
873 RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
875 /* Start the PnP thread */
876 if (hPnpThread
!= INVALID_HANDLE_VALUE
)
878 NtResumeThread(hPnpThread
, NULL
);
879 hPnpThread
= INVALID_HANDLE_VALUE
;
882 CheckUnattendedSetup();
884 if (IsUnattendedSetup
)
886 // TODO: Read options from inf
887 ComputerList
= CreateComputerTypeList(SetupInf
);
888 DisplayList
= CreateDisplayDriverList(SetupInf
);
889 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
890 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
891 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
894 wcscpy(SelectedLanguageId
, LocaleID
);
895 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
897 /* first we hack LanguageList */
898 ListEntry
= GetFirstListEntry(LanguageList
);
899 while (ListEntry
!= NULL
)
901 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
903 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry
));
904 SetCurrentListEntry(LanguageList
, ListEntry
);
908 ListEntry
= GetNextListEntry(ListEntry
);
912 ListEntry
= GetFirstListEntry(LayoutList
);
913 while (ListEntry
!= NULL
)
915 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
917 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry
));
918 SetCurrentListEntry(LayoutList
, ListEntry
);
922 ListEntry
= GetNextListEntry(ListEntry
);
925 SetConsoleCodePage();
927 return INSTALL_INTRO_PAGE
;
930 return LANGUAGE_PAGE
;
935 * Displays the WelcomePage.
938 * InstallIntroPage (default)
944 * Number of the next page.
947 WelcomePage(PINPUT_RECORD Ir
)
949 MUIDisplayPage(WELCOME_PAGE
);
953 CONSOLE_ConInKey(Ir
);
955 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
956 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
958 if (ConfirmQuit(Ir
) != FALSE
)
963 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
965 return INSTALL_INTRO_PAGE
;
967 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
969 return REPAIR_INTRO_PAGE
;
971 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
982 * Displays the License page.
985 * WelcomePage (default)
988 * Number of the next page.
991 LicensePage(PINPUT_RECORD Ir
)
993 MUIDisplayPage(LICENSE_PAGE
);
997 CONSOLE_ConInKey(Ir
);
999 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1001 return WELCOME_PAGE
;
1005 return LICENSE_PAGE
;
1010 * Displays the RepairIntroPage.
1013 * RebootPage (default)
1019 * Number of the next page.
1022 RepairIntroPage(PINPUT_RECORD Ir
)
1024 MUIDisplayPage(REPAIR_INTRO_PAGE
);
1028 CONSOLE_ConInKey(Ir
);
1030 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1034 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
1036 RepairUpdateFlag
= TRUE
;
1037 return INSTALL_INTRO_PAGE
;
1039 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
1041 return RECOVERY_PAGE
;
1043 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1044 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1046 return WELCOME_PAGE
;
1050 return REPAIR_INTRO_PAGE
;
1054 * Displays the InstallIntroPage.
1057 * DeviceSettingsPage (At once if repair or update is selected)
1058 * SelectPartitionPage (At once if unattended setup)
1059 * DeviceSettingsPage (default)
1063 * Number of the next page.
1066 InstallIntroPage(PINPUT_RECORD Ir
)
1068 if (RepairUpdateFlag
)
1070 //return SELECT_PARTITION_PAGE;
1071 return DEVICE_SETTINGS_PAGE
;
1074 if (IsUnattendedSetup
)
1075 return SELECT_PARTITION_PAGE
;
1077 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1081 CONSOLE_ConInKey(Ir
);
1083 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1084 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1086 if (ConfirmQuit(Ir
) != FALSE
)
1091 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1093 return DEVICE_SETTINGS_PAGE
;
1094 // return SCSI_CONTROLLER_PAGE;
1098 return INSTALL_INTRO_PAGE
;
1104 ScsiControllerPage(PINPUT_RECORD Ir
)
1106 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1108 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1110 /* FIXME: print loaded mass storage driver descriptions */
1112 CONSOLE_SetTextXY(8, 10, "TEST device");
1115 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1119 CONSOLE_ConInKey(Ir
);
1121 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1122 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1124 if (ConfirmQuit(Ir
) != FALSE
)
1129 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1131 return DEVICE_SETTINGS_PAGE
;
1135 return SCSI_CONTROLLER_PAGE
;
1139 OemDriverPage(PINPUT_RECORD Ir
)
1141 // MUIDisplayPage(OEM_DRIVER_PAGE);
1143 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1145 /* FIXME: Implement!! */
1147 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1151 CONSOLE_ConInKey(Ir
);
1153 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1154 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1156 if (ConfirmQuit(Ir
) == TRUE
)
1161 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1163 return DEVICE_SETTINGS_PAGE
;
1167 return OEM_DRIVER_PAGE
;
1173 * Displays the DeviceSettingsPage.
1176 * SelectPartitionPage (At once if repair or update is selected)
1177 * ComputerSettingsPage
1178 * DisplaySettingsPage
1179 * KeyboardSettingsPage
1180 * LayoutsettingsPage
1181 * SelectPartitionPage
1191 * Number of the next page.
1194 DeviceSettingsPage(PINPUT_RECORD Ir
)
1196 static ULONG Line
= 16;
1198 /* Initialize the computer settings list */
1199 if (ComputerList
== NULL
)
1201 ComputerList
= CreateComputerTypeList(SetupInf
);
1202 if (ComputerList
== NULL
)
1204 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1209 /* Initialize the display settings list */
1210 if (DisplayList
== NULL
)
1212 DisplayList
= CreateDisplayDriverList(SetupInf
);
1213 if (DisplayList
== NULL
)
1215 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1220 /* Initialize the keyboard settings list */
1221 if (KeyboardList
== NULL
)
1223 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1224 if (KeyboardList
== NULL
)
1226 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1231 /* Initialize the keyboard layout list */
1232 if (LayoutList
== NULL
)
1234 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
1235 if (LayoutList
== NULL
)
1237 /* FIXME: report error */
1238 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1243 if (RepairUpdateFlag
)
1244 return SELECT_PARTITION_PAGE
;
1246 // if (IsUnattendedSetup)
1247 // return SELECT_PARTITION_PAGE;
1249 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1251 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList
)));
1252 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList
)));
1253 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList
)));
1254 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList
)));
1256 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1260 CONSOLE_ConInKey(Ir
);
1262 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1263 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1265 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1269 else if (Line
== 16)
1274 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1276 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1277 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1279 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1283 else if (Line
== 16)
1288 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1290 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1291 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1293 if (ConfirmQuit(Ir
) != FALSE
)
1298 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1301 return COMPUTER_SETTINGS_PAGE
;
1302 else if (Line
== 12)
1303 return DISPLAY_SETTINGS_PAGE
;
1304 else if (Line
== 13)
1305 return KEYBOARD_SETTINGS_PAGE
;
1306 else if (Line
== 14)
1307 return LAYOUT_SETTINGS_PAGE
;
1308 else if (Line
== 16)
1309 return SELECT_PARTITION_PAGE
;
1313 return DEVICE_SETTINGS_PAGE
;
1318 * Handles generic selection lists.
1321 * GenericList: The list to handle.
1322 * nextPage: The page it needs to jump to after this page.
1323 * Ir: The PINPUT_RECORD
1326 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1327 PAGE_NUMBER nextPage
,
1332 CONSOLE_ConInKey(Ir
);
1334 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1335 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1337 ScrollDownGenericList(ListUi
);
1339 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1340 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1342 ScrollUpGenericList(ListUi
);
1344 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1345 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1347 ScrollPageDownGenericList(ListUi
);
1349 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1350 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1352 ScrollPageUpGenericList(ListUi
);
1354 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1355 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1357 if (ConfirmQuit(Ir
) != FALSE
)
1360 RedrawGenericList(ListUi
);
1362 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1363 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1365 RestoreGenericListState(ListUi
->List
);
1366 return nextPage
; // Use some "prevPage;" instead?
1368 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1372 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1375 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1382 * Displays the ComputerSettingsPage.
1385 * DeviceSettingsPage
1389 * Number of the next page.
1392 ComputerSettingsPage(PINPUT_RECORD Ir
)
1394 GENERIC_LIST_UI ListUi
;
1395 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1397 InitGenericListUi(&ListUi
, ComputerList
);
1398 DrawGenericList(&ListUi
,
1404 SaveGenericListState(ComputerList
);
1406 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1411 * Displays the DisplaySettingsPage.
1414 * DeviceSettingsPage
1418 * Number of the next page.
1421 DisplaySettingsPage(PINPUT_RECORD Ir
)
1423 GENERIC_LIST_UI ListUi
;
1424 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1426 InitGenericListUi(&ListUi
, DisplayList
);
1427 DrawGenericList(&ListUi
,
1433 SaveGenericListState(DisplayList
);
1435 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1440 * Displays the KeyboardSettingsPage.
1443 * DeviceSettingsPage
1447 * Number of the next page.
1450 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1452 GENERIC_LIST_UI ListUi
;
1453 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1455 InitGenericListUi(&ListUi
, KeyboardList
);
1456 DrawGenericList(&ListUi
,
1462 SaveGenericListState(KeyboardList
);
1464 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1469 * Displays the LayoutSettingsPage.
1472 * DeviceSettingsPage
1476 * Number of the next page.
1479 LayoutSettingsPage(PINPUT_RECORD Ir
)
1481 GENERIC_LIST_UI ListUi
;
1482 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1484 InitGenericListUi(&ListUi
, LayoutList
);
1485 DrawGenericList(&ListUi
,
1491 SaveGenericListState(LayoutList
);
1493 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1498 IsDiskSizeValid(PPARTENTRY PartEntry
)
1502 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1503 size
= (size
+ 524288) / 1048576; /* in MBytes */
1505 if (size
< RequiredPartitionDiskSpace
)
1507 /* Partition is too small so ask for another one */
1508 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, RequiredPartitionDiskSpace
);
1519 * Displays the SelectPartitionPage.
1522 * SelectFileSystemPage (At once if unattended)
1523 * SelectFileSystemPage (Default if free space is selected)
1524 * CreatePrimaryPartitionPage
1525 * CreateExtendedPartitionPage
1526 * CreateLogicalPartitionPage
1527 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1528 * DeletePartitionPage
1532 * Set InstallShortcut (only if not unattended + free space is selected)
1535 * Number of the next page.
1538 SelectPartitionPage(PINPUT_RECORD Ir
)
1543 if (PartitionList
== NULL
)
1545 PartitionList
= CreatePartitionList();
1546 if (PartitionList
== NULL
)
1548 /* FIXME: show an error dialog */
1549 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1552 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1554 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1558 TempPartition
= NULL
;
1559 FormatState
= Start
;
1562 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1564 InitPartitionListUi(&ListUi
, PartitionList
,
1569 DrawPartitionList(&ListUi
);
1571 if (IsUnattendedSetup
)
1573 if (!SelectPartition(PartitionList
, UnattendDestinationDiskNumber
, UnattendDestinationPartitionNumber
))
1577 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1579 CreateLogicalPartition(PartitionList
,
1580 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1585 CreatePrimaryPartition(PartitionList
,
1586 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1590 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1591 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1593 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1594 RequiredPartitionDiskSpace
);
1595 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1598 return SELECT_FILE_SYSTEM_PAGE
;
1603 DrawPartitionList(&ListUi
);
1605 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1606 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1608 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1609 RequiredPartitionDiskSpace
);
1610 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1613 return SELECT_FILE_SYSTEM_PAGE
;
1619 /* Update status text */
1620 if (PartitionList
->CurrentPartition
== NULL
)
1622 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1624 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1626 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1628 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1632 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1637 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1639 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1641 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1645 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1650 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1654 CONSOLE_ConInKey(Ir
);
1656 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1657 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1659 if (ConfirmQuit(Ir
) != FALSE
)
1661 DestroyPartitionList(PartitionList
);
1662 PartitionList
= NULL
;
1668 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1669 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1671 ScrollDownPartitionList(&ListUi
);
1673 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1674 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1676 ScrollUpPartitionList(&ListUi
);
1678 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1680 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1681 continue; // return SELECT_PARTITION_PAGE;
1683 if (PartitionList
->CurrentPartition
== NULL
||
1684 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1686 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1688 CreateLogicalPartition(PartitionList
,
1694 CreatePrimaryPartition(PartitionList
,
1700 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1702 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1703 RequiredPartitionDiskSpace
);
1704 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1707 return SELECT_FILE_SYSTEM_PAGE
;
1709 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1711 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1713 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1714 if (Error
!= NOT_AN_ERROR
)
1716 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1717 return SELECT_PARTITION_PAGE
;
1720 return CREATE_PRIMARY_PARTITION_PAGE
;
1723 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1725 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1727 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1728 if (Error
!= NOT_AN_ERROR
)
1730 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1731 return SELECT_PARTITION_PAGE
;
1734 return CREATE_EXTENDED_PARTITION_PAGE
;
1737 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1739 if (PartitionList
->CurrentPartition
->LogicalPartition
!= FALSE
)
1741 Error
= LogicalPartitionCreationChecks(PartitionList
);
1742 if (Error
!= NOT_AN_ERROR
)
1744 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1745 return SELECT_PARTITION_PAGE
;
1748 return CREATE_LOGICAL_PARTITION_PAGE
;
1751 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1753 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1755 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1756 return SELECT_PARTITION_PAGE
;
1759 if (PartitionList
->CurrentPartition
->BootIndicator
||
1760 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1762 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1765 return DELETE_PARTITION_PAGE
;
1769 return SELECT_PARTITION_PAGE
;
1773 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1774 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1775 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1778 ShowPartitionSizeInputBox(SHORT Left
,
1802 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
1807 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
1808 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
1811 WriteConsoleOutputCharacterA(StdOutput
,
1817 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
1818 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
1820 WriteConsoleOutputCharacterA(StdOutput
,
1826 swprintf(InputBuffer
, L
"%lu", MaxSize
);
1827 Length
= wcslen(InputBuffer
);
1829 CONSOLE_SetInputTextXY(iLeft
,
1831 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1833 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
1834 CONSOLE_SetCursorType(TRUE
, TRUE
);
1838 CONSOLE_ConInKey(&Ir
);
1840 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1841 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1846 InputBuffer
[0] = UNICODE_NULL
;
1847 CONSOLE_SetCursorType(TRUE
, FALSE
);
1850 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1852 CONSOLE_SetCursorType(TRUE
, FALSE
);
1855 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
1860 InputBuffer
[0] = UNICODE_NULL
;
1861 CONSOLE_SetCursorType(TRUE
, FALSE
);
1864 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1865 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
1868 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1870 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1871 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
1874 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1876 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1877 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
1882 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1885 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1886 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
1891 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1894 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1895 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
1899 memmove(&InputBuffer
[Pos
],
1900 &InputBuffer
[Pos
+ 1],
1901 (Length
- Pos
- 1) * sizeof(WCHAR
));
1902 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1905 CONSOLE_SetInputTextXY(iLeft
,
1907 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1909 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1912 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
1917 memmove(&InputBuffer
[Pos
- 1],
1919 (Length
- Pos
) * sizeof(WCHAR
));
1920 InputBuffer
[Length
- 1] = UNICODE_NULL
;
1924 CONSOLE_SetInputTextXY(iLeft
,
1926 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1928 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1931 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
1933 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
1935 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
1937 if ((ch
>= L
'0') && (ch
<= L
'9'))
1940 memmove(&InputBuffer
[Pos
+ 1],
1942 (Length
- Pos
) * sizeof(WCHAR
));
1943 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
1944 InputBuffer
[Pos
] = ch
;
1948 CONSOLE_SetInputTextXY(iLeft
,
1950 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
1952 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
1961 * Displays the CreatePrimaryPartitionPage.
1964 * SelectPartitionPage
1965 * SelectFileSystemPage (default)
1969 * Number of the next page.
1972 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
1974 PDISKENTRY DiskEntry
;
1975 PPARTENTRY PartEntry
;
1978 WCHAR InputBuffer
[50];
1982 ULONGLONG SectorCount
;
1985 if (PartitionList
== NULL
||
1986 PartitionList
->CurrentDisk
== NULL
||
1987 PartitionList
->CurrentPartition
== NULL
)
1989 /* FIXME: show an error dialog */
1993 DiskEntry
= PartitionList
->CurrentDisk
;
1994 PartEntry
= PartitionList
->CurrentPartition
;
1996 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
1998 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
2000 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2002 if (DiskSize
>= 10737418240) /* 10 GB */
2004 DiskSize
= DiskSize
/ 1073741824;
2005 Unit
= MUIGetString(STRING_GB
);
2010 DiskSize
= DiskSize
/ 1048576;
2014 Unit
= MUIGetString(STRING_MB
);
2017 if (DiskEntry
->DriverName
.Length
> 0)
2019 CONSOLE_PrintTextXY(6, 10,
2020 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2023 DiskEntry
->DiskNumber
,
2027 &DiskEntry
->DriverName
,
2028 DiskEntry
->NoMbr
? "GPT" : "MBR");
2032 CONSOLE_PrintTextXY(6, 10,
2033 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2036 DiskEntry
->DiskNumber
,
2040 DiskEntry
->NoMbr
? "GPT" : "MBR");
2043 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2046 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2047 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2050 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2052 PartEntry
= PartitionList
->CurrentPartition
;
2055 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2057 if (MaxSize
> PARTITION_MAXSIZE
)
2058 MaxSize
= PARTITION_MAXSIZE
;
2060 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2061 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2065 if (ConfirmQuit(Ir
) != FALSE
)
2070 else if (Cancel
!= FALSE
)
2072 return SELECT_PARTITION_PAGE
;
2076 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2084 if (PartSize
> MaxSize
)
2090 /* Convert to bytes */
2091 if (PartSize
== MaxSize
)
2093 /* Use all of the unpartitioned disk space */
2094 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2098 /* Calculate the sector count from the size in MB */
2099 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2101 /* But never get larger than the unpartitioned disk space */
2102 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2103 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2106 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2108 CreatePrimaryPartition(PartitionList
,
2112 return SELECT_PARTITION_PAGE
;
2116 return CREATE_PRIMARY_PARTITION_PAGE
;
2121 * Displays the CreateExtendedPartitionPage.
2124 * SelectPartitionPage (default)
2128 * Number of the next page.
2131 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2133 PDISKENTRY DiskEntry
;
2134 PPARTENTRY PartEntry
;
2137 WCHAR InputBuffer
[50];
2141 ULONGLONG SectorCount
;
2144 if (PartitionList
== NULL
||
2145 PartitionList
->CurrentDisk
== NULL
||
2146 PartitionList
->CurrentPartition
== NULL
)
2148 /* FIXME: show an error dialog */
2152 DiskEntry
= PartitionList
->CurrentDisk
;
2153 PartEntry
= PartitionList
->CurrentPartition
;
2155 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2157 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2159 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2161 if (DiskSize
>= 10737418240) /* 10 GB */
2163 DiskSize
= DiskSize
/ 1073741824;
2164 Unit
= MUIGetString(STRING_GB
);
2169 DiskSize
= DiskSize
/ 1048576;
2173 Unit
= MUIGetString(STRING_MB
);
2176 if (DiskEntry
->DriverName
.Length
> 0)
2178 CONSOLE_PrintTextXY(6, 10,
2179 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2182 DiskEntry
->DiskNumber
,
2186 &DiskEntry
->DriverName
,
2187 DiskEntry
->NoMbr
? "GPT" : "MBR");
2191 CONSOLE_PrintTextXY(6, 10,
2192 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2195 DiskEntry
->DiskNumber
,
2199 DiskEntry
->NoMbr
? "GPT" : "MBR");
2202 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2205 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2206 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2209 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2211 PartEntry
= PartitionList
->CurrentPartition
;
2214 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2216 if (MaxSize
> PARTITION_MAXSIZE
)
2217 MaxSize
= PARTITION_MAXSIZE
;
2219 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2220 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2224 if (ConfirmQuit(Ir
) != FALSE
)
2229 else if (Cancel
!= FALSE
)
2231 return SELECT_PARTITION_PAGE
;
2235 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2243 if (PartSize
> MaxSize
)
2249 /* Convert to bytes */
2250 if (PartSize
== MaxSize
)
2252 /* Use all of the unpartitioned disk space */
2253 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2257 /* Calculate the sector count from the size in MB */
2258 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2260 /* But never get larger than the unpartitioned disk space */
2261 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2262 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2265 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2267 CreateExtendedPartition(PartitionList
,
2270 return SELECT_PARTITION_PAGE
;
2274 return CREATE_EXTENDED_PARTITION_PAGE
;
2279 * Displays the CreateLogicalPartitionPage.
2282 * SelectFileSystemPage (default)
2286 * Number of the next page.
2289 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2291 PDISKENTRY DiskEntry
;
2292 PPARTENTRY PartEntry
;
2295 WCHAR InputBuffer
[50];
2299 ULONGLONG SectorCount
;
2302 if (PartitionList
== NULL
||
2303 PartitionList
->CurrentDisk
== NULL
||
2304 PartitionList
->CurrentPartition
== NULL
)
2306 /* FIXME: show an error dialog */
2310 DiskEntry
= PartitionList
->CurrentDisk
;
2311 PartEntry
= PartitionList
->CurrentPartition
;
2313 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2315 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2317 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2319 if (DiskSize
>= 10737418240) /* 10 GB */
2321 DiskSize
= DiskSize
/ 1073741824;
2322 Unit
= MUIGetString(STRING_GB
);
2327 DiskSize
= DiskSize
/ 1048576;
2331 Unit
= MUIGetString(STRING_MB
);
2334 if (DiskEntry
->DriverName
.Length
> 0)
2336 CONSOLE_PrintTextXY(6, 10,
2337 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2340 DiskEntry
->DiskNumber
,
2344 &DiskEntry
->DriverName
,
2345 DiskEntry
->NoMbr
? "GPT" : "MBR");
2349 CONSOLE_PrintTextXY(6, 10,
2350 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2353 DiskEntry
->DiskNumber
,
2357 DiskEntry
->NoMbr
? "GPT" : "MBR");
2360 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2363 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2364 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2367 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2369 PartEntry
= PartitionList
->CurrentPartition
;
2372 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2374 if (MaxSize
> PARTITION_MAXSIZE
)
2375 MaxSize
= PARTITION_MAXSIZE
;
2377 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2378 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2382 if (ConfirmQuit(Ir
) != FALSE
)
2387 else if (Cancel
!= FALSE
)
2389 return SELECT_PARTITION_PAGE
;
2393 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2401 if (PartSize
> MaxSize
)
2407 /* Convert to bytes */
2408 if (PartSize
== MaxSize
)
2410 /* Use all of the unpartitioned disk space */
2411 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2415 /* Calculate the sector count from the size in MB */
2416 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2418 /* But never get larger than the unpartitioned disk space */
2419 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2420 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2423 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2425 CreateLogicalPartition(PartitionList
,
2429 return SELECT_PARTITION_PAGE
;
2433 return CREATE_LOGICAL_PARTITION_PAGE
;
2438 * Displays the ConfirmDeleteSystemPartitionPage.
2441 * DeletePartitionPage (default)
2442 * SelectPartitionPage
2445 * Number of the next page.
2448 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2450 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2454 CONSOLE_ConInKey(Ir
);
2456 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2457 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2459 if (ConfirmQuit(Ir
) == TRUE
)
2464 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2466 return DELETE_PARTITION_PAGE
;
2468 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2470 return SELECT_PARTITION_PAGE
;
2474 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2479 * Displays the DeletePartitionPage.
2482 * SelectPartitionPage (default)
2486 * Number of the next page.
2489 DeletePartitionPage(PINPUT_RECORD Ir
)
2491 PDISKENTRY DiskEntry
;
2492 PPARTENTRY PartEntry
;
2496 CHAR PartTypeString
[32];
2498 if (PartitionList
== NULL
||
2499 PartitionList
->CurrentDisk
== NULL
||
2500 PartitionList
->CurrentPartition
== NULL
)
2502 /* FIXME: show an error dialog */
2506 DiskEntry
= PartitionList
->CurrentDisk
;
2507 PartEntry
= PartitionList
->CurrentPartition
;
2509 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2511 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2513 ARRAYSIZE(PartTypeString
));
2515 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2517 if (PartSize
>= 10737418240) /* 10 GB */
2519 PartSize
= PartSize
/ 1073741824;
2520 Unit
= MUIGetString(STRING_GB
);
2524 if (PartSize
>= 10485760) /* 10 MB */
2526 PartSize
= PartSize
/ 1048576;
2527 Unit
= MUIGetString(STRING_MB
);
2531 PartSize
= PartSize
/ 1024;
2532 Unit
= MUIGetString(STRING_KB
);
2535 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2537 CONSOLE_PrintTextXY(6, 10,
2538 MUIGetString(STRING_HDDINFOUNK2
),
2539 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2540 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2541 PartEntry
->PartitionType
,
2547 CONSOLE_PrintTextXY(6, 10,
2548 " %c%c %s %I64u %s",
2549 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2550 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2556 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2558 if (DiskSize
>= 10737418240) /* 10 GB */
2560 DiskSize
= DiskSize
/ 1073741824;
2561 Unit
= MUIGetString(STRING_GB
);
2566 DiskSize
= DiskSize
/ 1048576;
2570 Unit
= MUIGetString(STRING_MB
);
2573 if (DiskEntry
->DriverName
.Length
> 0)
2575 CONSOLE_PrintTextXY(6, 12,
2576 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2579 DiskEntry
->DiskNumber
,
2583 &DiskEntry
->DriverName
,
2584 DiskEntry
->NoMbr
? "GPT" : "MBR");
2588 CONSOLE_PrintTextXY(6, 12,
2589 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2592 DiskEntry
->DiskNumber
,
2596 DiskEntry
->NoMbr
? "GPT" : "MBR");
2601 CONSOLE_ConInKey(Ir
);
2603 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2604 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2606 if (ConfirmQuit(Ir
) != FALSE
)
2611 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2613 return SELECT_PARTITION_PAGE
;
2615 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2617 DeleteCurrentPartition(PartitionList
);
2619 return SELECT_PARTITION_PAGE
;
2623 return DELETE_PARTITION_PAGE
;
2628 * Displays the SelectFileSystemPage.
2631 * CheckFileSystemPage (At once if RepairUpdate is selected)
2632 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2633 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2634 * SelectPartitionPage (If the user aborts)
2635 * FormatPartitionPage (Default)
2639 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2640 * Calls CheckActiveSystemPartition()
2643 * Number of the next page.
2646 SelectFileSystemPage(PINPUT_RECORD Ir
)
2648 PDISKENTRY DiskEntry
;
2649 PPARTENTRY PartEntry
;
2654 CHAR PartTypeString
[32];
2655 FORMATMACHINESTATE PreviousFormatState
;
2657 DPRINT("SelectFileSystemPage()\n");
2659 if (PartitionList
== NULL
||
2660 PartitionList
->CurrentDisk
== NULL
||
2661 PartitionList
->CurrentPartition
== NULL
)
2663 /* FIXME: show an error dialog */
2667 /* Find or set the active system partition */
2668 CheckActiveSystemPartition(PartitionList
);
2669 if (PartitionList
->SystemPartition
== NULL
)
2671 /* FIXME: show an error dialog */
2673 // Error dialog should say that we cannot find a suitable
2674 // system partition and create one on the system. At this point,
2675 // it may be nice to ask the user whether he wants to continue,
2676 // or use an external drive as the system drive/partition
2677 // (e.g. floppy, USB drive, etc...)
2682 PreviousFormatState
= FormatState
;
2683 switch (FormatState
)
2687 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2689 TempPartition
= PartitionList
->SystemPartition
;
2690 TempPartition
->NeedsCheck
= TRUE
;
2692 FormatState
= FormatSystemPartition
;
2693 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2697 TempPartition
= PartitionList
->CurrentPartition
;
2698 TempPartition
->NeedsCheck
= TRUE
;
2700 FormatState
= FormatInstallPartition
;
2701 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2706 case FormatSystemPartition
:
2708 TempPartition
= PartitionList
->CurrentPartition
;
2709 TempPartition
->NeedsCheck
= TRUE
;
2711 FormatState
= FormatInstallPartition
;
2712 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2716 case FormatInstallPartition
:
2718 if (GetNextUnformattedPartition(PartitionList
,
2722 FormatState
= FormatOtherPartition
;
2723 TempPartition
->NeedsCheck
= TRUE
;
2724 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2728 FormatState
= FormatDone
;
2729 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2730 return CHECK_FILE_SYSTEM_PAGE
;
2735 case FormatOtherPartition
:
2737 if (GetNextUnformattedPartition(PartitionList
,
2741 FormatState
= FormatOtherPartition
;
2742 TempPartition
->NeedsCheck
= TRUE
;
2743 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2747 FormatState
= FormatDone
;
2748 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2749 return CHECK_FILE_SYSTEM_PAGE
;
2756 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2757 /* FIXME: show an error dialog */
2762 PartEntry
= TempPartition
;
2763 DiskEntry
= PartEntry
->DiskEntry
;
2765 /* Adjust disk size */
2766 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2767 if (DiskSize
>= 10737418240) /* 10 GB */
2769 DiskSize
= DiskSize
/ 1073741824;
2770 DiskUnit
= MUIGetString(STRING_GB
);
2774 DiskSize
= DiskSize
/ 1048576;
2775 DiskUnit
= MUIGetString(STRING_MB
);
2778 /* Adjust partition size */
2779 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2780 if (PartSize
>= 10737418240) /* 10 GB */
2782 PartSize
= PartSize
/ 1073741824;
2783 PartUnit
= MUIGetString(STRING_GB
);
2787 PartSize
= PartSize
/ 1048576;
2788 PartUnit
= MUIGetString(STRING_MB
);
2791 /* Adjust partition type */
2792 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2794 ARRAYSIZE(PartTypeString
));
2796 if (PartEntry
->AutoCreate
!= FALSE
)
2798 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
2801 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2802 PartEntry
->PartitionNumber
,
2808 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
2809 DiskEntry
->DiskNumber
,
2815 &DiskEntry
->DriverName
,
2816 DiskEntry
->NoMbr
? "GPT" : "MBR");
2818 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
2820 PartEntry
->AutoCreate
= FALSE
;
2822 else if (PartEntry
->New
!= FALSE
)
2824 switch (FormatState
)
2826 case FormatSystemPartition
:
2827 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
2830 case FormatInstallPartition
:
2831 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
2834 case FormatOtherPartition
:
2835 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
2842 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
2846 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
2848 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2850 CONSOLE_PrintTextXY(8, 10,
2851 MUIGetString(STRING_HDDINFOUNK4
),
2852 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2853 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2854 PartEntry
->PartitionType
,
2860 CONSOLE_PrintTextXY(8, 10,
2862 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2863 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2869 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
2870 DiskEntry
->DiskNumber
,
2876 &DiskEntry
->DriverName
,
2877 DiskEntry
->NoMbr
? "GPT" : "MBR");
2880 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
2882 if (FileSystemList
== NULL
)
2884 /* Create the file system list, and by default select the "FAT" file system */
2885 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
2886 if (FileSystemList
== NULL
)
2888 /* FIXME: show an error dialog */
2893 if (RepairUpdateFlag
)
2895 return CHECK_FILE_SYSTEM_PAGE
;
2896 //return SELECT_PARTITION_PAGE;
2899 if (IsUnattendedSetup
)
2901 if (UnattendFormatPartition
)
2904 * We use whatever currently selected file system we have
2905 * (by default, this is "FAT", as per the initialization
2906 * performed above). Note that it may be interesting to specify
2907 * which file system to use in unattended installations, in the
2908 * txtsetup.sif file.
2910 return FORMAT_PARTITION_PAGE
;
2913 return CHECK_FILE_SYSTEM_PAGE
;
2916 DrawFileSystemList(FileSystemList
);
2920 CONSOLE_ConInKey(Ir
);
2922 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2923 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2925 if (ConfirmQuit(Ir
) != FALSE
)
2930 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2931 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
2933 FormatState
= Start
;
2934 return SELECT_PARTITION_PAGE
;
2936 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2937 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
2939 ScrollDownFileSystemList(FileSystemList
);
2941 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2942 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
2944 ScrollUpFileSystemList(FileSystemList
);
2946 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2948 if (!FileSystemList
->Selected
->FileSystem
)
2949 return SELECT_FILE_SYSTEM_PAGE
;
2951 return FORMAT_PARTITION_PAGE
;
2955 FormatState
= PreviousFormatState
;
2957 return SELECT_FILE_SYSTEM_PAGE
;
2962 * Displays the FormatPartitionPage.
2965 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2966 * SelectPartitionPage (At once)
2970 * Sets PartitionList->CurrentPartition->FormatState
2971 * Sets DestinationRootPath
2974 * Number of the next page.
2977 FormatPartitionPage(PINPUT_RECORD Ir
)
2979 UNICODE_STRING PartitionRootPath
;
2980 WCHAR PathBuffer
[MAX_PATH
];
2981 PDISKENTRY DiskEntry
;
2982 PPARTENTRY PartEntry
;
2983 PFILE_SYSTEM_ITEM SelectedFileSystem
;
2989 PPARTITION_INFORMATION PartitionInfo
;
2992 DPRINT("FormatPartitionPage()\n");
2994 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
2996 if (PartitionList
== NULL
|| TempPartition
== NULL
)
2998 /* FIXME: show an error dialog */
3002 PartEntry
= TempPartition
;
3003 DiskEntry
= PartEntry
->DiskEntry
;
3005 SelectedFileSystem
= FileSystemList
->Selected
;
3009 if (!IsUnattendedSetup
)
3011 CONSOLE_ConInKey(Ir
);
3014 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3015 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3017 if (ConfirmQuit(Ir
) != FALSE
)
3022 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3024 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3026 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3028 /* FIXME: show an error dialog */
3033 CONSOLE_PrintTextXY(6, 12,
3034 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3035 DiskEntry
->Cylinders
,
3036 DiskEntry
->TracksPerCylinder
,
3037 DiskEntry
->SectorsPerTrack
,
3038 DiskEntry
->BytesPerSector
,
3039 DiskEntry
->Dirty
? '*' : ' ');
3043 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3045 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3047 CONSOLE_PrintTextXY(6, Line
,
3048 "%2u: %2lu %c %12I64u %12I64u %02x",
3050 PartitionInfo
->PartitionNumber
,
3051 PartitionInfo
->BootIndicator
? 'A' : '-',
3052 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3053 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3054 PartitionInfo
->PartitionType
);
3059 /* Commit the partition changes to the disk */
3060 if (!WritePartitionsToDisk(PartitionList
))
3062 DPRINT("WritePartitionsToDisk() failed\n");
3063 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3067 /* Set PartitionRootPath */
3068 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3069 L
"\\Device\\Harddisk%lu\\Partition%lu",
3070 DiskEntry
->DiskNumber
,
3071 PartEntry
->PartitionNumber
);
3072 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3073 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3075 /* Format the partition */
3076 if (SelectedFileSystem
->FileSystem
)
3078 Status
= FormatPartition(&PartitionRootPath
,
3079 SelectedFileSystem
);
3080 if (!NT_SUCCESS(Status
))
3082 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3083 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3087 PartEntry
->FormatState
= Formatted
;
3088 // PartEntry->FileSystem = FileSystem;
3089 PartEntry
->New
= FALSE
;
3093 CONSOLE_SetStatusText(" Done. Press any key ...");
3094 CONSOLE_ConInKey(Ir
);
3097 return SELECT_FILE_SYSTEM_PAGE
;
3101 return FORMAT_PARTITION_PAGE
;
3106 * Displays the CheckFileSystemPage.
3109 * InstallDirectoryPage (At once)
3113 * Inits or reloads FileSystemList
3116 * Number of the next page.
3119 CheckFileSystemPage(PINPUT_RECORD Ir
)
3121 PFILE_SYSTEM CurrentFileSystem
;
3122 UNICODE_STRING PartitionRootPath
;
3123 WCHAR PathBuffer
[MAX_PATH
];
3124 CHAR Buffer
[MAX_PATH
];
3125 PDISKENTRY DiskEntry
;
3126 PPARTENTRY PartEntry
;
3129 if (PartitionList
== NULL
)
3131 /* FIXME: show an error dialog */
3135 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3137 return INSTALL_DIRECTORY_PAGE
;
3140 /* Set PartitionRootPath */
3141 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3142 L
"\\Device\\Harddisk%lu\\Partition%lu",
3143 DiskEntry
->DiskNumber
,
3144 PartEntry
->PartitionNumber
);
3145 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3146 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3148 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3150 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3152 CurrentFileSystem
= PartEntry
->FileSystem
;
3153 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3154 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3156 /* HACK: Do not try to check a partition with an unknown filesystem */
3157 if (CurrentFileSystem
== NULL
)
3159 PartEntry
->NeedsCheck
= FALSE
;
3160 return CHECK_FILE_SYSTEM_PAGE
;
3163 if (CurrentFileSystem
->ChkdskFunc
== NULL
)
3166 "Setup is currently unable to check a partition formatted in %S.\n"
3168 " \x07 Press ENTER to continue Setup.\n"
3169 " \x07 Press F3 to quit Setup.",
3170 CurrentFileSystem
->FileSystemName
);
3173 MUIGetString(STRING_QUITCONTINUE
),
3174 NULL
, POPUP_WAIT_NONE
);
3178 CONSOLE_ConInKey(Ir
);
3180 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3181 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3183 if (ConfirmQuit(Ir
))
3186 return CHECK_FILE_SYSTEM_PAGE
;
3188 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3190 PartEntry
->NeedsCheck
= FALSE
;
3191 return CHECK_FILE_SYSTEM_PAGE
;
3197 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3198 if (!NT_SUCCESS(Status
))
3200 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3201 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3202 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3203 "(Status 0x%08lx).\n", Status
);
3205 // MUIGetString(STRING_REBOOTCOMPUTER),
3206 MUIGetString(STRING_CONTINUE
),
3207 Ir
, POPUP_WAIT_ENTER
);
3209 // return QUIT_PAGE;
3212 PartEntry
->NeedsCheck
= FALSE
;
3213 return CHECK_FILE_SYSTEM_PAGE
;
3219 BuildInstallPaths(PWSTR InstallDir
,
3220 PDISKENTRY DiskEntry
,
3221 PPARTENTRY PartEntry
)
3223 WCHAR PathBuffer
[MAX_PATH
];
3225 /* Create 'InstallPath' string */
3226 RtlFreeUnicodeString(&InstallPath
);
3227 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3229 /* Create 'DestinationRootPath' string */
3230 RtlFreeUnicodeString(&DestinationRootPath
);
3231 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3232 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3233 DiskEntry
->DiskNumber
,
3234 PartEntry
->PartitionNumber
);
3235 RtlCreateUnicodeString(&DestinationRootPath
, PathBuffer
);
3236 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath
);
3238 /* Create 'DestinationPath' string */
3239 RtlFreeUnicodeString(&DestinationPath
);
3240 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3241 DestinationRootPath
.Buffer
, InstallDir
);
3242 RtlCreateUnicodeString(&DestinationPath
, PathBuffer
);
3244 /* Create 'DestinationArcPath' */
3245 RtlFreeUnicodeString(&DestinationArcPath
);
3246 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3247 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3248 DiskEntry
->BiosDiskNumber
,
3249 PartEntry
->PartitionNumber
);
3250 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3251 RtlCreateUnicodeString(&DestinationArcPath
, PathBuffer
);
3253 /* Initialize DestinationDriveLetter */
3254 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3259 * Displays the InstallDirectoryPage.
3262 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3266 * Number of the next page.
3269 InstallDirectoryPage(PINPUT_RECORD Ir
)
3271 PDISKENTRY DiskEntry
;
3272 PPARTENTRY PartEntry
;
3273 WCHAR InstallDir
[51];
3277 /* We do not need the filesystem list any more */
3278 if (FileSystemList
!= NULL
)
3280 DestroyFileSystemList(FileSystemList
);
3281 FileSystemList
= NULL
;
3284 if (PartitionList
== NULL
||
3285 PartitionList
->CurrentDisk
== NULL
||
3286 PartitionList
->CurrentPartition
== NULL
)
3288 /* FIXME: show an error dialog */
3292 DiskEntry
= PartitionList
->CurrentDisk
;
3293 PartEntry
= PartitionList
->CurrentPartition
;
3296 if (RepairUpdateFlag
)
3298 if (!IsValidPath(CurrentInstallation
->PathComponent
)) // SystemNtPath
3300 /* FIXME: Log the error? */
3304 BuildInstallPaths(CurrentInstallation
->PathComponent
, // SystemNtPath
3308 return PREPARE_COPY_PAGE
;
3311 if (IsUnattendedSetup
)
3313 if (!IsValidPath(UnattendInstallationDirectory
))
3315 /* FIXME: Log the error? */
3319 BuildInstallPaths(UnattendInstallationDirectory
,
3323 return PREPARE_COPY_PAGE
;
3326 wcscpy(InstallDir
, L
"\\ReactOS");
3328 Length
= wcslen(InstallDir
);
3330 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3331 CONSOLE_SetCursorXY(8 + Pos
, 11);
3332 CONSOLE_SetCursorType(TRUE
, TRUE
);
3333 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3337 CONSOLE_ConInKey(Ir
);
3339 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3340 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3342 CONSOLE_SetCursorType(TRUE
, FALSE
);
3344 if (ConfirmQuit(Ir
) != FALSE
)
3347 CONSOLE_SetCursorType(TRUE
, TRUE
);
3350 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3351 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3355 memmove(&InstallDir
[Pos
],
3356 &InstallDir
[Pos
+ 1],
3357 (Length
- Pos
- 1) * sizeof(WCHAR
));
3358 InstallDir
[Length
- 1] = UNICODE_NULL
;
3361 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3362 CONSOLE_SetCursorXY(8 + Pos
, 11);
3365 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3366 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3369 CONSOLE_SetCursorXY(8 + Pos
, 11);
3371 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3372 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3375 CONSOLE_SetCursorXY(8 + Pos
, 11);
3377 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3378 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3383 CONSOLE_SetCursorXY(8 + Pos
, 11);
3386 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3387 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3392 CONSOLE_SetCursorXY(8 + Pos
, 11);
3395 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3397 CONSOLE_SetCursorType(TRUE
, FALSE
);
3400 * Check for the validity of the installation directory and pop up
3401 * an error if it is not the case. Then the user can fix its input.
3403 if (!IsValidPath(InstallDir
))
3405 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3406 return INSTALL_DIRECTORY_PAGE
;
3409 BuildInstallPaths(InstallDir
,
3413 return PREPARE_COPY_PAGE
;
3415 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3420 memmove(&InstallDir
[Pos
- 1],
3422 (Length
- Pos
) * sizeof(WCHAR
));
3423 InstallDir
[Length
- 1] = UNICODE_NULL
;
3427 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3428 CONSOLE_SetCursorXY(8 + Pos
, 11);
3431 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3435 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3436 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3439 memmove(&InstallDir
[Pos
+ 1],
3441 (Length
- Pos
) * sizeof(WCHAR
));
3442 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3443 InstallDir
[Pos
] = c
;
3447 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3448 CONSOLE_SetCursorXY(8 + Pos
, 11);
3454 return INSTALL_DIRECTORY_PAGE
;
3459 AddSectionToCopyQueueCab(HINF InfFile
,
3461 PWCHAR SourceCabinet
,
3462 PCUNICODE_STRING DestinationPath
,
3465 INFCONTEXT FilesContext
;
3466 INFCONTEXT DirContext
;
3468 PWCHAR FileKeyValue
;
3470 PWCHAR TargetFileName
;
3473 * This code enumerates the list of files in reactos.dff / reactos.inf
3474 * that need to be extracted from reactos.cab and be installed in their
3475 * respective directories.
3478 /* Search for the SectionName section */
3479 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3482 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3483 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3488 * Enumerate the files in the section and add them to the file queue.
3492 /* Get source file name and target directory id */
3493 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3495 /* FIXME: Handle error! */
3496 DPRINT1("INF_GetData() failed\n");
3500 /* Get optional target file name */
3501 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3502 TargetFileName
= NULL
;
3504 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3506 /* Lookup target directory */
3507 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3509 /* FIXME: Handle error! */
3510 DPRINT1("SetupFindFirstLine() failed\n");
3514 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3516 /* FIXME: Handle error! */
3517 DPRINT1("INF_GetData() failed\n");
3521 if (!SetupQueueCopy(SetupFileQueue
,
3523 SourceRootPath
.Buffer
,
3524 SourceRootDir
.Buffer
,
3529 /* FIXME: Handle error! */
3530 DPRINT1("SetupQueueCopy() failed\n");
3532 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3539 AddSectionToCopyQueue(HINF InfFile
,
3541 PWCHAR SourceCabinet
,
3542 PCUNICODE_STRING DestinationPath
,
3545 INFCONTEXT FilesContext
;
3546 INFCONTEXT DirContext
;
3548 PWCHAR FileKeyValue
;
3550 PWCHAR TargetFileName
;
3551 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3554 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3557 * This code enumerates the list of files in txtsetup.sif
3558 * that need to be installed in their respective directories.
3561 /* Search for the SectionName section */
3562 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3565 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3566 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3571 * Enumerate the files in the section and add them to the file queue.
3575 /* Get source file name and target directory id */
3576 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3578 /* FIXME: Handle error! */
3579 DPRINT1("INF_GetData() failed\n");
3583 /* Get target directory id */
3584 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3586 /* FIXME: Handle error! */
3587 DPRINT1("INF_GetData() failed\n");
3591 /* Get optional target file name */
3592 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3593 TargetFileName
= NULL
;
3594 else if (!*TargetFileName
)
3595 TargetFileName
= NULL
;
3597 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3599 /* Lookup target directory */
3600 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3602 /* FIXME: Handle error! */
3603 DPRINT1("SetupFindFirstLine() failed\n");
3607 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3609 /* FIXME: Handle error! */
3610 DPRINT1("INF_GetData() failed\n");
3614 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3616 /* Installation path */
3617 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3619 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3620 SourceRootDir
.Buffer
);
3622 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3624 else if (DirKeyValue
[0] == L
'\\')
3627 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3629 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3632 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3634 else // if (DirKeyValue[0] != L'\\')
3636 /* Path relative to the installation path */
3637 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3639 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3640 SourceRootDir
.Buffer
, DirKeyValue
);
3642 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3645 if (!SetupQueueCopy(SetupFileQueue
,
3647 SourceRootPath
.Buffer
,
3648 CompleteOrigDirName
,
3653 /* FIXME: Handle error! */
3654 DPRINT1("SetupQueueCopy() failed\n");
3656 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3663 PrepareCopyPageInfFile(HINF InfFile
,
3664 PWCHAR SourceCabinet
,
3668 INFCONTEXT DirContext
;
3669 PWCHAR AdditionalSectionName
= NULL
;
3671 WCHAR PathBuffer
[MAX_PATH
];
3673 /* Add common files */
3674 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &DestinationPath
, Ir
))
3677 /* Add specific files depending of computer type */
3678 if (SourceCabinet
== NULL
)
3680 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3683 if (AdditionalSectionName
)
3685 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &DestinationPath
, Ir
))
3690 /* Create directories */
3694 * Copying files to DestinationRootPath should be done from within
3695 * the SystemPartitionFiles section.
3696 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3697 * For installing to DestinationPath specify just '\' .
3700 /* Get destination path */
3701 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), DestinationPath
.Buffer
);
3703 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3705 /* Create the install directory */
3706 Status
= SetupCreateDirectory(PathBuffer
);
3707 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3709 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3710 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3714 /* Search for the 'Directories' section */
3715 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3719 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3723 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3729 /* Enumerate the directory values and create the subdirectories */
3732 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3738 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3740 /* Installation path */
3741 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3743 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3744 DestinationPath
.Buffer
);
3746 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3748 else if (DirKeyValue
[0] == L
'\\')
3751 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3753 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3754 DestinationRootPath
.Buffer
, DirKeyValue
);
3756 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3758 Status
= SetupCreateDirectory(PathBuffer
);
3759 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3761 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3762 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3766 else // if (DirKeyValue[0] != L'\\')
3768 /* Path relative to the installation path */
3769 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3771 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3772 DestinationPath
.Buffer
, DirKeyValue
);
3774 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3776 Status
= SetupCreateDirectory(PathBuffer
);
3777 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3779 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3780 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3784 } while (SetupFindNextLine(&DirContext
, &DirContext
));
3791 * Displays the PrepareCopyPage.
3794 * FileCopyPage(At once)
3798 * Inits SetupFileQueue
3799 * Calls PrepareCopyPageInfFile
3802 * Number of the next page.
3805 PrepareCopyPage(PINPUT_RECORD Ir
)
3808 WCHAR PathBuffer
[MAX_PATH
];
3809 INFCONTEXT CabinetsContext
;
3815 MUIDisplayPage(PREPARE_COPY_PAGE
);
3817 /* Create the file queue */
3818 SetupFileQueue
= SetupOpenFileQueue();
3819 if (SetupFileQueue
== NULL
)
3821 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
3825 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
3827 /* FIXME: show an error dialog */
3831 /* Search for the 'Cabinets' section */
3832 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
3834 return FILE_COPY_PAGE
;
3838 * Enumerate the directory values in the 'Cabinets'
3839 * section and parse their inf files.
3843 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
3846 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3847 SourcePath
.Buffer
, KeyValue
);
3849 CabinetInitialize();
3850 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
3851 CabinetSetCabinetName(PathBuffer
);
3853 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
3855 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3857 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
3858 if (InfFileData
== NULL
)
3860 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
3866 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3867 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
3871 InfHandle
= INF_OpenBufferedFileA((CHAR
*) InfFileData
,
3878 if (InfHandle
== INVALID_HANDLE_VALUE
)
3880 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
3886 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
3888 /* FIXME: show an error dialog */
3891 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
3893 return FILE_COPY_PAGE
;
3899 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
3902 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
3904 /* Get the memory information from the system */
3905 NtQuerySystemInformation(SystemPerformanceInformation
,
3910 /* Check if this is initial setup */
3913 /* Set maximum limits to be total RAM pages */
3914 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
3915 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
3916 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
3919 /* Set current values */
3920 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
3921 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
3922 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
3928 FileCopyCallback(PVOID Context
,
3933 PCOPYCONTEXT CopyContext
;
3935 CopyContext
= (PCOPYCONTEXT
)Context
;
3937 switch (Notification
)
3939 case SPFILENOTIFY_STARTSUBQUEUE
:
3940 CopyContext
->TotalOperations
= (ULONG
)Param2
;
3941 ProgressSetStepCount(CopyContext
->ProgressBar
,
3942 CopyContext
->TotalOperations
);
3943 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
3946 case SPFILENOTIFY_STARTCOPY
:
3947 /* Display copy message */
3948 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
3949 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3952 case SPFILENOTIFY_ENDCOPY
:
3953 CopyContext
->CompletedOperations
++;
3955 /* SYSREG checkpoint */
3956 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
3957 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3959 ProgressNextStep(CopyContext
->ProgressBar
);
3960 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
3969 * Displays the FileCopyPage.
3972 * RegistryPage(At once)
3975 * Calls SetupCommitFileQueueW
3976 * Calls SetupCloseFileQueue
3979 * Number of the next page.
3982 FileCopyPage(PINPUT_RECORD Ir
)
3984 COPYCONTEXT CopyContext
;
3985 unsigned int mem_bar_width
;
3987 MUIDisplayPage(FILE_COPY_PAGE
);
3989 /* Create context for the copy process */
3990 CopyContext
.DestinationRootPath
= DestinationRootPath
.Buffer
;
3991 CopyContext
.InstallPath
= InstallPath
.Buffer
;
3992 CopyContext
.TotalOperations
= 0;
3993 CopyContext
.CompletedOperations
= 0;
3995 /* Create the progress bar as well */
3996 CopyContext
.ProgressBar
= CreateProgressBar(13,
4003 MUIGetString(STRING_SETUPCOPYINGFILES
));
4005 // fit memory bars to screen width, distribute them uniform
4006 mem_bar_width
= (xScreen
- 26) / 5;
4007 mem_bar_width
-= mem_bar_width
% 2; // make even
4008 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4009 /* Create the paged pool progress bar */
4010 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4019 /* Create the non paged pool progress bar */
4020 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4022 (xScreen
/ 2) + (mem_bar_width
/ 2),
4024 (xScreen
/ 2)- (mem_bar_width
/ 2),
4029 /* Create the global memory progress bar */
4030 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4034 xScreen
- 13 - mem_bar_width
,
4039 /* Do the file copying */
4040 SetupCommitFileQueueW(NULL
,
4045 /* If we get here, we're done, so cleanup the queue and progress bar */
4046 SetupCloseFileQueue(SetupFileQueue
);
4047 DestroyProgressBar(CopyContext
.ProgressBar
);
4048 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4049 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4050 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4052 /* Go display the next page */
4053 return REGISTRY_PAGE
;
4058 * Displays the RegistryPage.
4061 * SuccessPage (if RepairUpdate)
4062 * BootLoaderPage (default)
4066 * Calls RegInitializeRegistry
4067 * Calls ImportRegistryFile
4068 * Calls SetDefaultPagefile
4069 * Calls SetMountedDeviceValues
4072 * Number of the next page.
4075 RegistryPage(PINPUT_RECORD Ir
)
4078 INFCONTEXT InfContext
;
4084 MUIDisplayPage(REGISTRY_PAGE
);
4086 if (RepairUpdateFlag
)
4088 BOOLEAN ShouldUpdateRegistry
= FALSE
;
4090 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
4092 /* Verify the registry hives and check whether we need to update or repair any of them */
4093 Status
= VerifyRegistryHives(&DestinationPath
, &ShouldUpdateRegistry
);
4094 if (!NT_SUCCESS(Status
))
4096 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status
);
4097 ShouldUpdateRegistry
= FALSE
;
4099 if (!ShouldUpdateRegistry
)
4101 DPRINT1("No need to update the registry\n");
4102 // return SUCCESS_PAGE;
4107 /* Initialize the registry and setup the default installation hives */
4108 Status
= RegInitializeRegistry(&DestinationPath
);
4109 if (!NT_SUCCESS(Status
))
4111 DPRINT1("RegInitializeRegistry() failed\n");
4112 /********** HACK!!!!!!!!!!! **********/
4113 if (Status
== STATUS_NOT_IMPLEMENTED
)
4115 /* The hack was called, display its corresponding error */
4116 MUIDisplayError(ERROR_INITIALIZE_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4119 /*************************************/
4121 /* Something else failed */
4122 MUIDisplayError(ERROR_CREATE_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4127 /* Update registry */
4128 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE
));
4130 if (!SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
))
4132 DPRINT1("SetupFindFirstLine() failed\n");
4133 MUIDisplayError(ERROR_FIND_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4139 INF_GetDataField(&InfContext
, 0, &Action
);
4140 INF_GetDataField(&InfContext
, 1, &File
);
4141 INF_GetDataField(&InfContext
, 2, &Section
);
4143 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
4148 if (!_wcsicmp(Action
, L
"AddReg"))
4150 else if (!_wcsicmp(Action
, L
"DelReg"))
4155 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE
), File
);
4157 if (!ImportRegistryFile(File
, Section
, LanguageId
, Delete
))
4159 DPRINT1("Importing %S failed\n", File
);
4160 MUIDisplayError(ERROR_IMPORT_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4163 } while (SetupFindNextLine(&InfContext
, &InfContext
));
4165 /* Update display registry settings */
4166 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE
));
4167 if (!ProcessDisplayRegistry(SetupInf
, DisplayList
))
4169 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4173 /* Set the locale */
4174 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE
));
4175 if (!ProcessLocaleRegistry(LanguageList
))
4177 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4181 /* Add keyboard layouts */
4182 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS
));
4183 if (!AddKeyboardLayouts())
4185 MUIDisplayError(ERROR_ADDING_KBLAYOUTS
, Ir
, POPUP_WAIT_ENTER
);
4190 if (!SetGeoID(MUIGetGeoID()))
4192 MUIDisplayError(ERROR_UPDATE_GEOID
, Ir
, POPUP_WAIT_ENTER
);
4196 if (!IsUnattendedSetup
)
4198 /* Update keyboard layout settings */
4199 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE
));
4200 if (!ProcessKeyboardLayoutRegistry(LayoutList
))
4202 MUIDisplayError(ERROR_UPDATE_KBSETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4207 /* Add codepage information to registry */
4208 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE
));
4211 MUIDisplayError(ERROR_ADDING_CODEPAGE
, Ir
, POPUP_WAIT_ENTER
);
4215 /* Set the default pagefile entry */
4216 SetDefaultPagefile(DestinationDriveLetter
);
4218 /* Update the mounted devices list */
4219 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
4220 SetMountedDeviceValues(PartitionList
);
4224 // TODO: Unload all the registry stuff, perform cleanup,
4225 // and copy the created hive files into .sav files.
4227 RegCleanupRegistry(&DestinationPath
);
4230 if (NT_SUCCESS(Status
))
4232 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4233 return BOOT_LOADER_PAGE
;
4243 * Displays the BootLoaderPage.
4246 * SuccessPage (if RepairUpdate)
4247 * BootLoaderHarddiskMbrPage
4248 * BootLoaderHarddiskVbrPage
4249 * BootLoaderFloppyPage
4254 * Calls RegInitializeRegistry
4255 * Calls ImportRegistryFile
4256 * Calls SetDefaultPagefile
4257 * Calls SetMountedDeviceValues
4260 * Number of the next page.
4263 BootLoaderPage(PINPUT_RECORD Ir
)
4265 UCHAR PartitionType
;
4266 BOOLEAN InstallOnFloppy
;
4268 WCHAR PathBuffer
[MAX_PATH
];
4270 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4272 RtlFreeUnicodeString(&SystemRootPath
);
4273 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4274 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4275 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4276 PartitionList
->SystemPartition
->PartitionNumber
);
4277 RtlCreateUnicodeString(&SystemRootPath
, PathBuffer
);
4278 DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath
);
4280 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4282 if (IsUnattendedSetup
)
4284 if (UnattendMBRInstallType
== 0) /* skip MBR installation */
4286 return SUCCESS_PAGE
;
4288 else if (UnattendMBRInstallType
== 1) /* install on floppy */
4290 return BOOT_LOADER_FLOPPY_PAGE
;
4294 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4296 DPRINT("Error: system partition invalid (unused)\n");
4297 InstallOnFloppy
= TRUE
;
4299 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4301 /* OS/2 boot manager partition */
4302 DPRINT("Found OS/2 boot manager partition\n");
4303 InstallOnFloppy
= TRUE
;
4305 else if (PartitionType
== PARTITION_EXT2
)
4307 /* Linux EXT2 partition */
4308 DPRINT("Found Linux EXT2 partition\n");
4309 InstallOnFloppy
= FALSE
;
4311 else if (PartitionType
== PARTITION_IFS
)
4313 /* NTFS partition */
4314 DPRINT("Found NTFS partition\n");
4316 // FIXME: Make it FALSE when we'll support NTFS installation!
4317 InstallOnFloppy
= TRUE
;
4319 else if ((PartitionType
== PARTITION_FAT_12
) ||
4320 (PartitionType
== PARTITION_FAT_16
) ||
4321 (PartitionType
== PARTITION_HUGE
) ||
4322 (PartitionType
== PARTITION_XINT13
) ||
4323 (PartitionType
== PARTITION_FAT32
) ||
4324 (PartitionType
== PARTITION_FAT32_XINT13
))
4326 DPRINT("Found FAT partition\n");
4327 InstallOnFloppy
= FALSE
;
4331 /* Unknown partition */
4332 DPRINT("Unknown partition found\n");
4333 InstallOnFloppy
= TRUE
;
4336 if (InstallOnFloppy
!= FALSE
)
4338 return BOOT_LOADER_FLOPPY_PAGE
;
4341 /* Unattended install on hdd? */
4342 if (IsUnattendedSetup
&& UnattendMBRInstallType
== 2)
4344 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4347 MUIDisplayPage(BOOT_LOADER_PAGE
);
4348 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4352 CONSOLE_ConInKey(Ir
);
4354 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4355 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4357 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4366 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4368 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4369 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4371 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4380 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4382 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4383 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4385 if (ConfirmQuit(Ir
) != FALSE
)
4390 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4394 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4396 else if (Line
== 13)
4398 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4400 else if (Line
== 14)
4402 return BOOT_LOADER_FLOPPY_PAGE
;
4404 else if (Line
== 15)
4406 return SUCCESS_PAGE
;
4409 return BOOT_LOADER_PAGE
;
4413 return BOOT_LOADER_PAGE
;
4418 * Displays the BootLoaderFloppyPage.
4421 * SuccessPage (At once)
4425 * Calls InstallFatBootcodeToFloppy()
4428 * Number of the next page.
4431 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4435 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4437 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4441 CONSOLE_ConInKey(Ir
);
4443 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4444 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4446 if (ConfirmQuit(Ir
) != FALSE
)
4451 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4453 if (DoesPathExist(NULL
, L
"\\Device\\Floppy0\\") == FALSE
)
4455 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4456 return BOOT_LOADER_FLOPPY_PAGE
;
4459 Status
= InstallFatBootcodeToFloppy(&SourceRootPath
, &DestinationArcPath
);
4460 if (!NT_SUCCESS(Status
))
4462 /* Print error message */
4463 return BOOT_LOADER_FLOPPY_PAGE
;
4466 return SUCCESS_PAGE
;
4470 return BOOT_LOADER_FLOPPY_PAGE
;
4475 * Displays the BootLoaderHarddiskVbrPage.
4478 * SuccessPage (At once)
4482 * Calls InstallVBRToPartition()
4485 * Number of the next page.
4488 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4492 Status
= InstallVBRToPartition(&SystemRootPath
,
4494 &DestinationArcPath
,
4495 PartitionList
->SystemPartition
->PartitionType
);
4496 if (!NT_SUCCESS(Status
))
4498 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4502 return SUCCESS_PAGE
;
4507 * Displays the BootLoaderHarddiskMbrPage.
4510 * SuccessPage (At once)
4514 * Calls InstallVBRToPartition()
4515 * Calls InstallMbrBootCodeToDisk()
4518 * Number of the next page.
4521 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4524 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4525 WCHAR SourceMbrPathBuffer
[MAX_PATH
];
4526 WCHAR DstPath
[MAX_PATH
];
4528 /* Step 1: Write the VBR */
4529 Status
= InstallVBRToPartition(&SystemRootPath
,
4531 &DestinationArcPath
,
4532 PartitionList
->SystemPartition
->PartitionType
);
4533 if (!NT_SUCCESS(Status
))
4535 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4539 /* Step 2: Write the MBR */
4540 StringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4541 L
"\\Device\\Harddisk%d\\Partition0",
4542 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4544 CombinePaths(SourceMbrPathBuffer
, ARRAYSIZE(SourceMbrPathBuffer
), 2, SourceRootPath
.Buffer
, L
"\\loader\\dosmbr.bin");
4546 if (IsThereAValidBootSector(DestinationDevicePathBuffer
))
4548 /* Save current MBR */
4549 CombinePaths(DstPath
, ARRAYSIZE(DstPath
), 2, SystemRootPath
.Buffer
, L
"mbr.old");
4551 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer
, DstPath
);
4552 Status
= SaveBootSector(DestinationDevicePathBuffer
, DstPath
, sizeof(PARTITION_SECTOR
));
4553 if (!NT_SUCCESS(Status
))
4555 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status
);
4556 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4560 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4561 SourceMbrPathBuffer
, DestinationDevicePathBuffer
);
4562 Status
= InstallMbrBootCodeToDisk(SourceMbrPathBuffer
,
4563 DestinationDevicePathBuffer
);
4564 if (!NT_SUCCESS(Status
))
4566 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4568 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4572 return SUCCESS_PAGE
;
4577 * @name ProgressTimeOutStringHandler
4579 * Handles the generation (displaying) of the timeout
4580 * countdown to the screen dynamically.
4583 * A pointer to a progress bar.
4585 * @param AlwaysUpdate
4586 * Constantly update the progress bar (boolean type).
4589 * A pointer to a string buffer.
4591 * @param cchBufferSize
4592 * The buffer's size in number of characters.
4595 * TRUE or FALSE on function termination.
4600 ProgressTimeOutStringHandler(
4601 IN PPROGRESSBAR Bar
,
4602 IN BOOLEAN AlwaysUpdate
,
4604 IN SIZE_T cchBufferSize
)
4606 ULONG OldProgress
= Bar
->Progress
;
4608 if (Bar
->StepCount
== 0)
4614 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4617 /* Build the progress string if it has changed */
4618 if (Bar
->ProgressFormatText
&&
4619 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4621 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4622 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4631 * @name ProgressCountdown
4633 * Displays and draws a red-coloured progress bar with a countdown.
4634 * When the timeout is reached, the flush page is displayed for reboot.
4637 * A pointer to an input keyboard record.
4640 * Initial countdown value in seconds.
4648 IN PINPUT_RECORD Ir
,
4652 ULONG StartTime
, BarWidth
, TimerDiv
;
4654 LONG TimerValue
, OldTimerValue
;
4655 LARGE_INTEGER Timeout
;
4656 PPROGRESSBAR ProgressBar
;
4657 BOOLEAN RefreshProgress
= TRUE
;
4659 /* Bail out if the timeout is already zero */
4663 /* Create the timeout progress bar and set it up */
4664 ProgressBar
= CreateProgressBarEx(13,
4671 FOREGROUND_RED
| BACKGROUND_BLUE
,
4674 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4675 ProgressTimeOutStringHandler
);
4677 BarWidth
= max(1, ProgressBar
->Width
);
4678 TimerValue
= TimeOut
* BarWidth
;
4679 ProgressSetStepCount(ProgressBar
, TimerValue
);
4681 StartTime
= NtGetTickCount();
4684 TimerDiv
= 1000 / BarWidth
;
4685 TimerDiv
= max(1, TimerDiv
);
4686 OldTimerValue
= TimerValue
;
4689 /* Decrease the timer */
4692 * Compute how much time the previous operations took.
4693 * This allows us in particular to take account for any time
4694 * elapsed if something slowed down.
4696 TimeElapsed
= NtGetTickCount() - StartTime
;
4697 if (TimeElapsed
>= TimerDiv
)
4699 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4700 TimeElapsed
/= TimerDiv
;
4701 StartTime
+= (TimerDiv
* TimeElapsed
);
4703 if (TimeElapsed
<= TimerValue
)
4704 TimerValue
-= TimeElapsed
;
4708 RefreshProgress
= TRUE
;
4711 if (RefreshProgress
)
4713 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4714 RefreshProgress
= FALSE
;
4717 /* Stop when the timer reaches zero */
4718 if (TimerValue
<= 0)
4721 /* Check for user key presses */
4724 * If the timer is used, use a passive wait of maximum 1 second
4725 * while monitoring for incoming console input events, so that
4726 * we are still able to display the timing count.
4729 /* Wait a maximum of 1 second for input events */
4730 TimeElapsed
= NtGetTickCount() - StartTime
;
4731 if (TimeElapsed
< TimerDiv
)
4733 /* Convert the time to NT Format */
4734 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4735 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4739 Status
= STATUS_TIMEOUT
;
4742 /* Check whether the input event has been signaled, or a timeout happened */
4743 if (Status
== STATUS_TIMEOUT
)
4747 if (Status
!= STATUS_WAIT_0
)
4749 /* An error happened, bail out */
4750 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
4754 /* Check for an ENTER key press */
4755 while (CONSOLE_ConInKeyPeek(Ir
))
4757 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4759 /* Found it, stop waiting */
4766 /* Destroy the progress bar and quit */
4767 DestroyProgressBar(ProgressBar
);
4772 * Displays the QuitPage.
4775 * FlushPage (At once)
4781 * Number of the next page.
4784 QuitPage(PINPUT_RECORD Ir
)
4786 MUIDisplayPage(QUIT_PAGE
);
4788 /* Destroy the partition list */
4789 if (PartitionList
!= NULL
)
4791 DestroyPartitionList(PartitionList
);
4792 PartitionList
= NULL
;
4794 TempPartition
= NULL
;
4795 FormatState
= Start
;
4797 /* Destroy the filesystem list */
4798 if (FileSystemList
!= NULL
)
4800 DestroyFileSystemList(FileSystemList
);
4801 FileSystemList
= NULL
;
4804 /* Destroy the computer settings list */
4805 if (ComputerList
!= NULL
)
4807 DestroyGenericList(ComputerList
, TRUE
);
4808 ComputerList
= NULL
;
4811 /* Destroy the display settings list */
4812 if (DisplayList
!= NULL
)
4814 DestroyGenericList(DisplayList
, TRUE
);
4818 /* Destroy the keyboard settings list */
4819 if (KeyboardList
!= NULL
)
4821 DestroyGenericList(KeyboardList
, TRUE
);
4822 KeyboardList
= NULL
;
4825 /* Destroy the keyboard layout list */
4826 if (LayoutList
!= NULL
)
4828 DestroyGenericList(LayoutList
, TRUE
);
4832 /* Destroy the languages list */
4833 if (LanguageList
!= NULL
)
4835 DestroyGenericList(LanguageList
, FALSE
);
4836 LanguageList
= NULL
;
4839 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
4841 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4842 ProgressCountdown(Ir
, 15);
4848 * Displays the SuccessPage.
4851 * FlushPage (At once)
4857 * Number of the next page.
4860 SuccessPage(PINPUT_RECORD Ir
)
4862 MUIDisplayPage(SUCCESS_PAGE
);
4864 if (IsUnattendedSetup
)
4867 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4868 ProgressCountdown(Ir
, 15);
4874 * Displays the FlushPage.
4877 * RebootPage (At once)
4880 * Number of the next page.
4883 FlushPage(PINPUT_RECORD Ir
)
4885 MUIDisplayPage(FLUSH_PAGE
);
4891 PnpEventThread(IN LPVOID lpParameter
);
4895 * The start routine and page management
4905 InfSetHeap(ProcessHeap
);
4907 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4908 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
4909 if (!NT_SUCCESS(Status
))
4910 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
4912 /* Create the PnP thread in suspended state */
4913 Status
= RtlCreateUserThread(NtCurrentProcess(),
4923 if (!NT_SUCCESS(Status
))
4924 hPnpThread
= INVALID_HANDLE_VALUE
;
4926 if (!CONSOLE_Init())
4928 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
4929 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
4930 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
4932 /* We failed to initialize the video, just quit the installer */
4933 return STATUS_APP_INIT_FAILURE
;
4936 /* Initialize global unicode strings */
4937 RtlInitUnicodeString(&SourcePath
, NULL
);
4938 RtlInitUnicodeString(&SourceRootPath
, NULL
);
4939 RtlInitUnicodeString(&SourceRootDir
, NULL
);
4940 RtlInitUnicodeString(&InstallPath
, NULL
);
4941 RtlInitUnicodeString(&DestinationPath
, NULL
);
4942 RtlInitUnicodeString(&DestinationArcPath
, NULL
);
4943 RtlInitUnicodeString(&DestinationRootPath
, NULL
);
4944 RtlInitUnicodeString(&SystemRootPath
, NULL
);
4946 /* Hide the cursor */
4947 CONSOLE_SetCursorType(TRUE
, FALSE
);
4949 /* Global Initialization page */
4950 CONSOLE_ClearScreen();
4952 Page
= SetupStartPage(&Ir
);
4954 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
4956 CONSOLE_ClearScreen();
4959 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4966 Page
= LanguagePage(&Ir
);
4971 Page
= WelcomePage(&Ir
);
4976 Page
= LicensePage(&Ir
);
4980 case INSTALL_INTRO_PAGE
:
4981 Page
= InstallIntroPage(&Ir
);
4985 case SCSI_CONTROLLER_PAGE
:
4986 Page
= ScsiControllerPage(&Ir
);
4989 case OEM_DRIVER_PAGE
:
4990 Page
= OemDriverPage(&Ir
);
4994 case DEVICE_SETTINGS_PAGE
:
4995 Page
= DeviceSettingsPage(&Ir
);
4998 case COMPUTER_SETTINGS_PAGE
:
4999 Page
= ComputerSettingsPage(&Ir
);
5002 case DISPLAY_SETTINGS_PAGE
:
5003 Page
= DisplaySettingsPage(&Ir
);
5006 case KEYBOARD_SETTINGS_PAGE
:
5007 Page
= KeyboardSettingsPage(&Ir
);
5010 case LAYOUT_SETTINGS_PAGE
:
5011 Page
= LayoutSettingsPage(&Ir
);
5014 case SELECT_PARTITION_PAGE
:
5015 Page
= SelectPartitionPage(&Ir
);
5018 case CREATE_PRIMARY_PARTITION_PAGE
:
5019 Page
= CreatePrimaryPartitionPage(&Ir
);
5022 case CREATE_EXTENDED_PARTITION_PAGE
:
5023 Page
= CreateExtendedPartitionPage(&Ir
);
5026 case CREATE_LOGICAL_PARTITION_PAGE
:
5027 Page
= CreateLogicalPartitionPage(&Ir
);
5030 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5031 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5034 case DELETE_PARTITION_PAGE
:
5035 Page
= DeletePartitionPage(&Ir
);
5038 case SELECT_FILE_SYSTEM_PAGE
:
5039 Page
= SelectFileSystemPage(&Ir
);
5042 case FORMAT_PARTITION_PAGE
:
5043 Page
= FormatPartitionPage(&Ir
);
5046 case CHECK_FILE_SYSTEM_PAGE
:
5047 Page
= CheckFileSystemPage(&Ir
);
5050 case INSTALL_DIRECTORY_PAGE
:
5051 Page
= InstallDirectoryPage(&Ir
);
5054 case PREPARE_COPY_PAGE
:
5055 Page
= PrepareCopyPage(&Ir
);
5058 case FILE_COPY_PAGE
:
5059 Page
= FileCopyPage(&Ir
);
5063 Page
= RegistryPage(&Ir
);
5066 case BOOT_LOADER_PAGE
:
5067 Page
= BootLoaderPage(&Ir
);
5070 case BOOT_LOADER_FLOPPY_PAGE
:
5071 Page
= BootLoaderFloppyPage(&Ir
);
5074 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5075 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5078 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5079 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5083 case REPAIR_INTRO_PAGE
:
5084 Page
= RepairIntroPage(&Ir
);
5088 Page
= SuccessPage(&Ir
);
5092 Page
= FlushPage(&Ir
);
5096 Page
= QuitPage(&Ir
);
5105 if (Page
== RECOVERY_PAGE
)
5111 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5112 NtShutdownSystem(ShutdownReboot
);
5113 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5115 return STATUS_SUCCESS
;
5120 NtProcessStartup(PPEB Peb
)
5125 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5127 ProcessHeap
= Peb
->ProcessHeap
;
5129 NtQuerySystemTime(&Time
);
5131 Status
= RunUSetup();
5133 if (NT_SUCCESS(Status
))
5136 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5137 * a protective waiting.
5138 * This wait is needed because, since we are started as SMSS.EXE,
5139 * the NT kernel explicitly waits 5 seconds for the initial process
5140 * SMSS.EXE to initialize (as a protective measure), and otherwise
5141 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5143 Time
.QuadPart
+= 50000000;
5144 NtDelayExecution(FALSE
, &Time
);
5148 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5149 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5150 0, 0, NULL
, 0, NULL
);
5153 NtTerminateProcess(NtCurrentProcess(), Status
);