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