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