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