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)
44 /* GLOBALS ******************************************************************/
48 static UNICODE_STRING SourceRootPath
;
49 static UNICODE_STRING SourceRootDir
;
50 static UNICODE_STRING SourcePath
;
52 BOOLEAN IsUnattendedSetup
= FALSE
;
53 LONG UnattendDestinationDiskNumber
;
54 LONG UnattendDestinationPartitionNumber
;
55 LONG UnattendMBRInstallType
= -1;
56 LONG UnattendFormatPartition
= 0;
57 LONG AutoPartition
= 0;
58 WCHAR UnattendInstallationDirectory
[MAX_PATH
];
59 PWCHAR SelectedLanguageId
;
61 WCHAR DefaultLanguage
[20];
62 WCHAR DefaultKBLayout
[20];
63 static BOOLEAN RepairUpdateFlag
= FALSE
;
64 static HANDLE hPnpThread
= INVALID_HANDLE_VALUE
;
66 static PPARTLIST PartitionList
= NULL
;
67 static PPARTENTRY TempPartition
= NULL
;
68 static FORMATMACHINESTATE FormatState
= Start
;
71 /* LOCALS *******************************************************************/
73 static PFILE_SYSTEM_LIST FileSystemList
= NULL
;
76 * NOTE: Technically only used for the COPYCONTEXT InstallPath member
77 * for the filequeue functionality.
79 static UNICODE_STRING InstallPath
;
82 * Path to the system partition, where the boot manager resides.
83 * On x86 PCs, this is usually the active partition.
84 * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
86 * For more information, see:
87 * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
88 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
89 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
90 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
91 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
92 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
94 static UNICODE_STRING SystemRootPath
;
96 /* Path to the installation directory inside the ReactOS boot partition */
97 static UNICODE_STRING DestinationPath
;
98 static UNICODE_STRING DestinationArcPath
;
99 static UNICODE_STRING DestinationRootPath
;
101 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
102 static WCHAR DestinationDriveLetter
;
104 static HINF SetupInf
;
106 static HSPFILEQ SetupFileQueue
= NULL
;
108 static PNTOS_INSTALLATION CurrentInstallation
= NULL
;
109 static PGENERIC_LIST NtOsInstallsList
= NULL
;
111 static PGENERIC_LIST ComputerList
= NULL
;
112 static PGENERIC_LIST DisplayList
= NULL
;
113 static PGENERIC_LIST KeyboardList
= NULL
;
114 static PGENERIC_LIST LayoutList
= NULL
;
115 static PGENERIC_LIST LanguageList
= NULL
;
117 static LANGID LanguageId
= 0;
119 static ULONG RequiredPartitionDiskSpace
= ~0;
121 /* FUNCTIONS ****************************************************************/
124 PrintString(char* fmt
,...)
128 UNICODE_STRING UnicodeString
;
129 ANSI_STRING AnsiString
;
132 vsprintf(buffer
, fmt
, ap
);
135 RtlInitAnsiString(&AnsiString
, buffer
);
136 RtlAnsiStringToUnicodeString(&UnicodeString
, &AnsiString
, TRUE
);
137 NtDisplayString(&UnicodeString
);
138 RtlFreeUnicodeString(&UnicodeString
);
143 DrawBox(IN SHORT xLeft
,
151 /* draw upper left corner */
154 FillConsoleOutputCharacterA(StdOutput
,
160 /* draw upper edge */
163 FillConsoleOutputCharacterA(StdOutput
,
169 /* draw upper right corner */
170 coPos
.X
= xLeft
+ Width
- 1;
172 FillConsoleOutputCharacterA(StdOutput
,
178 /* Draw right edge, inner space and left edge */
179 for (coPos
.Y
= yTop
+ 1; coPos
.Y
< yTop
+ Height
- 1; coPos
.Y
++)
182 FillConsoleOutputCharacterA(StdOutput
,
189 FillConsoleOutputCharacterA(StdOutput
,
195 coPos
.X
= xLeft
+ Width
- 1;
196 FillConsoleOutputCharacterA(StdOutput
,
203 /* draw lower left corner */
205 coPos
.Y
= yTop
+ Height
- 1;
206 FillConsoleOutputCharacterA(StdOutput
,
212 /* draw lower edge */
214 coPos
.Y
= yTop
+ Height
- 1;
215 FillConsoleOutputCharacterA(StdOutput
,
221 /* draw lower right corner */
222 coPos
.X
= xLeft
+ Width
- 1;
223 coPos
.Y
= yTop
+ Height
- 1;
224 FillConsoleOutputCharacterA(StdOutput
,
233 PopupError(PCCH Text
,
251 /* Count text lines and longest line */
258 p
= strchr(pnext
, '\n');
262 Length
= strlen(pnext
);
267 Length
= (ULONG
)(p
- pnext
);
273 if (Length
> MaxLength
)
276 if (LastLine
!= FALSE
)
282 /* Check length of status line */
285 Length
= strlen(Status
);
287 if (Length
> MaxLength
)
291 Width
= MaxLength
+ 4;
297 yTop
= (yScreen
- Height
) / 2;
298 xLeft
= (xScreen
- Width
) / 2;
301 /* Set screen attributes */
303 for (coPos
.Y
= yTop
; coPos
.Y
< yTop
+ Height
; coPos
.Y
++)
305 FillConsoleOutputAttribute(StdOutput
,
306 FOREGROUND_RED
| BACKGROUND_WHITE
,
312 DrawBox(xLeft
, yTop
, Width
, Height
);
314 /* Print message text */
319 p
= strchr(pnext
, '\n');
323 Length
= strlen(pnext
);
328 Length
= (ULONG
)(p
- pnext
);
335 WriteConsoleOutputCharacterA(StdOutput
,
342 if (LastLine
!= FALSE
)
349 /* Print separator line and status text */
352 coPos
.Y
= yTop
+ Height
- 3;
354 FillConsoleOutputCharacterA(StdOutput
,
361 FillConsoleOutputCharacterA(StdOutput
,
367 coPos
.X
= xLeft
+ Width
- 1;
368 FillConsoleOutputCharacterA(StdOutput
,
376 WriteConsoleOutputCharacterA(StdOutput
,
378 min(strlen(Status
), (SIZE_T
)Width
- 4),
383 if (WaitEvent
== POPUP_WAIT_NONE
)
388 CONSOLE_ConInKey(Ir
);
390 if (WaitEvent
== POPUP_WAIT_ANY_KEY
||
391 Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D)
403 * FALSE: Don't quit setup.
406 ConfirmQuit(PINPUT_RECORD Ir
)
409 MUIDisplayError(ERROR_NOT_INSTALLED
, NULL
, POPUP_WAIT_NONE
);
413 CONSOLE_ConInKey(Ir
);
415 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
416 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
421 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
433 CheckUnattendedSetup(VOID
)
435 WCHAR UnattendInfPath
[MAX_PATH
];
442 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2, SourcePath
.Buffer
, L
"unattend.inf");
444 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
446 DPRINT("Does not exist: %S\n", UnattendInfPath
);
450 /* Load 'unattend.inf' from install media. */
451 UnattendInf
= SetupOpenInfFileExW(UnattendInfPath
,
457 if (UnattendInf
== INVALID_HANDLE_VALUE
)
459 DPRINT("SetupOpenInfFileExW() failed\n");
463 /* Open 'Unattend' section */
464 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
466 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
467 SetupCloseInfFile(UnattendInf
);
471 /* Get pointer 'Signature' key */
472 if (!INF_GetData(&Context
, NULL
, &Value
))
474 DPRINT("INF_GetData() failed for key 'Signature'\n");
475 SetupCloseInfFile(UnattendInf
);
479 /* Check 'Signature' string */
480 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
482 DPRINT("Signature not $ReactOS$\n");
483 SetupCloseInfFile(UnattendInf
);
487 /* Check if Unattend setup is enabled */
488 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
490 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
491 SetupCloseInfFile(UnattendInf
);
495 if (!INF_GetData(&Context
, NULL
, &Value
))
497 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
498 SetupCloseInfFile(UnattendInf
);
502 if (_wcsicmp(Value
, L
"yes") != 0)
504 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
505 SetupCloseInfFile(UnattendInf
);
509 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
510 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
512 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
513 SetupCloseInfFile(UnattendInf
);
517 if (!SetupGetIntField(&Context
, 1, &IntValue
))
519 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
520 SetupCloseInfFile(UnattendInf
);
524 UnattendDestinationDiskNumber
= (LONG
)IntValue
;
526 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
527 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
529 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
530 SetupCloseInfFile(UnattendInf
);
534 if (!SetupGetIntField(&Context
, 1, &IntValue
))
536 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
537 SetupCloseInfFile(UnattendInf
);
541 UnattendDestinationPartitionNumber
= (LONG
)IntValue
;
543 /* Search for 'InstallationDirectory' in the 'Unattend' section */
544 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
546 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
547 SetupCloseInfFile(UnattendInf
);
551 /* Get pointer 'InstallationDirectory' key */
552 if (!INF_GetData(&Context
, NULL
, &Value
))
554 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
555 SetupCloseInfFile(UnattendInf
);
559 wcscpy(UnattendInstallationDirectory
, Value
);
561 IsUnattendedSetup
= TRUE
;
562 DPRINT("Running unattended setup\n");
564 /* Search for 'MBRInstallType' in the 'Unattend' section */
565 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
567 if (SetupGetIntField(&Context
, 1, &IntValue
))
569 UnattendMBRInstallType
= IntValue
;
573 /* Search for 'FormatPartition' in the 'Unattend' section */
574 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
576 if (SetupGetIntField(&Context
, 1, &IntValue
))
578 UnattendFormatPartition
= IntValue
;
582 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
584 if (SetupGetIntField(&Context
, 1, &IntValue
))
586 AutoPartition
= IntValue
;
590 /* search for LocaleID in the 'Unattend' section*/
591 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
593 if (INF_GetData(&Context
, NULL
, &Value
))
595 LONG Id
= wcstol(Value
, NULL
, 16);
596 swprintf(LocaleID
, L
"%08lx", Id
);
600 SetupCloseInfFile(UnattendInf
);
607 PGENERIC_LIST_ENTRY ListEntry
;
608 LPCWSTR pszNewLayout
;
610 pszNewLayout
= MUIDefaultKeyboardLayout();
612 if (LayoutList
== NULL
)
614 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
615 if (LayoutList
== NULL
)
617 /* FIXME: Handle error! */
622 ListEntry
= GetFirstListEntry(LayoutList
);
624 /* Search for default layout (if provided) */
625 if (pszNewLayout
!= NULL
)
627 while (ListEntry
!= NULL
)
629 if (!wcscmp(pszNewLayout
, GetListEntryUserData(ListEntry
)))
631 SetCurrentListEntry(LayoutList
, ListEntry
);
635 ListEntry
= GetNextListEntry(ListEntry
);
642 * Displays the LanguagePage.
644 * Next pages: WelcomePage, QuitPage
647 * Init SelectedLanguageId
651 * Number of the next page.
654 LanguagePage(PINPUT_RECORD Ir
)
656 GENERIC_LIST_UI ListUi
;
657 PWCHAR NewLanguageId
;
658 BOOL RefreshPage
= FALSE
;
660 /* Initialize the computer settings list */
661 if (LanguageList
== NULL
)
663 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
664 if (LanguageList
== NULL
)
666 PopupError("Setup failed to initialize available translations", NULL
, NULL
, POPUP_WAIT_NONE
);
672 SelectedLanguageId
= DefaultLanguage
;
673 SetConsoleCodePage();
676 /* If there's just a single language in the list skip
677 * the language selection process altogether! */
678 if (GenericListHasSingleEntry(LanguageList
))
680 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
684 InitGenericListUi(&ListUi
, LanguageList
);
685 DrawGenericList(&ListUi
,
691 ScrollToPositionGenericList(&ListUi
, GetDefaultLanguageIndex());
693 MUIDisplayPage(LANGUAGE_PAGE
);
697 CONSOLE_ConInKey(Ir
);
699 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
700 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
702 ScrollDownGenericList(&ListUi
);
705 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
706 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
708 ScrollUpGenericList(&ListUi
);
711 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
712 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
714 ScrollPageDownGenericList(&ListUi
);
717 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
718 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
720 ScrollPageUpGenericList(&ListUi
);
723 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
724 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
726 if (ConfirmQuit(Ir
) != FALSE
)
729 RedrawGenericList(&ListUi
);
731 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
733 SelectedLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
735 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
737 if (wcscmp(SelectedLanguageId
, DefaultLanguage
))
743 SetConsoleCodePage();
747 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
750 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
756 NewLanguageId
= (PWCHAR
)GetListEntryUserData(GetCurrentListEntry(LanguageList
));
758 if (SelectedLanguageId
!= NewLanguageId
)
760 /* Clear the language page */
761 MUIClearPage(LANGUAGE_PAGE
);
763 SelectedLanguageId
= NewLanguageId
;
766 SetConsoleCodePage();
768 /* Redraw language selection page in native language */
769 MUIDisplayPage(LANGUAGE_PAGE
);
782 OUT PUNICODE_STRING SourcePath
,
783 OUT PUNICODE_STRING SourceRootPath
,
784 OUT PUNICODE_STRING SourceRootDir
)
787 OBJECT_ATTRIBUTES ObjectAttributes
;
788 UNICODE_STRING LinkName
= RTL_CONSTANT_STRING(L
"\\SystemRoot");
789 UNICODE_STRING SourceName
;
790 WCHAR SourceBuffer
[MAX_PATH
] = L
"";
795 InitializeObjectAttributes(&ObjectAttributes
,
797 OBJ_CASE_INSENSITIVE
,
801 Status
= NtOpenSymbolicLinkObject(&Handle
,
802 SYMBOLIC_LINK_ALL_ACCESS
,
804 if (!NT_SUCCESS(Status
))
807 RtlInitEmptyUnicodeString(&SourceName
, SourceBuffer
, sizeof(SourceBuffer
));
809 Status
= NtQuerySymbolicLinkObject(Handle
,
814 if (!NT_SUCCESS(Status
))
817 RtlCreateUnicodeString(SourcePath
,
820 /* Strip trailing directory */
821 Ptr
= wcsrchr(SourceName
.Buffer
, OBJ_NAME_PATH_SEPARATOR
);
824 RtlCreateUnicodeString(SourceRootDir
, Ptr
);
829 RtlCreateUnicodeString(SourceRootDir
, L
"");
832 RtlCreateUnicodeString(SourceRootPath
,
835 return STATUS_SUCCESS
;
843 * LanguagePage (at once, default)
844 * InstallIntroPage (at once, if unattended)
850 * Init SourceRootPath
853 * Init RequiredPartitionDiskSpace
854 * Init IsUnattendedSetup
855 * If unattended, init *List and sets the Codepage
856 * If unattended, init SelectedLanguageId
857 * If unattended, init LanguageId
860 * Number of the next page.
863 SetupStartPage(PINPUT_RECORD Ir
)
866 WCHAR FileNameBuffer
[MAX_PATH
];
870 PGENERIC_LIST_ENTRY ListEntry
;
873 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
875 /* Get the source path and source root path */
876 Status
= GetSourcePaths(&SourcePath
,
879 if (!NT_SUCCESS(Status
))
881 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status
);
882 MUIDisplayError(ERROR_NO_SOURCE_DRIVE
, Ir
, POPUP_WAIT_ENTER
);
885 DPRINT1("SourcePath: '%wZ'\n", &SourcePath
);
886 DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath
);
887 DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir
);
889 /* Load txtsetup.sif from install media. */
890 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2, SourcePath
.Buffer
, L
"txtsetup.sif");
891 SetupInf
= SetupOpenInfFileExW(FileNameBuffer
,
897 if (SetupInf
== INVALID_HANDLE_VALUE
)
899 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
903 /* Open 'Version' section */
904 if (!SetupFindFirstLineW(SetupInf
, L
"Version", L
"Signature", &Context
))
906 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
910 /* Get pointer 'Signature' key */
911 if (!INF_GetData(&Context
, NULL
, &Value
))
913 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
917 /* Check 'Signature' string */
918 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
920 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
924 /* Open 'DiskSpaceRequirements' section */
925 if (!SetupFindFirstLineW(SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
927 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
931 /* Get the 'FreeSysPartDiskSpace' value */
932 if (!SetupGetIntField(&Context
, 1, &IntValue
))
934 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF
, Ir
, POPUP_WAIT_ENTER
);
938 RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
940 /* Start the PnP thread */
941 if (hPnpThread
!= INVALID_HANDLE_VALUE
)
943 NtResumeThread(hPnpThread
, NULL
);
944 hPnpThread
= INVALID_HANDLE_VALUE
;
947 CheckUnattendedSetup();
949 if (IsUnattendedSetup
)
951 // TODO: Read options from inf
952 ComputerList
= CreateComputerTypeList(SetupInf
);
953 DisplayList
= CreateDisplayDriverList(SetupInf
);
954 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
955 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
956 LanguageList
= CreateLanguageList(SetupInf
, DefaultLanguage
);
959 wcscpy(SelectedLanguageId
, LocaleID
);
960 LanguageId
= (LANGID
)(wcstol(SelectedLanguageId
, NULL
, 16) & 0xFFFF);
962 /* first we hack LanguageList */
963 ListEntry
= GetFirstListEntry(LanguageList
);
964 while (ListEntry
!= NULL
)
966 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
968 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry
));
969 SetCurrentListEntry(LanguageList
, ListEntry
);
973 ListEntry
= GetNextListEntry(ListEntry
);
977 ListEntry
= GetFirstListEntry(LayoutList
);
978 while (ListEntry
!= NULL
)
980 if (!wcsicmp(LocaleID
, GetListEntryUserData(ListEntry
)))
982 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry
));
983 SetCurrentListEntry(LayoutList
, ListEntry
);
987 ListEntry
= GetNextListEntry(ListEntry
);
990 SetConsoleCodePage();
992 return INSTALL_INTRO_PAGE
;
995 return LANGUAGE_PAGE
;
1000 * Displays the WelcomePage.
1003 * InstallIntroPage (default)
1010 * Number of the next page.
1013 WelcomePage(PINPUT_RECORD Ir
)
1015 MUIDisplayPage(WELCOME_PAGE
);
1019 CONSOLE_ConInKey(Ir
);
1021 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1022 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1024 if (ConfirmQuit(Ir
) != FALSE
)
1029 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1031 return INSTALL_INTRO_PAGE
;
1033 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
1035 return RECOVERY_PAGE
; // REPAIR_INTRO_PAGE;
1037 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'L') /* L */
1039 return LICENSE_PAGE
;
1043 return WELCOME_PAGE
;
1048 * Displays the License page.
1051 * WelcomePage (default)
1054 * Number of the next page.
1057 LicensePage(PINPUT_RECORD Ir
)
1059 MUIDisplayPage(LICENSE_PAGE
);
1063 CONSOLE_ConInKey(Ir
);
1065 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1067 return WELCOME_PAGE
;
1071 return LICENSE_PAGE
;
1076 * Displays the RepairIntroPage.
1079 * RebootPage (default)
1085 * Number of the next page.
1088 RepairIntroPage(PINPUT_RECORD Ir
)
1090 MUIDisplayPage(REPAIR_INTRO_PAGE
);
1094 CONSOLE_ConInKey(Ir
);
1096 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1100 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
1102 RepairUpdateFlag
= TRUE
;
1103 return INSTALL_INTRO_PAGE
;
1105 else if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'R') /* R */
1107 return RECOVERY_PAGE
;
1109 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1110 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1112 return WELCOME_PAGE
;
1116 return REPAIR_INTRO_PAGE
;
1120 * Displays the UpgradeRepairPage.
1123 * RebootPage (default)
1129 * Number of the next page.
1132 UpgradeRepairPage(PINPUT_RECORD Ir
)
1134 GENERIC_LIST_UI ListUi
;
1137 if (PartitionList
== NULL
)
1139 PartitionList
= CreatePartitionList();
1140 if (PartitionList
== NULL
)
1142 /* FIXME: show an error dialog */
1143 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1146 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1148 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1152 TempPartition
= NULL
;
1153 FormatState
= Start
;
1157 NtOsInstallsList
= CreateNTOSInstallationsList(PartitionList
);
1158 if (!NtOsInstallsList
)
1159 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
1160 if (!NtOsInstallsList
|| GetNumberOfListEntries(NtOsInstallsList
) == 0)
1162 RepairUpdateFlag
= FALSE
;
1164 // return INSTALL_INTRO_PAGE;
1165 return DEVICE_SETTINGS_PAGE
;
1166 // return SCSI_CONTROLLER_PAGE;
1169 MUIDisplayPage(UPGRADE_REPAIR_PAGE
);
1171 InitGenericListUi(&ListUi
, NtOsInstallsList
);
1172 DrawGenericList(&ListUi
,
1177 SaveGenericListState(NtOsInstallsList
);
1179 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1182 CONSOLE_ConInKey(Ir
);
1184 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00)
1186 switch (Ir
->Event
.KeyEvent
.wVirtualKeyCode
)
1188 case VK_DOWN
: /* DOWN */
1189 ScrollDownGenericList(&ListUi
);
1191 case VK_UP
: /* UP */
1192 ScrollUpGenericList(&ListUi
);
1194 case VK_NEXT
: /* PAGE DOWN */
1195 ScrollPageDownGenericList(&ListUi
);
1197 case VK_PRIOR
: /* PAGE UP */
1198 ScrollPageUpGenericList(&ListUi
);
1200 case VK_F3
: /* F3 */
1202 if (ConfirmQuit(Ir
) == TRUE
)
1205 RedrawGenericList(&ListUi
);
1208 case VK_ESCAPE
: /* ESC */
1210 RestoreGenericListState(NtOsInstallsList
);
1211 // return nextPage; // prevPage;
1213 // return INSTALL_INTRO_PAGE;
1214 return DEVICE_SETTINGS_PAGE
;
1215 // return SCSI_CONTROLLER_PAGE;
1221 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
1222 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1223 if (toupper(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
) == 'U') /* U */
1225 /* Retrieve the current installation */
1226 CurrentInstallation
= (PNTOS_INSTALLATION
)GetListEntryUserData(GetCurrentListEntry(NtOsInstallsList
));
1227 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
1228 CurrentInstallation
->InstallationName
, CurrentInstallation
->DiskNumber
, CurrentInstallation
->PartitionNumber
);
1230 RepairUpdateFlag
= TRUE
;
1233 /***/return INSTALL_INTRO_PAGE
;/***/
1235 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) &&
1236 (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b)) /* a-z */
1238 GenericListKeyPress(&ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1243 return UPGRADE_REPAIR_PAGE
;
1248 * Displays the InstallIntroPage.
1251 * DeviceSettingsPage (At once if repair or update is selected)
1252 * SelectPartitionPage (At once if unattended setup)
1253 * DeviceSettingsPage (default)
1257 * Number of the next page.
1260 InstallIntroPage(PINPUT_RECORD Ir
)
1262 if (RepairUpdateFlag
)
1264 #if 1 /* Old code that looks good */
1266 // return SELECT_PARTITION_PAGE;
1267 return DEVICE_SETTINGS_PAGE
;
1269 #else /* Possible new code? */
1271 return DEVICE_SETTINGS_PAGE
;
1272 // return SCSI_CONTROLLER_PAGE;
1277 if (IsUnattendedSetup
)
1278 return SELECT_PARTITION_PAGE
;
1280 MUIDisplayPage(INSTALL_INTRO_PAGE
);
1284 CONSOLE_ConInKey(Ir
);
1286 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1287 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1289 if (ConfirmQuit(Ir
) != FALSE
)
1294 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1296 return UPGRADE_REPAIR_PAGE
;
1300 return INSTALL_INTRO_PAGE
;
1306 ScsiControllerPage(PINPUT_RECORD Ir
)
1308 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1310 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1312 /* FIXME: print loaded mass storage driver descriptions */
1314 CONSOLE_SetTextXY(8, 10, "TEST device");
1317 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1321 CONSOLE_ConInKey(Ir
);
1323 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1324 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1326 if (ConfirmQuit(Ir
) != FALSE
)
1331 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1333 return DEVICE_SETTINGS_PAGE
;
1337 return SCSI_CONTROLLER_PAGE
;
1341 OemDriverPage(PINPUT_RECORD Ir
)
1343 // MUIDisplayPage(OEM_DRIVER_PAGE);
1345 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1347 /* FIXME: Implement!! */
1349 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1353 CONSOLE_ConInKey(Ir
);
1355 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1356 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1358 if (ConfirmQuit(Ir
) == TRUE
)
1363 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1365 return DEVICE_SETTINGS_PAGE
;
1369 return OEM_DRIVER_PAGE
;
1375 * Displays the DeviceSettingsPage.
1378 * SelectPartitionPage (At once if repair or update is selected)
1379 * ComputerSettingsPage
1380 * DisplaySettingsPage
1381 * KeyboardSettingsPage
1382 * LayoutsettingsPage
1383 * SelectPartitionPage
1393 * Number of the next page.
1396 DeviceSettingsPage(PINPUT_RECORD Ir
)
1398 static ULONG Line
= 16;
1400 /* Initialize the computer settings list */
1401 if (ComputerList
== NULL
)
1403 ComputerList
= CreateComputerTypeList(SetupInf
);
1404 if (ComputerList
== NULL
)
1406 MUIDisplayError(ERROR_LOAD_COMPUTER
, Ir
, POPUP_WAIT_ENTER
);
1411 /* Initialize the display settings list */
1412 if (DisplayList
== NULL
)
1414 DisplayList
= CreateDisplayDriverList(SetupInf
);
1415 if (DisplayList
== NULL
)
1417 MUIDisplayError(ERROR_LOAD_DISPLAY
, Ir
, POPUP_WAIT_ENTER
);
1422 /* Initialize the keyboard settings list */
1423 if (KeyboardList
== NULL
)
1425 KeyboardList
= CreateKeyboardDriverList(SetupInf
);
1426 if (KeyboardList
== NULL
)
1428 MUIDisplayError(ERROR_LOAD_KEYBOARD
, Ir
, POPUP_WAIT_ENTER
);
1433 /* Initialize the keyboard layout list */
1434 if (LayoutList
== NULL
)
1436 LayoutList
= CreateKeyboardLayoutList(SetupInf
, DefaultKBLayout
);
1437 if (LayoutList
== NULL
)
1439 /* FIXME: report error */
1440 MUIDisplayError(ERROR_LOAD_KBLAYOUT
, Ir
, POPUP_WAIT_ENTER
);
1445 if (RepairUpdateFlag
)
1446 return SELECT_PARTITION_PAGE
;
1448 // if (IsUnattendedSetup)
1449 // return SELECT_PARTITION_PAGE;
1451 MUIDisplayPage(DEVICE_SETTINGS_PAGE
);
1453 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList
)));
1454 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList
)));
1455 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList
)));
1456 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList
)));
1458 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1462 CONSOLE_ConInKey(Ir
);
1464 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1465 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1467 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1471 else if (Line
== 16)
1476 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1478 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1479 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1481 CONSOLE_NormalTextXY(24, Line
, 48, 1);
1485 else if (Line
== 16)
1490 CONSOLE_InvertTextXY(24, Line
, 48, 1);
1492 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1493 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1495 if (ConfirmQuit(Ir
) != FALSE
)
1500 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1503 return COMPUTER_SETTINGS_PAGE
;
1504 else if (Line
== 12)
1505 return DISPLAY_SETTINGS_PAGE
;
1506 else if (Line
== 13)
1507 return KEYBOARD_SETTINGS_PAGE
;
1508 else if (Line
== 14)
1509 return LAYOUT_SETTINGS_PAGE
;
1510 else if (Line
== 16)
1511 return SELECT_PARTITION_PAGE
;
1515 return DEVICE_SETTINGS_PAGE
;
1520 * Handles generic selection lists.
1523 * GenericList: The list to handle.
1524 * nextPage: The page it needs to jump to after this page.
1525 * Ir: The PINPUT_RECORD
1528 HandleGenericList(PGENERIC_LIST_UI ListUi
,
1529 PAGE_NUMBER nextPage
,
1534 CONSOLE_ConInKey(Ir
);
1536 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1537 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1539 ScrollDownGenericList(ListUi
);
1541 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1542 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1544 ScrollUpGenericList(ListUi
);
1546 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1547 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_NEXT
)) /* PAGE DOWN */
1549 ScrollPageDownGenericList(ListUi
);
1551 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1552 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_PRIOR
)) /* PAGE UP */
1554 ScrollPageUpGenericList(ListUi
);
1556 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1557 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1559 if (ConfirmQuit(Ir
) != FALSE
)
1562 RedrawGenericList(ListUi
);
1564 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1565 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
1567 RestoreGenericListState(ListUi
->List
);
1568 return nextPage
; // Use some "prevPage;" instead?
1570 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
1574 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
> 0x60) && (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
< 0x7b))
1577 GenericListKeyPress(ListUi
, Ir
->Event
.KeyEvent
.uChar
.AsciiChar
);
1584 * Displays the ComputerSettingsPage.
1587 * DeviceSettingsPage
1591 * Number of the next page.
1594 ComputerSettingsPage(PINPUT_RECORD Ir
)
1596 GENERIC_LIST_UI ListUi
;
1597 MUIDisplayPage(COMPUTER_SETTINGS_PAGE
);
1599 InitGenericListUi(&ListUi
, ComputerList
);
1600 DrawGenericList(&ListUi
,
1606 SaveGenericListState(ComputerList
);
1608 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1613 * Displays the DisplaySettingsPage.
1616 * DeviceSettingsPage
1620 * Number of the next page.
1623 DisplaySettingsPage(PINPUT_RECORD Ir
)
1625 GENERIC_LIST_UI ListUi
;
1626 MUIDisplayPage(DISPLAY_SETTINGS_PAGE
);
1628 InitGenericListUi(&ListUi
, DisplayList
);
1629 DrawGenericList(&ListUi
,
1635 SaveGenericListState(DisplayList
);
1637 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1642 * Displays the KeyboardSettingsPage.
1645 * DeviceSettingsPage
1649 * Number of the next page.
1652 KeyboardSettingsPage(PINPUT_RECORD Ir
)
1654 GENERIC_LIST_UI ListUi
;
1655 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE
);
1657 InitGenericListUi(&ListUi
, KeyboardList
);
1658 DrawGenericList(&ListUi
,
1664 SaveGenericListState(KeyboardList
);
1666 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1671 * Displays the LayoutSettingsPage.
1674 * DeviceSettingsPage
1678 * Number of the next page.
1681 LayoutSettingsPage(PINPUT_RECORD Ir
)
1683 GENERIC_LIST_UI ListUi
;
1684 MUIDisplayPage(LAYOUT_SETTINGS_PAGE
);
1686 InitGenericListUi(&ListUi
, LayoutList
);
1687 DrawGenericList(&ListUi
,
1693 SaveGenericListState(LayoutList
);
1695 return HandleGenericList(&ListUi
, DEVICE_SETTINGS_PAGE
, Ir
);
1700 IsDiskSizeValid(PPARTENTRY PartEntry
)
1704 size
= PartEntry
->SectorCount
.QuadPart
* PartEntry
->DiskEntry
->BytesPerSector
;
1705 size
= (size
+ 524288) / 1048576; /* in MBytes */
1707 if (size
< RequiredPartitionDiskSpace
)
1709 /* Partition is too small so ask for another one */
1710 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size
, RequiredPartitionDiskSpace
);
1721 * Displays the SelectPartitionPage.
1724 * SelectFileSystemPage (At once if unattended)
1725 * SelectFileSystemPage (Default if free space is selected)
1726 * CreatePrimaryPartitionPage
1727 * CreateExtendedPartitionPage
1728 * CreateLogicalPartitionPage
1729 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1730 * DeletePartitionPage
1734 * Set InstallShortcut (only if not unattended + free space is selected)
1737 * Number of the next page.
1740 SelectPartitionPage(PINPUT_RECORD Ir
)
1745 if (PartitionList
== NULL
)
1747 PartitionList
= CreatePartitionList();
1748 if (PartitionList
== NULL
)
1750 /* FIXME: show an error dialog */
1751 MUIDisplayError(ERROR_DRIVE_INFORMATION
, Ir
, POPUP_WAIT_ENTER
);
1754 else if (IsListEmpty(&PartitionList
->DiskListHead
))
1756 MUIDisplayError(ERROR_NO_HDD
, Ir
, POPUP_WAIT_ENTER
);
1760 TempPartition
= NULL
;
1761 FormatState
= Start
;
1764 if (RepairUpdateFlag
)
1766 /* Determine the selected installation disk & partition */
1767 if (!SelectPartition(PartitionList
,
1768 CurrentInstallation
->DiskNumber
,
1769 CurrentInstallation
->PartitionNumber
))
1771 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1775 return SELECT_FILE_SYSTEM_PAGE
;
1778 MUIDisplayPage(SELECT_PARTITION_PAGE
);
1780 InitPartitionListUi(&ListUi
, PartitionList
,
1785 DrawPartitionList(&ListUi
);
1787 if (IsUnattendedSetup
)
1789 if (!SelectPartition(PartitionList
, UnattendDestinationDiskNumber
, UnattendDestinationPartitionNumber
))
1793 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1795 CreateLogicalPartition(PartitionList
,
1796 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1801 CreatePrimaryPartition(PartitionList
,
1802 PartitionList
->CurrentPartition
->SectorCount
.QuadPart
,
1806 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1807 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1809 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1810 RequiredPartitionDiskSpace
);
1811 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1814 return SELECT_FILE_SYSTEM_PAGE
;
1819 DrawPartitionList(&ListUi
);
1821 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1822 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1824 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1825 RequiredPartitionDiskSpace
);
1826 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1829 return SELECT_FILE_SYSTEM_PAGE
;
1835 /* Update status text */
1836 if (PartitionList
->CurrentPartition
== NULL
)
1838 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1840 else if (PartitionList
->CurrentPartition
->LogicalPartition
)
1842 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1844 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1848 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL
));
1853 if (PartitionList
->CurrentPartition
->IsPartitioned
)
1855 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1857 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION
));
1861 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION
));
1866 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION
));
1870 CONSOLE_ConInKey(Ir
);
1872 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1873 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
1875 if (ConfirmQuit(Ir
) != FALSE
)
1877 DestroyPartitionList(PartitionList
);
1878 PartitionList
= NULL
;
1884 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1885 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
1887 ScrollDownPartitionList(&ListUi
);
1889 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
1890 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
1892 ScrollUpPartitionList(&ListUi
);
1894 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
1896 if (IsContainerPartition(PartitionList
->CurrentPartition
->PartitionType
))
1897 continue; // return SELECT_PARTITION_PAGE;
1899 if (PartitionList
->CurrentPartition
== NULL
||
1900 PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1902 if (PartitionList
->CurrentPartition
->LogicalPartition
)
1904 CreateLogicalPartition(PartitionList
,
1910 CreatePrimaryPartition(PartitionList
,
1916 if (!IsDiskSizeValid(PartitionList
->CurrentPartition
))
1918 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE
, Ir
, POPUP_WAIT_ANY_KEY
,
1919 RequiredPartitionDiskSpace
);
1920 return SELECT_PARTITION_PAGE
; /* let the user select another partition */
1923 return SELECT_FILE_SYSTEM_PAGE
;
1925 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'P') /* P */
1927 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1929 Error
= PrimaryPartitionCreationChecks(PartitionList
);
1930 if (Error
!= NOT_AN_ERROR
)
1932 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1933 return SELECT_PARTITION_PAGE
;
1936 return CREATE_PRIMARY_PARTITION_PAGE
;
1939 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'E') /* E */
1941 if (PartitionList
->CurrentPartition
->LogicalPartition
== FALSE
)
1943 Error
= ExtendedPartitionCreationChecks(PartitionList
);
1944 if (Error
!= NOT_AN_ERROR
)
1946 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1947 return SELECT_PARTITION_PAGE
;
1950 return CREATE_EXTENDED_PARTITION_PAGE
;
1953 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'L') /* L */
1955 if (PartitionList
->CurrentPartition
->LogicalPartition
!= FALSE
)
1957 Error
= LogicalPartitionCreationChecks(PartitionList
);
1958 if (Error
!= NOT_AN_ERROR
)
1960 MUIDisplayError(Error
, Ir
, POPUP_WAIT_ANY_KEY
);
1961 return SELECT_PARTITION_PAGE
;
1964 return CREATE_LOGICAL_PARTITION_PAGE
;
1967 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
1969 if (PartitionList
->CurrentPartition
->IsPartitioned
== FALSE
)
1971 MUIDisplayError(ERROR_DELETE_SPACE
, Ir
, POPUP_WAIT_ANY_KEY
);
1972 return SELECT_PARTITION_PAGE
;
1975 if (PartitionList
->CurrentPartition
->BootIndicator
||
1976 PartitionList
->CurrentPartition
== PartitionList
->SystemPartition
)
1978 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
1981 return DELETE_PARTITION_PAGE
;
1985 return SELECT_PARTITION_PAGE
;
1989 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1990 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1991 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1994 ShowPartitionSizeInputBox(SHORT Left
,
2018 DrawBox(Left
, Top
, Right
- Left
+ 1, Bottom
- Top
+ 1);
2023 strcpy(Buffer
, MUIGetString(STRING_PARTITIONSIZE
));
2024 iLeft
= coPos
.X
+ strlen(Buffer
) + 1;
2027 WriteConsoleOutputCharacterA(StdOutput
,
2033 sprintf(Buffer
, MUIGetString(STRING_MAXSIZE
), MaxSize
);
2034 coPos
.X
= iLeft
+ PARTITION_SIZE_INPUT_FIELD_LENGTH
+ 1;
2036 WriteConsoleOutputCharacterA(StdOutput
,
2042 swprintf(InputBuffer
, L
"%lu", MaxSize
);
2043 Length
= wcslen(InputBuffer
);
2045 CONSOLE_SetInputTextXY(iLeft
,
2047 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
2049 CONSOLE_SetCursorXY(iLeft
+ Length
, iTop
);
2050 CONSOLE_SetCursorType(TRUE
, TRUE
);
2054 CONSOLE_ConInKey(&Ir
);
2056 if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2057 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2062 InputBuffer
[0] = UNICODE_NULL
;
2063 CONSOLE_SetCursorType(TRUE
, FALSE
);
2066 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2068 CONSOLE_SetCursorType(TRUE
, FALSE
);
2071 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESCAPE */
2076 InputBuffer
[0] = UNICODE_NULL
;
2077 CONSOLE_SetCursorType(TRUE
, FALSE
);
2080 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2081 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
2084 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2086 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2087 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
2090 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2092 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2093 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
2098 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2101 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2102 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
2107 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2110 else if ((Ir
.Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2111 (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
2115 memmove(&InputBuffer
[Pos
],
2116 &InputBuffer
[Pos
+ 1],
2117 (Length
- Pos
- 1) * sizeof(WCHAR
));
2118 InputBuffer
[Length
- 1] = UNICODE_NULL
;
2121 CONSOLE_SetInputTextXY(iLeft
,
2123 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
2125 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2128 else if (Ir
.Event
.KeyEvent
.wVirtualKeyCode
== VK_BACK
) /* BACKSPACE */
2133 memmove(&InputBuffer
[Pos
- 1],
2135 (Length
- Pos
) * sizeof(WCHAR
));
2136 InputBuffer
[Length
- 1] = UNICODE_NULL
;
2140 CONSOLE_SetInputTextXY(iLeft
,
2142 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
2144 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2147 else if (Ir
.Event
.KeyEvent
.uChar
.AsciiChar
!= 0x00)
2149 if (Length
< PARTITION_SIZE_INPUT_FIELD_LENGTH
- 1)
2151 ch
= (WCHAR
)Ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
2153 if ((ch
>= L
'0') && (ch
<= L
'9'))
2156 memmove(&InputBuffer
[Pos
+ 1],
2158 (Length
- Pos
) * sizeof(WCHAR
));
2159 InputBuffer
[Length
+ 1] = UNICODE_NULL
;
2160 InputBuffer
[Pos
] = ch
;
2164 CONSOLE_SetInputTextXY(iLeft
,
2166 PARTITION_SIZE_INPUT_FIELD_LENGTH
,
2168 CONSOLE_SetCursorXY(iLeft
+ Pos
, iTop
);
2177 * Displays the CreatePrimaryPartitionPage.
2180 * SelectPartitionPage
2181 * SelectFileSystemPage (default)
2185 * Number of the next page.
2188 CreatePrimaryPartitionPage(PINPUT_RECORD Ir
)
2190 PDISKENTRY DiskEntry
;
2191 PPARTENTRY PartEntry
;
2194 WCHAR InputBuffer
[50];
2198 ULONGLONG SectorCount
;
2201 if (PartitionList
== NULL
||
2202 PartitionList
->CurrentDisk
== NULL
||
2203 PartitionList
->CurrentPartition
== NULL
)
2205 /* FIXME: show an error dialog */
2209 DiskEntry
= PartitionList
->CurrentDisk
;
2210 PartEntry
= PartitionList
->CurrentPartition
;
2212 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2214 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION
));
2216 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2218 if (DiskSize
>= 10737418240) /* 10 GB */
2220 DiskSize
= DiskSize
/ 1073741824;
2221 Unit
= MUIGetString(STRING_GB
);
2226 DiskSize
= DiskSize
/ 1048576;
2230 Unit
= MUIGetString(STRING_MB
);
2233 if (DiskEntry
->DriverName
.Length
> 0)
2235 CONSOLE_PrintTextXY(6, 10,
2236 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2239 DiskEntry
->DiskNumber
,
2243 &DiskEntry
->DriverName
,
2244 DiskEntry
->NoMbr
? "GPT" : "MBR");
2248 CONSOLE_PrintTextXY(6, 10,
2249 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2252 DiskEntry
->DiskNumber
,
2256 DiskEntry
->NoMbr
? "GPT" : "MBR");
2259 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2262 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2263 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2266 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2268 PartEntry
= PartitionList
->CurrentPartition
;
2271 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2273 if (MaxSize
> PARTITION_MAXSIZE
)
2274 MaxSize
= PARTITION_MAXSIZE
;
2276 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2277 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2281 if (ConfirmQuit(Ir
) != FALSE
)
2286 else if (Cancel
!= FALSE
)
2288 return SELECT_PARTITION_PAGE
;
2292 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2300 if (PartSize
> MaxSize
)
2306 /* Convert to bytes */
2307 if (PartSize
== MaxSize
)
2309 /* Use all of the unpartitioned disk space */
2310 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2314 /* Calculate the sector count from the size in MB */
2315 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2317 /* But never get larger than the unpartitioned disk space */
2318 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2319 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2322 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2324 CreatePrimaryPartition(PartitionList
,
2328 return SELECT_PARTITION_PAGE
;
2332 return CREATE_PRIMARY_PARTITION_PAGE
;
2337 * Displays the CreateExtendedPartitionPage.
2340 * SelectPartitionPage (default)
2344 * Number of the next page.
2347 CreateExtendedPartitionPage(PINPUT_RECORD Ir
)
2349 PDISKENTRY DiskEntry
;
2350 PPARTENTRY PartEntry
;
2353 WCHAR InputBuffer
[50];
2357 ULONGLONG SectorCount
;
2360 if (PartitionList
== NULL
||
2361 PartitionList
->CurrentDisk
== NULL
||
2362 PartitionList
->CurrentPartition
== NULL
)
2364 /* FIXME: show an error dialog */
2368 DiskEntry
= PartitionList
->CurrentDisk
;
2369 PartEntry
= PartitionList
->CurrentPartition
;
2371 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2373 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION
));
2375 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2377 if (DiskSize
>= 10737418240) /* 10 GB */
2379 DiskSize
= DiskSize
/ 1073741824;
2380 Unit
= MUIGetString(STRING_GB
);
2385 DiskSize
= DiskSize
/ 1048576;
2389 Unit
= MUIGetString(STRING_MB
);
2392 if (DiskEntry
->DriverName
.Length
> 0)
2394 CONSOLE_PrintTextXY(6, 10,
2395 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2398 DiskEntry
->DiskNumber
,
2402 &DiskEntry
->DriverName
,
2403 DiskEntry
->NoMbr
? "GPT" : "MBR");
2407 CONSOLE_PrintTextXY(6, 10,
2408 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2411 DiskEntry
->DiskNumber
,
2415 DiskEntry
->NoMbr
? "GPT" : "MBR");
2418 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2421 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2422 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2425 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2427 PartEntry
= PartitionList
->CurrentPartition
;
2430 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2432 if (MaxSize
> PARTITION_MAXSIZE
)
2433 MaxSize
= PARTITION_MAXSIZE
;
2435 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2436 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2440 if (ConfirmQuit(Ir
) != FALSE
)
2445 else if (Cancel
!= FALSE
)
2447 return SELECT_PARTITION_PAGE
;
2451 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2459 if (PartSize
> MaxSize
)
2465 /* Convert to bytes */
2466 if (PartSize
== MaxSize
)
2468 /* Use all of the unpartitioned disk space */
2469 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2473 /* Calculate the sector count from the size in MB */
2474 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2476 /* But never get larger than the unpartitioned disk space */
2477 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2478 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2481 DPRINT ("Partition size: %I64u bytes\n", PartSize
);
2483 CreateExtendedPartition(PartitionList
,
2486 return SELECT_PARTITION_PAGE
;
2490 return CREATE_EXTENDED_PARTITION_PAGE
;
2495 * Displays the CreateLogicalPartitionPage.
2498 * SelectFileSystemPage (default)
2502 * Number of the next page.
2505 CreateLogicalPartitionPage(PINPUT_RECORD Ir
)
2507 PDISKENTRY DiskEntry
;
2508 PPARTENTRY PartEntry
;
2511 WCHAR InputBuffer
[50];
2515 ULONGLONG SectorCount
;
2518 if (PartitionList
== NULL
||
2519 PartitionList
->CurrentDisk
== NULL
||
2520 PartitionList
->CurrentPartition
== NULL
)
2522 /* FIXME: show an error dialog */
2526 DiskEntry
= PartitionList
->CurrentDisk
;
2527 PartEntry
= PartitionList
->CurrentPartition
;
2529 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
2531 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION
));
2533 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2535 if (DiskSize
>= 10737418240) /* 10 GB */
2537 DiskSize
= DiskSize
/ 1073741824;
2538 Unit
= MUIGetString(STRING_GB
);
2543 DiskSize
= DiskSize
/ 1048576;
2547 Unit
= MUIGetString(STRING_MB
);
2550 if (DiskEntry
->DriverName
.Length
> 0)
2552 CONSOLE_PrintTextXY(6, 10,
2553 MUIGetString(STRING_HDINFOPARTCREATE_1
),
2556 DiskEntry
->DiskNumber
,
2560 &DiskEntry
->DriverName
,
2561 DiskEntry
->NoMbr
? "GPT" : "MBR");
2565 CONSOLE_PrintTextXY(6, 10,
2566 MUIGetString(STRING_HDINFOPARTCREATE_2
),
2569 DiskEntry
->DiskNumber
,
2573 DiskEntry
->NoMbr
? "GPT" : "MBR");
2576 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE
));
2579 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2580 PartitionList
->CurrentPartition
->SectorCount
* DiskEntry
->BytesPerSector
/ 1048576);
2583 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION
));
2585 PartEntry
= PartitionList
->CurrentPartition
;
2588 MaxSize
= (PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
) / 1048576; /* in MBytes (rounded) */
2590 if (MaxSize
> PARTITION_MAXSIZE
)
2591 MaxSize
= PARTITION_MAXSIZE
;
2593 ShowPartitionSizeInputBox(12, 14, xScreen
- 12, 17, /* left, top, right, bottom */
2594 MaxSize
, InputBuffer
, &Quit
, &Cancel
);
2598 if (ConfirmQuit(Ir
) != FALSE
)
2603 else if (Cancel
!= FALSE
)
2605 return SELECT_PARTITION_PAGE
;
2609 PartSize
= _wcstoui64(InputBuffer
, NULL
, 10);
2617 if (PartSize
> MaxSize
)
2623 /* Convert to bytes */
2624 if (PartSize
== MaxSize
)
2626 /* Use all of the unpartitioned disk space */
2627 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2631 /* Calculate the sector count from the size in MB */
2632 SectorCount
= PartSize
* 1048576 / DiskEntry
->BytesPerSector
;
2634 /* But never get larger than the unpartitioned disk space */
2635 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
2636 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
2639 DPRINT("Partition size: %I64u bytes\n", PartSize
);
2641 CreateLogicalPartition(PartitionList
,
2645 return SELECT_PARTITION_PAGE
;
2649 return CREATE_LOGICAL_PARTITION_PAGE
;
2654 * Displays the ConfirmDeleteSystemPartitionPage.
2657 * DeletePartitionPage (default)
2658 * SelectPartitionPage
2661 * Number of the next page.
2664 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir
)
2666 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
);
2670 CONSOLE_ConInKey(Ir
);
2672 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2673 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2675 if (ConfirmQuit(Ir
) == TRUE
)
2680 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
2682 return DELETE_PARTITION_PAGE
;
2684 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2686 return SELECT_PARTITION_PAGE
;
2690 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
;
2695 * Displays the DeletePartitionPage.
2698 * SelectPartitionPage (default)
2702 * Number of the next page.
2705 DeletePartitionPage(PINPUT_RECORD Ir
)
2707 PDISKENTRY DiskEntry
;
2708 PPARTENTRY PartEntry
;
2712 CHAR PartTypeString
[32];
2714 if (PartitionList
== NULL
||
2715 PartitionList
->CurrentDisk
== NULL
||
2716 PartitionList
->CurrentPartition
== NULL
)
2718 /* FIXME: show an error dialog */
2722 DiskEntry
= PartitionList
->CurrentDisk
;
2723 PartEntry
= PartitionList
->CurrentPartition
;
2725 MUIDisplayPage(DELETE_PARTITION_PAGE
);
2727 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
2729 ARRAYSIZE(PartTypeString
));
2731 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2733 if (PartSize
>= 10737418240) /* 10 GB */
2735 PartSize
= PartSize
/ 1073741824;
2736 Unit
= MUIGetString(STRING_GB
);
2740 if (PartSize
>= 10485760) /* 10 MB */
2742 PartSize
= PartSize
/ 1048576;
2743 Unit
= MUIGetString(STRING_MB
);
2747 PartSize
= PartSize
/ 1024;
2748 Unit
= MUIGetString(STRING_KB
);
2751 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
2753 CONSOLE_PrintTextXY(6, 10,
2754 MUIGetString(STRING_HDDINFOUNK2
),
2755 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2756 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2757 PartEntry
->PartitionType
,
2763 CONSOLE_PrintTextXY(6, 10,
2764 " %c%c %s %I64u %s",
2765 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
2766 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
2772 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2774 if (DiskSize
>= 10737418240) /* 10 GB */
2776 DiskSize
= DiskSize
/ 1073741824;
2777 Unit
= MUIGetString(STRING_GB
);
2782 DiskSize
= DiskSize
/ 1048576;
2786 Unit
= MUIGetString(STRING_MB
);
2789 if (DiskEntry
->DriverName
.Length
> 0)
2791 CONSOLE_PrintTextXY(6, 12,
2792 MUIGetString(STRING_HDINFOPARTDELETE_1
),
2795 DiskEntry
->DiskNumber
,
2799 &DiskEntry
->DriverName
,
2800 DiskEntry
->NoMbr
? "GPT" : "MBR");
2804 CONSOLE_PrintTextXY(6, 12,
2805 MUIGetString(STRING_HDINFOPARTDELETE_2
),
2808 DiskEntry
->DiskNumber
,
2812 DiskEntry
->NoMbr
? "GPT" : "MBR");
2817 CONSOLE_ConInKey(Ir
);
2819 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
2820 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
2822 if (ConfirmQuit(Ir
) != FALSE
)
2827 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
) /* ESC */
2829 return SELECT_PARTITION_PAGE
;
2831 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== 'D') /* D */
2833 DeleteCurrentPartition(PartitionList
);
2835 return SELECT_PARTITION_PAGE
;
2839 return DELETE_PARTITION_PAGE
;
2844 * Displays the SelectFileSystemPage.
2847 * CheckFileSystemPage (At once if RepairUpdate is selected)
2848 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2849 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2850 * SelectPartitionPage (If the user aborts)
2851 * FormatPartitionPage (Default)
2855 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2856 * Calls CheckActiveSystemPartition()
2859 * Number of the next page.
2862 SelectFileSystemPage(PINPUT_RECORD Ir
)
2864 PDISKENTRY DiskEntry
;
2865 PPARTENTRY PartEntry
;
2870 CHAR PartTypeString
[32];
2871 FORMATMACHINESTATE PreviousFormatState
;
2873 DPRINT("SelectFileSystemPage()\n");
2875 if (PartitionList
== NULL
||
2876 PartitionList
->CurrentDisk
== NULL
||
2877 PartitionList
->CurrentPartition
== NULL
)
2879 /* FIXME: show an error dialog */
2883 /* Find or set the active system partition */
2884 CheckActiveSystemPartition(PartitionList
);
2885 if (PartitionList
->SystemPartition
== NULL
)
2887 /* FIXME: show an error dialog */
2889 // Error dialog should say that we cannot find a suitable
2890 // system partition and create one on the system. At this point,
2891 // it may be nice to ask the user whether he wants to continue,
2892 // or use an external drive as the system drive/partition
2893 // (e.g. floppy, USB drive, etc...)
2898 PreviousFormatState
= FormatState
;
2899 switch (FormatState
)
2903 if (PartitionList
->CurrentPartition
!= PartitionList
->SystemPartition
)
2905 TempPartition
= PartitionList
->SystemPartition
;
2906 TempPartition
->NeedsCheck
= TRUE
;
2908 FormatState
= FormatSystemPartition
;
2909 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2913 TempPartition
= PartitionList
->CurrentPartition
;
2914 TempPartition
->NeedsCheck
= TRUE
;
2916 FormatState
= FormatInstallPartition
;
2917 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2922 case FormatSystemPartition
:
2924 TempPartition
= PartitionList
->CurrentPartition
;
2925 TempPartition
->NeedsCheck
= TRUE
;
2927 FormatState
= FormatInstallPartition
;
2928 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2932 case FormatInstallPartition
:
2934 if (GetNextUnformattedPartition(PartitionList
,
2938 FormatState
= FormatOtherPartition
;
2939 TempPartition
->NeedsCheck
= TRUE
;
2940 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2944 FormatState
= FormatDone
;
2945 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2946 return CHECK_FILE_SYSTEM_PAGE
;
2951 case FormatOtherPartition
:
2953 if (GetNextUnformattedPartition(PartitionList
,
2957 FormatState
= FormatOtherPartition
;
2958 TempPartition
->NeedsCheck
= TRUE
;
2959 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2963 FormatState
= FormatDone
;
2964 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2965 return CHECK_FILE_SYSTEM_PAGE
;
2972 DPRINT1("FormatState: Invalid value %ld\n", FormatState
);
2973 /* FIXME: show an error dialog */
2978 PartEntry
= TempPartition
;
2979 DiskEntry
= PartEntry
->DiskEntry
;
2981 /* Adjust disk size */
2982 DiskSize
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2983 if (DiskSize
>= 10737418240) /* 10 GB */
2985 DiskSize
= DiskSize
/ 1073741824;
2986 DiskUnit
= MUIGetString(STRING_GB
);
2990 DiskSize
= DiskSize
/ 1048576;
2991 DiskUnit
= MUIGetString(STRING_MB
);
2994 /* Adjust partition size */
2995 PartSize
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2996 if (PartSize
>= 10737418240) /* 10 GB */
2998 PartSize
= PartSize
/ 1073741824;
2999 PartUnit
= MUIGetString(STRING_GB
);
3003 PartSize
= PartSize
/ 1048576;
3004 PartUnit
= MUIGetString(STRING_MB
);
3007 /* Adjust partition type */
3008 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
3010 ARRAYSIZE(PartTypeString
));
3012 if (PartEntry
->AutoCreate
!= FALSE
)
3014 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION
));
3017 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
3018 PartEntry
->PartitionNumber
,
3024 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1
),
3025 DiskEntry
->DiskNumber
,
3031 &DiskEntry
->DriverName
,
3032 DiskEntry
->NoMbr
? "GPT" : "MBR");
3034 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT
));
3036 PartEntry
->AutoCreate
= FALSE
;
3038 else if (PartEntry
->New
!= FALSE
)
3040 switch (FormatState
)
3042 case FormatSystemPartition
:
3043 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART
));
3046 case FormatInstallPartition
:
3047 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART
));
3050 case FormatOtherPartition
:
3051 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART
));
3058 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT
));
3062 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART
));
3064 if (*PartTypeString
== '\0') // STRING_FORMATUNKNOWN ??
3066 CONSOLE_PrintTextXY(8, 10,
3067 MUIGetString(STRING_HDDINFOUNK4
),
3068 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
3069 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
3070 PartEntry
->PartitionType
,
3076 CONSOLE_PrintTextXY(8, 10,
3078 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
3079 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
3085 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1
),
3086 DiskEntry
->DiskNumber
,
3092 &DiskEntry
->DriverName
,
3093 DiskEntry
->NoMbr
? "GPT" : "MBR");
3096 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE
);
3098 if (FileSystemList
== NULL
)
3100 /* Create the file system list, and by default select the "FAT" file system */
3101 FileSystemList
= CreateFileSystemList(6, 26, PartEntry
->New
, L
"FAT");
3102 if (FileSystemList
== NULL
)
3104 /* FIXME: show an error dialog */
3109 if (RepairUpdateFlag
)
3111 return CHECK_FILE_SYSTEM_PAGE
;
3112 //return SELECT_PARTITION_PAGE;
3115 if (IsUnattendedSetup
)
3117 if (UnattendFormatPartition
)
3120 * We use whatever currently selected file system we have
3121 * (by default, this is "FAT", as per the initialization
3122 * performed above). Note that it may be interesting to specify
3123 * which file system to use in unattended installations, in the
3124 * txtsetup.sif file.
3126 return FORMAT_PARTITION_PAGE
;
3129 return CHECK_FILE_SYSTEM_PAGE
;
3132 DrawFileSystemList(FileSystemList
);
3136 CONSOLE_ConInKey(Ir
);
3138 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3139 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3141 if (ConfirmQuit(Ir
) != FALSE
)
3146 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3147 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
)) /* ESC */
3149 FormatState
= Start
;
3150 return SELECT_PARTITION_PAGE
;
3152 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3153 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
3155 ScrollDownFileSystemList(FileSystemList
);
3157 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3158 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
3160 ScrollUpFileSystemList(FileSystemList
);
3162 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
) /* ENTER */
3164 if (!FileSystemList
->Selected
->FileSystem
)
3165 return SELECT_FILE_SYSTEM_PAGE
;
3167 return FORMAT_PARTITION_PAGE
;
3171 FormatState
= PreviousFormatState
;
3173 return SELECT_FILE_SYSTEM_PAGE
;
3178 * Displays the FormatPartitionPage.
3181 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3182 * SelectPartitionPage (At once)
3186 * Sets PartitionList->CurrentPartition->FormatState
3187 * Sets DestinationRootPath
3190 * Number of the next page.
3193 FormatPartitionPage(PINPUT_RECORD Ir
)
3195 UNICODE_STRING PartitionRootPath
;
3196 WCHAR PathBuffer
[MAX_PATH
];
3197 PDISKENTRY DiskEntry
;
3198 PPARTENTRY PartEntry
;
3199 PFILE_SYSTEM_ITEM SelectedFileSystem
;
3205 PPARTITION_INFORMATION PartitionInfo
;
3208 DPRINT("FormatPartitionPage()\n");
3210 MUIDisplayPage(FORMAT_PARTITION_PAGE
);
3212 if (PartitionList
== NULL
|| TempPartition
== NULL
)
3214 /* FIXME: show an error dialog */
3218 PartEntry
= TempPartition
;
3219 DiskEntry
= PartEntry
->DiskEntry
;
3221 SelectedFileSystem
= FileSystemList
->Selected
;
3225 if (!IsUnattendedSetup
)
3227 CONSOLE_ConInKey(Ir
);
3230 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3231 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3233 if (ConfirmQuit(Ir
) != FALSE
)
3238 else if (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RETURN
|| IsUnattendedSetup
) /* ENTER */
3240 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3242 if (!PreparePartitionForFormatting(PartEntry
, SelectedFileSystem
->FileSystem
))
3244 /* FIXME: show an error dialog */
3249 CONSOLE_PrintTextXY(6, 12,
3250 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3251 DiskEntry
->Cylinders
,
3252 DiskEntry
->TracksPerCylinder
,
3253 DiskEntry
->SectorsPerTrack
,
3254 DiskEntry
->BytesPerSector
,
3255 DiskEntry
->Dirty
? '*' : ' ');
3259 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
3261 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
3263 CONSOLE_PrintTextXY(6, Line
,
3264 "%2u: %2lu %c %12I64u %12I64u %02x",
3266 PartitionInfo
->PartitionNumber
,
3267 PartitionInfo
->BootIndicator
? 'A' : '-',
3268 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
3269 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
3270 PartitionInfo
->PartitionType
);
3275 /* Commit the partition changes to the disk */
3276 if (!WritePartitionsToDisk(PartitionList
))
3278 DPRINT("WritePartitionsToDisk() failed\n");
3279 MUIDisplayError(ERROR_WRITE_PTABLE
, Ir
, POPUP_WAIT_ENTER
);
3283 /* Set PartitionRootPath */
3284 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3285 L
"\\Device\\Harddisk%lu\\Partition%lu",
3286 DiskEntry
->DiskNumber
,
3287 PartEntry
->PartitionNumber
);
3288 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3289 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3291 /* Format the partition */
3292 if (SelectedFileSystem
->FileSystem
)
3294 Status
= FormatPartition(&PartitionRootPath
,
3295 SelectedFileSystem
);
3296 if (!NT_SUCCESS(Status
))
3298 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status
);
3299 MUIDisplayError(ERROR_FORMATTING_PARTITION
, Ir
, POPUP_WAIT_ANY_KEY
, PathBuffer
);
3303 PartEntry
->FormatState
= Formatted
;
3304 // PartEntry->FileSystem = FileSystem;
3305 PartEntry
->New
= FALSE
;
3309 CONSOLE_SetStatusText(" Done. Press any key ...");
3310 CONSOLE_ConInKey(Ir
);
3313 return SELECT_FILE_SYSTEM_PAGE
;
3317 return FORMAT_PARTITION_PAGE
;
3322 * Displays the CheckFileSystemPage.
3325 * InstallDirectoryPage (At once)
3329 * Inits or reloads FileSystemList
3332 * Number of the next page.
3335 CheckFileSystemPage(PINPUT_RECORD Ir
)
3337 PFILE_SYSTEM CurrentFileSystem
;
3338 UNICODE_STRING PartitionRootPath
;
3339 WCHAR PathBuffer
[MAX_PATH
];
3340 CHAR Buffer
[MAX_PATH
];
3341 PDISKENTRY DiskEntry
;
3342 PPARTENTRY PartEntry
;
3345 if (PartitionList
== NULL
)
3347 /* FIXME: show an error dialog */
3351 if (!GetNextUncheckedPartition(PartitionList
, &DiskEntry
, &PartEntry
))
3353 return INSTALL_DIRECTORY_PAGE
;
3356 /* Set PartitionRootPath */
3357 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3358 L
"\\Device\\Harddisk%lu\\Partition%lu",
3359 DiskEntry
->DiskNumber
,
3360 PartEntry
->PartitionNumber
);
3361 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
3362 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
3364 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART
));
3366 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
3368 CurrentFileSystem
= PartEntry
->FileSystem
;
3369 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3370 PartEntry
->PartitionType
, (CurrentFileSystem
? CurrentFileSystem
->FileSystemName
: L
"n/a"));
3372 /* HACK: Do not try to check a partition with an unknown filesystem */
3373 if (CurrentFileSystem
== NULL
)
3375 PartEntry
->NeedsCheck
= FALSE
;
3376 return CHECK_FILE_SYSTEM_PAGE
;
3379 if (CurrentFileSystem
->ChkdskFunc
== NULL
)
3382 "Setup is currently unable to check a partition formatted in %S.\n"
3384 " \x07 Press ENTER to continue Setup.\n"
3385 " \x07 Press F3 to quit Setup.",
3386 CurrentFileSystem
->FileSystemName
);
3389 MUIGetString(STRING_QUITCONTINUE
),
3390 NULL
, POPUP_WAIT_NONE
);
3394 CONSOLE_ConInKey(Ir
);
3396 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00 &&
3397 Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
) /* F3 */
3399 if (ConfirmQuit(Ir
))
3402 return CHECK_FILE_SYSTEM_PAGE
;
3404 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== VK_RETURN
) /* ENTER */
3406 PartEntry
->NeedsCheck
= FALSE
;
3407 return CHECK_FILE_SYSTEM_PAGE
;
3413 Status
= ChkdskPartition(&PartitionRootPath
, CurrentFileSystem
);
3414 if (!NT_SUCCESS(Status
))
3416 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status
);
3417 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3418 sprintf(Buffer
, "ChkDsk detected some disk errors.\n"
3419 "(Status 0x%08lx).\n", Status
);
3421 // MUIGetString(STRING_REBOOTCOMPUTER),
3422 MUIGetString(STRING_CONTINUE
),
3423 Ir
, POPUP_WAIT_ENTER
);
3425 // return QUIT_PAGE;
3428 PartEntry
->NeedsCheck
= FALSE
;
3429 return CHECK_FILE_SYSTEM_PAGE
;
3435 BuildInstallPaths(PWSTR InstallDir
,
3436 PDISKENTRY DiskEntry
,
3437 PPARTENTRY PartEntry
)
3439 WCHAR PathBuffer
[MAX_PATH
];
3441 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3442 /* Create 'InstallPath' string */
3443 RtlFreeUnicodeString(&InstallPath
);
3444 RtlCreateUnicodeString(&InstallPath
, InstallDir
);
3446 /* Create 'DestinationRootPath' string */
3447 RtlFreeUnicodeString(&DestinationRootPath
);
3448 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3449 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
3450 DiskEntry
->DiskNumber
,
3451 PartEntry
->PartitionNumber
);
3452 RtlCreateUnicodeString(&DestinationRootPath
, PathBuffer
);
3453 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath
);
3455 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3456 /* Create 'DestinationPath' string */
3457 RtlFreeUnicodeString(&DestinationPath
);
3458 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3459 DestinationRootPath
.Buffer
, InstallDir
);
3460 RtlCreateUnicodeString(&DestinationPath
, PathBuffer
);
3462 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3463 /* Create 'DestinationArcPath' */
3464 RtlFreeUnicodeString(&DestinationArcPath
);
3465 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3466 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3467 DiskEntry
->BiosDiskNumber
,
3468 PartEntry
->PartitionNumber
);
3469 ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallDir
);
3470 RtlCreateUnicodeString(&DestinationArcPath
, PathBuffer
);
3472 /* Initialize DestinationDriveLetter */
3473 DestinationDriveLetter
= (WCHAR
)PartEntry
->DriveLetter
;
3478 * Displays the InstallDirectoryPage.
3485 * Number of the next page.
3488 InstallDirectoryPage(PINPUT_RECORD Ir
)
3490 PDISKENTRY DiskEntry
;
3491 PPARTENTRY PartEntry
;
3492 WCHAR InstallDir
[51];
3496 /* We do not need the filesystem list anymore */
3497 if (FileSystemList
!= NULL
)
3499 DestroyFileSystemList(FileSystemList
);
3500 FileSystemList
= NULL
;
3503 if (PartitionList
== NULL
||
3504 PartitionList
->CurrentDisk
== NULL
||
3505 PartitionList
->CurrentPartition
== NULL
)
3507 /* FIXME: show an error dialog */
3511 DiskEntry
= PartitionList
->CurrentDisk
;
3512 PartEntry
= PartitionList
->CurrentPartition
;
3514 if (IsUnattendedSetup
)
3515 wcscpy(InstallDir
, UnattendInstallationDirectory
);
3516 else if (RepairUpdateFlag
)
3517 wcscpy(InstallDir
, CurrentInstallation
->PathComponent
); // SystemNtPath
3519 wcscpy(InstallDir
, L
"\\ReactOS");
3522 * Check the validity of the predefined 'InstallDir'. If we are either
3523 * in unattended setup or in update/repair mode, and the installation path
3524 * is valid, just perform the installation. Otherwise (either in the case
3525 * of an invalid path, or we are in regular setup), display the UI and allow
3526 * the user to specify a new installation path.
3528 if ((RepairUpdateFlag
|| IsUnattendedSetup
) && IsValidPath(InstallDir
))
3530 BuildInstallPaths(InstallDir
,
3534 return PREPARE_COPY_PAGE
;
3537 Length
= wcslen(InstallDir
);
3540 MUIDisplayPage(INSTALL_DIRECTORY_PAGE
);
3541 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3542 CONSOLE_SetCursorXY(8 + Pos
, 11);
3543 CONSOLE_SetCursorType(TRUE
, TRUE
);
3547 CONSOLE_ConInKey(Ir
);
3549 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3550 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
3552 CONSOLE_SetCursorType(TRUE
, FALSE
);
3554 if (ConfirmQuit(Ir
) != FALSE
)
3557 CONSOLE_SetCursorType(TRUE
, TRUE
);
3560 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3561 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)) /* DEL */
3565 memmove(&InstallDir
[Pos
],
3566 &InstallDir
[Pos
+ 1],
3567 (Length
- Pos
- 1) * sizeof(WCHAR
));
3568 InstallDir
[Length
- 1] = UNICODE_NULL
;
3571 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3572 CONSOLE_SetCursorXY(8 + Pos
, 11);
3575 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3576 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)) /* HOME */
3579 CONSOLE_SetCursorXY(8 + Pos
, 11);
3581 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3582 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)) /* END */
3585 CONSOLE_SetCursorXY(8 + Pos
, 11);
3587 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3588 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)) /* LEFT */
3593 CONSOLE_SetCursorXY(8 + Pos
, 11);
3596 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
3597 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)) /* RIGHT */
3602 CONSOLE_SetCursorXY(8 + Pos
, 11);
3605 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
3607 CONSOLE_SetCursorType(TRUE
, FALSE
);
3610 * Check for the validity of the installation directory and pop up
3611 * an error if it is not the case. Then the user can fix its input.
3613 if (!IsValidPath(InstallDir
))
3615 MUIDisplayError(ERROR_DIRECTORY_NAME
, Ir
, POPUP_WAIT_ENTER
);
3616 return INSTALL_DIRECTORY_PAGE
;
3619 BuildInstallPaths(InstallDir
,
3623 return PREPARE_COPY_PAGE
;
3625 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x08) /* BACKSPACE */
3630 memmove(&InstallDir
[Pos
- 1],
3632 (Length
- Pos
) * sizeof(WCHAR
));
3633 InstallDir
[Length
- 1] = UNICODE_NULL
;
3637 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3638 CONSOLE_SetCursorXY(8 + Pos
, 11);
3641 else if (isprint(Ir
->Event
.KeyEvent
.uChar
.AsciiChar
))
3645 c
= (WCHAR
)Ir
->Event
.KeyEvent
.uChar
.AsciiChar
;
3646 if (iswalpha(c
) || iswdigit(c
) || c
== '.' || c
== '\\' || c
== '-' || c
== '_')
3649 memmove(&InstallDir
[Pos
+ 1],
3651 (Length
- Pos
) * sizeof(WCHAR
));
3652 InstallDir
[Length
+ 1] = UNICODE_NULL
;
3653 InstallDir
[Pos
] = c
;
3657 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir
);
3658 CONSOLE_SetCursorXY(8 + Pos
, 11);
3664 return INSTALL_DIRECTORY_PAGE
;
3669 AddSectionToCopyQueueCab(HINF InfFile
,
3671 PWCHAR SourceCabinet
,
3672 PCUNICODE_STRING DestinationPath
,
3675 INFCONTEXT FilesContext
;
3676 INFCONTEXT DirContext
;
3678 PWCHAR FileKeyValue
;
3680 PWCHAR TargetFileName
;
3683 * This code enumerates the list of files in reactos.dff / reactos.inf
3684 * that need to be extracted from reactos.cab and be installed in their
3685 * respective directories.
3688 /* Search for the SectionName section */
3689 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3692 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3693 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3698 * Enumerate the files in the section and add them to the file queue.
3702 /* Get source file name and target directory id */
3703 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3705 /* FIXME: Handle error! */
3706 DPRINT1("INF_GetData() failed\n");
3710 /* Get optional target file name */
3711 if (!INF_GetDataField(&FilesContext
, 2, &TargetFileName
))
3712 TargetFileName
= NULL
;
3714 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3716 /* Lookup target directory */
3717 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3719 /* FIXME: Handle error! */
3720 DPRINT1("SetupFindFirstLine() failed\n");
3724 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3726 /* FIXME: Handle error! */
3727 DPRINT1("INF_GetData() failed\n");
3731 if (!SetupQueueCopy(SetupFileQueue
,
3733 SourceRootPath
.Buffer
,
3734 SourceRootDir
.Buffer
,
3739 /* FIXME: Handle error! */
3740 DPRINT1("SetupQueueCopy() failed\n");
3742 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3749 AddSectionToCopyQueue(HINF InfFile
,
3751 PWCHAR SourceCabinet
,
3752 PCUNICODE_STRING DestinationPath
,
3755 INFCONTEXT FilesContext
;
3756 INFCONTEXT DirContext
;
3758 PWCHAR FileKeyValue
;
3760 PWCHAR TargetFileName
;
3761 WCHAR CompleteOrigDirName
[512]; // FIXME: MAX_PATH is not enough?
3764 return AddSectionToCopyQueueCab(InfFile
, L
"SourceFiles", SourceCabinet
, DestinationPath
, Ir
);
3767 * This code enumerates the list of files in txtsetup.sif
3768 * that need to be installed in their respective directories.
3771 /* Search for the SectionName section */
3772 if (!SetupFindFirstLineW(InfFile
, SectionName
, NULL
, &FilesContext
))
3775 sprintf(Buffer
, MUIGetString(STRING_TXTSETUPFAILED
), SectionName
);
3776 PopupError(Buffer
, MUIGetString(STRING_REBOOTCOMPUTER
), Ir
, POPUP_WAIT_ENTER
);
3781 * Enumerate the files in the section and add them to the file queue.
3785 /* Get source file name and target directory id */
3786 if (!INF_GetData(&FilesContext
, &FileKeyName
, &FileKeyValue
))
3788 /* FIXME: Handle error! */
3789 DPRINT1("INF_GetData() failed\n");
3793 /* Get target directory id */
3794 if (!INF_GetDataField(&FilesContext
, 13, &FileKeyValue
))
3796 /* FIXME: Handle error! */
3797 DPRINT1("INF_GetData() failed\n");
3801 /* Get optional target file name */
3802 if (!INF_GetDataField(&FilesContext
, 11, &TargetFileName
))
3803 TargetFileName
= NULL
;
3804 else if (!*TargetFileName
)
3805 TargetFileName
= NULL
;
3807 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName
, FileKeyValue
);
3809 /* Lookup target directory */
3810 if (!SetupFindFirstLineW(InfFile
, L
"Directories", FileKeyValue
, &DirContext
))
3812 /* FIXME: Handle error! */
3813 DPRINT1("SetupFindFirstLine() failed\n");
3817 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3819 /* FIXME: Handle error! */
3820 DPRINT1("INF_GetData() failed\n");
3824 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3826 /* Installation path */
3827 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3829 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3830 SourceRootDir
.Buffer
);
3832 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName
);
3834 else if (DirKeyValue
[0] == L
'\\')
3837 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3839 StringCchCopyW(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
),
3842 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName
);
3844 else // if (DirKeyValue[0] != L'\\')
3846 /* Path relative to the installation path */
3847 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3849 CombinePaths(CompleteOrigDirName
, ARRAYSIZE(CompleteOrigDirName
), 2,
3850 SourceRootDir
.Buffer
, DirKeyValue
);
3852 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName
);
3855 if (!SetupQueueCopy(SetupFileQueue
,
3857 SourceRootPath
.Buffer
,
3858 CompleteOrigDirName
,
3863 /* FIXME: Handle error! */
3864 DPRINT1("SetupQueueCopy() failed\n");
3866 } while (SetupFindNextLine(&FilesContext
, &FilesContext
));
3873 PrepareCopyPageInfFile(HINF InfFile
,
3874 PWCHAR SourceCabinet
,
3878 INFCONTEXT DirContext
;
3879 PWCHAR AdditionalSectionName
= NULL
;
3881 WCHAR PathBuffer
[MAX_PATH
];
3883 /* Add common files */
3884 if (!AddSectionToCopyQueue(InfFile
, L
"SourceDisksFiles", SourceCabinet
, &DestinationPath
, Ir
))
3887 /* Add specific files depending of computer type */
3888 if (SourceCabinet
== NULL
)
3890 if (!ProcessComputerFiles(InfFile
, ComputerList
, &AdditionalSectionName
))
3893 if (AdditionalSectionName
)
3895 if (!AddSectionToCopyQueue(InfFile
, AdditionalSectionName
, SourceCabinet
, &DestinationPath
, Ir
))
3900 /* Create directories */
3904 * Copying files to DestinationRootPath should be done from within
3905 * the SystemPartitionFiles section.
3906 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3907 * For installing to DestinationPath specify just '\' .
3910 /* Get destination path */
3911 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
), DestinationPath
.Buffer
);
3913 DPRINT("FullPath(1): '%S'\n", PathBuffer
);
3915 /* Create the install directory */
3916 Status
= SetupCreateDirectory(PathBuffer
);
3917 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3919 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer
, Status
);
3920 MUIDisplayError(ERROR_CREATE_INSTALL_DIR
, Ir
, POPUP_WAIT_ENTER
);
3924 /* Search for the 'Directories' section */
3925 if (!SetupFindFirstLineW(InfFile
, L
"Directories", NULL
, &DirContext
))
3929 MUIDisplayError(ERROR_CABINET_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3933 MUIDisplayError(ERROR_TXTSETUP_SECTION
, Ir
, POPUP_WAIT_ENTER
);
3939 /* Enumerate the directory values and create the subdirectories */
3942 if (!INF_GetData(&DirContext
, NULL
, &DirKeyValue
))
3948 if ((DirKeyValue
[0] == UNICODE_NULL
) || (DirKeyValue
[0] == L
'\\' && DirKeyValue
[1] == UNICODE_NULL
))
3950 /* Installation path */
3951 DPRINT("InstallationPath: '%S'\n", DirKeyValue
);
3953 StringCchCopyW(PathBuffer
, ARRAYSIZE(PathBuffer
),
3954 DestinationPath
.Buffer
);
3956 DPRINT("InstallationPath(2): '%S'\n", PathBuffer
);
3958 else if (DirKeyValue
[0] == L
'\\')
3961 DPRINT("AbsolutePath: '%S'\n", DirKeyValue
);
3963 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3964 DestinationRootPath
.Buffer
, DirKeyValue
);
3966 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer
);
3968 Status
= SetupCreateDirectory(PathBuffer
);
3969 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3971 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3972 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3976 else // if (DirKeyValue[0] != L'\\')
3978 /* Path relative to the installation path */
3979 DPRINT("RelativePath: '%S'\n", DirKeyValue
);
3981 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
3982 DestinationPath
.Buffer
, DirKeyValue
);
3984 DPRINT("RelativePath(2): '%S'\n", PathBuffer
);
3986 Status
= SetupCreateDirectory(PathBuffer
);
3987 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_COLLISION
)
3989 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer
, Status
);
3990 MUIDisplayError(ERROR_CREATE_DIR
, Ir
, POPUP_WAIT_ENTER
);
3994 } while (SetupFindNextLine(&DirContext
, &DirContext
));
4001 * Displays the PrepareCopyPage.
4004 * FileCopyPage(At once)
4008 * Inits SetupFileQueue
4009 * Calls PrepareCopyPageInfFile
4012 * Number of the next page.
4015 PrepareCopyPage(PINPUT_RECORD Ir
)
4018 WCHAR PathBuffer
[MAX_PATH
];
4019 INFCONTEXT CabinetsContext
;
4025 MUIDisplayPage(PREPARE_COPY_PAGE
);
4027 /* Create the file queue */
4028 SetupFileQueue
= SetupOpenFileQueue();
4029 if (SetupFileQueue
== NULL
)
4031 MUIDisplayError(ERROR_COPY_QUEUE
, Ir
, POPUP_WAIT_ENTER
);
4035 if (!PrepareCopyPageInfFile(SetupInf
, NULL
, Ir
))
4037 /* FIXME: show an error dialog */
4041 /* Search for the 'Cabinets' section */
4042 if (!SetupFindFirstLineW(SetupInf
, L
"Cabinets", NULL
, &CabinetsContext
))
4044 return FILE_COPY_PAGE
;
4048 * Enumerate the directory values in the 'Cabinets'
4049 * section and parse their inf files.
4053 if (!INF_GetData(&CabinetsContext
, NULL
, &KeyValue
))
4056 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
4057 SourcePath
.Buffer
, KeyValue
);
4059 CabinetInitialize();
4060 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
4061 CabinetSetCabinetName(PathBuffer
);
4063 if (CabinetOpen() == CAB_STATUS_SUCCESS
)
4065 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
4067 InfFileData
= CabinetGetCabinetReservedArea(&InfFileSize
);
4068 if (InfFileData
== NULL
)
4070 MUIDisplayError(ERROR_CABINET_SCRIPT
, Ir
, POPUP_WAIT_ENTER
);
4076 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
4077 MUIDisplayError(ERROR_CABINET_MISSING
, Ir
, POPUP_WAIT_ENTER
);
4081 InfHandle
= INF_OpenBufferedFileA((CHAR
*) InfFileData
,
4088 if (InfHandle
== INVALID_HANDLE_VALUE
)
4090 MUIDisplayError(ERROR_INVALID_CABINET_INF
, Ir
, POPUP_WAIT_ENTER
);
4096 if (!PrepareCopyPageInfFile(InfHandle
, KeyValue
, Ir
))
4098 /* FIXME: show an error dialog */
4101 } while (SetupFindNextLine(&CabinetsContext
, &CabinetsContext
));
4103 return FILE_COPY_PAGE
;
4109 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext
,
4112 SYSTEM_PERFORMANCE_INFORMATION PerfInfo
;
4114 /* Get the memory information from the system */
4115 NtQuerySystemInformation(SystemPerformanceInformation
,
4120 /* Check if this is initial setup */
4123 /* Set maximum limits to be total RAM pages */
4124 ProgressSetStepCount(CopyContext
->MemoryBars
[0], PerfInfo
.CommitLimit
);
4125 ProgressSetStepCount(CopyContext
->MemoryBars
[1], PerfInfo
.CommitLimit
);
4126 ProgressSetStepCount(CopyContext
->MemoryBars
[2], PerfInfo
.CommitLimit
);
4129 /* Set current values */
4130 ProgressSetStep(CopyContext
->MemoryBars
[0], PerfInfo
.PagedPoolPages
+ PerfInfo
.NonPagedPoolPages
);
4131 ProgressSetStep(CopyContext
->MemoryBars
[1], PerfInfo
.ResidentSystemCachePage
);
4132 ProgressSetStep(CopyContext
->MemoryBars
[2], PerfInfo
.AvailablePages
);
4138 FileCopyCallback(PVOID Context
,
4143 PCOPYCONTEXT CopyContext
;
4145 CopyContext
= (PCOPYCONTEXT
)Context
;
4147 switch (Notification
)
4149 case SPFILENOTIFY_STARTSUBQUEUE
:
4150 CopyContext
->TotalOperations
= (ULONG
)Param2
;
4151 ProgressSetStepCount(CopyContext
->ProgressBar
,
4152 CopyContext
->TotalOperations
);
4153 SetupUpdateMemoryInfo(CopyContext
, TRUE
);
4156 case SPFILENOTIFY_STARTCOPY
:
4157 /* Display copy message */
4158 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING
), (PWSTR
)Param1
);
4159 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4162 case SPFILENOTIFY_ENDCOPY
:
4163 CopyContext
->CompletedOperations
++;
4165 /* SYSREG checkpoint */
4166 if (CopyContext
->TotalOperations
>> 1 == CopyContext
->CompletedOperations
)
4167 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4169 ProgressNextStep(CopyContext
->ProgressBar
);
4170 SetupUpdateMemoryInfo(CopyContext
, FALSE
);
4179 * Displays the FileCopyPage.
4182 * RegistryPage(At once)
4185 * Calls SetupCommitFileQueueW
4186 * Calls SetupCloseFileQueue
4189 * Number of the next page.
4192 FileCopyPage(PINPUT_RECORD Ir
)
4194 COPYCONTEXT CopyContext
;
4195 unsigned int mem_bar_width
;
4197 MUIDisplayPage(FILE_COPY_PAGE
);
4199 /* Create context for the copy process */
4200 CopyContext
.DestinationRootPath
= DestinationRootPath
.Buffer
;
4201 CopyContext
.InstallPath
= InstallPath
.Buffer
;
4202 CopyContext
.TotalOperations
= 0;
4203 CopyContext
.CompletedOperations
= 0;
4205 /* Create the progress bar as well */
4206 CopyContext
.ProgressBar
= CreateProgressBar(13,
4213 MUIGetString(STRING_SETUPCOPYINGFILES
));
4215 // fit memory bars to screen width, distribute them uniform
4216 mem_bar_width
= (xScreen
- 26) / 5;
4217 mem_bar_width
-= mem_bar_width
% 2; // make even
4218 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4219 /* Create the paged pool progress bar */
4220 CopyContext
.MemoryBars
[0] = CreateProgressBar(13,
4229 /* Create the non paged pool progress bar */
4230 CopyContext
.MemoryBars
[1] = CreateProgressBar((xScreen
/ 2)- (mem_bar_width
/ 2),
4232 (xScreen
/ 2) + (mem_bar_width
/ 2),
4234 (xScreen
/ 2)- (mem_bar_width
/ 2),
4239 /* Create the global memory progress bar */
4240 CopyContext
.MemoryBars
[2] = CreateProgressBar(xScreen
- 13 - mem_bar_width
,
4244 xScreen
- 13 - mem_bar_width
,
4249 /* Do the file copying */
4250 SetupCommitFileQueueW(NULL
,
4255 /* If we get here, we're done, so cleanup the queue and progress bar */
4256 SetupCloseFileQueue(SetupFileQueue
);
4257 DestroyProgressBar(CopyContext
.ProgressBar
);
4258 DestroyProgressBar(CopyContext
.MemoryBars
[0]);
4259 DestroyProgressBar(CopyContext
.MemoryBars
[1]);
4260 DestroyProgressBar(CopyContext
.MemoryBars
[2]);
4262 /* Go display the next page */
4263 return REGISTRY_PAGE
;
4268 * Displays the RegistryPage.
4271 * SuccessPage (if RepairUpdate)
4272 * BootLoaderPage (default)
4276 * Calls RegInitializeRegistry
4277 * Calls ImportRegistryFile
4278 * Calls SetDefaultPagefile
4279 * Calls SetMountedDeviceValues
4282 * Number of the next page.
4285 RegistryPage(PINPUT_RECORD Ir
)
4288 INFCONTEXT InfContext
;
4293 BOOLEAN ShouldRepairRegistry
= FALSE
;
4296 MUIDisplayPage(REGISTRY_PAGE
);
4298 if (RepairUpdateFlag
)
4300 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
4302 /* Verify the registry hives and check whether we need to update or repair any of them */
4303 Status
= VerifyRegistryHives(&DestinationPath
, &ShouldRepairRegistry
);
4304 if (!NT_SUCCESS(Status
))
4306 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status
);
4307 ShouldRepairRegistry
= FALSE
;
4309 if (!ShouldRepairRegistry
)
4310 DPRINT1("No need to repair the registry\n");
4314 /* Update the registry */
4315 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE
));
4317 /* Initialize the registry and setup the registry hives */
4318 Status
= RegInitializeRegistry(&DestinationPath
);
4319 if (!NT_SUCCESS(Status
))
4321 DPRINT1("RegInitializeRegistry() failed\n");
4322 /********** HACK!!!!!!!!!!! **********/
4323 if (Status
== STATUS_NOT_IMPLEMENTED
)
4325 /* The hack was called, display its corresponding error */
4326 MUIDisplayError(ERROR_INITIALIZE_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4329 /*************************************/
4331 /* Something else failed */
4332 MUIDisplayError(ERROR_CREATE_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4337 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
4340 * We fully setup the hives, in case we are doing a fresh installation
4341 * (RepairUpdateFlag == FALSE), or in case we are doing an update
4342 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
4343 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
4346 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Fresh", NULL
, &InfContext
); // Windows-compatible
4348 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
); // ReactOS-specific
4352 DPRINT1("SetupFindFirstLine() failed\n");
4353 MUIDisplayError(ERROR_FIND_REGISTRY
, Ir
, POPUP_WAIT_ENTER
);
4357 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
4360 * In case we are doing an update (RepairUpdateFlag == TRUE) and
4361 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
4362 * we only update the hives.
4365 Success
= SetupFindFirstLineW(SetupInf
, L
"HiveInfs.Upgrade", NULL
, &InfContext
);
4368 /* Nothing to do for update! */
4369 DPRINT1("No update needed for the registry!\n");
4376 INF_GetDataField(&InfContext
, 0, &Action
);
4377 INF_GetDataField(&InfContext
, 1, &File
);
4378 INF_GetDataField(&InfContext
, 2, &Section
);
4380 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
4385 if (!_wcsicmp(Action
, L
"AddReg"))
4387 else if (!_wcsicmp(Action
, L
"DelReg"))
4391 DPRINT1("Unrecognized registry INF action '%S'\n", Action
);
4395 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE
), File
);
4397 if (!ImportRegistryFile(SourcePath
.Buffer
, File
, Section
, LanguageId
, Delete
))
4399 DPRINT1("Importing %S failed\n", File
);
4400 MUIDisplayError(ERROR_IMPORT_HIVE
, Ir
, POPUP_WAIT_ENTER
);
4403 } while (SetupFindNextLine(&InfContext
, &InfContext
));
4405 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
4407 /* See the explanation for this test above */
4409 /* Update display registry settings */
4410 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE
));
4411 if (!ProcessDisplayRegistry(SetupInf
, DisplayList
))
4413 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4417 /* Set the locale */
4418 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE
));
4419 if (!ProcessLocaleRegistry(LanguageList
))
4421 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4425 /* Add keyboard layouts */
4426 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS
));
4427 if (!AddKeyboardLayouts())
4429 MUIDisplayError(ERROR_ADDING_KBLAYOUTS
, Ir
, POPUP_WAIT_ENTER
);
4434 if (!SetGeoID(MUIGetGeoID()))
4436 MUIDisplayError(ERROR_UPDATE_GEOID
, Ir
, POPUP_WAIT_ENTER
);
4440 if (!IsUnattendedSetup
)
4442 /* Update keyboard layout settings */
4443 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE
));
4444 if (!ProcessKeyboardLayoutRegistry(LayoutList
))
4446 MUIDisplayError(ERROR_UPDATE_KBSETTINGS
, Ir
, POPUP_WAIT_ENTER
);
4451 /* Add codepage information to registry */
4452 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE
));
4455 MUIDisplayError(ERROR_ADDING_CODEPAGE
, Ir
, POPUP_WAIT_ENTER
);
4459 /* Set the default pagefile entry */
4460 SetDefaultPagefile(DestinationDriveLetter
);
4462 /* Update the mounted devices list */
4463 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
4464 SetMountedDeviceValues(PartitionList
);
4469 // TODO: Unload all the registry stuff, perform cleanup,
4470 // and copy the created hive files into .sav files.
4472 RegCleanupRegistry(&DestinationPath
);
4475 * Check whether we were in update/repair mode but we were actually
4476 * repairing the registry hives. If so, we have finished repairing them,
4477 * and we now reset the flag and run the proper registry update.
4478 * Otherwise we have finished the registry update!
4480 if (RepairUpdateFlag
&& ShouldRepairRegistry
)
4482 ShouldRepairRegistry
= FALSE
;
4486 if (NT_SUCCESS(Status
))
4488 CONSOLE_SetStatusText(MUIGetString(STRING_DONE
));
4489 return BOOT_LOADER_PAGE
;
4499 * Displays the BootLoaderPage.
4502 * SuccessPage (if RepairUpdate)
4503 * BootLoaderHarddiskMbrPage
4504 * BootLoaderHarddiskVbrPage
4505 * BootLoaderFloppyPage
4510 * Calls RegInitializeRegistry
4511 * Calls ImportRegistryFile
4512 * Calls SetDefaultPagefile
4513 * Calls SetMountedDeviceValues
4516 * Number of the next page.
4519 BootLoaderPage(PINPUT_RECORD Ir
)
4521 UCHAR PartitionType
;
4522 BOOLEAN InstallOnFloppy
;
4524 WCHAR PathBuffer
[MAX_PATH
];
4526 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT
));
4528 RtlFreeUnicodeString(&SystemRootPath
);
4529 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
4530 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
4531 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
,
4532 PartitionList
->SystemPartition
->PartitionNumber
);
4533 RtlCreateUnicodeString(&SystemRootPath
, PathBuffer
);
4534 DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath
);
4536 PartitionType
= PartitionList
->SystemPartition
->PartitionType
;
4538 if (IsUnattendedSetup
)
4540 if (UnattendMBRInstallType
== 0) /* skip MBR installation */
4542 return SUCCESS_PAGE
;
4544 else if (UnattendMBRInstallType
== 1) /* install on floppy */
4546 return BOOT_LOADER_FLOPPY_PAGE
;
4550 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
4552 DPRINT("Error: system partition invalid (unused)\n");
4553 InstallOnFloppy
= TRUE
;
4555 else if (PartitionType
== PARTITION_OS2BOOTMGR
)
4557 /* OS/2 boot manager partition */
4558 DPRINT("Found OS/2 boot manager partition\n");
4559 InstallOnFloppy
= TRUE
;
4561 else if (PartitionType
== PARTITION_EXT2
)
4563 /* Linux EXT2 partition */
4564 DPRINT("Found Linux EXT2 partition\n");
4565 InstallOnFloppy
= FALSE
;
4567 else if (PartitionType
== PARTITION_IFS
)
4569 /* NTFS partition */
4570 DPRINT("Found NTFS partition\n");
4572 // FIXME: Make it FALSE when we'll support NTFS installation!
4573 InstallOnFloppy
= TRUE
;
4575 else if ((PartitionType
== PARTITION_FAT_12
) ||
4576 (PartitionType
== PARTITION_FAT_16
) ||
4577 (PartitionType
== PARTITION_HUGE
) ||
4578 (PartitionType
== PARTITION_XINT13
) ||
4579 (PartitionType
== PARTITION_FAT32
) ||
4580 (PartitionType
== PARTITION_FAT32_XINT13
))
4582 DPRINT("Found FAT partition\n");
4583 InstallOnFloppy
= FALSE
;
4587 /* Unknown partition */
4588 DPRINT("Unknown partition found\n");
4589 InstallOnFloppy
= TRUE
;
4592 if (InstallOnFloppy
!= FALSE
)
4594 return BOOT_LOADER_FLOPPY_PAGE
;
4597 /* Unattended install on hdd? */
4598 if (IsUnattendedSetup
&& UnattendMBRInstallType
== 2)
4600 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4603 MUIDisplayPage(BOOT_LOADER_PAGE
);
4604 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4608 CONSOLE_ConInKey(Ir
);
4610 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4611 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)) /* DOWN */
4613 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4622 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4624 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4625 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)) /* UP */
4627 CONSOLE_NormalTextXY(8, Line
, 60, 1);
4636 CONSOLE_InvertTextXY(8, Line
, 60, 1);
4638 else if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4639 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4641 if (ConfirmQuit(Ir
) != FALSE
)
4646 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4650 return BOOT_LOADER_HARDDISK_MBR_PAGE
;
4652 else if (Line
== 13)
4654 return BOOT_LOADER_HARDDISK_VBR_PAGE
;
4656 else if (Line
== 14)
4658 return BOOT_LOADER_FLOPPY_PAGE
;
4660 else if (Line
== 15)
4662 return SUCCESS_PAGE
;
4665 return BOOT_LOADER_PAGE
;
4669 return BOOT_LOADER_PAGE
;
4674 * Displays the BootLoaderFloppyPage.
4677 * SuccessPage (At once)
4681 * Calls InstallFatBootcodeToFloppy()
4684 * Number of the next page.
4687 BootLoaderFloppyPage(PINPUT_RECORD Ir
)
4691 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE
);
4693 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4697 CONSOLE_ConInKey(Ir
);
4699 if ((Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x00) &&
4700 (Ir
->Event
.KeyEvent
.wVirtualKeyCode
== VK_F3
)) /* F3 */
4702 if (ConfirmQuit(Ir
) != FALSE
)
4707 else if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
4709 if (DoesPathExist(NULL
, L
"\\Device\\Floppy0\\") == FALSE
)
4711 MUIDisplayError(ERROR_NO_FLOPPY
, Ir
, POPUP_WAIT_ENTER
);
4712 return BOOT_LOADER_FLOPPY_PAGE
;
4715 Status
= InstallFatBootcodeToFloppy(&SourceRootPath
, &DestinationArcPath
);
4716 if (!NT_SUCCESS(Status
))
4718 /* Print error message */
4719 return BOOT_LOADER_FLOPPY_PAGE
;
4722 return SUCCESS_PAGE
;
4726 return BOOT_LOADER_FLOPPY_PAGE
;
4731 * Displays the BootLoaderHarddiskVbrPage.
4734 * SuccessPage (At once)
4738 * Calls InstallVBRToPartition()
4741 * Number of the next page.
4744 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir
)
4748 Status
= InstallVBRToPartition(&SystemRootPath
,
4750 &DestinationArcPath
,
4751 PartitionList
->SystemPartition
->PartitionType
);
4752 if (!NT_SUCCESS(Status
))
4754 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4758 return SUCCESS_PAGE
;
4763 * Displays the BootLoaderHarddiskMbrPage.
4766 * SuccessPage (At once)
4770 * Calls InstallVBRToPartition()
4771 * Calls InstallMbrBootCodeToDisk()
4774 * Number of the next page.
4777 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir
)
4780 WCHAR DestinationDevicePathBuffer
[MAX_PATH
];
4781 WCHAR SourceMbrPathBuffer
[MAX_PATH
];
4782 WCHAR DstPath
[MAX_PATH
];
4784 /* Step 1: Write the VBR */
4785 Status
= InstallVBRToPartition(&SystemRootPath
,
4787 &DestinationArcPath
,
4788 PartitionList
->SystemPartition
->PartitionType
);
4789 if (!NT_SUCCESS(Status
))
4791 MUIDisplayError(ERROR_WRITE_BOOT
, Ir
, POPUP_WAIT_ENTER
);
4795 /* Step 2: Write the MBR */
4796 StringCchPrintfW(DestinationDevicePathBuffer
, ARRAYSIZE(DestinationDevicePathBuffer
),
4797 L
"\\Device\\Harddisk%d\\Partition0",
4798 PartitionList
->SystemPartition
->DiskEntry
->DiskNumber
);
4800 CombinePaths(SourceMbrPathBuffer
, ARRAYSIZE(SourceMbrPathBuffer
), 2, SourceRootPath
.Buffer
, L
"\\loader\\dosmbr.bin");
4802 if (IsThereAValidBootSector(DestinationDevicePathBuffer
))
4804 /* Save current MBR */
4805 CombinePaths(DstPath
, ARRAYSIZE(DstPath
), 2, SystemRootPath
.Buffer
, L
"mbr.old");
4807 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer
, DstPath
);
4808 Status
= SaveBootSector(DestinationDevicePathBuffer
, DstPath
, sizeof(PARTITION_SECTOR
));
4809 if (!NT_SUCCESS(Status
))
4811 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status
);
4812 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4816 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4817 SourceMbrPathBuffer
, DestinationDevicePathBuffer
);
4818 Status
= InstallMbrBootCodeToDisk(SourceMbrPathBuffer
,
4819 DestinationDevicePathBuffer
);
4820 if (!NT_SUCCESS(Status
))
4822 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4824 MUIDisplayError(ERROR_INSTALL_BOOTCODE
, Ir
, POPUP_WAIT_ENTER
);
4828 return SUCCESS_PAGE
;
4833 * @name ProgressTimeOutStringHandler
4835 * Handles the generation (displaying) of the timeout
4836 * countdown to the screen dynamically.
4839 * A pointer to a progress bar.
4841 * @param AlwaysUpdate
4842 * Constantly update the progress bar (boolean type).
4845 * A pointer to a string buffer.
4847 * @param cchBufferSize
4848 * The buffer's size in number of characters.
4851 * TRUE or FALSE on function termination.
4856 ProgressTimeOutStringHandler(
4857 IN PPROGRESSBAR Bar
,
4858 IN BOOLEAN AlwaysUpdate
,
4860 IN SIZE_T cchBufferSize
)
4862 ULONG OldProgress
= Bar
->Progress
;
4864 if (Bar
->StepCount
== 0)
4870 Bar
->Progress
= Bar
->StepCount
- Bar
->CurrentStep
;
4873 /* Build the progress string if it has changed */
4874 if (Bar
->ProgressFormatText
&&
4875 (AlwaysUpdate
|| (Bar
->Progress
!= OldProgress
)))
4877 RtlStringCchPrintfA(Buffer
, cchBufferSize
,
4878 Bar
->ProgressFormatText
, Bar
->Progress
/ max(1, Bar
->Width
) + 1);
4887 * @name ProgressCountdown
4889 * Displays and draws a red-coloured progress bar with a countdown.
4890 * When the timeout is reached, the flush page is displayed for reboot.
4893 * A pointer to an input keyboard record.
4896 * Initial countdown value in seconds.
4904 IN PINPUT_RECORD Ir
,
4908 ULONG StartTime
, BarWidth
, TimerDiv
;
4910 LONG TimerValue
, OldTimerValue
;
4911 LARGE_INTEGER Timeout
;
4912 PPROGRESSBAR ProgressBar
;
4913 BOOLEAN RefreshProgress
= TRUE
;
4915 /* Bail out if the timeout is already zero */
4919 /* Create the timeout progress bar and set it up */
4920 ProgressBar
= CreateProgressBarEx(13,
4927 FOREGROUND_RED
| BACKGROUND_BLUE
,
4930 MUIGetString(STRING_REBOOTPROGRESSBAR
),
4931 ProgressTimeOutStringHandler
);
4933 BarWidth
= max(1, ProgressBar
->Width
);
4934 TimerValue
= TimeOut
* BarWidth
;
4935 ProgressSetStepCount(ProgressBar
, TimerValue
);
4937 StartTime
= NtGetTickCount();
4940 TimerDiv
= 1000 / BarWidth
;
4941 TimerDiv
= max(1, TimerDiv
);
4942 OldTimerValue
= TimerValue
;
4945 /* Decrease the timer */
4948 * Compute how much time the previous operations took.
4949 * This allows us in particular to take account for any time
4950 * elapsed if something slowed down.
4952 TimeElapsed
= NtGetTickCount() - StartTime
;
4953 if (TimeElapsed
>= TimerDiv
)
4955 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4956 TimeElapsed
/= TimerDiv
;
4957 StartTime
+= (TimerDiv
* TimeElapsed
);
4959 if (TimeElapsed
<= TimerValue
)
4960 TimerValue
-= TimeElapsed
;
4964 RefreshProgress
= TRUE
;
4967 if (RefreshProgress
)
4969 ProgressSetStep(ProgressBar
, OldTimerValue
- TimerValue
);
4970 RefreshProgress
= FALSE
;
4973 /* Stop when the timer reaches zero */
4974 if (TimerValue
<= 0)
4977 /* Check for user key presses */
4980 * If the timer is used, use a passive wait of maximum 1 second
4981 * while monitoring for incoming console input events, so that
4982 * we are still able to display the timing count.
4985 /* Wait a maximum of 1 second for input events */
4986 TimeElapsed
= NtGetTickCount() - StartTime
;
4987 if (TimeElapsed
< TimerDiv
)
4989 /* Convert the time to NT Format */
4990 Timeout
.QuadPart
= (TimerDiv
- TimeElapsed
) * -10000LL;
4991 Status
= NtWaitForSingleObject(StdInput
, FALSE
, &Timeout
);
4995 Status
= STATUS_TIMEOUT
;
4998 /* Check whether the input event has been signaled, or a timeout happened */
4999 if (Status
== STATUS_TIMEOUT
)
5003 if (Status
!= STATUS_WAIT_0
)
5005 /* An error happened, bail out */
5006 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status
);
5010 /* Check for an ENTER key press */
5011 while (CONSOLE_ConInKeyPeek(Ir
))
5013 if (Ir
->Event
.KeyEvent
.uChar
.AsciiChar
== 0x0D) /* ENTER */
5015 /* Found it, stop waiting */
5022 /* Destroy the progress bar and quit */
5023 DestroyProgressBar(ProgressBar
);
5028 * Displays the QuitPage.
5031 * FlushPage (At once)
5037 * Number of the next page.
5040 QuitPage(PINPUT_RECORD Ir
)
5042 MUIDisplayPage(QUIT_PAGE
);
5044 /* Destroy the NTOS installations list */
5045 if (NtOsInstallsList
!= NULL
)
5047 DestroyGenericList(NtOsInstallsList
, TRUE
);
5048 NtOsInstallsList
= NULL
;
5051 /* Destroy the partition list */
5052 if (PartitionList
!= NULL
)
5054 DestroyPartitionList(PartitionList
);
5055 PartitionList
= NULL
;
5057 TempPartition
= NULL
;
5058 FormatState
= Start
;
5060 /* Destroy the filesystem list */
5061 if (FileSystemList
!= NULL
)
5063 DestroyFileSystemList(FileSystemList
);
5064 FileSystemList
= NULL
;
5067 /* Destroy the computer settings list */
5068 if (ComputerList
!= NULL
)
5070 DestroyGenericList(ComputerList
, TRUE
);
5071 ComputerList
= NULL
;
5074 /* Destroy the display settings list */
5075 if (DisplayList
!= NULL
)
5077 DestroyGenericList(DisplayList
, TRUE
);
5081 /* Destroy the keyboard settings list */
5082 if (KeyboardList
!= NULL
)
5084 DestroyGenericList(KeyboardList
, TRUE
);
5085 KeyboardList
= NULL
;
5088 /* Destroy the keyboard layout list */
5089 if (LayoutList
!= NULL
)
5091 DestroyGenericList(LayoutList
, TRUE
);
5095 /* Destroy the languages list */
5096 if (LanguageList
!= NULL
)
5098 DestroyGenericList(LanguageList
, FALSE
);
5099 LanguageList
= NULL
;
5102 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2
));
5104 /* Wait for maximum 15 seconds or an ENTER key before quitting */
5105 ProgressCountdown(Ir
, 15);
5111 * Displays the SuccessPage.
5114 * FlushPage (At once)
5120 * Number of the next page.
5123 SuccessPage(PINPUT_RECORD Ir
)
5125 MUIDisplayPage(SUCCESS_PAGE
);
5127 if (IsUnattendedSetup
)
5130 /* Wait for maximum 15 seconds or an ENTER key before quitting */
5131 ProgressCountdown(Ir
, 15);
5137 * Displays the FlushPage.
5140 * RebootPage (At once)
5143 * Number of the next page.
5146 FlushPage(PINPUT_RECORD Ir
)
5148 MUIDisplayPage(FLUSH_PAGE
);
5154 PnpEventThread(IN LPVOID lpParameter
);
5158 * The start routine and page management
5168 InfSetHeap(ProcessHeap
);
5170 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
5171 Status
= NtInitializeRegistry(CM_BOOT_FLAG_SETUP
);
5172 if (!NT_SUCCESS(Status
))
5173 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status
);
5175 /* Create the PnP thread in suspended state */
5176 Status
= RtlCreateUserThread(NtCurrentProcess(),
5186 if (!NT_SUCCESS(Status
))
5187 hPnpThread
= INVALID_HANDLE_VALUE
;
5189 if (!CONSOLE_Init())
5191 PrintString(MUIGetString(STRING_CONSOLEFAIL1
));
5192 PrintString(MUIGetString(STRING_CONSOLEFAIL2
));
5193 PrintString(MUIGetString(STRING_CONSOLEFAIL3
));
5195 /* We failed to initialize the video, just quit the installer */
5196 return STATUS_APP_INIT_FAILURE
;
5199 /* Initialize global unicode strings */
5200 RtlInitUnicodeString(&SourcePath
, NULL
);
5201 RtlInitUnicodeString(&SourceRootPath
, NULL
);
5202 RtlInitUnicodeString(&SourceRootDir
, NULL
);
5203 RtlInitUnicodeString(&InstallPath
, NULL
);
5204 RtlInitUnicodeString(&DestinationPath
, NULL
);
5205 RtlInitUnicodeString(&DestinationArcPath
, NULL
);
5206 RtlInitUnicodeString(&DestinationRootPath
, NULL
);
5207 RtlInitUnicodeString(&SystemRootPath
, NULL
);
5209 /* Hide the cursor */
5210 CONSOLE_SetCursorType(TRUE
, FALSE
);
5212 /* Global Initialization page */
5213 CONSOLE_ClearScreen();
5215 Page
= SetupStartPage(&Ir
);
5217 while (Page
!= REBOOT_PAGE
&& Page
!= RECOVERY_PAGE
)
5219 CONSOLE_ClearScreen();
5222 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
5229 Page
= LanguagePage(&Ir
);
5234 Page
= WelcomePage(&Ir
);
5239 Page
= LicensePage(&Ir
);
5243 case INSTALL_INTRO_PAGE
:
5244 Page
= InstallIntroPage(&Ir
);
5248 case SCSI_CONTROLLER_PAGE
:
5249 Page
= ScsiControllerPage(&Ir
);
5252 case OEM_DRIVER_PAGE
:
5253 Page
= OemDriverPage(&Ir
);
5257 case DEVICE_SETTINGS_PAGE
:
5258 Page
= DeviceSettingsPage(&Ir
);
5261 case COMPUTER_SETTINGS_PAGE
:
5262 Page
= ComputerSettingsPage(&Ir
);
5265 case DISPLAY_SETTINGS_PAGE
:
5266 Page
= DisplaySettingsPage(&Ir
);
5269 case KEYBOARD_SETTINGS_PAGE
:
5270 Page
= KeyboardSettingsPage(&Ir
);
5273 case LAYOUT_SETTINGS_PAGE
:
5274 Page
= LayoutSettingsPage(&Ir
);
5277 case SELECT_PARTITION_PAGE
:
5278 Page
= SelectPartitionPage(&Ir
);
5281 case CREATE_PRIMARY_PARTITION_PAGE
:
5282 Page
= CreatePrimaryPartitionPage(&Ir
);
5285 case CREATE_EXTENDED_PARTITION_PAGE
:
5286 Page
= CreateExtendedPartitionPage(&Ir
);
5289 case CREATE_LOGICAL_PARTITION_PAGE
:
5290 Page
= CreateLogicalPartitionPage(&Ir
);
5293 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE
:
5294 Page
= ConfirmDeleteSystemPartitionPage(&Ir
);
5297 case DELETE_PARTITION_PAGE
:
5298 Page
= DeletePartitionPage(&Ir
);
5301 case SELECT_FILE_SYSTEM_PAGE
:
5302 Page
= SelectFileSystemPage(&Ir
);
5305 case FORMAT_PARTITION_PAGE
:
5306 Page
= FormatPartitionPage(&Ir
);
5309 case CHECK_FILE_SYSTEM_PAGE
:
5310 Page
= CheckFileSystemPage(&Ir
);
5313 case INSTALL_DIRECTORY_PAGE
:
5314 Page
= InstallDirectoryPage(&Ir
);
5317 case PREPARE_COPY_PAGE
:
5318 Page
= PrepareCopyPage(&Ir
);
5321 case FILE_COPY_PAGE
:
5322 Page
= FileCopyPage(&Ir
);
5326 Page
= RegistryPage(&Ir
);
5329 case BOOT_LOADER_PAGE
:
5330 Page
= BootLoaderPage(&Ir
);
5333 case BOOT_LOADER_FLOPPY_PAGE
:
5334 Page
= BootLoaderFloppyPage(&Ir
);
5337 case BOOT_LOADER_HARDDISK_MBR_PAGE
:
5338 Page
= BootLoaderHarddiskMbrPage(&Ir
);
5341 case BOOT_LOADER_HARDDISK_VBR_PAGE
:
5342 Page
= BootLoaderHarddiskVbrPage(&Ir
);
5346 case REPAIR_INTRO_PAGE
:
5347 Page
= RepairIntroPage(&Ir
);
5350 case UPGRADE_REPAIR_PAGE
:
5351 Page
= UpgradeRepairPage(&Ir
);
5355 Page
= SuccessPage(&Ir
);
5359 Page
= FlushPage(&Ir
);
5363 Page
= QuitPage(&Ir
);
5372 if (Page
== RECOVERY_PAGE
)
5378 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
5379 NtShutdownSystem(ShutdownReboot
);
5380 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
, Old
, FALSE
, &Old
);
5382 return STATUS_SUCCESS
;
5387 NtProcessStartup(PPEB Peb
)
5392 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
5394 ProcessHeap
= Peb
->ProcessHeap
;
5396 NtQuerySystemTime(&Time
);
5398 Status
= RunUSetup();
5400 if (NT_SUCCESS(Status
))
5403 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5404 * a protective waiting.
5405 * This wait is needed because, since we are started as SMSS.EXE,
5406 * the NT kernel explicitly waits 5 seconds for the initial process
5407 * SMSS.EXE to initialize (as a protective measure), and otherwise
5408 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5410 Time
.QuadPart
+= 50000000;
5411 NtDelayExecution(FALSE
, &Time
);
5415 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5416 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
5417 0, 0, NULL
, 0, NULL
);
5420 NtTerminateProcess(NtCurrentProcess(), Status
);