[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
[reactos.git] / base / setup / usetup / usetup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 #include <usetup.h>
29 #include <math.h>
30 #include <ntstrsafe.h>
31
32 #include "bootsup.h"
33 #include "chkdsk.h"
34 #include "cmdcons.h"
35 #include "devinst.h"
36 #include "format.h"
37
38 #define NDEBUG
39 #include <debug.h>
40
41
42 /* GLOBALS & LOCALS *********************************************************/
43
44 HANDLE ProcessHeap;
45 BOOLEAN IsUnattendedSetup = FALSE;
46
47 static USETUP_DATA USetupData;
48
49 /* The partition where to perform the installation */
50 static PPARTENTRY InstallPartition = NULL;
51 /*
52 * The system partition we will actually use. It can be different from
53 * PartitionList->SystemPartition in case we don't support it, or we install
54 * on a removable disk.
55 * We may indeed not support the original system partition in case we do not
56 * have write support on it. Please note that this situation is partly a HACK
57 * and MUST NEVER happen on architectures where real system partitions are
58 * mandatory (because then they are formatted in FAT FS and we support write
59 * operation on them).
60 */
61 static PPARTENTRY SystemPartition = NULL;
62
63
64 /* OTHER Stuff *****/
65
66 PCWSTR SelectedLanguageId;
67 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
68 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
69
70 static BOOLEAN RepairUpdateFlag = FALSE;
71
72 /* Global partition list on the system */
73 static PPARTLIST PartitionList = NULL;
74
75 /* Currently selected partition entry in the list */
76 static PPARTENTRY CurrentPartition = NULL;
77
78 /* List of supported file systems for the partition to be formatted */
79 static PFILE_SYSTEM_LIST FileSystemList = NULL;
80
81 /* Machine state for the formatter */
82 static PPARTENTRY TempPartition = NULL;
83 static FORMATMACHINESTATE FormatState = Start;
84
85 /*****************************************************/
86
87 static PNTOS_INSTALLATION CurrentInstallation = NULL;
88 static PGENERIC_LIST NtOsInstallsList = NULL;
89
90 #ifdef __REACTOS__ /* HACK */
91
92 /* FONT SUBSTITUTION WORKAROUND *************************************************/
93
94 /* For font file check */
95 FONTSUBSTSETTINGS s_SubstSettings = { FALSE };
96
97 static void
98 DoWatchDestFileName(LPCWSTR FileName)
99 {
100 if (FileName[0] == 'm' || FileName[0] == 'M')
101 {
102 if (wcsicmp(FileName, L"mingliu.ttc") == 0)
103 {
104 DPRINT("mingliu.ttc found\n");
105 s_SubstSettings.bFoundFontMINGLIU = TRUE;
106 }
107 else if (wcsicmp(FileName, L"msgothic.ttc") == 0)
108 {
109 DPRINT("msgothic.ttc found\n");
110 s_SubstSettings.bFoundFontMSGOTHIC = TRUE;
111 }
112 else if (wcsicmp(FileName, L"msmincho.ttc") == 0)
113 {
114 DPRINT("msmincho.ttc found\n");
115 s_SubstSettings.bFoundFontMSMINCHO = TRUE;
116 }
117 else if (wcsicmp(FileName, L"mssong.ttf") == 0)
118 {
119 DPRINT("mssong.ttf found\n");
120 s_SubstSettings.bFoundFontMSSONG = TRUE;
121 }
122 }
123 else
124 {
125 if (wcsicmp(FileName, L"simsun.ttc") == 0)
126 {
127 DPRINT("simsun.ttc found\n");
128 s_SubstSettings.bFoundFontSIMSUN = TRUE;
129 }
130 else if (wcsicmp(FileName, L"gulim.ttc") == 0)
131 {
132 DPRINT("gulim.ttc found\n");
133 s_SubstSettings.bFoundFontGULIM = TRUE;
134 }
135 else if (wcsicmp(FileName, L"batang.ttc") == 0)
136 {
137 DPRINT("batang.ttc found\n");
138 s_SubstSettings.bFoundFontBATANG = TRUE;
139 }
140 }
141 }
142 #endif /* HACK */
143
144 /* FUNCTIONS ****************************************************************/
145
146 static VOID
147 PrintString(IN PCSTR fmt,...)
148 {
149 CHAR buffer[512];
150 va_list ap;
151 UNICODE_STRING UnicodeString;
152 ANSI_STRING AnsiString;
153
154 va_start(ap, fmt);
155 vsprintf(buffer, fmt, ap);
156 va_end(ap);
157
158 RtlInitAnsiString(&AnsiString, buffer);
159 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
160 NtDisplayString(&UnicodeString);
161 RtlFreeUnicodeString(&UnicodeString);
162 }
163
164
165 static VOID
166 DrawBox(IN SHORT xLeft,
167 IN SHORT yTop,
168 IN SHORT Width,
169 IN SHORT Height)
170 {
171 COORD coPos;
172 DWORD Written;
173
174 /* Draw upper left corner */
175 coPos.X = xLeft;
176 coPos.Y = yTop;
177 FillConsoleOutputCharacterA(StdOutput,
178 0xDA, // '+',
179 1,
180 coPos,
181 &Written);
182
183 /* Draw upper edge */
184 coPos.X = xLeft + 1;
185 coPos.Y = yTop;
186 FillConsoleOutputCharacterA(StdOutput,
187 0xC4, // '-',
188 Width - 2,
189 coPos,
190 &Written);
191
192 /* Draw upper right corner */
193 coPos.X = xLeft + Width - 1;
194 coPos.Y = yTop;
195 FillConsoleOutputCharacterA(StdOutput,
196 0xBF, // '+',
197 1,
198 coPos,
199 &Written);
200
201 /* Draw right edge, inner space and left edge */
202 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
203 {
204 coPos.X = xLeft;
205 FillConsoleOutputCharacterA(StdOutput,
206 0xB3, // '|',
207 1,
208 coPos,
209 &Written);
210
211 coPos.X = xLeft + 1;
212 FillConsoleOutputCharacterA(StdOutput,
213 ' ',
214 Width - 2,
215 coPos,
216 &Written);
217
218 coPos.X = xLeft + Width - 1;
219 FillConsoleOutputCharacterA(StdOutput,
220 0xB3, // '|',
221 1,
222 coPos,
223 &Written);
224 }
225
226 /* Draw lower left corner */
227 coPos.X = xLeft;
228 coPos.Y = yTop + Height - 1;
229 FillConsoleOutputCharacterA(StdOutput,
230 0xC0, // '+',
231 1,
232 coPos,
233 &Written);
234
235 /* Draw lower edge */
236 coPos.X = xLeft + 1;
237 coPos.Y = yTop + Height - 1;
238 FillConsoleOutputCharacterA(StdOutput,
239 0xC4, // '-',
240 Width - 2,
241 coPos,
242 &Written);
243
244 /* Draw lower right corner */
245 coPos.X = xLeft + Width - 1;
246 coPos.Y = yTop + Height - 1;
247 FillConsoleOutputCharacterA(StdOutput,
248 0xD9, // '+',
249 1,
250 coPos,
251 &Written);
252 }
253
254
255 VOID
256 PopupError(PCCH Text,
257 PCCH Status,
258 PINPUT_RECORD Ir,
259 ULONG WaitEvent)
260 {
261 SHORT yTop;
262 SHORT xLeft;
263 COORD coPos;
264 DWORD Written;
265 ULONG Length;
266 ULONG MaxLength;
267 ULONG Lines;
268 PCHAR p;
269 PCCH pnext;
270 BOOLEAN LastLine;
271 SHORT Width;
272 SHORT Height;
273
274 /* Count text lines and longest line */
275 MaxLength = 0;
276 Lines = 0;
277 pnext = Text;
278
279 while (TRUE)
280 {
281 p = strchr(pnext, '\n');
282
283 if (p == NULL)
284 {
285 Length = strlen(pnext);
286 LastLine = TRUE;
287 }
288 else
289 {
290 Length = (ULONG)(p - pnext);
291 LastLine = FALSE;
292 }
293
294 Lines++;
295
296 if (Length > MaxLength)
297 MaxLength = Length;
298
299 if (LastLine)
300 break;
301
302 pnext = p + 1;
303 }
304
305 /* Check length of status line */
306 if (Status != NULL)
307 {
308 Length = strlen(Status);
309
310 if (Length > MaxLength)
311 MaxLength = Length;
312 }
313
314 Width = MaxLength + 4;
315 Height = Lines + 2;
316
317 if (Status != NULL)
318 Height += 2;
319
320 yTop = (yScreen - Height) / 2;
321 xLeft = (xScreen - Width) / 2;
322
323
324 /* Set screen attributes */
325 coPos.X = xLeft;
326 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
327 {
328 FillConsoleOutputAttribute(StdOutput,
329 FOREGROUND_RED | BACKGROUND_WHITE,
330 Width,
331 coPos,
332 &Written);
333 }
334
335 DrawBox(xLeft, yTop, Width, Height);
336
337 /* Print message text */
338 coPos.Y = yTop + 1;
339 pnext = Text;
340 while (TRUE)
341 {
342 p = strchr(pnext, '\n');
343
344 if (p == NULL)
345 {
346 Length = strlen(pnext);
347 LastLine = TRUE;
348 }
349 else
350 {
351 Length = (ULONG)(p - pnext);
352 LastLine = FALSE;
353 }
354
355 if (Length != 0)
356 {
357 coPos.X = xLeft + 2;
358 WriteConsoleOutputCharacterA(StdOutput,
359 pnext,
360 Length,
361 coPos,
362 &Written);
363 }
364
365 if (LastLine)
366 break;
367
368 coPos.Y++;
369 pnext = p + 1;
370 }
371
372 /* Print separator line and status text */
373 if (Status != NULL)
374 {
375 coPos.Y = yTop + Height - 3;
376 coPos.X = xLeft;
377 FillConsoleOutputCharacterA(StdOutput,
378 0xC3, // '+',
379 1,
380 coPos,
381 &Written);
382
383 coPos.X = xLeft + 1;
384 FillConsoleOutputCharacterA(StdOutput,
385 0xC4, // '-',
386 Width - 2,
387 coPos,
388 &Written);
389
390 coPos.X = xLeft + Width - 1;
391 FillConsoleOutputCharacterA(StdOutput,
392 0xB4, // '+',
393 1,
394 coPos,
395 &Written);
396
397 coPos.Y++;
398 coPos.X = xLeft + 2;
399 WriteConsoleOutputCharacterA(StdOutput,
400 Status,
401 min(strlen(Status), (SIZE_T)Width - 4),
402 coPos,
403 &Written);
404 }
405
406 if (WaitEvent == POPUP_WAIT_NONE)
407 return;
408
409 while (TRUE)
410 {
411 CONSOLE_ConInKey(Ir);
412
413 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
414 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
415 {
416 return;
417 }
418 }
419 }
420
421
422 /*
423 * Confirm quit setup
424 * RETURNS
425 * TRUE: Quit setup.
426 * FALSE: Don't quit setup.
427 */
428 static BOOL
429 ConfirmQuit(PINPUT_RECORD Ir)
430 {
431 BOOL Result = FALSE;
432 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
433
434 while (TRUE)
435 {
436 CONSOLE_ConInKey(Ir);
437
438 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
439 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
440 {
441 Result = TRUE;
442 break;
443 }
444 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
445 {
446 Result = FALSE;
447 break;
448 }
449 }
450
451 return Result;
452 }
453
454
455 static VOID
456 UpdateKBLayout(VOID)
457 {
458 PGENERIC_LIST_ENTRY ListEntry;
459 PCWSTR pszNewLayout;
460
461 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
462
463 if (USetupData.LayoutList == NULL)
464 {
465 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
466 if (USetupData.LayoutList == NULL)
467 {
468 /* FIXME: Handle error! */
469 return;
470 }
471 }
472
473 /* Search for default layout (if provided) */
474 if (pszNewLayout != NULL)
475 {
476 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
477 ListEntry = GetNextListEntry(ListEntry))
478 {
479 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
480 {
481 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
482 break;
483 }
484 }
485 }
486 }
487
488
489 static NTSTATUS
490 NTAPI
491 GetSettingDescription(
492 IN PGENERIC_LIST_ENTRY Entry,
493 OUT PSTR Buffer,
494 IN SIZE_T cchBufferSize)
495 {
496 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
497 ((PGENENTRY)GetListEntryData(Entry))->Value);
498 }
499
500 static NTSTATUS
501 NTAPI
502 GetNTOSInstallationName(
503 IN PGENERIC_LIST_ENTRY Entry,
504 OUT PSTR Buffer,
505 IN SIZE_T cchBufferSize)
506 {
507 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
508 PPARTENTRY PartEntry = NtOsInstall->PartEntry;
509
510 if (PartEntry && PartEntry->DriveLetter)
511 {
512 /* We have retrieved a partition that is mounted */
513 return RtlStringCchPrintfA(Buffer, cchBufferSize,
514 "%C:%S \"%S\"",
515 PartEntry->DriveLetter,
516 NtOsInstall->PathComponent,
517 NtOsInstall->InstallationName);
518 }
519 else
520 {
521 /* We failed somewhere, just show the NT path */
522 return RtlStringCchPrintfA(Buffer, cchBufferSize,
523 "%wZ \"%S\"",
524 &NtOsInstall->SystemNtPath,
525 NtOsInstall->InstallationName);
526 }
527 }
528
529
530 /*
531 * Displays the LanguagePage.
532 *
533 * Next pages: WelcomePage, QuitPage
534 *
535 * SIDEEFFECTS
536 * Init SelectedLanguageId
537 * Init USetupData.LanguageId
538 *
539 * RETURNS
540 * Number of the next page.
541 */
542 static PAGE_NUMBER
543 LanguagePage(PINPUT_RECORD Ir)
544 {
545 GENERIC_LIST_UI ListUi;
546 PCWSTR NewLanguageId;
547 BOOL RefreshPage = FALSE;
548
549 /* Initialize the computer settings list */
550 if (USetupData.LanguageList == NULL)
551 {
552 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
553 if (USetupData.LanguageList == NULL)
554 {
555 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
556 return WELCOME_PAGE;
557 }
558 }
559
560 SelectedLanguageId = DefaultLanguage;
561 USetupData.LanguageId = 0;
562
563 /* Load the font */
564 SetConsoleCodePage();
565 UpdateKBLayout();
566
567 /*
568 * If there is no language or just a single one in the list,
569 * skip the language selection process altogether.
570 */
571 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
572 {
573 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
574 return WELCOME_PAGE;
575 }
576
577 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
578 DrawGenericList(&ListUi,
579 2, 18,
580 xScreen - 3,
581 yScreen - 3);
582
583 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
584
585 MUIDisplayPage(LANGUAGE_PAGE);
586
587 while (TRUE)
588 {
589 CONSOLE_ConInKey(Ir);
590
591 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
592 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
593 {
594 ScrollDownGenericList(&ListUi);
595 RefreshPage = TRUE;
596 }
597 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
598 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
599 {
600 ScrollUpGenericList(&ListUi);
601 RefreshPage = TRUE;
602 }
603 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
604 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
605 {
606 ScrollPageDownGenericList(&ListUi);
607 RefreshPage = TRUE;
608 }
609 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
610 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
611 {
612 ScrollPageUpGenericList(&ListUi);
613 RefreshPage = TRUE;
614 }
615 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
616 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
617 {
618 if (ConfirmQuit(Ir))
619 return QUIT_PAGE;
620 else
621 RedrawGenericList(&ListUi);
622 }
623 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
624 {
625 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
626
627 SelectedLanguageId =
628 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
629
630 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
631
632 if (wcscmp(SelectedLanguageId, DefaultLanguage))
633 {
634 UpdateKBLayout();
635 }
636
637 /* Load the font */
638 SetConsoleCodePage();
639
640 return WELCOME_PAGE;
641 }
642 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
643 {
644 /* a-z */
645 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
646 RefreshPage = TRUE;
647 }
648
649 if (RefreshPage)
650 {
651 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
652
653 NewLanguageId =
654 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
655
656 if (wcscmp(SelectedLanguageId, NewLanguageId))
657 {
658 /* Clear the language page */
659 MUIClearPage(LANGUAGE_PAGE);
660
661 SelectedLanguageId = NewLanguageId;
662
663 /* Load the font */
664 SetConsoleCodePage();
665
666 /* Redraw language selection page in native language */
667 MUIDisplayPage(LANGUAGE_PAGE);
668 }
669
670 RefreshPage = FALSE;
671 }
672 }
673
674 return WELCOME_PAGE;
675 }
676
677
678 /*
679 * Start page
680 *
681 * Next pages:
682 * LanguagePage (at once, default)
683 * InstallIntroPage (at once, if unattended)
684 * QuitPage
685 *
686 * SIDEEFFECTS
687 * Init Sdi
688 * Init USetupData.SourcePath
689 * Init USetupData.SourceRootPath
690 * Init USetupData.SourceRootDir
691 * Init USetupData.SetupInf
692 * Init USetupData.RequiredPartitionDiskSpace
693 * Init IsUnattendedSetup
694 * If unattended, init *List and sets the Codepage
695 * If unattended, init SelectedLanguageId
696 * If unattended, init USetupData.LanguageId
697 *
698 * RETURNS
699 * Number of the next page.
700 */
701 static PAGE_NUMBER
702 SetupStartPage(PINPUT_RECORD Ir)
703 {
704 ULONG Error;
705 PGENERIC_LIST_ENTRY ListEntry;
706 PCWSTR LocaleId;
707
708 MUIDisplayPage(SETUP_INIT_PAGE);
709
710 /* Initialize Setup, phase 1 */
711 Error = InitializeSetup(&USetupData, 1);
712 if (Error != ERROR_SUCCESS)
713 {
714 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
715 return QUIT_PAGE;
716 }
717
718 /* Initialize the user-mode PnP manager */
719 if (!EnableUserModePnpManager())
720 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
721
722 /* Wait for any immediate pending installations to finish */
723 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0)
724 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
725
726 CheckUnattendedSetup(&USetupData);
727
728 if (IsUnattendedSetup)
729 {
730 // TODO: Read options from inf
731 /* Load the hardware, language and keyboard layout lists */
732
733 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
734 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
735 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
736
737 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
738
739 /* new part */
740 SelectedLanguageId = DefaultLanguage;
741 wcscpy(DefaultLanguage, USetupData.LocaleID);
742 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
743
744 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
745
746 /* first we hack LanguageList */
747 for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
748 ListEntry = GetNextListEntry(ListEntry))
749 {
750 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
751 if (!wcsicmp(USetupData.LocaleID, LocaleId))
752 {
753 DPRINT("found %S in LanguageList\n", LocaleId);
754 SetCurrentListEntry(USetupData.LanguageList, ListEntry);
755 break;
756 }
757 }
758
759 /* now LayoutList */
760 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
761 ListEntry = GetNextListEntry(ListEntry))
762 {
763 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
764 if (!wcsicmp(USetupData.LocaleID, LocaleId))
765 {
766 DPRINT("found %S in LayoutList\n", LocaleId);
767 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
768 break;
769 }
770 }
771
772 SetConsoleCodePage();
773
774 return INSTALL_INTRO_PAGE;
775 }
776
777 return LANGUAGE_PAGE;
778 }
779
780
781 /*
782 * Displays the WelcomePage.
783 *
784 * Next pages:
785 * InstallIntroPage (default)
786 * RepairIntroPage
787 * RecoveryPage
788 * LicensePage
789 * QuitPage
790 *
791 * RETURNS
792 * Number of the next page.
793 */
794 static PAGE_NUMBER
795 WelcomePage(PINPUT_RECORD Ir)
796 {
797 MUIDisplayPage(WELCOME_PAGE);
798
799 while (TRUE)
800 {
801 CONSOLE_ConInKey(Ir);
802
803 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
804 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
805 {
806 if (ConfirmQuit(Ir))
807 return QUIT_PAGE;
808
809 break;
810 }
811 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
812 {
813 return INSTALL_INTRO_PAGE;
814 }
815 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
816 {
817 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
818 }
819 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
820 {
821 return LICENSE_PAGE;
822 }
823 }
824
825 return WELCOME_PAGE;
826 }
827
828
829 /*
830 * Displays the License page.
831 *
832 * Next page:
833 * WelcomePage (default)
834 *
835 * RETURNS
836 * Number of the next page.
837 */
838 static PAGE_NUMBER
839 LicensePage(PINPUT_RECORD Ir)
840 {
841 MUIDisplayPage(LICENSE_PAGE);
842
843 while (TRUE)
844 {
845 CONSOLE_ConInKey(Ir);
846
847 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
848 {
849 return WELCOME_PAGE;
850 }
851 }
852
853 return LICENSE_PAGE;
854 }
855
856
857 /*
858 * Displays the RepairIntroPage.
859 *
860 * Next pages:
861 * RebootPage (default)
862 * InstallIntroPage
863 * RecoveryPage
864 * IntroPage
865 *
866 * RETURNS
867 * Number of the next page.
868 */
869 static PAGE_NUMBER
870 RepairIntroPage(PINPUT_RECORD Ir)
871 {
872 MUIDisplayPage(REPAIR_INTRO_PAGE);
873
874 while (TRUE)
875 {
876 CONSOLE_ConInKey(Ir);
877
878 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
879 {
880 return REBOOT_PAGE;
881 }
882 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
883 {
884 RepairUpdateFlag = TRUE;
885 return INSTALL_INTRO_PAGE;
886 }
887 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
888 {
889 return RECOVERY_PAGE;
890 }
891 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
892 {
893 return WELCOME_PAGE;
894 }
895 }
896
897 return REPAIR_INTRO_PAGE;
898 }
899
900 /*
901 * Displays the UpgradeRepairPage.
902 *
903 * Next pages:
904 * RebootPage (default)
905 * InstallIntroPage
906 * RecoveryPage
907 * WelcomePage
908 *
909 * RETURNS
910 * Number of the next page.
911 */
912 static PAGE_NUMBER
913 UpgradeRepairPage(PINPUT_RECORD Ir)
914 {
915 GENERIC_LIST_UI ListUi;
916
917 /*** HACK!! ***/
918 if (PartitionList == NULL)
919 {
920 PartitionList = CreatePartitionList();
921 if (PartitionList == NULL)
922 {
923 /* FIXME: show an error dialog */
924 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
925 return QUIT_PAGE;
926 }
927 else if (IsListEmpty(&PartitionList->DiskListHead))
928 {
929 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
930 return QUIT_PAGE;
931 }
932
933 /* Reset the formatter machine state */
934 TempPartition = NULL;
935 FormatState = Start;
936 }
937 /**************/
938
939 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
940 if (!NtOsInstallsList)
941 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
942
943 /*
944 * If there is no available installation (or just a single one??) that can
945 * be updated in the list, just continue with the regular installation.
946 */
947 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
948 {
949 RepairUpdateFlag = FALSE;
950
951 // return INSTALL_INTRO_PAGE;
952 return DEVICE_SETTINGS_PAGE;
953 // return SCSI_CONTROLLER_PAGE;
954 }
955
956 MUIDisplayPage(UPGRADE_REPAIR_PAGE);
957
958 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
959 DrawGenericList(&ListUi,
960 2, 23,
961 xScreen - 3,
962 yScreen - 3);
963
964 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
965 while (TRUE)
966 {
967 CONSOLE_ConInKey(Ir);
968
969 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
970 {
971 switch (Ir->Event.KeyEvent.wVirtualKeyCode)
972 {
973 case VK_DOWN: /* DOWN */
974 ScrollDownGenericList(&ListUi);
975 break;
976 case VK_UP: /* UP */
977 ScrollUpGenericList(&ListUi);
978 break;
979 case VK_NEXT: /* PAGE DOWN */
980 ScrollPageDownGenericList(&ListUi);
981 break;
982 case VK_PRIOR: /* PAGE UP */
983 ScrollPageUpGenericList(&ListUi);
984 break;
985 case VK_F3: /* F3 */
986 {
987 if (ConfirmQuit(Ir))
988 return QUIT_PAGE;
989 else
990 RedrawGenericList(&ListUi);
991 break;
992 }
993 #if 1
994 /* TODO: Temporarily kept until correct keyboard layout is in place.
995 * (Actual AsciiChar of ESCAPE should be 0x1B instead of 0.)
996 * Addendum to commit 8b94515b.
997 */
998 case VK_ESCAPE: /* ESC */
999 {
1000 RestoreGenericListUiState(&ListUi);
1001 // return nextPage; // prevPage;
1002
1003 // return INSTALL_INTRO_PAGE;
1004 return DEVICE_SETTINGS_PAGE;
1005 // return SCSI_CONTROLLER_PAGE;
1006 }
1007
1008 #endif
1009 }
1010 }
1011 #if 0
1012 /* TODO: Restore this once correct keyboard layout is in place. */
1013 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
1014 {
1015 RestoreGenericListUiState(&ListUi);
1016 // return nextPage; // prevPage;
1017
1018 // return INSTALL_INTRO_PAGE;
1019 return DEVICE_SETTINGS_PAGE;
1020 // return SCSI_CONTROLLER_PAGE;
1021 }
1022 #endif
1023 else
1024 {
1025 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
1026 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1027 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1028 {
1029 /* Retrieve the current installation */
1030 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1);
1031
1032 CurrentInstallation =
1033 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
1034
1035 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
1036 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
1037
1038 RepairUpdateFlag = TRUE;
1039
1040 // return nextPage;
1041 /***/return INSTALL_INTRO_PAGE;/***/
1042 }
1043 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
1044 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
1045 {
1046 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1047 }
1048 }
1049 }
1050
1051 return UPGRADE_REPAIR_PAGE;
1052 }
1053
1054
1055 /*
1056 * Displays the InstallIntroPage.
1057 *
1058 * Next pages:
1059 * DeviceSettingsPage (At once if repair or update is selected)
1060 * SelectPartitionPage (At once if unattended setup)
1061 * DeviceSettingsPage (default)
1062 * QuitPage
1063 *
1064 * RETURNS
1065 * Number of the next page.
1066 */
1067 static PAGE_NUMBER
1068 InstallIntroPage(PINPUT_RECORD Ir)
1069 {
1070 if (RepairUpdateFlag)
1071 {
1072 #if 1 /* Old code that looks good */
1073
1074 // return SELECT_PARTITION_PAGE;
1075 return DEVICE_SETTINGS_PAGE;
1076
1077 #else /* Possible new code? */
1078
1079 return DEVICE_SETTINGS_PAGE;
1080 // return SCSI_CONTROLLER_PAGE;
1081
1082 #endif
1083 }
1084
1085 if (IsUnattendedSetup)
1086 return SELECT_PARTITION_PAGE;
1087
1088 MUIDisplayPage(INSTALL_INTRO_PAGE);
1089
1090 while (TRUE)
1091 {
1092 CONSOLE_ConInKey(Ir);
1093
1094 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1095 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1096 {
1097 if (ConfirmQuit(Ir))
1098 return QUIT_PAGE;
1099
1100 break;
1101 }
1102 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1103 {
1104 return UPGRADE_REPAIR_PAGE;
1105 }
1106 }
1107
1108 return INSTALL_INTRO_PAGE;
1109 }
1110
1111
1112 #if 0
1113 static PAGE_NUMBER
1114 ScsiControllerPage(PINPUT_RECORD Ir)
1115 {
1116 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1117
1118 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1119
1120 /* FIXME: print loaded mass storage driver descriptions */
1121 #if 0
1122 CONSOLE_SetTextXY(8, 10, "TEST device");
1123 #endif
1124
1125 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1126
1127 while (TRUE)
1128 {
1129 CONSOLE_ConInKey(Ir);
1130
1131 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1132 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1133 {
1134 if (ConfirmQuit(Ir))
1135 return QUIT_PAGE;
1136
1137 break;
1138 }
1139 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1140 {
1141 return DEVICE_SETTINGS_PAGE;
1142 }
1143 }
1144
1145 return SCSI_CONTROLLER_PAGE;
1146 }
1147
1148 static PAGE_NUMBER
1149 OemDriverPage(PINPUT_RECORD Ir)
1150 {
1151 // MUIDisplayPage(OEM_DRIVER_PAGE);
1152
1153 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1154
1155 /* FIXME: Implement!! */
1156
1157 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1158
1159 while (TRUE)
1160 {
1161 CONSOLE_ConInKey(Ir);
1162
1163 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1164 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1165 {
1166 if (ConfirmQuit(Ir))
1167 return QUIT_PAGE;
1168
1169 break;
1170 }
1171 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1172 {
1173 return DEVICE_SETTINGS_PAGE;
1174 }
1175 }
1176
1177 return OEM_DRIVER_PAGE;
1178 }
1179 #endif
1180
1181
1182 /*
1183 * Displays the DeviceSettingsPage.
1184 *
1185 * Next pages:
1186 * SelectPartitionPage (At once if repair or update is selected)
1187 * ComputerSettingsPage
1188 * DisplaySettingsPage
1189 * KeyboardSettingsPage
1190 * LayoutsettingsPage
1191 * SelectPartitionPage
1192 * QuitPage
1193 *
1194 * SIDEEFFECTS
1195 * Init USetupData.ComputerList
1196 * Init USetupData.DisplayList
1197 * Init USetupData.KeyboardList
1198 * Init USetupData.LayoutList
1199 *
1200 * RETURNS
1201 * Number of the next page.
1202 */
1203 static PAGE_NUMBER
1204 DeviceSettingsPage(PINPUT_RECORD Ir)
1205 {
1206 static ULONG Line = 16;
1207
1208 /* Initialize the computer settings list */
1209 if (USetupData.ComputerList == NULL)
1210 {
1211 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
1212 if (USetupData.ComputerList == NULL)
1213 {
1214 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1215 return QUIT_PAGE;
1216 }
1217 }
1218
1219 /* Initialize the display settings list */
1220 if (USetupData.DisplayList == NULL)
1221 {
1222 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
1223 if (USetupData.DisplayList == NULL)
1224 {
1225 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1226 return QUIT_PAGE;
1227 }
1228 }
1229
1230 /* Initialize the keyboard settings list */
1231 if (USetupData.KeyboardList == NULL)
1232 {
1233 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
1234 if (USetupData.KeyboardList == NULL)
1235 {
1236 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1237 return QUIT_PAGE;
1238 }
1239 }
1240
1241 /* Initialize the keyboard layout list */
1242 if (USetupData.LayoutList == NULL)
1243 {
1244 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
1245 if (USetupData.LayoutList == NULL)
1246 {
1247 /* FIXME: report error */
1248 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1249 return QUIT_PAGE;
1250 }
1251 }
1252
1253 if (RepairUpdateFlag)
1254 return SELECT_PARTITION_PAGE;
1255
1256 // if (IsUnattendedSetup)
1257 // return SELECT_PARTITION_PAGE;
1258
1259 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1260
1261 DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11);
1262 DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12);
1263 DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13);
1264 DrawGenericListCurrentItem(USetupData.LayoutList , GetSettingDescription, 25, 14);
1265
1266 CONSOLE_InvertTextXY(24, Line, 48, 1);
1267
1268 while (TRUE)
1269 {
1270 CONSOLE_ConInKey(Ir);
1271
1272 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1273 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1274 {
1275 CONSOLE_NormalTextXY(24, Line, 48, 1);
1276
1277 if (Line == 14)
1278 Line = 16;
1279 else if (Line == 16)
1280 Line = 11;
1281 else
1282 Line++;
1283
1284 CONSOLE_InvertTextXY(24, Line, 48, 1);
1285 }
1286 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1287 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1288 {
1289 CONSOLE_NormalTextXY(24, Line, 48, 1);
1290
1291 if (Line == 11)
1292 Line = 16;
1293 else if (Line == 16)
1294 Line = 14;
1295 else
1296 Line--;
1297
1298 CONSOLE_InvertTextXY(24, Line, 48, 1);
1299 }
1300 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1301 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1302 {
1303 if (ConfirmQuit(Ir))
1304 return QUIT_PAGE;
1305
1306 break;
1307 }
1308 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1309 {
1310 if (Line == 11)
1311 return COMPUTER_SETTINGS_PAGE;
1312 else if (Line == 12)
1313 return DISPLAY_SETTINGS_PAGE;
1314 else if (Line == 13)
1315 return KEYBOARD_SETTINGS_PAGE;
1316 else if (Line == 14)
1317 return LAYOUT_SETTINGS_PAGE;
1318 else if (Line == 16)
1319 return SELECT_PARTITION_PAGE;
1320 }
1321 }
1322
1323 return DEVICE_SETTINGS_PAGE;
1324 }
1325
1326
1327 /*
1328 * Handles generic selection lists.
1329 *
1330 * PARAMS
1331 * GenericList: The list to handle.
1332 * nextPage: The page it needs to jump to after this page.
1333 * Ir: The PINPUT_RECORD
1334 */
1335 static PAGE_NUMBER
1336 HandleGenericList(PGENERIC_LIST_UI ListUi,
1337 PAGE_NUMBER nextPage,
1338 PINPUT_RECORD Ir)
1339 {
1340 while (TRUE)
1341 {
1342 CONSOLE_ConInKey(Ir);
1343
1344 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1345 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1346 {
1347 ScrollDownGenericList(ListUi);
1348 }
1349 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1350 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1351 {
1352 ScrollUpGenericList(ListUi);
1353 }
1354 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1355 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1356 {
1357 ScrollPageDownGenericList(ListUi);
1358 }
1359 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1360 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1361 {
1362 ScrollPageUpGenericList(ListUi);
1363 }
1364 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1365 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1366 {
1367 if (ConfirmQuit(Ir))
1368 return QUIT_PAGE;
1369 else
1370 RedrawGenericList(ListUi);
1371 }
1372 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
1373 {
1374 RestoreGenericListUiState(ListUi);
1375 return nextPage; // Use some "prevPage;" instead?
1376 }
1377 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1378 {
1379 return nextPage;
1380 }
1381 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1382 {
1383 /* a-z */
1384 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1385 }
1386 }
1387 }
1388
1389
1390 /*
1391 * Displays the ComputerSettingsPage.
1392 *
1393 * Next pages:
1394 * DeviceSettingsPage
1395 * QuitPage
1396 *
1397 * RETURNS
1398 * Number of the next page.
1399 */
1400 static PAGE_NUMBER
1401 ComputerSettingsPage(PINPUT_RECORD Ir)
1402 {
1403 GENERIC_LIST_UI ListUi;
1404 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1405
1406 InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
1407 DrawGenericList(&ListUi,
1408 2, 18,
1409 xScreen - 3,
1410 yScreen - 3);
1411
1412 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1413 }
1414
1415
1416 /*
1417 * Displays the DisplaySettingsPage.
1418 *
1419 * Next pages:
1420 * DeviceSettingsPage
1421 * QuitPage
1422 *
1423 * RETURNS
1424 * Number of the next page.
1425 */
1426 static PAGE_NUMBER
1427 DisplaySettingsPage(PINPUT_RECORD Ir)
1428 {
1429 GENERIC_LIST_UI ListUi;
1430 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1431
1432 InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
1433 DrawGenericList(&ListUi,
1434 2, 18,
1435 xScreen - 3,
1436 yScreen - 3);
1437
1438 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1439 }
1440
1441
1442 /*
1443 * Displays the KeyboardSettingsPage.
1444 *
1445 * Next pages:
1446 * DeviceSettingsPage
1447 * QuitPage
1448 *
1449 * RETURNS
1450 * Number of the next page.
1451 */
1452 static PAGE_NUMBER
1453 KeyboardSettingsPage(PINPUT_RECORD Ir)
1454 {
1455 GENERIC_LIST_UI ListUi;
1456 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1457
1458 InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
1459 DrawGenericList(&ListUi,
1460 2, 18,
1461 xScreen - 3,
1462 yScreen - 3);
1463
1464 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1465 }
1466
1467
1468 /*
1469 * Displays the LayoutSettingsPage.
1470 *
1471 * Next pages:
1472 * DeviceSettingsPage
1473 * QuitPage
1474 *
1475 * RETURNS
1476 * Number of the next page.
1477 */
1478 static PAGE_NUMBER
1479 LayoutSettingsPage(PINPUT_RECORD Ir)
1480 {
1481 GENERIC_LIST_UI ListUi;
1482 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1483
1484 InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
1485 DrawGenericList(&ListUi,
1486 2, 18,
1487 xScreen - 3,
1488 yScreen - 3);
1489
1490 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1491 }
1492
1493
1494 static BOOL
1495 IsDiskSizeValid(PPARTENTRY PartEntry)
1496 {
1497 ULONGLONG size;
1498
1499 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1500 size = (size + (512 * KB)) / MB; /* in MBytes */
1501
1502 if (size < USetupData.RequiredPartitionDiskSpace)
1503 {
1504 /* Partition is too small so ask for another one */
1505 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1506 return FALSE;
1507 }
1508 else
1509 {
1510 return TRUE;
1511 }
1512 }
1513
1514
1515 /*
1516 * Displays the SelectPartitionPage.
1517 *
1518 * Next pages:
1519 * SelectFileSystemPage (At once if unattended)
1520 * SelectFileSystemPage (Default if free space is selected)
1521 * CreatePrimaryPartitionPage
1522 * CreateExtendedPartitionPage
1523 * CreateLogicalPartitionPage
1524 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1525 * DeletePartitionPage
1526 * QuitPage
1527 *
1528 * SIDEEFFECTS
1529 * Set InstallShortcut (only if not unattended + free space is selected)
1530 *
1531 * RETURNS
1532 * Number of the next page.
1533 */
1534 static PAGE_NUMBER
1535 SelectPartitionPage(PINPUT_RECORD Ir)
1536 {
1537 PARTLIST_UI ListUi;
1538 ULONG Error;
1539
1540 if (PartitionList == NULL)
1541 {
1542 PartitionList = CreatePartitionList();
1543 if (PartitionList == NULL)
1544 {
1545 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1546 return QUIT_PAGE;
1547 }
1548 else if (IsListEmpty(&PartitionList->DiskListHead))
1549 {
1550 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1551 return QUIT_PAGE;
1552 }
1553
1554 /* Reset the formatter machine state */
1555 TempPartition = NULL;
1556 FormatState = Start;
1557 }
1558
1559 if (RepairUpdateFlag)
1560 {
1561 ASSERT(CurrentInstallation);
1562
1563 /* Determine the selected installation disk & partition */
1564 InstallPartition = SelectPartition(PartitionList,
1565 CurrentInstallation->DiskNumber,
1566 CurrentInstallation->PartitionNumber);
1567 if (!InstallPartition)
1568 {
1569 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1570 ASSERT(FALSE);
1571 }
1572 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1573
1574 return SELECT_FILE_SYSTEM_PAGE;
1575 }
1576
1577 MUIDisplayPage(SELECT_PARTITION_PAGE);
1578
1579 InitPartitionListUi(&ListUi, PartitionList,
1580 CurrentPartition,
1581 2, 23,
1582 xScreen - 3,
1583 yScreen - 3);
1584 DrawPartitionList(&ListUi);
1585
1586 if (IsUnattendedSetup)
1587 {
1588 /* Determine the selected installation disk & partition */
1589 InstallPartition = SelectPartition(PartitionList,
1590 USetupData.DestinationDiskNumber,
1591 USetupData.DestinationPartitionNumber);
1592 if (!InstallPartition)
1593 {
1594 CurrentPartition = ListUi.CurrentPartition;
1595
1596 if (USetupData.AutoPartition)
1597 {
1598 ASSERT(CurrentPartition != NULL);
1599 ASSERT(!IsContainerPartition(CurrentPartition->PartitionType));
1600
1601 if (CurrentPartition->LogicalPartition)
1602 {
1603 CreateLogicalPartition(PartitionList,
1604 CurrentPartition,
1605 CurrentPartition->SectorCount.QuadPart,
1606 TRUE);
1607 }
1608 else
1609 {
1610 CreatePrimaryPartition(PartitionList,
1611 CurrentPartition,
1612 CurrentPartition->SectorCount.QuadPart,
1613 TRUE);
1614 }
1615
1616 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1617 if (!IsDiskSizeValid(CurrentPartition))
1618 {
1619 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1620 USetupData.RequiredPartitionDiskSpace);
1621 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1622 }
1623
1624 InstallPartition = CurrentPartition;
1625 return SELECT_FILE_SYSTEM_PAGE;
1626 }
1627 }
1628 else
1629 {
1630 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1631
1632 DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense...
1633
1634 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1635 if (!IsDiskSizeValid(InstallPartition))
1636 {
1637 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1638 USetupData.RequiredPartitionDiskSpace);
1639 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1640 }
1641
1642 return SELECT_FILE_SYSTEM_PAGE;
1643 }
1644 }
1645
1646 while (TRUE)
1647 {
1648 CurrentPartition = ListUi.CurrentPartition;
1649
1650 /* Update status text */
1651 if (CurrentPartition == NULL)
1652 {
1653 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1654 }
1655 else if (CurrentPartition->LogicalPartition)
1656 {
1657 if (CurrentPartition->IsPartitioned)
1658 {
1659 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1660 }
1661 else
1662 {
1663 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1664 }
1665 }
1666 else
1667 {
1668 if (CurrentPartition->IsPartitioned)
1669 {
1670 if (IsContainerPartition(CurrentPartition->PartitionType))
1671 {
1672 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1673 }
1674 else
1675 {
1676 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1677 }
1678 }
1679 else
1680 {
1681 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1682 }
1683 }
1684
1685 CONSOLE_ConInKey(Ir);
1686
1687 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1688 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1689 {
1690 if (ConfirmQuit(Ir))
1691 {
1692 DestroyPartitionList(PartitionList);
1693 PartitionList = NULL;
1694 return QUIT_PAGE;
1695 }
1696
1697 break;
1698 }
1699 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1700 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1701 {
1702 ScrollDownPartitionList(&ListUi);
1703 }
1704 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1705 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1706 {
1707 ScrollUpPartitionList(&ListUi);
1708 }
1709 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1710 {
1711 ASSERT(CurrentPartition != NULL);
1712
1713 if (IsContainerPartition(CurrentPartition->PartitionType))
1714 continue; // return SELECT_PARTITION_PAGE;
1715
1716 /*
1717 * Check whether the user wants to install ReactOS on a disk that
1718 * is not recognized by the computer's firmware and if so, display
1719 * a warning since such disks may not be bootable.
1720 */
1721 if (CurrentPartition->DiskEntry->MediaType == FixedMedia &&
1722 !CurrentPartition->DiskEntry->BiosFound)
1723 {
1724 PopupError("The disk you have selected for installing ReactOS\n"
1725 "is not visible by the firmware of your computer,\n"
1726 "and so may not be bootable.\n"
1727 "Press ENTER to continue nonetheless.",
1728 MUIGetString(STRING_CONTINUE),
1729 Ir, POPUP_WAIT_ENTER);
1730 // return SELECT_PARTITION_PAGE;
1731 }
1732
1733 if (CurrentPartition->IsPartitioned == FALSE)
1734 {
1735 if (CurrentPartition->LogicalPartition)
1736 {
1737 Error = LogicalPartitionCreationChecks(CurrentPartition);
1738 if (Error != NOT_AN_ERROR)
1739 {
1740 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1741 return SELECT_PARTITION_PAGE;
1742 }
1743
1744 CreateLogicalPartition(PartitionList,
1745 CurrentPartition,
1746 0ULL,
1747 TRUE);
1748 }
1749 else
1750 {
1751 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1752 if (Error != NOT_AN_ERROR)
1753 {
1754 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1755 return SELECT_PARTITION_PAGE;
1756 }
1757
1758 CreatePrimaryPartition(PartitionList,
1759 CurrentPartition,
1760 0ULL,
1761 TRUE);
1762 }
1763 }
1764
1765 if (!IsDiskSizeValid(CurrentPartition))
1766 {
1767 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1768 USetupData.RequiredPartitionDiskSpace);
1769 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1770 }
1771
1772 InstallPartition = CurrentPartition;
1773 return SELECT_FILE_SYSTEM_PAGE;
1774 }
1775 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1776 {
1777 ASSERT(CurrentPartition != NULL);
1778
1779 if (CurrentPartition->LogicalPartition == FALSE)
1780 {
1781 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1782 if (Error != NOT_AN_ERROR)
1783 {
1784 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1785 return SELECT_PARTITION_PAGE;
1786 }
1787
1788 return CREATE_PRIMARY_PARTITION_PAGE;
1789 }
1790 }
1791 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1792 {
1793 ASSERT(CurrentPartition != NULL);
1794
1795 if (CurrentPartition->LogicalPartition == FALSE)
1796 {
1797 Error = ExtendedPartitionCreationChecks(CurrentPartition);
1798 if (Error != NOT_AN_ERROR)
1799 {
1800 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1801 return SELECT_PARTITION_PAGE;
1802 }
1803
1804 return CREATE_EXTENDED_PARTITION_PAGE;
1805 }
1806 }
1807 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1808 {
1809 ASSERT(CurrentPartition != NULL);
1810
1811 if (CurrentPartition->LogicalPartition)
1812 {
1813 Error = LogicalPartitionCreationChecks(CurrentPartition);
1814 if (Error != NOT_AN_ERROR)
1815 {
1816 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1817 return SELECT_PARTITION_PAGE;
1818 }
1819
1820 return CREATE_LOGICAL_PARTITION_PAGE;
1821 }
1822 }
1823 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1824 {
1825 UNICODE_STRING CurrentPartitionU;
1826 WCHAR PathBuffer[MAX_PATH];
1827
1828 ASSERT(CurrentPartition != NULL);
1829
1830 if (CurrentPartition->IsPartitioned == FALSE)
1831 {
1832 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1833 return SELECT_PARTITION_PAGE;
1834 }
1835
1836 // TODO: Do something similar before trying to format the partition?
1837 if (!CurrentPartition->New &&
1838 !IsContainerPartition(CurrentPartition->PartitionType) &&
1839 CurrentPartition->FormatState != Unformatted)
1840 {
1841 ASSERT(CurrentPartition->PartitionNumber != 0);
1842
1843 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1844 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1845 CurrentPartition->DiskEntry->DiskNumber,
1846 CurrentPartition->PartitionNumber);
1847 RtlInitUnicodeString(&CurrentPartitionU, PathBuffer);
1848
1849 /*
1850 * Check whether the user attempts to delete the partition on which
1851 * the installation source is present. If so, fail with an error.
1852 */
1853 // &USetupData.SourceRootPath
1854 if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE))
1855 {
1856 MUIDisplayError(ERROR_SOURCE_PATH, Ir, POPUP_WAIT_ENTER);
1857 return SELECT_PARTITION_PAGE;
1858 }
1859 }
1860
1861 if (CurrentPartition == PartitionList->SystemPartition ||
1862 IsPartitionActive(CurrentPartition))
1863 {
1864 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1865 }
1866
1867 return DELETE_PARTITION_PAGE;
1868 }
1869 }
1870
1871 return SELECT_PARTITION_PAGE;
1872 }
1873
1874
1875 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1876 /* Restriction for MaxSize */
1877 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1878
1879 static VOID
1880 ShowPartitionSizeInputBox(SHORT Left,
1881 SHORT Top,
1882 SHORT Right,
1883 SHORT Bottom,
1884 ULONG MaxSize,
1885 PWSTR InputBuffer,
1886 PBOOLEAN Quit,
1887 PBOOLEAN Cancel)
1888 {
1889 INPUT_RECORD Ir;
1890 COORD coPos;
1891 DWORD Written;
1892 CHAR Buffer[128];
1893 INT Length, Pos;
1894 WCHAR ch;
1895 SHORT iLeft;
1896 SHORT iTop;
1897
1898 if (Quit != NULL)
1899 *Quit = FALSE;
1900
1901 if (Cancel != NULL)
1902 *Cancel = FALSE;
1903
1904 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1905
1906 /* Print message */
1907 coPos.X = Left + 2;
1908 coPos.Y = Top + 2;
1909 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1910 iLeft = coPos.X + (USHORT)strlen(Buffer) + 1;
1911 iTop = coPos.Y;
1912
1913 WriteConsoleOutputCharacterA(StdOutput,
1914 Buffer,
1915 strlen(Buffer),
1916 coPos,
1917 &Written);
1918
1919 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1920 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1921 coPos.Y = iTop;
1922 WriteConsoleOutputCharacterA(StdOutput,
1923 Buffer,
1924 strlen(Buffer),
1925 coPos,
1926 &Written);
1927
1928 swprintf(InputBuffer, L"%lu", MaxSize);
1929 Length = wcslen(InputBuffer);
1930 Pos = Length;
1931 CONSOLE_SetInputTextXY(iLeft,
1932 iTop,
1933 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1934 InputBuffer);
1935 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1936 CONSOLE_SetCursorType(TRUE, TRUE);
1937
1938 while (TRUE)
1939 {
1940 CONSOLE_ConInKey(&Ir);
1941
1942 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1943 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1944 {
1945 if (Quit != NULL)
1946 *Quit = TRUE;
1947
1948 InputBuffer[0] = UNICODE_NULL;
1949 CONSOLE_SetCursorType(TRUE, FALSE);
1950 break;
1951 }
1952 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1953 {
1954 CONSOLE_SetCursorType(TRUE, FALSE);
1955 break;
1956 }
1957 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
1958 {
1959 if (Cancel != NULL)
1960 *Cancel = TRUE;
1961
1962 InputBuffer[0] = UNICODE_NULL;
1963 CONSOLE_SetCursorType(TRUE, FALSE);
1964 break;
1965 }
1966 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1967 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1968 {
1969 Pos = 0;
1970 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1971 }
1972 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1973 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1974 {
1975 Pos = Length;
1976 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1977 }
1978 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1979 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1980 {
1981 if (Pos > 0)
1982 {
1983 Pos--;
1984 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1985 }
1986 }
1987 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1988 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1989 {
1990 if (Pos < Length)
1991 {
1992 Pos++;
1993 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1994 }
1995 }
1996 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1997 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1998 {
1999 if (Pos < Length)
2000 {
2001 memmove(&InputBuffer[Pos],
2002 &InputBuffer[Pos + 1],
2003 (Length - Pos - 1) * sizeof(WCHAR));
2004 InputBuffer[Length - 1] = UNICODE_NULL;
2005
2006 Length--;
2007 CONSOLE_SetInputTextXY(iLeft,
2008 iTop,
2009 PARTITION_SIZE_INPUT_FIELD_LENGTH,
2010 InputBuffer);
2011 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2012 }
2013 }
2014 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
2015 {
2016 if (Pos > 0)
2017 {
2018 if (Pos < Length)
2019 memmove(&InputBuffer[Pos - 1],
2020 &InputBuffer[Pos],
2021 (Length - Pos) * sizeof(WCHAR));
2022 InputBuffer[Length - 1] = UNICODE_NULL;
2023
2024 Pos--;
2025 Length--;
2026 CONSOLE_SetInputTextXY(iLeft,
2027 iTop,
2028 PARTITION_SIZE_INPUT_FIELD_LENGTH,
2029 InputBuffer);
2030 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2031 }
2032 }
2033 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
2034 {
2035 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
2036 {
2037 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
2038
2039 if ((ch >= L'0') && (ch <= L'9'))
2040 {
2041 if (Pos < Length)
2042 memmove(&InputBuffer[Pos + 1],
2043 &InputBuffer[Pos],
2044 (Length - Pos) * sizeof(WCHAR));
2045 InputBuffer[Length + 1] = UNICODE_NULL;
2046 InputBuffer[Pos] = ch;
2047
2048 Pos++;
2049 Length++;
2050 CONSOLE_SetInputTextXY(iLeft,
2051 iTop,
2052 PARTITION_SIZE_INPUT_FIELD_LENGTH,
2053 InputBuffer);
2054 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2055 }
2056 }
2057 }
2058 }
2059 }
2060
2061
2062 /*
2063 * Displays the CreatePrimaryPartitionPage.
2064 *
2065 * Next pages:
2066 * SelectPartitionPage
2067 * SelectFileSystemPage (default)
2068 * QuitPage
2069 *
2070 * RETURNS
2071 * Number of the next page.
2072 */
2073 static PAGE_NUMBER
2074 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
2075 {
2076 PPARTENTRY PartEntry;
2077 PDISKENTRY DiskEntry;
2078 BOOLEAN Quit;
2079 BOOLEAN Cancel;
2080 ULONG MaxSize;
2081 ULONGLONG PartSize;
2082 ULONGLONG SectorCount;
2083 WCHAR InputBuffer[50];
2084 CHAR LineBuffer[100];
2085
2086 if (PartitionList == NULL || CurrentPartition == NULL)
2087 {
2088 /* FIXME: show an error dialog */
2089 return QUIT_PAGE;
2090 }
2091
2092 PartEntry = CurrentPartition;
2093 DiskEntry = CurrentPartition->DiskEntry;
2094
2095 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2096
2097 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
2098
2099 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2100 CONSOLE_PrintTextXY(6, 10, MUIGetString(STRING_HDINFOPARTCREATE_1),
2101 LineBuffer);
2102
2103 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2104
2105 #if 0
2106 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2107 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2108 #endif
2109
2110 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2111
2112 PartEntry = CurrentPartition;
2113 while (TRUE)
2114 {
2115 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2116
2117 if (MaxSize > PARTITION_MAXSIZE)
2118 MaxSize = PARTITION_MAXSIZE;
2119
2120 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2121 MaxSize, InputBuffer, &Quit, &Cancel);
2122
2123 if (Quit)
2124 {
2125 if (ConfirmQuit(Ir))
2126 return QUIT_PAGE;
2127
2128 break;
2129 }
2130 else if (Cancel)
2131 {
2132 return SELECT_PARTITION_PAGE;
2133 }
2134 else
2135 {
2136 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2137
2138 if (PartSize < 1)
2139 {
2140 /* Too small */
2141 continue;
2142 }
2143
2144 if (PartSize > MaxSize)
2145 {
2146 /* Too large */
2147 continue;
2148 }
2149
2150 /* Convert to bytes */
2151 if (PartSize == MaxSize)
2152 {
2153 /* Use all of the unpartitioned disk space */
2154 SectorCount = PartEntry->SectorCount.QuadPart;
2155 }
2156 else
2157 {
2158 /* Calculate the sector count from the size in MB */
2159 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2160
2161 /* But never get larger than the unpartitioned disk space */
2162 if (SectorCount > PartEntry->SectorCount.QuadPart)
2163 SectorCount = PartEntry->SectorCount.QuadPart;
2164 }
2165
2166 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2167
2168 CreatePrimaryPartition(PartitionList,
2169 CurrentPartition,
2170 SectorCount,
2171 FALSE);
2172
2173 return SELECT_PARTITION_PAGE;
2174 }
2175 }
2176
2177 return CREATE_PRIMARY_PARTITION_PAGE;
2178 }
2179
2180
2181 /*
2182 * Displays the CreateExtendedPartitionPage.
2183 *
2184 * Next pages:
2185 * SelectPartitionPage (default)
2186 * QuitPage
2187 *
2188 * RETURNS
2189 * Number of the next page.
2190 */
2191 static PAGE_NUMBER
2192 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2193 {
2194 PPARTENTRY PartEntry;
2195 PDISKENTRY DiskEntry;
2196 BOOLEAN Quit;
2197 BOOLEAN Cancel;
2198 ULONG MaxSize;
2199 ULONGLONG PartSize;
2200 ULONGLONG SectorCount;
2201 WCHAR InputBuffer[50];
2202 CHAR LineBuffer[100];
2203
2204 if (PartitionList == NULL || CurrentPartition == NULL)
2205 {
2206 /* FIXME: show an error dialog */
2207 return QUIT_PAGE;
2208 }
2209
2210 PartEntry = CurrentPartition;
2211 DiskEntry = CurrentPartition->DiskEntry;
2212
2213 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2214
2215 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2216
2217 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2218 CONSOLE_PrintTextXY(6, 10, MUIGetString(STRING_HDINFOPARTCREATE_1),
2219 LineBuffer);
2220
2221 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2222
2223 #if 0
2224 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2225 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2226 #endif
2227
2228 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2229
2230 PartEntry = CurrentPartition;
2231 while (TRUE)
2232 {
2233 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2234
2235 if (MaxSize > PARTITION_MAXSIZE)
2236 MaxSize = PARTITION_MAXSIZE;
2237
2238 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2239 MaxSize, InputBuffer, &Quit, &Cancel);
2240
2241 if (Quit)
2242 {
2243 if (ConfirmQuit(Ir))
2244 return QUIT_PAGE;
2245
2246 break;
2247 }
2248 else if (Cancel)
2249 {
2250 return SELECT_PARTITION_PAGE;
2251 }
2252 else
2253 {
2254 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2255
2256 if (PartSize < 1)
2257 {
2258 /* Too small */
2259 continue;
2260 }
2261
2262 if (PartSize > MaxSize)
2263 {
2264 /* Too large */
2265 continue;
2266 }
2267
2268 /* Convert to bytes */
2269 if (PartSize == MaxSize)
2270 {
2271 /* Use all of the unpartitioned disk space */
2272 SectorCount = PartEntry->SectorCount.QuadPart;
2273 }
2274 else
2275 {
2276 /* Calculate the sector count from the size in MB */
2277 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2278
2279 /* But never get larger than the unpartitioned disk space */
2280 if (SectorCount > PartEntry->SectorCount.QuadPart)
2281 SectorCount = PartEntry->SectorCount.QuadPart;
2282 }
2283
2284 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2285
2286 CreateExtendedPartition(PartitionList,
2287 CurrentPartition,
2288 SectorCount);
2289
2290 return SELECT_PARTITION_PAGE;
2291 }
2292 }
2293
2294 return CREATE_EXTENDED_PARTITION_PAGE;
2295 }
2296
2297
2298 /*
2299 * Displays the CreateLogicalPartitionPage.
2300 *
2301 * Next pages:
2302 * SelectFileSystemPage (default)
2303 * QuitPage
2304 *
2305 * RETURNS
2306 * Number of the next page.
2307 */
2308 static PAGE_NUMBER
2309 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2310 {
2311 PPARTENTRY PartEntry;
2312 PDISKENTRY DiskEntry;
2313 BOOLEAN Quit;
2314 BOOLEAN Cancel;
2315 ULONG MaxSize;
2316 ULONGLONG PartSize;
2317 ULONGLONG SectorCount;
2318 WCHAR InputBuffer[50];
2319 CHAR LineBuffer[100];
2320
2321 if (PartitionList == NULL || CurrentPartition == NULL)
2322 {
2323 /* FIXME: show an error dialog */
2324 return QUIT_PAGE;
2325 }
2326
2327 PartEntry = CurrentPartition;
2328 DiskEntry = CurrentPartition->DiskEntry;
2329
2330 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2331
2332 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2333
2334 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2335 CONSOLE_PrintTextXY(6, 10, MUIGetString(STRING_HDINFOPARTCREATE_1),
2336 LineBuffer);
2337
2338 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2339
2340 #if 0
2341 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2342 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2343 #endif
2344
2345 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2346
2347 PartEntry = CurrentPartition;
2348 while (TRUE)
2349 {
2350 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2351
2352 if (MaxSize > PARTITION_MAXSIZE)
2353 MaxSize = PARTITION_MAXSIZE;
2354
2355 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2356 MaxSize, InputBuffer, &Quit, &Cancel);
2357
2358 if (Quit)
2359 {
2360 if (ConfirmQuit(Ir))
2361 return QUIT_PAGE;
2362
2363 break;
2364 }
2365 else if (Cancel)
2366 {
2367 return SELECT_PARTITION_PAGE;
2368 }
2369 else
2370 {
2371 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2372
2373 if (PartSize < 1)
2374 {
2375 /* Too small */
2376 continue;
2377 }
2378
2379 if (PartSize > MaxSize)
2380 {
2381 /* Too large */
2382 continue;
2383 }
2384
2385 /* Convert to bytes */
2386 if (PartSize == MaxSize)
2387 {
2388 /* Use all of the unpartitioned disk space */
2389 SectorCount = PartEntry->SectorCount.QuadPart;
2390 }
2391 else
2392 {
2393 /* Calculate the sector count from the size in MB */
2394 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2395
2396 /* But never get larger than the unpartitioned disk space */
2397 if (SectorCount > PartEntry->SectorCount.QuadPart)
2398 SectorCount = PartEntry->SectorCount.QuadPart;
2399 }
2400
2401 DPRINT("Partition size: %I64u bytes\n", PartSize);
2402
2403 CreateLogicalPartition(PartitionList,
2404 CurrentPartition,
2405 SectorCount,
2406 FALSE);
2407
2408 return SELECT_PARTITION_PAGE;
2409 }
2410 }
2411
2412 return CREATE_LOGICAL_PARTITION_PAGE;
2413 }
2414
2415
2416 /*
2417 * Displays the ConfirmDeleteSystemPartitionPage.
2418 *
2419 * Next pages:
2420 * DeletePartitionPage (default)
2421 * SelectPartitionPage
2422 *
2423 * RETURNS
2424 * Number of the next page.
2425 */
2426 static PAGE_NUMBER
2427 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2428 {
2429 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2430
2431 while (TRUE)
2432 {
2433 CONSOLE_ConInKey(Ir);
2434
2435 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2436 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2437 {
2438 if (ConfirmQuit(Ir))
2439 return QUIT_PAGE;
2440
2441 break;
2442 }
2443 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2444 {
2445 return DELETE_PARTITION_PAGE;
2446 }
2447 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2448 {
2449 return SELECT_PARTITION_PAGE;
2450 }
2451 }
2452
2453 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2454 }
2455
2456
2457 /*
2458 * Displays the DeletePartitionPage.
2459 *
2460 * Next pages:
2461 * SelectPartitionPage (default)
2462 * QuitPage
2463 *
2464 * RETURNS
2465 * Number of the next page.
2466 */
2467 static PAGE_NUMBER
2468 DeletePartitionPage(PINPUT_RECORD Ir)
2469 {
2470 PPARTENTRY PartEntry;
2471 PDISKENTRY DiskEntry;
2472 CHAR LineBuffer[100];
2473
2474 if (PartitionList == NULL || CurrentPartition == NULL)
2475 {
2476 /* FIXME: show an error dialog */
2477 return QUIT_PAGE;
2478 }
2479
2480 PartEntry = CurrentPartition;
2481 DiskEntry = CurrentPartition->DiskEntry;
2482
2483 MUIDisplayPage(DELETE_PARTITION_PAGE);
2484
2485 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2486 CONSOLE_PrintTextXY(6, 10, " %s", LineBuffer);
2487
2488 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2489 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTDELETE_1),
2490 LineBuffer);
2491
2492 while (TRUE)
2493 {
2494 CONSOLE_ConInKey(Ir);
2495
2496 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2497 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2498 {
2499 if (ConfirmQuit(Ir))
2500 return QUIT_PAGE;
2501
2502 break;
2503 }
2504 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2505 {
2506 return SELECT_PARTITION_PAGE;
2507 }
2508 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
2509 {
2510 DeletePartition(PartitionList,
2511 CurrentPartition,
2512 &CurrentPartition);
2513 return SELECT_PARTITION_PAGE;
2514 }
2515 }
2516
2517 return DELETE_PARTITION_PAGE;
2518 }
2519
2520
2521 static VOID
2522 ResetFileSystemList(VOID)
2523 {
2524 if (!FileSystemList)
2525 return;
2526
2527 DestroyFileSystemList(FileSystemList);
2528 FileSystemList = NULL;
2529 }
2530
2531 /*
2532 * Displays the SelectFileSystemPage.
2533 *
2534 * Next pages:
2535 * CheckFileSystemPage (At once if RepairUpdate is selected)
2536 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2537 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2538 * SelectPartitionPage (If the user aborts)
2539 * FormatPartitionPage (Default)
2540 * QuitPage
2541 *
2542 * SIDEEFFECTS
2543 * Calls UpdatePartitionType()
2544 * Calls FindSupportedSystemPartition()
2545 *
2546 * RETURNS
2547 * Number of the next page.
2548 */
2549 static PAGE_NUMBER
2550 SelectFileSystemPage(PINPUT_RECORD Ir)
2551 {
2552 PPARTENTRY PartEntry;
2553 PDISKENTRY DiskEntry;
2554 FORMATMACHINESTATE PreviousFormatState;
2555 PCWSTR DefaultFs;
2556 CHAR LineBuffer[100];
2557
2558 DPRINT("SelectFileSystemPage()\n");
2559
2560 if (PartitionList == NULL || InstallPartition == NULL)
2561 {
2562 /* FIXME: show an error dialog */
2563 return QUIT_PAGE;
2564 }
2565
2566 /* Find or set the active system partition when starting formatting */
2567 if (FormatState == Start)
2568 {
2569 /*
2570 * If we install on a fixed disk, try to find a supported system
2571 * partition on the system. Otherwise if we install on a removable disk
2572 * use the install partition as the system partition.
2573 */
2574 if (InstallPartition->DiskEntry->MediaType == FixedMedia)
2575 {
2576 SystemPartition = FindSupportedSystemPartition(PartitionList,
2577 FALSE,
2578 InstallPartition->DiskEntry,
2579 InstallPartition);
2580 /* Use the original system partition as the old active partition hint */
2581 PartEntry = PartitionList->SystemPartition;
2582
2583 if ( SystemPartition && PartitionList->SystemPartition &&
2584 (SystemPartition != PartitionList->SystemPartition) )
2585 {
2586 DPRINT1("We are using a different system partition!!!!\n");
2587
2588 MUIDisplayPage(CHANGE_SYSTEM_PARTITION);
2589
2590 {
2591 PPARTENTRY PartEntry; // Shadow variable
2592
2593 PartEntry = PartitionList->SystemPartition;
2594 DiskEntry = PartEntry->DiskEntry;
2595
2596 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2597 CONSOLE_SetTextXY(8, 10, LineBuffer);
2598
2599 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2600 CONSOLE_PrintTextXY(8, 14, MUIGetString(STRING_HDINFOPARTCREATE_1),
2601 LineBuffer);
2602
2603
2604 PartEntry = SystemPartition;
2605 DiskEntry = PartEntry->DiskEntry;
2606
2607 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2608 CONSOLE_SetTextXY(8, 23, LineBuffer);
2609 }
2610
2611 while (TRUE)
2612 {
2613 CONSOLE_ConInKey(Ir);
2614
2615 if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2616 {
2617 break;
2618 }
2619 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2620 {
2621 return SELECT_PARTITION_PAGE;
2622 }
2623 }
2624
2625 CONSOLE_ClearScreen();
2626 CONSOLE_Flush();
2627 }
2628 }
2629 else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia)
2630 {
2631 SystemPartition = InstallPartition;
2632 /* Don't specify any old active partition hint */
2633 PartEntry = NULL;
2634 }
2635
2636 if (!SystemPartition)
2637 {
2638 /* FIXME: improve the error dialog */
2639 //
2640 // Error dialog should say that we cannot find a suitable
2641 // system partition and create one on the system. At this point,
2642 // it may be nice to ask the user whether he wants to continue,
2643 // or use an external drive as the system drive/partition
2644 // (e.g. floppy, USB drive, etc...)
2645 //
2646 PopupError("The ReactOS Setup could not find a supported system partition\n"
2647 "on your system or could not create a new one. Without such partition\n"
2648 "the Setup program cannot install ReactOS.\n"
2649 "Press ENTER to return to the partition selection list.",
2650 MUIGetString(STRING_CONTINUE),
2651 Ir, POPUP_WAIT_ENTER);
2652 return SELECT_PARTITION_PAGE;
2653 }
2654
2655 /*
2656 * If the system partition can be created in some
2657 * non-partitioned space, create it now.
2658 */
2659 if (!SystemPartition->IsPartitioned)
2660 {
2661 CreatePrimaryPartition(PartitionList,
2662 SystemPartition,
2663 0LL, // SystemPartition->SectorCount.QuadPart,
2664 TRUE);
2665 ASSERT(SystemPartition->IsPartitioned);
2666 }
2667
2668 /* Set it as such */
2669 if (!SetActivePartition(PartitionList, SystemPartition, PartEntry))
2670 {
2671 DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition);
2672 ASSERT(FALSE);
2673 }
2674
2675 /* Commit all partition changes to all the disks */
2676 if (!WritePartitionsToDisk(PartitionList))
2677 {
2678 DPRINT("WritePartitionsToDisk() failed\n");
2679 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
2680 return QUIT_PAGE;
2681 }
2682
2683 /*
2684 * In all cases, whether or not we are going to perform a formatting,
2685 * we must perform a filesystem check of both the system and the
2686 * installation partitions.
2687 */
2688 InstallPartition->NeedsCheck = TRUE;
2689 if (SystemPartition != InstallPartition)
2690 SystemPartition->NeedsCheck = TRUE;
2691
2692 /*
2693 * In case we just repair an existing installation, or make
2694 * an unattended setup without formatting, just go to the
2695 * filesystem check step.
2696 */
2697 if (RepairUpdateFlag)
2698 return CHECK_FILE_SYSTEM_PAGE;
2699
2700 if (IsUnattendedSetup && !USetupData.FormatPartition)
2701 return CHECK_FILE_SYSTEM_PAGE;
2702 }
2703
2704 // ASSERT(SystemPartition->IsPartitioned);
2705
2706 /* Reset the filesystem list for each partition that is to be formatted */
2707 ResetFileSystemList();
2708
2709 PreviousFormatState = FormatState;
2710 switch (FormatState)
2711 {
2712 case Start:
2713 {
2714 /*
2715 * We start by formatting the system partition in case it is new
2716 * (it didn't exist before) and is not the same as the installation
2717 * partition. Otherwise we just require a filesystem check on it,
2718 * and start by formatting the installation partition instead.
2719 */
2720
2721 ASSERT(SystemPartition->IsPartitioned);
2722
2723 if ((SystemPartition != InstallPartition) &&
2724 (SystemPartition->FormatState == Unformatted))
2725 {
2726 TempPartition = SystemPartition;
2727 TempPartition->NeedsCheck = TRUE;
2728
2729 // TODO: Should we let the user using a custom file-system,
2730 // or should we always use FAT(32) for it?
2731 // For "compatibility", FAT(32) would be best indeed.
2732
2733 FormatState = FormatSystemPartition;
2734 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2735 }
2736 else
2737 {
2738 TempPartition = InstallPartition;
2739 TempPartition->NeedsCheck = TRUE;
2740
2741 if (SystemPartition != InstallPartition)
2742 {
2743 /* The system partition is separate, so it had better be formatted! */
2744 ASSERT((SystemPartition->FormatState == Preformatted) ||
2745 (SystemPartition->FormatState == Formatted));
2746
2747 /* Require a filesystem check on the system partition too */
2748 SystemPartition->NeedsCheck = TRUE;
2749 }
2750
2751 FormatState = FormatInstallPartition;
2752 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2753 }
2754 break;
2755 }
2756
2757 case FormatSystemPartition:
2758 {
2759 TempPartition = InstallPartition;
2760 TempPartition->NeedsCheck = TRUE;
2761
2762 FormatState = FormatInstallPartition;
2763 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2764 break;
2765 }
2766
2767 case FormatInstallPartition:
2768 case FormatOtherPartition:
2769 {
2770 if (GetNextUnformattedPartition(PartitionList,
2771 NULL,
2772 &TempPartition))
2773 {
2774 FormatState = FormatOtherPartition;
2775 TempPartition->NeedsCheck = TRUE;
2776
2777 if (FormatState == FormatInstallPartition)
2778 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2779 else
2780 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2781 }
2782 else
2783 {
2784 FormatState = FormatDone;
2785
2786 if (FormatState == FormatInstallPartition)
2787 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2788 else
2789 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2790
2791 return CHECK_FILE_SYSTEM_PAGE;
2792 }
2793 break;
2794 }
2795
2796 case FormatDone:
2797 {
2798 DPRINT1("FormatState: FormatDone\n");
2799 return CHECK_FILE_SYSTEM_PAGE;
2800 }
2801
2802 default:
2803 {
2804 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2805 ASSERT(FALSE);
2806 return QUIT_PAGE;
2807 }
2808 }
2809
2810 PartEntry = TempPartition;
2811 DiskEntry = TempPartition->DiskEntry;
2812
2813 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
2814
2815 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2816
2817 if (PartEntry->AutoCreate)
2818 {
2819 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2820
2821 #if 0
2822 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2823 CONSOLE_SetTextXY(8, 10, LineBuffer);
2824 #endif
2825
2826 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2827 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTCREATE_1),
2828 LineBuffer);
2829
2830 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2831
2832 PartEntry->AutoCreate = FALSE;
2833 }
2834 else if (PartEntry->New)
2835 {
2836 switch (FormatState)
2837 {
2838 case FormatSystemPartition:
2839 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2840 break;
2841
2842 case FormatInstallPartition:
2843 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2844 break;
2845
2846 case FormatOtherPartition:
2847 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2848 break;
2849
2850 default:
2851 ASSERT(FALSE);
2852 break;
2853 }
2854
2855 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2856 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTCREATE_1),
2857 LineBuffer);
2858
2859 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2860 }
2861 else
2862 {
2863 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2864
2865 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2866 CONSOLE_SetTextXY(8, 10, LineBuffer);
2867
2868 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
2869 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTDELETE_1),
2870 LineBuffer);
2871 }
2872
2873 ASSERT(FileSystemList == NULL);
2874
2875 if (IsUnattendedSetup)
2876 {
2877 ASSERT(USetupData.FormatPartition);
2878
2879 switch (USetupData.FsType)
2880 {
2881 /* 1 is for BtrFS */
2882 case 1:
2883 DefaultFs = L"BTRFS";
2884 break;
2885
2886 /* If we don't understand input, default to FAT */
2887 default:
2888 DefaultFs = L"FAT";
2889 break;
2890 }
2891 }
2892 else
2893 {
2894 /* By default select the "FAT" file system */
2895 DefaultFs = L"FAT";
2896 }
2897
2898 /* Create the file system list */
2899 // TODO: Display only the FSes compatible with the selected partition!
2900 FileSystemList = CreateFileSystemList(6, 26,
2901 PartEntry->New ||
2902 PartEntry->FormatState == Unformatted,
2903 DefaultFs);
2904 if (FileSystemList == NULL)
2905 {
2906 /* FIXME: show an error dialog */
2907 return QUIT_PAGE;
2908 }
2909
2910 if (IsUnattendedSetup)
2911 {
2912 ASSERT(USetupData.FormatPartition);
2913 return FORMAT_PARTITION_PAGE;
2914 }
2915
2916 DrawFileSystemList(FileSystemList);
2917
2918 while (TRUE)
2919 {
2920 CONSOLE_ConInKey(Ir);
2921
2922 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2923 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2924 {
2925 if (ConfirmQuit(Ir))
2926 {
2927 /* Reset the filesystem list */
2928 ResetFileSystemList();
2929 return QUIT_PAGE;
2930 }
2931
2932 break;
2933 }
2934 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2935 {
2936 /* Reset the formatter machine state */
2937 TempPartition = NULL;
2938 FormatState = Start;
2939
2940 /* Reset the filesystem list */
2941 ResetFileSystemList();
2942
2943 return SELECT_PARTITION_PAGE;
2944 }
2945 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2946 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2947 {
2948 ScrollDownFileSystemList(FileSystemList);
2949 }
2950 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2951 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2952 {
2953 ScrollUpFileSystemList(FileSystemList);
2954 }
2955 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2956 {
2957 if (!FileSystemList->Selected->FileSystem)
2958 {
2959 ASSERT(!TempPartition->New && TempPartition->FormatState != Unformatted);
2960
2961 /*
2962 * Skip formatting this partition. We will also ignore
2963 * filesystem checks on it, unless it is either the system
2964 * or the installation partition.
2965 */
2966 if (TempPartition != SystemPartition &&
2967 TempPartition != InstallPartition)
2968 {
2969 PartEntry->NeedsCheck = FALSE;
2970 }
2971
2972 return SELECT_FILE_SYSTEM_PAGE;
2973 }
2974 else
2975 {
2976 /* Format this partition */
2977 return FORMAT_PARTITION_PAGE;
2978 }
2979 }
2980 }
2981
2982 FormatState = PreviousFormatState;
2983
2984 return SELECT_FILE_SYSTEM_PAGE;
2985 }
2986
2987
2988 /*
2989 * Displays the FormatPartitionPage.
2990 *
2991 * Next pages:
2992 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2993 * SelectPartitionPage (At once)
2994 * QuitPage
2995 *
2996 * SIDEEFFECTS
2997 * Sets InstallPartition->FormatState
2998 * Sets USetupData.DestinationRootPath
2999 *
3000 * RETURNS
3001 * Number of the next page.
3002 */
3003 static PAGE_NUMBER
3004 FormatPartitionPage(PINPUT_RECORD Ir)
3005 {
3006 NTSTATUS Status;
3007 PPARTENTRY PartEntry;
3008 PDISKENTRY DiskEntry;
3009 PFILE_SYSTEM_ITEM SelectedFileSystem;
3010 WCHAR PathBuffer[MAX_PATH];
3011 CHAR Buffer[MAX_PATH];
3012
3013 DPRINT("FormatPartitionPage()\n");
3014
3015 MUIDisplayPage(FORMAT_PARTITION_PAGE);
3016
3017 if (PartitionList == NULL || TempPartition == NULL)
3018 {
3019 /* FIXME: show an error dialog */
3020 return QUIT_PAGE;
3021 }
3022
3023 PartEntry = TempPartition;
3024 DiskEntry = TempPartition->DiskEntry;
3025
3026 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3027
3028 SelectedFileSystem = FileSystemList->Selected;
3029 ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem);
3030
3031 while (TRUE)
3032 {
3033 if (!IsUnattendedSetup)
3034 CONSOLE_ConInKey(Ir);
3035
3036 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3037 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3038 {
3039 if (ConfirmQuit(Ir))
3040 {
3041 /* Reset the filesystem list */
3042 ResetFileSystemList();
3043 return QUIT_PAGE;
3044 }
3045
3046 break;
3047 }
3048 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3049 {
3050 /*
3051 * Remove the "Press ENTER to continue" message prompt when the ENTER
3052 * key is pressed as the user wants to begin the partition formatting.
3053 */
3054 MUIClearStyledText(FORMAT_PARTITION_PAGE, TEXT_ID_FORMAT_PROMPT, TEXT_TYPE_REGULAR);
3055 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3056
3057 /* Format the partition */
3058 Status = DoFormat(PartEntry,
3059 SelectedFileSystem->FileSystem,
3060 SelectedFileSystem->QuickFormat);
3061 if (Status == STATUS_PARTITION_FAILURE)
3062 {
3063 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3064
3065 /* Reset the filesystem list */
3066 ResetFileSystemList();
3067 return QUIT_PAGE;
3068 }
3069 else if (Status == STATUS_UNRECOGNIZED_VOLUME)
3070 {
3071 /* FIXME: show an error dialog */
3072 // MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3073
3074 /* Reset the filesystem list */
3075 ResetFileSystemList();
3076 return QUIT_PAGE;
3077 }
3078 else if (Status == STATUS_NOT_SUPPORTED)
3079 {
3080 RtlStringCbPrintfA(Buffer,
3081 sizeof(Buffer),
3082 "Setup is currently unable to format a partition in %S.\n"
3083 "\n"
3084 " \x07 Press ENTER to continue Setup.\n"
3085 " \x07 Press F3 to quit Setup.",
3086 SelectedFileSystem->FileSystem);
3087
3088 PopupError(Buffer,
3089 MUIGetString(STRING_QUITCONTINUE),
3090 NULL, POPUP_WAIT_NONE);
3091
3092 while (TRUE)
3093 {
3094 CONSOLE_ConInKey(Ir);
3095
3096 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3097 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3098 {
3099 if (ConfirmQuit(Ir))
3100 {
3101 /* Reset the filesystem list */
3102 ResetFileSystemList();
3103 return QUIT_PAGE;
3104 }
3105 else
3106 {
3107 return SELECT_FILE_SYSTEM_PAGE;
3108 }
3109 }
3110 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3111 {
3112 return SELECT_FILE_SYSTEM_PAGE;
3113 }
3114 }
3115 }
3116 else if (!NT_SUCCESS(Status))
3117 {
3118 /** HACK!! **/
3119 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3120 L"\\Device\\Harddisk%lu\\Partition%lu",
3121 DiskEntry->DiskNumber,
3122 PartEntry->PartitionNumber);
3123
3124 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3125 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3126
3127 /* Reset the filesystem list */
3128 ResetFileSystemList();
3129 return QUIT_PAGE;
3130 }
3131
3132 return SELECT_FILE_SYSTEM_PAGE;
3133 }
3134 }
3135
3136 return FORMAT_PARTITION_PAGE;
3137 }
3138
3139
3140 /*
3141 * Displays the CheckFileSystemPage.
3142 *
3143 * Next pages:
3144 * InstallDirectoryPage (At once)
3145 * QuitPage
3146 *
3147 * SIDEEFFECTS
3148 * Inits or reloads FileSystemList
3149 *
3150 * RETURNS
3151 * Number of the next page.
3152 */
3153 static PAGE_NUMBER
3154 CheckFileSystemPage(PINPUT_RECORD Ir)
3155 {
3156 NTSTATUS Status;
3157 PPARTENTRY PartEntry;
3158 CHAR Buffer[MAX_PATH];
3159
3160 MUIDisplayPage(CHECK_FILE_SYSTEM_PAGE);
3161
3162 if (PartitionList == NULL)
3163 {
3164 /* FIXME: show an error dialog */
3165 return QUIT_PAGE;
3166 }
3167
3168 if (!GetNextUncheckedPartition(PartitionList, NULL, &PartEntry))
3169 {
3170 return INSTALL_DIRECTORY_PAGE;
3171 }
3172
3173 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3174
3175 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3176 PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a"));
3177
3178 /* Check the partition */
3179 Status = DoChkdsk(PartEntry);
3180 if (Status == STATUS_NOT_SUPPORTED)
3181 {
3182 /*
3183 * Partition checking is not supported with the current filesystem,
3184 * so disable FS checks on it.
3185 */
3186 PartEntry->NeedsCheck = FALSE;
3187
3188 RtlStringCbPrintfA(Buffer,
3189 sizeof(Buffer),
3190 "Setup is currently unable to check a partition formatted in %S.\n"
3191 "\n"
3192 " \x07 Press ENTER to continue Setup.\n"
3193 " \x07 Press F3 to quit Setup.",
3194 PartEntry->FileSystem);
3195
3196 PopupError(Buffer,
3197 MUIGetString(STRING_QUITCONTINUE),
3198 NULL, POPUP_WAIT_NONE);
3199
3200 while (TRUE)
3201 {
3202 CONSOLE_ConInKey(Ir);
3203
3204 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3205 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3206 {
3207 if (ConfirmQuit(Ir))
3208 return QUIT_PAGE;
3209 else
3210 return CHECK_FILE_SYSTEM_PAGE;
3211 }
3212 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3213 {
3214 return CHECK_FILE_SYSTEM_PAGE;
3215 }
3216 }
3217 }
3218 else if (!NT_SUCCESS(Status))
3219 {
3220 DPRINT1("ChkdskPartition() failed with status 0x%08lx\n", Status);
3221
3222 RtlStringCbPrintfA(Buffer,
3223 sizeof(Buffer),
3224 "ChkDsk detected some disk errors.\n(Status 0x%08lx).\n",
3225 Status);
3226
3227 PopupError(Buffer,
3228 MUIGetString(STRING_CONTINUE),
3229 Ir, POPUP_WAIT_ENTER);
3230 }
3231
3232 PartEntry->NeedsCheck = FALSE;
3233 return CHECK_FILE_SYSTEM_PAGE;
3234 }
3235
3236
3237 static BOOLEAN
3238 IsValidPath(
3239 IN PCWSTR InstallDir)
3240 {
3241 UINT i, Length;
3242
3243 Length = wcslen(InstallDir);
3244
3245 // TODO: Add check for 8.3 too.
3246
3247 /* Path must be at least 2 characters long */
3248 // if (Length < 2)
3249 // return FALSE;
3250
3251 /* Path must start with a backslash */
3252 // if (InstallDir[0] != L'\\')
3253 // return FALSE;
3254
3255 /* Path must not end with a backslash */
3256 if (InstallDir[Length - 1] == L'\\')
3257 return FALSE;
3258
3259 /* Path must not contain whitespace characters */
3260 for (i = 0; i < Length; i++)
3261 {
3262 if (iswspace(InstallDir[i]))
3263 return FALSE;
3264 }
3265
3266 /* Path component must not end with a dot */
3267 for (i = 0; i < Length; i++)
3268 {
3269 if (InstallDir[i] == L'\\' && i > 0)
3270 {
3271 if (InstallDir[i - 1] == L'.')
3272 return FALSE;
3273 }
3274 }
3275
3276 if (InstallDir[Length - 1] == L'.')
3277 return FALSE;
3278
3279 return TRUE;
3280 }
3281
3282
3283 /*
3284 * Displays the InstallDirectoryPage.
3285 *
3286 * Next pages:
3287 * PrepareCopyPage
3288 * QuitPage
3289 *
3290 * RETURNS
3291 * Number of the next page.
3292 */
3293 static PAGE_NUMBER
3294 InstallDirectoryPage(PINPUT_RECORD Ir)
3295 {
3296 NTSTATUS Status;
3297 ULONG Length, Pos;
3298 WCHAR c;
3299 WCHAR InstallDir[MAX_PATH];
3300
3301 /* We do not need the filesystem list anymore */
3302 ResetFileSystemList();
3303
3304 if (PartitionList == NULL || InstallPartition == NULL)
3305 {
3306 /* FIXME: show an error dialog */
3307 return QUIT_PAGE;
3308 }
3309
3310 // if (IsUnattendedSetup)
3311 if (RepairUpdateFlag)
3312 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3313 else if (USetupData.InstallationDirectory[0])
3314 wcscpy(InstallDir, USetupData.InstallationDirectory);
3315 else
3316 wcscpy(InstallDir, L"\\ReactOS");
3317
3318 /*
3319 * Check the validity of the predefined 'InstallDir'. If we are either
3320 * in unattended setup or in update/repair mode, and the installation path
3321 * is valid, just perform the installation. Otherwise (either in the case
3322 * of an invalid path, or we are in regular setup), display the UI and allow
3323 * the user to specify a new installation path.
3324 */
3325 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3326 {
3327 Status = InitDestinationPaths(&USetupData, InstallDir, InstallPartition);
3328 if (!NT_SUCCESS(Status))
3329 {
3330 DPRINT1("InitDestinationPaths() failed. Status code: 0x%lx", Status);
3331 MUIDisplayError(ERROR_NO_BUILD_PATH, Ir, POPUP_WAIT_ENTER);
3332 return QUIT_PAGE;
3333 }
3334
3335 /*
3336 * Check whether the user attempts to install ReactOS within the
3337 * installation source directory, or in a subdirectory thereof.
3338 * If so, fail with an error.
3339 */
3340 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3341 {
3342 MUIDisplayError(ERROR_SOURCE_DIR, Ir, POPUP_WAIT_ENTER);
3343 return INSTALL_DIRECTORY_PAGE;
3344 }
3345
3346 return PREPARE_COPY_PAGE;
3347 }
3348
3349 Length = wcslen(InstallDir);
3350 Pos = Length;
3351
3352 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3353 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3354 CONSOLE_SetCursorXY(8 + Pos, 11);
3355 CONSOLE_SetCursorType(TRUE, TRUE);
3356
3357 while (TRUE)
3358 {
3359 CONSOLE_ConInKey(Ir);
3360
3361 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3362 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3363 {
3364 CONSOLE_SetCursorType(TRUE, FALSE);
3365
3366 if (ConfirmQuit(Ir))
3367 return QUIT_PAGE;
3368
3369 CONSOLE_SetCursorType(TRUE, TRUE);
3370 break;
3371 }
3372 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3373 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3374 {
3375 if (Pos < Length)
3376 {
3377 memmove(&InstallDir[Pos],
3378 &InstallDir[Pos + 1],
3379 (Length - Pos - 1) * sizeof(WCHAR));
3380 InstallDir[Length - 1] = UNICODE_NULL;
3381
3382 Length--;
3383 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3384 CONSOLE_SetCursorXY(8 + Pos, 11);
3385 }
3386 }
3387 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3388 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3389 {
3390 Pos = 0;
3391 CONSOLE_SetCursorXY(8 + Pos, 11);
3392 }
3393 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3394 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3395 {
3396 Pos = Length;
3397 CONSOLE_SetCursorXY(8 + Pos, 11);
3398 }
3399 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3400 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3401 {
3402 if (Pos > 0)
3403 {
3404 Pos--;
3405 CONSOLE_SetCursorXY(8 + Pos, 11);
3406 }
3407 }
3408 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3409 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3410 {
3411 if (Pos < Length)
3412 {
3413 Pos++;
3414 CONSOLE_SetCursorXY(8 + Pos, 11);
3415 }
3416 }
3417 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3418 {
3419 CONSOLE_SetCursorType(TRUE, FALSE);
3420
3421 /*
3422 * Check for the validity of the installation directory and pop up
3423 * an error if it is not the case. Then the user can fix its input.
3424 */
3425 if (!IsValidPath(InstallDir))
3426 {
3427 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3428 return INSTALL_DIRECTORY_PAGE;
3429 }
3430
3431 Status = InitDestinationPaths(&USetupData, InstallDir, InstallPartition);
3432 if (!NT_SUCCESS(Status))
3433 {
3434 DPRINT1("InitDestinationPaths() failed. Status code: 0x%lx", Status);
3435 MUIDisplayError(ERROR_NO_BUILD_PATH, Ir, POPUP_WAIT_ENTER);
3436 return QUIT_PAGE;
3437 }
3438
3439 /*
3440 * Check whether the user attempts to install ReactOS within the
3441 * installation source directory, or in a subdirectory thereof.
3442 * If so, fail with an error.
3443 */
3444 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3445 {
3446 MUIDisplayError(ERROR_SOURCE_DIR, Ir, POPUP_WAIT_ENTER);
3447 return INSTALL_DIRECTORY_PAGE;
3448 }
3449
3450 return PREPARE_COPY_PAGE;
3451 }
3452 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3453 {
3454 if (Pos > 0)
3455 {
3456 if (Pos < Length)
3457 memmove(&InstallDir[Pos - 1],
3458 &InstallDir[Pos],
3459 (Length - Pos) * sizeof(WCHAR));
3460 InstallDir[Length - 1] = UNICODE_NULL;
3461
3462 Pos--;
3463 Length--;
3464 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3465 CONSOLE_SetCursorXY(8 + Pos, 11);
3466 }
3467 }
3468 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3469 {
3470 if (Length < 50)
3471 {
3472 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3473 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3474 {
3475 if (Pos < Length)
3476 memmove(&InstallDir[Pos + 1],
3477 &InstallDir[Pos],
3478 (Length - Pos) * sizeof(WCHAR));
3479 InstallDir[Length + 1] = UNICODE_NULL;
3480 InstallDir[Pos] = c;
3481
3482 Pos++;
3483 Length++;
3484 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3485 CONSOLE_SetCursorXY(8 + Pos, 11);
3486 }
3487 }
3488 }
3489 }
3490
3491 return INSTALL_DIRECTORY_PAGE;
3492 }
3493
3494
3495 // PSETUP_ERROR_ROUTINE
3496 static VOID
3497 __cdecl
3498 USetupErrorRoutine(
3499 IN PUSETUP_DATA pSetupData,
3500 ...)
3501 {
3502 INPUT_RECORD Ir;
3503 va_list arg_ptr;
3504
3505 va_start(arg_ptr, pSetupData);
3506
3507 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
3508 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE)
3509 {
3510 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3511 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
3512 }
3513
3514 va_end(arg_ptr);
3515 }
3516
3517 /*
3518 * Displays the PrepareCopyPage.
3519 *
3520 * Next pages:
3521 * FileCopyPage(At once)
3522 * QuitPage
3523 *
3524 * SIDEEFFECTS
3525 * Calls PrepareFileCopy
3526 *
3527 * RETURNS
3528 * Number of the next page.
3529 */
3530 static PAGE_NUMBER
3531 PrepareCopyPage(PINPUT_RECORD Ir)
3532 {
3533 // ERROR_NUMBER ErrorNumber;
3534 BOOLEAN Success;
3535
3536 MUIDisplayPage(PREPARE_COPY_PAGE);
3537
3538 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
3539 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
3540 {
3541 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3542 return QUIT_PAGE;
3543 }
3544
3545 return FILE_COPY_PAGE;
3546 }
3547
3548 typedef struct _COPYCONTEXT
3549 {
3550 ULONG TotalOperations;
3551 ULONG CompletedOperations;
3552 PPROGRESSBAR ProgressBar;
3553 PPROGRESSBAR MemoryBars[4];
3554 } COPYCONTEXT, *PCOPYCONTEXT;
3555
3556 static VOID
3557 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3558 IN BOOLEAN First)
3559 {
3560 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3561
3562 /* Get the memory information from the system */
3563 NtQuerySystemInformation(SystemPerformanceInformation,
3564 &PerfInfo,
3565 sizeof(PerfInfo),
3566 NULL);
3567
3568 /* Check if this is initial setup */
3569 if (First)
3570 {
3571 /* Set maximum limits to be total RAM pages */
3572 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3573 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3574 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3575 }
3576
3577 /* Set current values */
3578 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3579 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3580 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3581 }
3582
3583 static UINT
3584 CALLBACK
3585 FileCopyCallback(PVOID Context,
3586 UINT Notification,
3587 UINT_PTR Param1,
3588 UINT_PTR Param2)
3589 {
3590 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
3591 PFILEPATHS_W FilePathInfo;
3592 PCWSTR SrcFileName, DstFileName;
3593
3594 switch (Notification)
3595 {
3596 case SPFILENOTIFY_STARTSUBQUEUE:
3597 {
3598 CopyContext->TotalOperations = (ULONG)Param2;
3599 CopyContext->CompletedOperations = 0;
3600 ProgressSetStepCount(CopyContext->ProgressBar,
3601 CopyContext->TotalOperations);
3602 SetupUpdateMemoryInfo(CopyContext, TRUE);
3603 break;
3604 }
3605
3606 case SPFILENOTIFY_STARTDELETE:
3607 case SPFILENOTIFY_STARTRENAME:
3608 case SPFILENOTIFY_STARTCOPY:
3609 {
3610 FilePathInfo = (PFILEPATHS_W)Param1;
3611
3612 if (Notification == SPFILENOTIFY_STARTDELETE)
3613 {
3614 /* Display delete message */
3615 ASSERT(Param2 == FILEOP_DELETE);
3616
3617 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3618 if (DstFileName) ++DstFileName;
3619 else DstFileName = FilePathInfo->Target;
3620
3621 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
3622 DstFileName);
3623 }
3624 else if (Notification == SPFILENOTIFY_STARTRENAME)
3625 {
3626 /* Display move/rename message */
3627 ASSERT(Param2 == FILEOP_RENAME);
3628
3629 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
3630 if (SrcFileName) ++SrcFileName;
3631 else SrcFileName = FilePathInfo->Source;
3632
3633 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3634 if (DstFileName) ++DstFileName;
3635 else DstFileName = FilePathInfo->Target;
3636
3637 if (!wcsicmp(SrcFileName, DstFileName))
3638 Param2 = STRING_MOVING;
3639 else
3640 Param2 = STRING_RENAMING;
3641
3642 CONSOLE_SetStatusText(MUIGetString(Param2),
3643 SrcFileName, DstFileName);
3644 }
3645 else if (Notification == SPFILENOTIFY_STARTCOPY)
3646 {
3647 /* Display copy message */
3648 ASSERT(Param2 == FILEOP_COPY);
3649
3650 /* NOTE: When extracting from CABs the Source is the CAB name */
3651 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3652 if (DstFileName) ++DstFileName;
3653 else DstFileName = FilePathInfo->Target;
3654
3655 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
3656 DstFileName);
3657 #ifdef __REACTOS__ /* HACK */
3658 DoWatchDestFileName(DstFileName);
3659 #endif
3660 }
3661
3662 SetupUpdateMemoryInfo(CopyContext, FALSE);
3663 break;
3664 }
3665
3666 case SPFILENOTIFY_COPYERROR:
3667 {
3668 FilePathInfo = (PFILEPATHS_W)Param1;
3669
3670 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3671 FilePathInfo->Target, FilePathInfo->Win32Error);
3672 return FILEOP_SKIP;
3673 }
3674
3675 case SPFILENOTIFY_ENDDELETE:
3676 case SPFILENOTIFY_ENDRENAME:
3677 case SPFILENOTIFY_ENDCOPY:
3678 {
3679 CopyContext->CompletedOperations++;
3680
3681 /* SYSREG checkpoint */
3682 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3683 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3684
3685 ProgressNextStep(CopyContext->ProgressBar);
3686 SetupUpdateMemoryInfo(CopyContext, FALSE);
3687 break;
3688 }
3689 }
3690
3691 return FILEOP_DOIT;
3692 }
3693
3694
3695 /*
3696 * Displays the FileCopyPage.
3697 *
3698 * Next pages:
3699 * RegistryPage(At once)
3700 *
3701 * SIDEEFFECTS
3702 * Calls DoFileCopy
3703 *
3704 * RETURNS
3705 * Number of the next page.
3706 */
3707 static PAGE_NUMBER
3708 FileCopyPage(PINPUT_RECORD Ir)
3709 {
3710 COPYCONTEXT CopyContext;
3711 UINT MemBarWidth;
3712
3713 MUIDisplayPage(FILE_COPY_PAGE);
3714
3715 /* Create context for the copy process */
3716 CopyContext.TotalOperations = 0;
3717 CopyContext.CompletedOperations = 0;
3718
3719 /* Create the progress bar as well */
3720 CopyContext.ProgressBar = CreateProgressBar(13,
3721 26,
3722 xScreen - 13,
3723 yScreen - 20,
3724 10,
3725 24,
3726 TRUE,
3727 MUIGetString(STRING_SETUPCOPYINGFILES));
3728
3729 // fit memory bars to screen width, distribute them uniform
3730 MemBarWidth = (xScreen - 26) / 5;
3731 MemBarWidth -= MemBarWidth % 2; // make even
3732 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3733 /* Create the paged pool progress bar */
3734 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3735 40,
3736 13 + MemBarWidth,
3737 43,
3738 13,
3739 44,
3740 FALSE,
3741 "Kernel Pool");
3742
3743 /* Create the non paged pool progress bar */
3744 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
3745 40,
3746 (xScreen / 2) + (MemBarWidth / 2),
3747 43,
3748 (xScreen / 2)- (MemBarWidth / 2),
3749 44,
3750 FALSE,
3751 "Kernel Cache");
3752
3753 /* Create the global memory progress bar */
3754 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
3755 40,
3756 xScreen - 13,
3757 43,
3758 xScreen - 13 - MemBarWidth,
3759 44,
3760 FALSE,
3761 "Free Memory");
3762
3763 /* Do the file copying */
3764 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
3765
3766 /* If we get here, we're done, so cleanup the progress bar */
3767 DestroyProgressBar(CopyContext.ProgressBar);
3768 DestroyProgressBar(CopyContext.MemoryBars[0]);
3769 DestroyProgressBar(CopyContext.MemoryBars[1]);
3770 DestroyProgressBar(CopyContext.MemoryBars[2]);
3771
3772 /* Create the $winnt$.inf file */
3773 InstallSetupInfFile(&USetupData);
3774
3775 /* Go display the next page */
3776 return REGISTRY_PAGE;
3777 }
3778
3779
3780 static VOID
3781 __cdecl
3782 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
3783 {
3784 /* WARNING: Please keep this lookup table in sync with the resources! */
3785 static const UINT StringIDs[] =
3786 {
3787 STRING_DONE, /* Success */
3788 STRING_REGHIVEUPDATE, /* RegHiveUpdate */
3789 STRING_IMPORTFILE, /* ImportRegHive */
3790 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
3791 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
3792 STRING_ADDKBLAYOUTS, /* KeybLayouts */
3793 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
3794 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
3795 };
3796
3797 va_list args;
3798
3799 if (RegStatus < ARRAYSIZE(StringIDs))
3800 {
3801 va_start(args, RegStatus);
3802 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
3803 va_end(args);
3804 }
3805 else
3806 {
3807 CONSOLE_SetStatusText("Unknown status %d", RegStatus);
3808 }
3809 }
3810
3811 /*
3812 * Displays the RegistryPage.
3813 *
3814 * Next pages:
3815 * SuccessPage (if RepairUpdate)
3816 * BootLoaderPage (default)
3817 * QuitPage
3818 *
3819 * SIDEEFFECTS
3820 * Calls UpdateRegistry
3821 *
3822 * RETURNS
3823 * Number of the next page.
3824 */
3825 static PAGE_NUMBER
3826 RegistryPage(PINPUT_RECORD Ir)
3827 {
3828 ULONG Error;
3829
3830 MUIDisplayPage(REGISTRY_PAGE);
3831
3832 Error = UpdateRegistry(&USetupData,
3833 RepairUpdateFlag,
3834 PartitionList,
3835 InstallPartition->DriveLetter,
3836 SelectedLanguageId,
3837 RegistryStatus,
3838 &s_SubstSettings);
3839 if (Error != ERROR_SUCCESS)
3840 {
3841 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
3842 return QUIT_PAGE;
3843 }
3844 else
3845 {
3846 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
3847 return BOOT_LOADER_PAGE;
3848 }
3849 }
3850
3851
3852 /*
3853 * Displays the BootLoaderPage.
3854 *
3855 * Next pages:
3856 * SuccessPage (if RepairUpdate)
3857 * BootLoaderHarddiskMbrPage
3858 * BootLoaderHarddiskVbrPage
3859 * BootLoaderFloppyPage
3860 * SuccessPage
3861 * QuitPage
3862 *
3863 * SIDEEFFECTS
3864 * Calls RegInitializeRegistry
3865 * Calls ImportRegistryFile
3866 * Calls SetDefaultPagefile
3867 * Calls SetMountedDeviceValues
3868 *
3869 * RETURNS
3870 * Number of the next page.
3871 */
3872 static PAGE_NUMBER
3873 BootLoaderPage(PINPUT_RECORD Ir)
3874 {
3875 USHORT Line = 12;
3876 WCHAR PathBuffer[MAX_PATH];
3877
3878 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3879
3880 /* We must have a supported system partition by now */
3881 ASSERT(SystemPartition && SystemPartition->IsPartitioned && SystemPartition->PartitionNumber != 0);
3882
3883 RtlFreeUnicodeString(&USetupData.SystemRootPath);
3884 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3885 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3886 SystemPartition->DiskEntry->DiskNumber,
3887 SystemPartition->PartitionNumber);
3888 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
3889 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
3890
3891 /* For unattended setup, skip MBR installation or install on floppy if needed */
3892 if (IsUnattendedSetup)
3893 {
3894 if ((USetupData.MBRInstallType == 0) ||
3895 (USetupData.MBRInstallType == 1))
3896 {
3897 goto Quit;
3898 }
3899 }
3900
3901 /*
3902 * We may install an MBR or VBR, but before that, check whether
3903 * we need to actually install the VBR on floppy/removable media
3904 * if the system partition is not recognized.
3905 */
3906 if ((SystemPartition->DiskEntry->DiskStyle != PARTITION_STYLE_MBR) ||
3907 !IsRecognizedPartition(SystemPartition->PartitionType))
3908 {
3909 USetupData.MBRInstallType = 1;
3910 goto Quit;
3911 }
3912
3913 /* Is it an unattended install on hdd? */
3914 if (IsUnattendedSetup)
3915 {
3916 if ((USetupData.MBRInstallType == 2) ||
3917 (USetupData.MBRInstallType == 3))
3918 {
3919 goto Quit;
3920 }
3921 }
3922
3923 MUIDisplayPage(BOOT_LOADER_PAGE);
3924 CONSOLE_InvertTextXY(8, Line, 60, 1);
3925
3926 while (TRUE)
3927 {
3928 CONSOLE_ConInKey(Ir);
3929
3930 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3931 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3932 {
3933 CONSOLE_NormalTextXY(8, Line, 60, 1);
3934
3935 Line++;
3936 if (Line < 12)
3937 Line = 15;
3938
3939 if (Line > 15)
3940 Line = 12;
3941
3942 CONSOLE_InvertTextXY(8, Line, 60, 1);
3943 }
3944 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3945 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
3946 {
3947 CONSOLE_NormalTextXY(8, Line, 60, 1);
3948
3949 Line--;
3950 if (Line < 12)
3951 Line = 15;
3952
3953 if (Line > 15)
3954 Line = 12;
3955
3956 CONSOLE_InvertTextXY(8, Line, 60, 1);
3957 }
3958 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3959 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3960 {
3961 CONSOLE_NormalTextXY(8, Line, 60, 1);
3962
3963 Line = 12;
3964
3965 CONSOLE_InvertTextXY(8, Line, 60, 1);
3966 }
3967 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3968 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3969 {
3970 CONSOLE_NormalTextXY(8, Line, 60, 1);
3971
3972 Line = 15;
3973
3974 CONSOLE_InvertTextXY(8, Line, 60, 1);
3975 }
3976 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3977 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3978 {
3979 if (ConfirmQuit(Ir))
3980 return QUIT_PAGE;
3981
3982 break;
3983 }
3984 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3985 {
3986 if (Line == 12)
3987 {
3988 /* Install on both MBR and VBR */
3989 USetupData.MBRInstallType = 2;
3990 break;
3991 }
3992 else if (Line == 13)
3993 {
3994 /* Install on VBR only */
3995 USetupData.MBRInstallType = 3;
3996 break;
3997 }
3998 else if (Line == 14)
3999 {
4000 /* Install on floppy */
4001 USetupData.MBRInstallType = 1;
4002 break;
4003 }
4004 else if (Line == 15)
4005 {
4006 /* Skip MBR installation */
4007 USetupData.MBRInstallType = 0;
4008 break;
4009 }
4010
4011 return BOOT_LOADER_PAGE;
4012 }
4013 }
4014
4015 Quit:
4016 switch (USetupData.MBRInstallType)
4017 {
4018 /* Skip MBR installation */
4019 case 0:
4020 return SUCCESS_PAGE;
4021
4022 /* Install on floppy */
4023 case 1:
4024 return BOOT_LOADER_FLOPPY_PAGE;
4025
4026 /* Install on both MBR and VBR or VBR only */
4027 case 2:
4028 case 3:
4029 return BOOT_LOADER_INSTALLATION_PAGE;
4030 }
4031
4032 return BOOT_LOADER_PAGE;
4033 }
4034
4035
4036 /*
4037 * Displays the BootLoaderFloppyPage.
4038 *
4039 * Next pages:
4040 * SuccessPage (At once)
4041 * QuitPage
4042 *
4043 * SIDEEFFECTS
4044 * Calls InstallFatBootcodeToFloppy()
4045 *
4046 * RETURNS
4047 * Number of the next page.
4048 */
4049 static PAGE_NUMBER
4050 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4051 {
4052 NTSTATUS Status;
4053
4054 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4055
4056 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4057
4058 while (TRUE)
4059 {
4060 CONSOLE_ConInKey(Ir);
4061
4062 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4063 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4064 {
4065 if (ConfirmQuit(Ir))
4066 return QUIT_PAGE;
4067
4068 break;
4069 }
4070 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4071 {
4072 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
4073 &USetupData.DestinationArcPath);
4074 if (!NT_SUCCESS(Status))
4075 {
4076 if (Status == STATUS_DEVICE_NOT_READY)
4077 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4078
4079 /* TODO: Print error message */
4080 return BOOT_LOADER_FLOPPY_PAGE;
4081 }
4082
4083 return SUCCESS_PAGE;
4084 }
4085 }
4086
4087 return BOOT_LOADER_FLOPPY_PAGE;
4088 }
4089
4090
4091 /*
4092 * Displays the BootLoaderInstallationPage.
4093 *
4094 * Next pages:
4095 * SuccessPage (At once)
4096 * QuitPage
4097 *
4098 * SIDEEFFECTS
4099 * Calls InstallVBRToPartition() if VBR installation is chosen.
4100 * Otherwise both InstallVBRToPartition() and InstallMbrBootCodeToDisk()
4101 * are called if both MBR and VBR installation is chosen.
4102 *
4103 * RETURNS
4104 * Number of the next page.
4105 */
4106 static PAGE_NUMBER
4107 BootLoaderInstallationPage(PINPUT_RECORD Ir)
4108 {
4109 NTSTATUS Status;
4110 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4111
4112 MUIDisplayPage(BOOT_LOADER_INSTALLATION_PAGE);
4113
4114 if (USetupData.MBRInstallType == 2)
4115 {
4116 /* Step 1: Write the VBR */
4117 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4118 &USetupData.SourceRootPath,
4119 &USetupData.DestinationArcPath,
4120 SystemPartition->FileSystem);
4121 if (!NT_SUCCESS(Status))
4122 {
4123 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
4124 SystemPartition->FileSystem);
4125 return QUIT_PAGE;
4126 }
4127
4128 /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */
4129 if (!IsSuperFloppy(SystemPartition->DiskEntry))
4130 {
4131 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4132 L"\\Device\\Harddisk%d\\Partition0",
4133 SystemPartition->DiskEntry->DiskNumber);
4134 Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
4135 &USetupData.SourceRootPath,
4136 DestinationDevicePathBuffer);
4137 if (!NT_SUCCESS(Status))
4138 {
4139 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
4140 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR");
4141 return QUIT_PAGE;
4142 }
4143 }
4144 }
4145 else
4146 {
4147 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4148 &USetupData.SourceRootPath,
4149 &USetupData.DestinationArcPath,
4150 SystemPartition->FileSystem);
4151 if (!NT_SUCCESS(Status))
4152 {
4153 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
4154 SystemPartition->FileSystem);
4155 return QUIT_PAGE;
4156 }
4157 }
4158
4159 return SUCCESS_PAGE;
4160 }
4161
4162
4163 /**
4164 * @name ProgressTimeOutStringHandler
4165 *
4166 * Handles the generation (displaying) of the timeout
4167 * countdown to the screen dynamically.
4168 *
4169 * @param Bar
4170 * A pointer to a progress bar.
4171 *
4172 * @param AlwaysUpdate
4173 * Constantly update the progress bar (boolean type).
4174 *
4175 * @param Buffer
4176 * A pointer to a string buffer.
4177 *
4178 * @param cchBufferSize
4179 * The buffer's size in number of characters.
4180 *
4181 * @return
4182 * TRUE or FALSE on function termination.
4183 *
4184 */
4185 static
4186 BOOLEAN NTAPI
4187 ProgressTimeOutStringHandler(
4188 IN PPROGRESSBAR Bar,
4189 IN BOOLEAN AlwaysUpdate,
4190 OUT PSTR Buffer,
4191 IN SIZE_T cchBufferSize)
4192 {
4193 ULONG OldProgress = Bar->Progress;
4194
4195 if (Bar->StepCount == 0)
4196 {
4197 Bar->Progress = 0;
4198 }
4199 else
4200 {
4201 Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4202 }
4203
4204 /* Build the progress string if it has changed */
4205 if (Bar->ProgressFormatText &&
4206 (AlwaysUpdate || (Bar->Progress != OldProgress)))
4207 {
4208 RtlStringCchPrintfA(Buffer, cchBufferSize,
4209 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4210
4211 return TRUE;
4212 }
4213
4214 return FALSE;
4215 }
4216
4217 /**
4218 * @name ProgressCountdown
4219 *
4220 * Displays and draws a red-coloured progress bar with a countdown.
4221 * When the timeout is reached, the flush page is displayed for reboot.
4222 *
4223 * @param Ir
4224 * A pointer to an input keyboard record.
4225 *
4226 * @param TimeOut
4227 * Initial countdown value in seconds.
4228 *
4229 * @return
4230 * Nothing.
4231 *
4232 */
4233 static VOID
4234 ProgressCountdown(
4235 IN PINPUT_RECORD Ir,
4236 IN LONG TimeOut)
4237 {
4238 NTSTATUS Status;
4239 ULONG StartTime, BarWidth, TimerDiv;
4240 LONG TimeElapsed;
4241 LONG TimerValue, OldTimerValue;
4242 LARGE_INTEGER Timeout;
4243 PPROGRESSBAR ProgressBar;
4244 BOOLEAN RefreshProgress = TRUE;
4245
4246 /* Bail out if the timeout is already zero */
4247 if (TimeOut <= 0)
4248 return;
4249
4250 /* Create the timeout progress bar and set it up */
4251 ProgressBar = CreateProgressBarEx(13,
4252 26,
4253 xScreen - 13,
4254 yScreen - 20,
4255 10,
4256 24,
4257 TRUE,
4258 FOREGROUND_RED | BACKGROUND_BLUE,
4259 0,
4260 NULL,
4261 MUIGetString(STRING_REBOOTPROGRESSBAR),
4262 ProgressTimeOutStringHandler);
4263
4264 BarWidth = max(1, ProgressBar->Width);
4265 TimerValue = TimeOut * BarWidth;
4266 ProgressSetStepCount(ProgressBar, TimerValue);
4267
4268 StartTime = NtGetTickCount();
4269 CONSOLE_Flush();
4270
4271 TimerDiv = 1000 / BarWidth;
4272 TimerDiv = max(1, TimerDiv);
4273 OldTimerValue = TimerValue;
4274 while (TRUE)
4275 {
4276 /* Decrease the timer */
4277
4278 /*
4279 * Compute how much time the previous operations took.
4280 * This allows us in particular to take account for any time
4281 * elapsed if something slowed down.
4282 */
4283 TimeElapsed = NtGetTickCount() - StartTime;
4284 if (TimeElapsed >= TimerDiv)
4285 {
4286 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4287 TimeElapsed /= TimerDiv;
4288 StartTime += (TimerDiv * TimeElapsed);
4289
4290 if (TimeElapsed <= TimerValue)
4291 TimerValue -= TimeElapsed;
4292 else
4293 TimerValue = 0;
4294
4295 RefreshProgress = TRUE;
4296 }
4297
4298 if (RefreshProgress)
4299 {
4300 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4301 RefreshProgress = FALSE;
4302 }
4303
4304 /* Stop when the timer reaches zero */
4305 if (TimerValue <= 0)
4306 break;
4307
4308 /* Check for user key presses */
4309
4310 /*
4311 * If the timer is used, use a passive wait of maximum 1 second
4312 * while monitoring for incoming console input events, so that
4313 * we are still able to display the timing count.
4314 */
4315
4316 /* Wait a maximum of 1 second for input events */
4317 TimeElapsed = NtGetTickCount() - StartTime;
4318 if (TimeElapsed < TimerDiv)
4319 {
4320 /* Convert the time to NT format */
4321 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4322 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
4323 }
4324 else
4325 {
4326 Status = STATUS_TIMEOUT;
4327 }
4328
4329 /* Check whether the input event has been signaled, or a timeout happened */
4330 if (Status == STATUS_TIMEOUT)
4331 {
4332 continue;
4333 }
4334 if (Status != STATUS_WAIT_0)
4335 {
4336 /* An error happened, bail out */
4337 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
4338 break;
4339 }
4340
4341 /* Check for an ENTER key press */
4342 while (CONSOLE_ConInKeyPeek(Ir))
4343 {
4344 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4345 {
4346 /* Found it, stop waiting */
4347 goto Exit;
4348 }
4349 }
4350 }
4351
4352 Exit:
4353 /* Destroy the progress bar and quit */
4354 DestroyProgressBar(ProgressBar);
4355 }
4356
4357
4358 /*
4359 * Displays the QuitPage.
4360 *
4361 * Next pages:
4362 * FlushPage (At once)
4363 *
4364 * SIDEEFFECTS
4365 * Destroy the Lists
4366 *
4367 * RETURNS
4368 * Number of the next page.
4369 */
4370 static PAGE_NUMBER
4371 QuitPage(PINPUT_RECORD Ir)
4372 {
4373 MUIDisplayPage(QUIT_PAGE);
4374
4375 /* Destroy the NTOS installations list */
4376 if (NtOsInstallsList != NULL)
4377 {
4378 DestroyGenericList(NtOsInstallsList, TRUE);
4379 NtOsInstallsList = NULL;
4380 }
4381
4382 /* Destroy the partition list */
4383 if (PartitionList != NULL)
4384 {
4385 DestroyPartitionList(PartitionList);
4386 PartitionList = NULL;
4387 }
4388
4389 /* Reset the formatter machine state */
4390 TempPartition = NULL;
4391 FormatState = Start;
4392
4393 /* Destroy the filesystem list */
4394 ResetFileSystemList();
4395
4396 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
4397
4398 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4399 ProgressCountdown(Ir, 15);
4400 return FLUSH_PAGE;
4401 }
4402
4403
4404 /*
4405 * Displays the SuccessPage.
4406 *
4407 * Next pages:
4408 * FlushPage (At once)
4409 *
4410 * SIDEEFFECTS
4411 * Destroy the Lists
4412 *
4413 * RETURNS
4414 * Number of the next page.
4415 */
4416 static PAGE_NUMBER
4417 SuccessPage(PINPUT_RECORD Ir)
4418 {
4419 MUIDisplayPage(SUCCESS_PAGE);
4420
4421 if (IsUnattendedSetup)
4422 return FLUSH_PAGE;
4423
4424 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4425 ProgressCountdown(Ir, 15);
4426 return FLUSH_PAGE;
4427 }
4428
4429
4430 /*
4431 * Displays the FlushPage.
4432 *
4433 * Next pages:
4434 * RebootPage (At once)
4435 *
4436 * RETURNS
4437 * Number of the next page.
4438 */
4439 static PAGE_NUMBER
4440 FlushPage(PINPUT_RECORD Ir)
4441 {
4442 MUIDisplayPage(FLUSH_PAGE);
4443 return REBOOT_PAGE;
4444 }
4445
4446
4447 /*
4448 * The start routine and page management
4449 */
4450 NTSTATUS
4451 RunUSetup(VOID)
4452 {
4453 NTSTATUS Status;
4454 INPUT_RECORD Ir;
4455 PAGE_NUMBER Page;
4456 BOOLEAN Old;
4457
4458 InfSetHeap(ProcessHeap);
4459
4460 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4461 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
4462 if (!NT_SUCCESS(Status))
4463 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
4464
4465 /* Initialize the user-mode PnP manager */
4466 Status = InitializeUserModePnpManager(&USetupData.SetupInf);
4467 if (!NT_SUCCESS(Status))
4468 {
4469 // PrintString(??);
4470 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status);
4471 }
4472
4473 if (!CONSOLE_Init())
4474 {
4475 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
4476 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
4477 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
4478
4479 /* We failed to initialize the video, just quit the installer */
4480 return STATUS_APP_INIT_FAILURE;
4481 }
4482
4483 /* Initialize Setup, phase 0 */
4484 InitializeSetup(&USetupData, 0);
4485 USetupData.ErrorRoutine = USetupErrorRoutine;
4486
4487 /* Hide the cursor and clear the screen and keyboard buffer */
4488 CONSOLE_SetCursorType(TRUE, FALSE);
4489 CONSOLE_ClearScreen();
4490 CONSOLE_Flush();
4491
4492 /* Global Initialization page */
4493 Page = SetupStartPage(&Ir);
4494
4495 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4496 {
4497 CONSOLE_ClearScreen();
4498 CONSOLE_Flush();
4499
4500 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4501
4502 switch (Page)
4503 {
4504 /* Language page */
4505 case LANGUAGE_PAGE:
4506 Page = LanguagePage(&Ir);
4507 break;
4508
4509 /* Welcome page */
4510 case WELCOME_PAGE:
4511 Page = WelcomePage(&Ir);
4512 break;
4513
4514 /* License page */
4515 case LICENSE_PAGE:
4516 Page = LicensePage(&Ir);
4517 break;
4518
4519 /* Install pages */
4520 case INSTALL_INTRO_PAGE:
4521 Page = InstallIntroPage(&Ir);
4522 break;
4523
4524 #if 0
4525 case SCSI_CONTROLLER_PAGE:
4526 Page = ScsiControllerPage(&Ir);
4527 break;
4528
4529 case OEM_DRIVER_PAGE:
4530 Page = OemDriverPage(&Ir);
4531 break;
4532 #endif
4533
4534 case DEVICE_SETTINGS_PAGE:
4535 Page = DeviceSettingsPage(&Ir);
4536 break;
4537
4538 case COMPUTER_SETTINGS_PAGE:
4539 Page = ComputerSettingsPage(&Ir);
4540 break;
4541
4542 case DISPLAY_SETTINGS_PAGE:
4543 Page = DisplaySettingsPage(&Ir);
4544 break;
4545
4546 case KEYBOARD_SETTINGS_PAGE:
4547 Page = KeyboardSettingsPage(&Ir);
4548 break;
4549
4550 case LAYOUT_SETTINGS_PAGE:
4551 Page = LayoutSettingsPage(&Ir);
4552 break;
4553
4554 /* Partitioning pages */
4555 case SELECT_PARTITION_PAGE:
4556 Page = SelectPartitionPage(&Ir);
4557 break;
4558
4559 case CREATE_PRIMARY_PARTITION_PAGE:
4560 Page = CreatePrimaryPartitionPage(&Ir);
4561 break;
4562
4563 case CREATE_EXTENDED_PARTITION_PAGE:
4564 Page = CreateExtendedPartitionPage(&Ir);
4565 break;
4566
4567 case CREATE_LOGICAL_PARTITION_PAGE:
4568 Page = CreateLogicalPartitionPage(&Ir);
4569 break;
4570
4571 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
4572 Page = ConfirmDeleteSystemPartitionPage(&Ir);
4573 break;
4574
4575 case DELETE_PARTITION_PAGE:
4576 Page = DeletePartitionPage(&Ir);
4577 break;
4578
4579 /* Filesystem partition operations pages */
4580 case SELECT_FILE_SYSTEM_PAGE:
4581 Page = SelectFileSystemPage(&Ir);
4582 break;
4583
4584 case FORMAT_PARTITION_PAGE:
4585 Page = FormatPartitionPage(&Ir);
4586 break;
4587
4588 case CHECK_FILE_SYSTEM_PAGE:
4589 Page = CheckFileSystemPage(&Ir);
4590 break;
4591
4592 /* Installation pages */
4593 case INSTALL_DIRECTORY_PAGE:
4594 Page = InstallDirectoryPage(&Ir);
4595 break;
4596
4597 case PREPARE_COPY_PAGE:
4598 Page = PrepareCopyPage(&Ir);
4599 break;
4600
4601 case FILE_COPY_PAGE:
4602 Page = FileCopyPage(&Ir);
4603 break;
4604
4605 case REGISTRY_PAGE:
4606 Page = RegistryPage(&Ir);
4607 break;
4608
4609 /* Bootloader installation pages */
4610 case BOOT_LOADER_PAGE:
4611 Page = BootLoaderPage(&Ir);
4612 break;
4613
4614 case BOOT_LOADER_FLOPPY_PAGE:
4615 Page = BootLoaderFloppyPage(&Ir);
4616 break;
4617
4618 case BOOT_LOADER_INSTALLATION_PAGE:
4619 Page = BootLoaderInstallationPage(&Ir);
4620 break;
4621
4622 /* Repair pages */
4623 case REPAIR_INTRO_PAGE:
4624 Page = RepairIntroPage(&Ir);
4625 break;
4626
4627 case UPGRADE_REPAIR_PAGE:
4628 Page = UpgradeRepairPage(&Ir);
4629 break;
4630
4631 case SUCCESS_PAGE:
4632 Page = SuccessPage(&Ir);
4633 break;
4634
4635 case FLUSH_PAGE:
4636 Page = FlushPage(&Ir);
4637 break;
4638
4639 case QUIT_PAGE:
4640 Page = QuitPage(&Ir);
4641 break;
4642
4643 /* Virtual pages */
4644 case SETUP_INIT_PAGE:
4645 case REBOOT_PAGE:
4646 case RECOVERY_PAGE:
4647 break;
4648
4649 default:
4650 break;
4651 }
4652 }
4653
4654 /* Terminate the user-mode PnP manager */
4655 TerminateUserModePnpManager();
4656
4657 /* Setup has finished */
4658 FinishSetup(&USetupData);
4659
4660 if (Page == RECOVERY_PAGE)
4661 RecoveryConsole();
4662
4663 FreeConsole();
4664
4665 /* Reboot */
4666 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
4667 NtShutdownSystem(ShutdownReboot);
4668 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
4669
4670 return STATUS_SUCCESS;
4671 }
4672
4673
4674 VOID NTAPI
4675 NtProcessStartup(PPEB Peb)
4676 {
4677 NTSTATUS Status;
4678 LARGE_INTEGER Time;
4679
4680 RtlNormalizeProcessParams(Peb->ProcessParameters);
4681
4682 ProcessHeap = Peb->ProcessHeap;
4683
4684 NtQuerySystemTime(&Time);
4685
4686 Status = RunUSetup();
4687
4688 if (NT_SUCCESS(Status))
4689 {
4690 /*
4691 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
4692 * a protective waiting.
4693 * This wait is needed because, since we are started as SMSS.EXE,
4694 * the NT kernel explicitly waits 5 seconds for the initial process
4695 * SMSS.EXE to initialize (as a protective measure), and otherwise
4696 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
4697 */
4698 Time.QuadPart += 50000000;
4699 NtDelayExecution(FALSE, &Time);
4700 }
4701 else
4702 {
4703 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
4704 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
4705 0, 0, NULL, 0, NULL);
4706 }
4707
4708 NtTerminateProcess(NtCurrentProcess(), Status);
4709 }
4710
4711 /* EOF */