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