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