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