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