[USETUP] Massage the USETUP interface code.
[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 static UNICODE_STRING SourceRootPath;
49 static UNICODE_STRING SourceRootDir;
50 /* static */ UNICODE_STRING SourcePath;
51 BOOLEAN IsUnattendedSetup = FALSE;
52 LONG UnattendDestinationDiskNumber;
53 LONG UnattendDestinationPartitionNumber;
54 LONG UnattendMBRInstallType = -1;
55 LONG UnattendFormatPartition = 0;
56 LONG AutoPartition = 0;
57 WCHAR UnattendInstallationDirectory[MAX_PATH];
58 PWCHAR SelectedLanguageId;
59 WCHAR LocaleID[9];
60 WCHAR DefaultLanguage[20];
61 WCHAR DefaultKBLayout[20];
62 BOOLEAN RepairUpdateFlag = FALSE;
63 HANDLE hPnpThread = INVALID_HANDLE_VALUE;
64
65 PPARTLIST PartitionList = NULL;
66 PPARTENTRY TempPartition = NULL;
67 FORMATMACHINESTATE FormatState = Start;
68
69
70 /* LOCALS *******************************************************************/
71
72 static PFILE_SYSTEM_LIST FileSystemList = NULL;
73
74 static UNICODE_STRING InstallPath;
75
76 /*
77 * Path to the system partition, where the boot manager resides.
78 * On x86 PCs, this is usually the active partition.
79 * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
80 *
81 * For more information, see:
82 * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
83 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
84 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
85 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
86 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
87 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
88 */
89 static UNICODE_STRING SystemRootPath;
90
91 /* Path to the install directory inside the ReactOS boot partition */
92 static UNICODE_STRING DestinationPath;
93 static UNICODE_STRING DestinationArcPath;
94 static UNICODE_STRING DestinationRootPath;
95
96 static WCHAR DestinationDriveLetter; // FIXME: Is it really useful??
97
98 static HINF SetupInf;
99
100 static HSPFILEQ SetupFileQueue = NULL;
101
102 static PGENERIC_LIST ComputerList = NULL;
103 static PGENERIC_LIST DisplayList = NULL;
104 static PGENERIC_LIST KeyboardList = NULL;
105 static PGENERIC_LIST LayoutList = NULL;
106 static PGENERIC_LIST LanguageList = NULL;
107
108 static LANGID LanguageId = 0;
109
110 static ULONG RequiredPartitionDiskSpace = ~0;
111
112 /* FUNCTIONS ****************************************************************/
113
114 static VOID
115 PrintString(char* fmt,...)
116 {
117 char buffer[512];
118 va_list ap;
119 UNICODE_STRING UnicodeString;
120 ANSI_STRING AnsiString;
121
122 va_start(ap, fmt);
123 vsprintf(buffer, fmt, ap);
124 va_end(ap);
125
126 RtlInitAnsiString(&AnsiString, buffer);
127 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
128 NtDisplayString(&UnicodeString);
129 RtlFreeUnicodeString(&UnicodeString);
130 }
131
132
133 static VOID
134 DrawBox(IN SHORT xLeft,
135 IN SHORT yTop,
136 IN SHORT Width,
137 IN SHORT Height)
138 {
139 COORD coPos;
140 DWORD Written;
141
142 /* draw upper left corner */
143 coPos.X = xLeft;
144 coPos.Y = yTop;
145 FillConsoleOutputCharacterA(StdOutput,
146 0xDA, // '+',
147 1,
148 coPos,
149 &Written);
150
151 /* draw upper edge */
152 coPos.X = xLeft + 1;
153 coPos.Y = yTop;
154 FillConsoleOutputCharacterA(StdOutput,
155 0xC4, // '-',
156 Width - 2,
157 coPos,
158 &Written);
159
160 /* draw upper right corner */
161 coPos.X = xLeft + Width - 1;
162 coPos.Y = yTop;
163 FillConsoleOutputCharacterA(StdOutput,
164 0xBF, // '+',
165 1,
166 coPos,
167 &Written);
168
169 /* Draw right edge, inner space and left edge */
170 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
171 {
172 coPos.X = xLeft;
173 FillConsoleOutputCharacterA(StdOutput,
174 0xB3, // '|',
175 1,
176 coPos,
177 &Written);
178
179 coPos.X = xLeft + 1;
180 FillConsoleOutputCharacterA(StdOutput,
181 ' ',
182 Width - 2,
183 coPos,
184 &Written);
185
186 coPos.X = xLeft + Width - 1;
187 FillConsoleOutputCharacterA(StdOutput,
188 0xB3, // '|',
189 1,
190 coPos,
191 &Written);
192 }
193
194 /* draw lower left corner */
195 coPos.X = xLeft;
196 coPos.Y = yTop + Height - 1;
197 FillConsoleOutputCharacterA(StdOutput,
198 0xC0, // '+',
199 1,
200 coPos,
201 &Written);
202
203 /* draw lower edge */
204 coPos.X = xLeft + 1;
205 coPos.Y = yTop + Height - 1;
206 FillConsoleOutputCharacterA(StdOutput,
207 0xC4, // '-',
208 Width - 2,
209 coPos,
210 &Written);
211
212 /* draw lower right corner */
213 coPos.X = xLeft + Width - 1;
214 coPos.Y = yTop + Height - 1;
215 FillConsoleOutputCharacterA(StdOutput,
216 0xD9, // '+',
217 1,
218 coPos,
219 &Written);
220 }
221
222
223 VOID
224 PopupError(PCCH Text,
225 PCCH Status,
226 PINPUT_RECORD Ir,
227 ULONG WaitEvent)
228 {
229 SHORT yTop;
230 SHORT xLeft;
231 COORD coPos;
232 DWORD Written;
233 ULONG Length;
234 ULONG MaxLength;
235 ULONG Lines;
236 PCHAR p;
237 PCCH pnext;
238 BOOLEAN LastLine;
239 SHORT Width;
240 SHORT Height;
241
242 /* Count text lines and longest line */
243 MaxLength = 0;
244 Lines = 0;
245 pnext = Text;
246
247 while (TRUE)
248 {
249 p = strchr(pnext, '\n');
250
251 if (p == NULL)
252 {
253 Length = strlen(pnext);
254 LastLine = TRUE;
255 }
256 else
257 {
258 Length = (ULONG)(p - pnext);
259 LastLine = FALSE;
260 }
261
262 Lines++;
263
264 if (Length > MaxLength)
265 MaxLength = Length;
266
267 if (LastLine != FALSE)
268 break;
269
270 pnext = p + 1;
271 }
272
273 /* Check length of status line */
274 if (Status != NULL)
275 {
276 Length = strlen(Status);
277
278 if (Length > MaxLength)
279 MaxLength = Length;
280 }
281
282 Width = MaxLength + 4;
283 Height = Lines + 2;
284
285 if (Status != NULL)
286 Height += 2;
287
288 yTop = (yScreen - Height) / 2;
289 xLeft = (xScreen - Width) / 2;
290
291
292 /* Set screen attributes */
293 coPos.X = xLeft;
294 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
295 {
296 FillConsoleOutputAttribute(StdOutput,
297 FOREGROUND_RED | BACKGROUND_WHITE,
298 Width,
299 coPos,
300 &Written);
301 }
302
303 DrawBox(xLeft, yTop, Width, Height);
304
305 /* Print message text */
306 coPos.Y = yTop + 1;
307 pnext = Text;
308 while (TRUE)
309 {
310 p = strchr(pnext, '\n');
311
312 if (p == NULL)
313 {
314 Length = strlen(pnext);
315 LastLine = TRUE;
316 }
317 else
318 {
319 Length = (ULONG)(p - pnext);
320 LastLine = FALSE;
321 }
322
323 if (Length != 0)
324 {
325 coPos.X = xLeft + 2;
326 WriteConsoleOutputCharacterA(StdOutput,
327 pnext,
328 Length,
329 coPos,
330 &Written);
331 }
332
333 if (LastLine != FALSE)
334 break;
335
336 coPos.Y++;
337 pnext = p + 1;
338 }
339
340 /* Print separator line and status text */
341 if (Status != NULL)
342 {
343 coPos.Y = yTop + Height - 3;
344 coPos.X = xLeft;
345 FillConsoleOutputCharacterA(StdOutput,
346 0xC3, // '+',
347 1,
348 coPos,
349 &Written);
350
351 coPos.X = xLeft + 1;
352 FillConsoleOutputCharacterA(StdOutput,
353 0xC4, // '-',
354 Width - 2,
355 coPos,
356 &Written);
357
358 coPos.X = xLeft + Width - 1;
359 FillConsoleOutputCharacterA(StdOutput,
360 0xB4, // '+',
361 1,
362 coPos,
363 &Written);
364
365 coPos.Y++;
366 coPos.X = xLeft + 2;
367 WriteConsoleOutputCharacterA(StdOutput,
368 Status,
369 min(strlen(Status), (SIZE_T)Width - 4),
370 coPos,
371 &Written);
372 }
373
374 if (WaitEvent == POPUP_WAIT_NONE)
375 return;
376
377 while (TRUE)
378 {
379 CONSOLE_ConInKey(Ir);
380
381 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
382 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
383 {
384 return;
385 }
386 }
387 }
388
389
390 /*
391 * Confirm quit setup
392 * RETURNS
393 * TRUE: Quit setup.
394 * FALSE: Don't quit setup.
395 */
396 static BOOL
397 ConfirmQuit(PINPUT_RECORD Ir)
398 {
399 BOOL Result = FALSE;
400 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
401
402 while (TRUE)
403 {
404 CONSOLE_ConInKey(Ir);
405
406 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
407 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
408 {
409 Result = TRUE;
410 break;
411 }
412 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
413 {
414 Result = FALSE;
415 break;
416 }
417 }
418
419 return Result;
420 }
421
422
423 static VOID
424 CheckUnattendedSetup(VOID)
425 {
426 WCHAR UnattendInfPath[MAX_PATH];
427 INFCONTEXT Context;
428 HINF UnattendInf;
429 UINT ErrorLine;
430 INT IntValue;
431 PWCHAR Value;
432
433 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"unattend.inf");
434
435 if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
436 {
437 DPRINT("Does not exist: %S\n", UnattendInfPath);
438 return;
439 }
440
441 /* Load 'unattend.inf' from install media. */
442 UnattendInf = SetupOpenInfFileW(UnattendInfPath,
443 NULL,
444 INF_STYLE_WIN4,
445 LanguageId,
446 &ErrorLine);
447
448 if (UnattendInf == INVALID_HANDLE_VALUE)
449 {
450 DPRINT("SetupOpenInfFileW() failed\n");
451 return;
452 }
453
454 /* Open 'Unattend' section */
455 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
456 {
457 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
458 SetupCloseInfFile(UnattendInf);
459 return;
460 }
461
462 /* Get pointer 'Signature' key */
463 if (!INF_GetData(&Context, NULL, &Value))
464 {
465 DPRINT("INF_GetData() failed for key 'Signature'\n");
466 SetupCloseInfFile(UnattendInf);
467 return;
468 }
469
470 /* Check 'Signature' string */
471 if (_wcsicmp(Value, L"$ReactOS$") != 0)
472 {
473 DPRINT("Signature not $ReactOS$\n");
474 SetupCloseInfFile(UnattendInf);
475 return;
476 }
477
478 /* Check if Unattend setup is enabled */
479 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
480 {
481 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
482 SetupCloseInfFile(UnattendInf);
483 return;
484 }
485
486 if (!INF_GetData(&Context, NULL, &Value))
487 {
488 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
489 SetupCloseInfFile(UnattendInf);
490 return;
491 }
492
493 if (_wcsicmp(Value, L"yes") != 0)
494 {
495 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
496 SetupCloseInfFile(UnattendInf);
497 return;
498 }
499
500 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
501 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
502 {
503 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
504 SetupCloseInfFile(UnattendInf);
505 return;
506 }
507
508 if (!SetupGetIntField(&Context, 1, &IntValue))
509 {
510 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
511 SetupCloseInfFile(UnattendInf);
512 return;
513 }
514
515 UnattendDestinationDiskNumber = (LONG)IntValue;
516
517 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
518 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
519 {
520 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
521 SetupCloseInfFile(UnattendInf);
522 return;
523 }
524
525 if (!SetupGetIntField(&Context, 1, &IntValue))
526 {
527 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
528 SetupCloseInfFile(UnattendInf);
529 return;
530 }
531
532 UnattendDestinationPartitionNumber = (LONG)IntValue;
533
534 /* Search for 'InstallationDirectory' in the 'Unattend' section */
535 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
536 {
537 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
538 SetupCloseInfFile(UnattendInf);
539 return;
540 }
541
542 /* Get pointer 'InstallationDirectory' key */
543 if (!INF_GetData(&Context, NULL, &Value))
544 {
545 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
546 SetupCloseInfFile(UnattendInf);
547 return;
548 }
549
550 wcscpy(UnattendInstallationDirectory, Value);
551
552 IsUnattendedSetup = TRUE;
553
554 /* Search for 'MBRInstallType' in the 'Unattend' section */
555 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
556 {
557 if (SetupGetIntField(&Context, 1, &IntValue))
558 {
559 UnattendMBRInstallType = IntValue;
560 }
561 }
562
563 /* Search for 'FormatPartition' in the 'Unattend' section */
564 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
565 {
566 if (SetupGetIntField(&Context, 1, &IntValue))
567 {
568 UnattendFormatPartition = IntValue;
569 }
570 }
571
572 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
573 {
574 if (SetupGetIntField(&Context, 1, &IntValue))
575 {
576 AutoPartition = IntValue;
577 }
578 }
579
580 /* search for LocaleID in the 'Unattend' section*/
581 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"LocaleID", &Context))
582 {
583 if (INF_GetData(&Context, NULL, &Value))
584 {
585 LONG Id = wcstol(Value, NULL, 16);
586 swprintf(LocaleID, L"%08lx", Id);
587 }
588 }
589
590 SetupCloseInfFile(UnattendInf);
591
592 DPRINT("Running unattended setup\n");
593 }
594
595
596 static VOID
597 UpdateKBLayout(VOID)
598 {
599 PGENERIC_LIST_ENTRY ListEntry;
600 LPCWSTR pszNewLayout;
601
602 pszNewLayout = MUIDefaultKeyboardLayout();
603
604 if (LayoutList == NULL)
605 {
606 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
607 if (LayoutList == NULL)
608 {
609 /* FIXME: Handle error! */
610 return;
611 }
612 }
613
614 ListEntry = GetFirstListEntry(LayoutList);
615
616 /* Search for default layout (if provided) */
617 if (pszNewLayout != NULL)
618 {
619 while (ListEntry != NULL)
620 {
621 if (!wcscmp(pszNewLayout, GetListEntryUserData(ListEntry)))
622 {
623 SetCurrentListEntry(LayoutList, ListEntry);
624 break;
625 }
626
627 ListEntry = GetNextListEntry(ListEntry);
628 }
629 }
630 }
631
632
633 /*
634 * Displays the LanguagePage.
635 *
636 * Next pages: WelcomePage, QuitPage
637 *
638 * SIDEEFFECTS
639 * Init SelectedLanguageId
640 * Init LanguageId
641 *
642 * RETURNS
643 * Number of the next page.
644 */
645 static PAGE_NUMBER
646 LanguagePage(PINPUT_RECORD Ir)
647 {
648 GENERIC_LIST_UI ListUi;
649 PWCHAR NewLanguageId;
650 BOOL RefreshPage = FALSE;
651
652 /* Initialize the computer settings list */
653 if (LanguageList == NULL)
654 {
655 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
656 if (LanguageList == NULL)
657 {
658 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
659 return WELCOME_PAGE;
660 }
661 }
662
663 /* Load the font */
664 SelectedLanguageId = DefaultLanguage;
665 SetConsoleCodePage();
666 UpdateKBLayout();
667
668 /* If there's just a single language in the list skip
669 * the language selection process altogether! */
670 if (GenericListHasSingleEntry(LanguageList))
671 {
672 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
673 return WELCOME_PAGE;
674 }
675
676 InitGenericListUi(&ListUi, LanguageList);
677 DrawGenericList(&ListUi,
678 2,
679 18,
680 xScreen - 3,
681 yScreen - 3);
682
683 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
684
685 MUIDisplayPage(LANGUAGE_PAGE);
686
687 while (TRUE)
688 {
689 CONSOLE_ConInKey(Ir);
690
691 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
692 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
693 {
694 ScrollDownGenericList(&ListUi);
695 RefreshPage = TRUE;
696 }
697 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
698 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
699 {
700 ScrollUpGenericList(&ListUi);
701 RefreshPage = TRUE;
702 }
703 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
704 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
705 {
706 ScrollPageDownGenericList(&ListUi);
707 RefreshPage = TRUE;
708 }
709 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
710 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
711 {
712 ScrollPageUpGenericList(&ListUi);
713 RefreshPage = TRUE;
714 }
715 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
716 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
717 {
718 if (ConfirmQuit(Ir) != FALSE)
719 return QUIT_PAGE;
720 else
721 RedrawGenericList(&ListUi);
722 }
723 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
724 {
725 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
726
727 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
728
729 if (wcscmp(SelectedLanguageId, DefaultLanguage))
730 {
731 UpdateKBLayout();
732 }
733
734 /* Load the font */
735 SetConsoleCodePage();
736
737 return WELCOME_PAGE;
738 }
739 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
740 {
741 /* a-z */
742 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
743 RefreshPage = TRUE;
744 }
745
746 if (RefreshPage)
747 {
748 NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
749
750 if (SelectedLanguageId != NewLanguageId)
751 {
752 /* Clear the language page */
753 MUIClearPage(LANGUAGE_PAGE);
754
755 SelectedLanguageId = NewLanguageId;
756
757 /* Load the font */
758 SetConsoleCodePage();
759
760 /* Redraw language selection page in native language */
761 MUIDisplayPage(LANGUAGE_PAGE);
762 }
763
764 RefreshPage = FALSE;
765 }
766 }
767
768 return WELCOME_PAGE;
769 }
770
771
772 /*
773 * Start page
774 *
775 * Next pages:
776 * LanguagePage (at once, default)
777 * InstallIntroPage (at once, if unattended)
778 * QuitPage
779 *
780 * SIDEEFFECTS
781 * Init Sdi
782 * Init SourcePath
783 * Init SourceRootPath
784 * Init SourceRootDir
785 * Init SetupInf
786 * Init RequiredPartitionDiskSpace
787 * Init IsUnattendedSetup
788 * If unattended, init *List and sets the Codepage
789 * If unattended, init SelectedLanguageId
790 * If unattended, init LanguageId
791 *
792 * RETURNS
793 * Number of the next page.
794 */
795 static PAGE_NUMBER
796 SetupStartPage(PINPUT_RECORD Ir)
797 {
798 NTSTATUS Status;
799 WCHAR FileNameBuffer[MAX_PATH];
800 INFCONTEXT Context;
801 PWCHAR Value;
802 UINT ErrorLine;
803 PGENERIC_LIST_ENTRY ListEntry;
804 INT IntValue;
805
806 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
807
808 /* Get the source path and source root path */
809 Status = GetSourcePaths(&SourcePath,
810 &SourceRootPath,
811 &SourceRootDir);
812 if (!NT_SUCCESS(Status))
813 {
814 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
815 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
816 return QUIT_PAGE;
817 }
818 DPRINT1("SourcePath: '%wZ'", &SourcePath);
819 DPRINT1("SourceRootPath: '%wZ'", &SourceRootPath);
820 DPRINT1("SourceRootDir: '%wZ'", &SourceRootDir);
821
822 /* Load txtsetup.sif from install media. */
823 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath.Buffer, L"txtsetup.sif");
824 SetupInf = SetupOpenInfFileW(FileNameBuffer,
825 NULL,
826 INF_STYLE_WIN4,
827 LanguageId,
828 &ErrorLine);
829
830 if (SetupInf == INVALID_HANDLE_VALUE)
831 {
832 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
833 return QUIT_PAGE;
834 }
835
836 /* Open 'Version' section */
837 if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
838 {
839 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
840 return QUIT_PAGE;
841 }
842
843 /* Get pointer 'Signature' key */
844 if (!INF_GetData(&Context, NULL, &Value))
845 {
846 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
847 return QUIT_PAGE;
848 }
849
850 /* Check 'Signature' string */
851 if (_wcsicmp(Value, L"$ReactOS$") != 0)
852 {
853 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
854 return QUIT_PAGE;
855 }
856
857 /* Open 'DiskSpaceRequirements' section */
858 if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
859 {
860 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
861 return QUIT_PAGE;
862 }
863
864 /* Get the 'FreeSysPartDiskSpace' value */
865 if (!SetupGetIntField(&Context, 1, &IntValue))
866 {
867 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
868 return QUIT_PAGE;
869 }
870
871 RequiredPartitionDiskSpace = (ULONG)IntValue;
872
873 /* Start the PnP thread */
874 if (hPnpThread != INVALID_HANDLE_VALUE)
875 {
876 NtResumeThread(hPnpThread, NULL);
877 hPnpThread = INVALID_HANDLE_VALUE;
878 }
879
880 CheckUnattendedSetup();
881
882 if (IsUnattendedSetup)
883 {
884 // TODO: Read options from inf
885 ComputerList = CreateComputerTypeList(SetupInf);
886 DisplayList = CreateDisplayDriverList(SetupInf);
887 KeyboardList = CreateKeyboardDriverList(SetupInf);
888 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
889 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
890
891 /* new part */
892 wcscpy(SelectedLanguageId, LocaleID);
893 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
894
895 /* first we hack LanguageList */
896 ListEntry = GetFirstListEntry(LanguageList);
897 while (ListEntry != NULL)
898 {
899 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
900 {
901 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
902 SetCurrentListEntry(LanguageList, ListEntry);
903 break;
904 }
905
906 ListEntry = GetNextListEntry(ListEntry);
907 }
908
909 /* now LayoutList */
910 ListEntry = GetFirstListEntry(LayoutList);
911 while (ListEntry != NULL)
912 {
913 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
914 {
915 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
916 SetCurrentListEntry(LayoutList, ListEntry);
917 break;
918 }
919
920 ListEntry = GetNextListEntry(ListEntry);
921 }
922
923 SetConsoleCodePage();
924
925 return INSTALL_INTRO_PAGE;
926 }
927
928 return LANGUAGE_PAGE;
929 }
930
931
932 /*
933 * Displays the WelcomePage.
934 *
935 * Next pages:
936 * InstallIntroPage (default)
937 * RepairIntroPage
938 * LicensePage
939 * QuitPage
940 *
941 * RETURNS
942 * Number of the next page.
943 */
944 static PAGE_NUMBER
945 WelcomePage(PINPUT_RECORD Ir)
946 {
947 MUIDisplayPage(WELCOME_PAGE);
948
949 while (TRUE)
950 {
951 CONSOLE_ConInKey(Ir);
952
953 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
954 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
955 {
956 if (ConfirmQuit(Ir) != FALSE)
957 return QUIT_PAGE;
958
959 break;
960 }
961 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
962 {
963 return INSTALL_INTRO_PAGE;
964 }
965 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
966 {
967 return REPAIR_INTRO_PAGE;
968 }
969 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
970 {
971 return LICENSE_PAGE;
972 }
973 }
974
975 return WELCOME_PAGE;
976 }
977
978
979 /*
980 * Displays the License page.
981 *
982 * Next page:
983 * WelcomePage (default)
984 *
985 * RETURNS
986 * Number of the next page.
987 */
988 static PAGE_NUMBER
989 LicensePage(PINPUT_RECORD Ir)
990 {
991 MUIDisplayPage(LICENSE_PAGE);
992
993 while (TRUE)
994 {
995 CONSOLE_ConInKey(Ir);
996
997 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
998 {
999 return WELCOME_PAGE;
1000 }
1001 }
1002
1003 return LICENSE_PAGE;
1004 }
1005
1006
1007 /*
1008 * Displays the RepairIntroPage.
1009 *
1010 * Next pages:
1011 * RebootPage (default)
1012 * InstallIntroPage
1013 * RecoveryPage
1014 * IntroPage
1015 *
1016 * RETURNS
1017 * Number of the next page.
1018 */
1019 static PAGE_NUMBER
1020 RepairIntroPage(PINPUT_RECORD Ir)
1021 {
1022 MUIDisplayPage(REPAIR_INTRO_PAGE);
1023
1024 while(TRUE)
1025 {
1026 CONSOLE_ConInKey(Ir);
1027
1028 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1029 {
1030 return REBOOT_PAGE;
1031 }
1032 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1033 {
1034 RepairUpdateFlag = TRUE;
1035 return INSTALL_INTRO_PAGE;
1036 }
1037 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
1038 {
1039 return RECOVERY_PAGE;
1040 }
1041 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1042 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1043 {
1044 return WELCOME_PAGE;
1045 }
1046 }
1047
1048 return REPAIR_INTRO_PAGE;
1049 }
1050
1051 /*
1052 * Displays the InstallIntroPage.
1053 *
1054 * Next pages:
1055 * DeviceSettingsPage (At once if repair or update is selected)
1056 * SelectPartitionPage (At once if unattended setup)
1057 * DeviceSettingsPage (default)
1058 * QuitPage
1059 *
1060 * RETURNS
1061 * Number of the next page.
1062 */
1063 static PAGE_NUMBER
1064 InstallIntroPage(PINPUT_RECORD Ir)
1065 {
1066 if (RepairUpdateFlag)
1067 {
1068 //return SELECT_PARTITION_PAGE;
1069 return DEVICE_SETTINGS_PAGE;
1070 }
1071
1072 if (IsUnattendedSetup)
1073 return SELECT_PARTITION_PAGE;
1074
1075 MUIDisplayPage(INSTALL_INTRO_PAGE);
1076
1077 while (TRUE)
1078 {
1079 CONSOLE_ConInKey(Ir);
1080
1081 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1082 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1083 {
1084 if (ConfirmQuit(Ir) != FALSE)
1085 return QUIT_PAGE;
1086
1087 break;
1088 }
1089 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1090 {
1091 return DEVICE_SETTINGS_PAGE;
1092 // return SCSI_CONTROLLER_PAGE;
1093 }
1094 }
1095
1096 return INSTALL_INTRO_PAGE;
1097 }
1098
1099
1100 #if 0
1101 static PAGE_NUMBER
1102 ScsiControllerPage(PINPUT_RECORD Ir)
1103 {
1104 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1105
1106 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1107
1108 /* FIXME: print loaded mass storage driver descriptions */
1109 #if 0
1110 CONSOLE_SetTextXY(8, 10, "TEST device");
1111 #endif
1112
1113 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1114
1115 while (TRUE)
1116 {
1117 CONSOLE_ConInKey(Ir);
1118
1119 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1120 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1121 {
1122 if (ConfirmQuit(Ir) != FALSE)
1123 return QUIT_PAGE;
1124
1125 break;
1126 }
1127 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1128 {
1129 return DEVICE_SETTINGS_PAGE;
1130 }
1131 }
1132
1133 return SCSI_CONTROLLER_PAGE;
1134 }
1135
1136 static PAGE_NUMBER
1137 OemDriverPage(PINPUT_RECORD Ir)
1138 {
1139 // MUIDisplayPage(OEM_DRIVER_PAGE);
1140
1141 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1142
1143 /* FIXME: Implement!! */
1144
1145 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1146
1147 while (TRUE)
1148 {
1149 CONSOLE_ConInKey(Ir);
1150
1151 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1152 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1153 {
1154 if (ConfirmQuit(Ir) == TRUE)
1155 return QUIT_PAGE;
1156
1157 break;
1158 }
1159 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1160 {
1161 return DEVICE_SETTINGS_PAGE;
1162 }
1163 }
1164
1165 return OEM_DRIVER_PAGE;
1166 }
1167 #endif
1168
1169
1170 /*
1171 * Displays the DeviceSettingsPage.
1172 *
1173 * Next pages:
1174 * SelectPartitionPage (At once if repair or update is selected)
1175 * ComputerSettingsPage
1176 * DisplaySettingsPage
1177 * KeyboardSettingsPage
1178 * LayoutsettingsPage
1179 * SelectPartitionPage
1180 * QuitPage
1181 *
1182 * SIDEEFFECTS
1183 * Init ComputerList
1184 * Init DisplayList
1185 * Init KeyboardList
1186 * Init LayoutList
1187 *
1188 * RETURNS
1189 * Number of the next page.
1190 */
1191 static PAGE_NUMBER
1192 DeviceSettingsPage(PINPUT_RECORD Ir)
1193 {
1194 static ULONG Line = 16;
1195
1196 /* Initialize the computer settings list */
1197 if (ComputerList == NULL)
1198 {
1199 ComputerList = CreateComputerTypeList(SetupInf);
1200 if (ComputerList == NULL)
1201 {
1202 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1203 return QUIT_PAGE;
1204 }
1205 }
1206
1207 /* Initialize the display settings list */
1208 if (DisplayList == NULL)
1209 {
1210 DisplayList = CreateDisplayDriverList(SetupInf);
1211 if (DisplayList == NULL)
1212 {
1213 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1214 return QUIT_PAGE;
1215 }
1216 }
1217
1218 /* Initialize the keyboard settings list */
1219 if (KeyboardList == NULL)
1220 {
1221 KeyboardList = CreateKeyboardDriverList(SetupInf);
1222 if (KeyboardList == NULL)
1223 {
1224 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1225 return QUIT_PAGE;
1226 }
1227 }
1228
1229 /* Initialize the keyboard layout list */
1230 if (LayoutList == NULL)
1231 {
1232 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
1233 if (LayoutList == NULL)
1234 {
1235 /* FIXME: report error */
1236 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1237 return QUIT_PAGE;
1238 }
1239 }
1240
1241 if (RepairUpdateFlag)
1242 return SELECT_PARTITION_PAGE;
1243
1244 // if (IsUnattendedSetup)
1245 // return SELECT_PARTITION_PAGE;
1246
1247 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1248
1249 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList)));
1250 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList)));
1251 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList)));
1252 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList)));
1253
1254 CONSOLE_InvertTextXY(24, Line, 48, 1);
1255
1256 while (TRUE)
1257 {
1258 CONSOLE_ConInKey(Ir);
1259
1260 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1261 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1262 {
1263 CONSOLE_NormalTextXY(24, Line, 48, 1);
1264
1265 if (Line == 14)
1266 Line = 16;
1267 else if (Line == 16)
1268 Line = 11;
1269 else
1270 Line++;
1271
1272 CONSOLE_InvertTextXY(24, Line, 48, 1);
1273 }
1274 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1275 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1276 {
1277 CONSOLE_NormalTextXY(24, Line, 48, 1);
1278
1279 if (Line == 11)
1280 Line = 16;
1281 else if (Line == 16)
1282 Line = 14;
1283 else
1284 Line--;
1285
1286 CONSOLE_InvertTextXY(24, Line, 48, 1);
1287 }
1288 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1289 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1290 {
1291 if (ConfirmQuit(Ir) != FALSE)
1292 return QUIT_PAGE;
1293
1294 break;
1295 }
1296 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1297 {
1298 if (Line == 11)
1299 return COMPUTER_SETTINGS_PAGE;
1300 else if (Line == 12)
1301 return DISPLAY_SETTINGS_PAGE;
1302 else if (Line == 13)
1303 return KEYBOARD_SETTINGS_PAGE;
1304 else if (Line == 14)
1305 return LAYOUT_SETTINGS_PAGE;
1306 else if (Line == 16)
1307 return SELECT_PARTITION_PAGE;
1308 }
1309 }
1310
1311 return DEVICE_SETTINGS_PAGE;
1312 }
1313
1314
1315 /*
1316 * Handles generic selection lists.
1317 *
1318 * PARAMS
1319 * GenericList: The list to handle.
1320 * nextPage: The page it needs to jump to after this page.
1321 * Ir: The PINPUT_RECORD
1322 */
1323 static PAGE_NUMBER
1324 HandleGenericList(PGENERIC_LIST_UI ListUi,
1325 PAGE_NUMBER nextPage,
1326 PINPUT_RECORD Ir)
1327 {
1328 while (TRUE)
1329 {
1330 CONSOLE_ConInKey(Ir);
1331
1332 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1333 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1334 {
1335 ScrollDownGenericList(ListUi);
1336 }
1337 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1338 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1339 {
1340 ScrollUpGenericList(ListUi);
1341 }
1342 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1343 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1344 {
1345 ScrollPageDownGenericList(ListUi);
1346 }
1347 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1348 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1349 {
1350 ScrollPageUpGenericList(ListUi);
1351 }
1352 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1353 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1354 {
1355 if (ConfirmQuit(Ir) != FALSE)
1356 return QUIT_PAGE;
1357 else
1358 RedrawGenericList(ListUi);
1359 }
1360 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1361 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1362 {
1363 RestoreGenericListState(ListUi->List);
1364 return nextPage; // Use some "prevPage;" instead?
1365 }
1366 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1367 {
1368 return nextPage;
1369 }
1370 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1371 {
1372 /* a-z */
1373 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1374 }
1375 }
1376 }
1377
1378
1379 /*
1380 * Displays the ComputerSettingsPage.
1381 *
1382 * Next pages:
1383 * DeviceSettingsPage
1384 * QuitPage
1385 *
1386 * RETURNS
1387 * Number of the next page.
1388 */
1389 static PAGE_NUMBER
1390 ComputerSettingsPage(PINPUT_RECORD Ir)
1391 {
1392 GENERIC_LIST_UI ListUi;
1393 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1394
1395 InitGenericListUi(&ListUi, ComputerList);
1396 DrawGenericList(&ListUi,
1397 2,
1398 18,
1399 xScreen - 3,
1400 yScreen - 3);
1401
1402 SaveGenericListState(ComputerList);
1403
1404 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1405 }
1406
1407
1408 /*
1409 * Displays the DisplaySettingsPage.
1410 *
1411 * Next pages:
1412 * DeviceSettingsPage
1413 * QuitPage
1414 *
1415 * RETURNS
1416 * Number of the next page.
1417 */
1418 static PAGE_NUMBER
1419 DisplaySettingsPage(PINPUT_RECORD Ir)
1420 {
1421 GENERIC_LIST_UI ListUi;
1422 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1423
1424 InitGenericListUi(&ListUi, DisplayList);
1425 DrawGenericList(&ListUi,
1426 2,
1427 18,
1428 xScreen - 3,
1429 yScreen - 3);
1430
1431 SaveGenericListState(DisplayList);
1432
1433 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1434 }
1435
1436
1437 /*
1438 * Displays the KeyboardSettingsPage.
1439 *
1440 * Next pages:
1441 * DeviceSettingsPage
1442 * QuitPage
1443 *
1444 * RETURNS
1445 * Number of the next page.
1446 */
1447 static PAGE_NUMBER
1448 KeyboardSettingsPage(PINPUT_RECORD Ir)
1449 {
1450 GENERIC_LIST_UI ListUi;
1451 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1452
1453 InitGenericListUi(&ListUi, KeyboardList);
1454 DrawGenericList(&ListUi,
1455 2,
1456 18,
1457 xScreen - 3,
1458 yScreen - 3);
1459
1460 SaveGenericListState(KeyboardList);
1461
1462 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1463 }
1464
1465
1466 /*
1467 * Displays the LayoutSettingsPage.
1468 *
1469 * Next pages:
1470 * DeviceSettingsPage
1471 * QuitPage
1472 *
1473 * RETURNS
1474 * Number of the next page.
1475 */
1476 static PAGE_NUMBER
1477 LayoutSettingsPage(PINPUT_RECORD Ir)
1478 {
1479 GENERIC_LIST_UI ListUi;
1480 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1481
1482 InitGenericListUi(&ListUi, LayoutList);
1483 DrawGenericList(&ListUi,
1484 2,
1485 18,
1486 xScreen - 3,
1487 yScreen - 3);
1488
1489 SaveGenericListState(LayoutList);
1490
1491 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1492 }
1493
1494
1495 static BOOL
1496 IsDiskSizeValid(PPARTENTRY PartEntry)
1497 {
1498 ULONGLONG size;
1499
1500 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1501 size = (size + 524288) / 1048576; /* in MBytes */
1502
1503 if (size < RequiredPartitionDiskSpace)
1504 {
1505 /* partition is too small so ask for another partition */
1506 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
1507 return FALSE;
1508 }
1509 else
1510 {
1511 return TRUE;
1512 }
1513 }
1514
1515
1516 /*
1517 * Displays the SelectPartitionPage.
1518 *
1519 * Next pages:
1520 * SelectFileSystemPage (At once if unattended)
1521 * SelectFileSystemPage (Default if free space is selected)
1522 * CreatePrimaryPartitionPage
1523 * CreateExtendedPartitionPage
1524 * CreateLogicalPartitionPage
1525 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1526 * DeletePartitionPage
1527 * QuitPage
1528 *
1529 * SIDEEFFECTS
1530 * Init DestinationDriveLetter (only if unattended or not free space is selected)
1531 * Set InstallShortcut (only if not unattended + free space is selected)
1532 *
1533 * RETURNS
1534 * Number of the next page.
1535 */
1536 static PAGE_NUMBER
1537 SelectPartitionPage(PINPUT_RECORD Ir)
1538 {
1539 PARTLIST_UI ListUi;
1540 ULONG Error;
1541
1542 if (PartitionList == NULL)
1543 {
1544 PartitionList = CreatePartitionList();
1545 if (PartitionList == NULL)
1546 {
1547 /* FIXME: show an error dialog */
1548 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1549 return QUIT_PAGE;
1550 }
1551 else if (IsListEmpty(&PartitionList->DiskListHead))
1552 {
1553 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1554 return QUIT_PAGE;
1555 }
1556
1557 TempPartition = NULL;
1558 FormatState = Start;
1559 }
1560
1561 MUIDisplayPage(SELECT_PARTITION_PAGE);
1562
1563 InitPartitionListUi(&ListUi, PartitionList,
1564 2,
1565 23,
1566 xScreen - 3,
1567 yScreen - 3);
1568 DrawPartitionList(&ListUi);
1569
1570 if (IsUnattendedSetup)
1571 {
1572 if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
1573 {
1574 if (AutoPartition)
1575 {
1576 if (PartitionList->CurrentPartition->LogicalPartition)
1577 {
1578 CreateLogicalPartition(PartitionList,
1579 PartitionList->CurrentPartition->SectorCount.QuadPart,
1580 TRUE);
1581 }
1582 else
1583 {
1584 CreatePrimaryPartition(PartitionList,
1585 PartitionList->CurrentPartition->SectorCount.QuadPart,
1586 TRUE);
1587 }
1588
1589 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1590 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1591 {
1592 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1593 RequiredPartitionDiskSpace);
1594 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1595 }
1596
1597 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1598
1599 return SELECT_FILE_SYSTEM_PAGE;
1600 }
1601 }
1602 else
1603 {
1604 DrawPartitionList(&ListUi);
1605
1606 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1607 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1608 {
1609 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1610 RequiredPartitionDiskSpace);
1611 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1612 }
1613
1614 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1615
1616 return SELECT_FILE_SYSTEM_PAGE;
1617 }
1618 }
1619
1620 while (TRUE)
1621 {
1622 /* Update status text */
1623 if (PartitionList->CurrentPartition == NULL)
1624 {
1625 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1626 }
1627 else if (PartitionList->CurrentPartition->LogicalPartition)
1628 {
1629 if (PartitionList->CurrentPartition->IsPartitioned)
1630 {
1631 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1632 }
1633 else
1634 {
1635 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1636 }
1637 }
1638 else
1639 {
1640 if (PartitionList->CurrentPartition->IsPartitioned)
1641 {
1642 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1643 {
1644 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1645 }
1646 else
1647 {
1648 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1649 }
1650 }
1651 else
1652 {
1653 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1654 }
1655 }
1656
1657 CONSOLE_ConInKey(Ir);
1658
1659 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1660 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1661 {
1662 if (ConfirmQuit(Ir) != FALSE)
1663 {
1664 DestroyPartitionList(PartitionList);
1665 PartitionList = NULL;
1666 return QUIT_PAGE;
1667 }
1668
1669 break;
1670 }
1671 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1672 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1673 {
1674 ScrollDownPartitionList(&ListUi);
1675 }
1676 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1677 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1678 {
1679 ScrollUpPartitionList(&ListUi);
1680 }
1681 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1682 {
1683 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1684 continue; // return SELECT_PARTITION_PAGE;
1685
1686 if (PartitionList->CurrentPartition == NULL ||
1687 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1688 {
1689 if (PartitionList->CurrentPartition->LogicalPartition)
1690 {
1691 CreateLogicalPartition(PartitionList,
1692 0ULL,
1693 TRUE);
1694 }
1695 else
1696 {
1697 CreatePrimaryPartition(PartitionList,
1698 0ULL,
1699 TRUE);
1700 }
1701 }
1702
1703 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1704 {
1705 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1706 RequiredPartitionDiskSpace);
1707 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1708 }
1709
1710 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1711
1712 return SELECT_FILE_SYSTEM_PAGE;
1713 }
1714 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1715 {
1716 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1717 {
1718 Error = PrimaryPartitionCreationChecks(PartitionList);
1719 if (Error != NOT_AN_ERROR)
1720 {
1721 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1722 return SELECT_PARTITION_PAGE;
1723 }
1724
1725 return CREATE_PRIMARY_PARTITION_PAGE;
1726 }
1727 }
1728 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1729 {
1730 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1731 {
1732 Error = ExtendedPartitionCreationChecks(PartitionList);
1733 if (Error != NOT_AN_ERROR)
1734 {
1735 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1736 return SELECT_PARTITION_PAGE;
1737 }
1738
1739 return CREATE_EXTENDED_PARTITION_PAGE;
1740 }
1741 }
1742 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1743 {
1744 if (PartitionList->CurrentPartition->LogicalPartition != FALSE)
1745 {
1746 Error = LogicalPartitionCreationChecks(PartitionList);
1747 if (Error != NOT_AN_ERROR)
1748 {
1749 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1750 return SELECT_PARTITION_PAGE;
1751 }
1752
1753 return CREATE_LOGICAL_PARTITION_PAGE;
1754 }
1755 }
1756 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1757 {
1758 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1759 {
1760 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1761 return SELECT_PARTITION_PAGE;
1762 }
1763
1764 if (PartitionList->CurrentPartition->BootIndicator ||
1765 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1766 {
1767 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1768 }
1769
1770 return DELETE_PARTITION_PAGE;
1771 }
1772 }
1773
1774 return SELECT_PARTITION_PAGE;
1775 }
1776
1777
1778 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1779 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1780 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1781
1782 static VOID
1783 ShowPartitionSizeInputBox(SHORT Left,
1784 SHORT Top,
1785 SHORT Right,
1786 SHORT Bottom,
1787 ULONG MaxSize,
1788 PWSTR InputBuffer,
1789 PBOOLEAN Quit,
1790 PBOOLEAN Cancel)
1791 {
1792 INPUT_RECORD Ir;
1793 COORD coPos;
1794 DWORD Written;
1795 CHAR Buffer[128];
1796 INT Length, Pos;
1797 WCHAR ch;
1798 SHORT iLeft;
1799 SHORT iTop;
1800
1801 if (Quit != NULL)
1802 *Quit = FALSE;
1803
1804 if (Cancel != NULL)
1805 *Cancel = FALSE;
1806
1807 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1808
1809 /* Print message */
1810 coPos.X = Left + 2;
1811 coPos.Y = Top + 2;
1812 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1813 iLeft = coPos.X + strlen(Buffer) + 1;
1814 iTop = coPos.Y;
1815
1816 WriteConsoleOutputCharacterA(StdOutput,
1817 Buffer,
1818 strlen(Buffer),
1819 coPos,
1820 &Written);
1821
1822 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1823 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1824 coPos.Y = iTop;
1825 WriteConsoleOutputCharacterA(StdOutput,
1826 Buffer,
1827 strlen(Buffer),
1828 coPos,
1829 &Written);
1830
1831 swprintf(InputBuffer, L"%lu", MaxSize);
1832 Length = wcslen(InputBuffer);
1833 Pos = Length;
1834 CONSOLE_SetInputTextXY(iLeft,
1835 iTop,
1836 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1837 InputBuffer);
1838 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1839 CONSOLE_SetCursorType(TRUE, TRUE);
1840
1841 while (TRUE)
1842 {
1843 CONSOLE_ConInKey(&Ir);
1844
1845 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1846 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1847 {
1848 if (Quit != NULL)
1849 *Quit = TRUE;
1850
1851 InputBuffer[0] = UNICODE_NULL;
1852 CONSOLE_SetCursorType(TRUE, FALSE);
1853 break;
1854 }
1855 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1856 {
1857 CONSOLE_SetCursorType(TRUE, FALSE);
1858 break;
1859 }
1860 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1861 {
1862 if (Cancel != NULL)
1863 *Cancel = TRUE;
1864
1865 InputBuffer[0] = UNICODE_NULL;
1866 CONSOLE_SetCursorType(TRUE, FALSE);
1867 break;
1868 }
1869 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1870 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1871 {
1872 Pos = 0;
1873 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1874 }
1875 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1876 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1877 {
1878 Pos = Length;
1879 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1880 }
1881 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1882 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1883 {
1884 if (Pos > 0)
1885 {
1886 Pos--;
1887 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1888 }
1889 }
1890 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1891 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1892 {
1893 if (Pos < Length)
1894 {
1895 Pos++;
1896 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1897 }
1898 }
1899 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1900 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1901 {
1902 if (Pos < Length)
1903 {
1904 memmove(&InputBuffer[Pos],
1905 &InputBuffer[Pos + 1],
1906 (Length - Pos - 1) * sizeof(WCHAR));
1907 InputBuffer[Length - 1] = UNICODE_NULL;
1908
1909 Length--;
1910 CONSOLE_SetInputTextXY(iLeft,
1911 iTop,
1912 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1913 InputBuffer);
1914 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1915 }
1916 }
1917 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1918 {
1919 if (Pos > 0)
1920 {
1921 if (Pos < Length)
1922 memmove(&InputBuffer[Pos - 1],
1923 &InputBuffer[Pos],
1924 (Length - Pos) * sizeof(WCHAR));
1925 InputBuffer[Length - 1] = UNICODE_NULL;
1926
1927 Pos--;
1928 Length--;
1929 CONSOLE_SetInputTextXY(iLeft,
1930 iTop,
1931 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1932 InputBuffer);
1933 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1934 }
1935 }
1936 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1937 {
1938 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1939 {
1940 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1941
1942 if ((ch >= L'0') && (ch <= L'9'))
1943 {
1944 if (Pos < Length)
1945 memmove(&InputBuffer[Pos + 1],
1946 &InputBuffer[Pos],
1947 (Length - Pos) * sizeof(WCHAR));
1948 InputBuffer[Length + 1] = UNICODE_NULL;
1949 InputBuffer[Pos] = ch;
1950
1951 Pos++;
1952 Length++;
1953 CONSOLE_SetInputTextXY(iLeft,
1954 iTop,
1955 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1956 InputBuffer);
1957 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1958 }
1959 }
1960 }
1961 }
1962 }
1963
1964
1965 /*
1966 * Displays the CreatePrimaryPartitionPage.
1967 *
1968 * Next pages:
1969 * SelectPartitionPage
1970 * SelectFileSystemPage (default)
1971 * QuitPage
1972 *
1973 * RETURNS
1974 * Number of the next page.
1975 */
1976 static PAGE_NUMBER
1977 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1978 {
1979 PDISKENTRY DiskEntry;
1980 PPARTENTRY PartEntry;
1981 BOOLEAN Quit;
1982 BOOLEAN Cancel;
1983 WCHAR InputBuffer[50];
1984 ULONG MaxSize;
1985 ULONGLONG PartSize;
1986 ULONGLONG DiskSize;
1987 ULONGLONG SectorCount;
1988 PCHAR Unit;
1989
1990 if (PartitionList == NULL ||
1991 PartitionList->CurrentDisk == NULL ||
1992 PartitionList->CurrentPartition == NULL)
1993 {
1994 /* FIXME: show an error dialog */
1995 return QUIT_PAGE;
1996 }
1997
1998 DiskEntry = PartitionList->CurrentDisk;
1999 PartEntry = PartitionList->CurrentPartition;
2000
2001 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2002
2003 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
2004
2005 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2006 #if 0
2007 if (DiskSize >= 10737418240) /* 10 GB */
2008 {
2009 DiskSize = DiskSize / 1073741824;
2010 Unit = MUIGetString(STRING_GB);
2011 }
2012 else
2013 #endif
2014 {
2015 DiskSize = DiskSize / 1048576;
2016 if (DiskSize == 0)
2017 DiskSize = 1;
2018
2019 Unit = MUIGetString(STRING_MB);
2020 }
2021
2022 if (DiskEntry->DriverName.Length > 0)
2023 {
2024 CONSOLE_PrintTextXY(6, 10,
2025 MUIGetString(STRING_HDINFOPARTCREATE),
2026 DiskSize,
2027 Unit,
2028 DiskEntry->DiskNumber,
2029 DiskEntry->Port,
2030 DiskEntry->Bus,
2031 DiskEntry->Id,
2032 &DiskEntry->DriverName);
2033 }
2034 else
2035 {
2036 CONSOLE_PrintTextXY(6, 10,
2037 MUIGetString(STRING_HDDINFOUNK1),
2038 DiskSize,
2039 Unit,
2040 DiskEntry->DiskNumber,
2041 DiskEntry->Port,
2042 DiskEntry->Bus,
2043 DiskEntry->Id);
2044 }
2045
2046 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2047
2048 #if 0
2049 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2050 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2051 #endif
2052
2053 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2054
2055 PartEntry = PartitionList->CurrentPartition;
2056 while (TRUE)
2057 {
2058 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2059
2060 if (MaxSize > PARTITION_MAXSIZE)
2061 MaxSize = PARTITION_MAXSIZE;
2062
2063 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2064 MaxSize, InputBuffer, &Quit, &Cancel);
2065
2066 if (Quit != FALSE)
2067 {
2068 if (ConfirmQuit(Ir) != FALSE)
2069 return QUIT_PAGE;
2070
2071 break;
2072 }
2073 else if (Cancel != FALSE)
2074 {
2075 return SELECT_PARTITION_PAGE;
2076 }
2077 else
2078 {
2079 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2080
2081 if (PartSize < 1)
2082 {
2083 /* Too small */
2084 continue;
2085 }
2086
2087 if (PartSize > MaxSize)
2088 {
2089 /* Too large */
2090 continue;
2091 }
2092
2093 /* Convert to bytes */
2094 if (PartSize == MaxSize)
2095 {
2096 /* Use all of the unpartitioned disk space */
2097 SectorCount = PartEntry->SectorCount.QuadPart;
2098 }
2099 else
2100 {
2101 /* Calculate the sector count from the size in MB */
2102 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2103
2104 /* But never get larger than the unpartitioned disk space */
2105 if (SectorCount > PartEntry->SectorCount.QuadPart)
2106 SectorCount = PartEntry->SectorCount.QuadPart;
2107 }
2108
2109 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2110
2111 CreatePrimaryPartition(PartitionList,
2112 SectorCount,
2113 FALSE);
2114
2115 return SELECT_PARTITION_PAGE;
2116 }
2117 }
2118
2119 return CREATE_PRIMARY_PARTITION_PAGE;
2120 }
2121
2122
2123 /*
2124 * Displays the CreateExtendedPartitionPage.
2125 *
2126 * Next pages:
2127 * SelectPartitionPage (default)
2128 * QuitPage
2129 *
2130 * RETURNS
2131 * Number of the next page.
2132 */
2133 static PAGE_NUMBER
2134 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2135 {
2136 PDISKENTRY DiskEntry;
2137 PPARTENTRY PartEntry;
2138 BOOLEAN Quit;
2139 BOOLEAN Cancel;
2140 WCHAR InputBuffer[50];
2141 ULONG MaxSize;
2142 ULONGLONG PartSize;
2143 ULONGLONG DiskSize;
2144 ULONGLONG SectorCount;
2145 PCHAR Unit;
2146
2147 if (PartitionList == NULL ||
2148 PartitionList->CurrentDisk == NULL ||
2149 PartitionList->CurrentPartition == NULL)
2150 {
2151 /* FIXME: show an error dialog */
2152 return QUIT_PAGE;
2153 }
2154
2155 DiskEntry = PartitionList->CurrentDisk;
2156 PartEntry = PartitionList->CurrentPartition;
2157
2158 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2159
2160 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2161
2162 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2163 #if 0
2164 if (DiskSize >= 10737418240) /* 10 GB */
2165 {
2166 DiskSize = DiskSize / 1073741824;
2167 Unit = MUIGetString(STRING_GB);
2168 }
2169 else
2170 #endif
2171 {
2172 DiskSize = DiskSize / 1048576;
2173 if (DiskSize == 0)
2174 DiskSize = 1;
2175
2176 Unit = MUIGetString(STRING_MB);
2177 }
2178
2179 if (DiskEntry->DriverName.Length > 0)
2180 {
2181 CONSOLE_PrintTextXY(6, 10,
2182 MUIGetString(STRING_HDINFOPARTCREATE),
2183 DiskSize,
2184 Unit,
2185 DiskEntry->DiskNumber,
2186 DiskEntry->Port,
2187 DiskEntry->Bus,
2188 DiskEntry->Id,
2189 &DiskEntry->DriverName);
2190 }
2191 else
2192 {
2193 CONSOLE_PrintTextXY(6, 10,
2194 MUIGetString(STRING_HDDINFOUNK1),
2195 DiskSize,
2196 Unit,
2197 DiskEntry->DiskNumber,
2198 DiskEntry->Port,
2199 DiskEntry->Bus,
2200 DiskEntry->Id);
2201 }
2202
2203 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2204
2205 #if 0
2206 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2207 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2208 #endif
2209
2210 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2211
2212 PartEntry = PartitionList->CurrentPartition;
2213 while (TRUE)
2214 {
2215 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2216
2217 if (MaxSize > PARTITION_MAXSIZE)
2218 MaxSize = PARTITION_MAXSIZE;
2219
2220 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2221 MaxSize, InputBuffer, &Quit, &Cancel);
2222
2223 if (Quit != FALSE)
2224 {
2225 if (ConfirmQuit(Ir) != FALSE)
2226 return QUIT_PAGE;
2227
2228 break;
2229 }
2230 else if (Cancel != FALSE)
2231 {
2232 return SELECT_PARTITION_PAGE;
2233 }
2234 else
2235 {
2236 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2237
2238 if (PartSize < 1)
2239 {
2240 /* Too small */
2241 continue;
2242 }
2243
2244 if (PartSize > MaxSize)
2245 {
2246 /* Too large */
2247 continue;
2248 }
2249
2250 /* Convert to bytes */
2251 if (PartSize == MaxSize)
2252 {
2253 /* Use all of the unpartitioned disk space */
2254 SectorCount = PartEntry->SectorCount.QuadPart;
2255 }
2256 else
2257 {
2258 /* Calculate the sector count from the size in MB */
2259 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2260
2261 /* But never get larger than the unpartitioned disk space */
2262 if (SectorCount > PartEntry->SectorCount.QuadPart)
2263 SectorCount = PartEntry->SectorCount.QuadPart;
2264 }
2265
2266 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2267
2268 CreateExtendedPartition(PartitionList,
2269 SectorCount);
2270
2271 return SELECT_PARTITION_PAGE;
2272 }
2273 }
2274
2275 return CREATE_EXTENDED_PARTITION_PAGE;
2276 }
2277
2278
2279 /*
2280 * Displays the CreateLogicalPartitionPage.
2281 *
2282 * Next pages:
2283 * SelectFileSystemPage (default)
2284 * QuitPage
2285 *
2286 * RETURNS
2287 * Number of the next page.
2288 */
2289 static PAGE_NUMBER
2290 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2291 {
2292 PDISKENTRY DiskEntry;
2293 PPARTENTRY PartEntry;
2294 BOOLEAN Quit;
2295 BOOLEAN Cancel;
2296 WCHAR InputBuffer[50];
2297 ULONG MaxSize;
2298 ULONGLONG PartSize;
2299 ULONGLONG DiskSize;
2300 ULONGLONG SectorCount;
2301 PCHAR Unit;
2302
2303 if (PartitionList == NULL ||
2304 PartitionList->CurrentDisk == NULL ||
2305 PartitionList->CurrentPartition == NULL)
2306 {
2307 /* FIXME: show an error dialog */
2308 return QUIT_PAGE;
2309 }
2310
2311 DiskEntry = PartitionList->CurrentDisk;
2312 PartEntry = PartitionList->CurrentPartition;
2313
2314 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2315
2316 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2317
2318 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2319 #if 0
2320 if (DiskSize >= 10737418240) /* 10 GB */
2321 {
2322 DiskSize = DiskSize / 1073741824;
2323 Unit = MUIGetString(STRING_GB);
2324 }
2325 else
2326 #endif
2327 {
2328 DiskSize = DiskSize / 1048576;
2329 if (DiskSize == 0)
2330 DiskSize = 1;
2331
2332 Unit = MUIGetString(STRING_MB);
2333 }
2334
2335 if (DiskEntry->DriverName.Length > 0)
2336 {
2337 CONSOLE_PrintTextXY(6, 10,
2338 MUIGetString(STRING_HDINFOPARTCREATE),
2339 DiskSize,
2340 Unit,
2341 DiskEntry->DiskNumber,
2342 DiskEntry->Port,
2343 DiskEntry->Bus,
2344 DiskEntry->Id,
2345 &DiskEntry->DriverName);
2346 }
2347 else
2348 {
2349 CONSOLE_PrintTextXY(6, 10,
2350 MUIGetString(STRING_HDDINFOUNK1),
2351 DiskSize,
2352 Unit,
2353 DiskEntry->DiskNumber,
2354 DiskEntry->Port,
2355 DiskEntry->Bus,
2356 DiskEntry->Id);
2357 }
2358
2359 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2360
2361 #if 0
2362 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2363 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2364 #endif
2365
2366 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2367
2368 PartEntry = PartitionList->CurrentPartition;
2369 while (TRUE)
2370 {
2371 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2372
2373 if (MaxSize > PARTITION_MAXSIZE)
2374 MaxSize = PARTITION_MAXSIZE;
2375
2376 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2377 MaxSize, InputBuffer, &Quit, &Cancel);
2378
2379 if (Quit != FALSE)
2380 {
2381 if (ConfirmQuit(Ir) != FALSE)
2382 return QUIT_PAGE;
2383
2384 break;
2385 }
2386 else if (Cancel != FALSE)
2387 {
2388 return SELECT_PARTITION_PAGE;
2389 }
2390 else
2391 {
2392 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2393
2394 if (PartSize < 1)
2395 {
2396 /* Too small */
2397 continue;
2398 }
2399
2400 if (PartSize > MaxSize)
2401 {
2402 /* Too large */
2403 continue;
2404 }
2405
2406 /* Convert to bytes */
2407 if (PartSize == MaxSize)
2408 {
2409 /* Use all of the unpartitioned disk space */
2410 SectorCount = PartEntry->SectorCount.QuadPart;
2411 }
2412 else
2413 {
2414 /* Calculate the sector count from the size in MB */
2415 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2416
2417 /* But never get larger than the unpartitioned disk space */
2418 if (SectorCount > PartEntry->SectorCount.QuadPart)
2419 SectorCount = PartEntry->SectorCount.QuadPart;
2420 }
2421
2422 DPRINT("Partition size: %I64u bytes\n", PartSize);
2423
2424 CreateLogicalPartition(PartitionList,
2425 SectorCount,
2426 FALSE);
2427
2428 return SELECT_PARTITION_PAGE;
2429 }
2430 }
2431
2432 return CREATE_LOGICAL_PARTITION_PAGE;
2433 }
2434
2435
2436 /*
2437 * Displays the ConfirmDeleteSystemPartitionPage.
2438 *
2439 * Next pages:
2440 * DeletePartitionPage (default)
2441 * SelectPartitionPage
2442 *
2443 * RETURNS
2444 * Number of the next page.
2445 */
2446 static PAGE_NUMBER
2447 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2448 {
2449 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2450
2451 while (TRUE)
2452 {
2453 CONSOLE_ConInKey(Ir);
2454
2455 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2456 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2457 {
2458 if (ConfirmQuit(Ir) == TRUE)
2459 return QUIT_PAGE;
2460
2461 break;
2462 }
2463 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2464 {
2465 return DELETE_PARTITION_PAGE;
2466 }
2467 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2468 {
2469 return SELECT_PARTITION_PAGE;
2470 }
2471 }
2472
2473 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2474 }
2475
2476
2477 /*
2478 * Displays the DeletePartitionPage.
2479 *
2480 * Next pages:
2481 * SelectPartitionPage (default)
2482 * QuitPage
2483 *
2484 * RETURNS
2485 * Number of the next page.
2486 */
2487 static PAGE_NUMBER
2488 DeletePartitionPage(PINPUT_RECORD Ir)
2489 {
2490 PDISKENTRY DiskEntry;
2491 PPARTENTRY PartEntry;
2492 ULONGLONG DiskSize;
2493 ULONGLONG PartSize;
2494 PCHAR Unit;
2495 CHAR PartTypeString[32];
2496
2497 if (PartitionList == NULL ||
2498 PartitionList->CurrentDisk == NULL ||
2499 PartitionList->CurrentPartition == NULL)
2500 {
2501 /* FIXME: show an error dialog */
2502 return QUIT_PAGE;
2503 }
2504
2505 DiskEntry = PartitionList->CurrentDisk;
2506 PartEntry = PartitionList->CurrentPartition;
2507
2508 MUIDisplayPage(DELETE_PARTITION_PAGE);
2509
2510 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2511 PartTypeString,
2512 ARRAYSIZE(PartTypeString));
2513
2514 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2515 #if 0
2516 if (PartSize >= 10737418240) /* 10 GB */
2517 {
2518 PartSize = PartSize / 1073741824;
2519 Unit = MUIGetString(STRING_GB);
2520 }
2521 else
2522 #endif
2523 if (PartSize >= 10485760) /* 10 MB */
2524 {
2525 PartSize = PartSize / 1048576;
2526 Unit = MUIGetString(STRING_MB);
2527 }
2528 else
2529 {
2530 PartSize = PartSize / 1024;
2531 Unit = MUIGetString(STRING_KB);
2532 }
2533
2534 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2535 {
2536 CONSOLE_PrintTextXY(6, 10,
2537 MUIGetString(STRING_HDDINFOUNK2),
2538 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2539 (PartEntry->DriveLetter == 0) ? '-' : ':',
2540 PartEntry->PartitionType,
2541 PartSize,
2542 Unit);
2543 }
2544 else
2545 {
2546 CONSOLE_PrintTextXY(6, 10,
2547 " %c%c %s %I64u %s",
2548 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2549 (PartEntry->DriveLetter == 0) ? '-' : ':',
2550 PartTypeString,
2551 PartSize,
2552 Unit);
2553 }
2554
2555 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2556 #if 0
2557 if (DiskSize >= 10737418240) /* 10 GB */
2558 {
2559 DiskSize = DiskSize / 1073741824;
2560 Unit = MUIGetString(STRING_GB);
2561 }
2562 else
2563 #endif
2564 {
2565 DiskSize = DiskSize / 1048576;
2566 if (DiskSize == 0)
2567 DiskSize = 1;
2568
2569 Unit = MUIGetString(STRING_MB);
2570 }
2571
2572 if (DiskEntry->DriverName.Length > 0)
2573 {
2574 CONSOLE_PrintTextXY(6, 12,
2575 MUIGetString(STRING_HDINFOPARTDELETE),
2576 DiskSize,
2577 Unit,
2578 DiskEntry->DiskNumber,
2579 DiskEntry->Port,
2580 DiskEntry->Bus,
2581 DiskEntry->Id,
2582 &DiskEntry->DriverName);
2583 }
2584 else
2585 {
2586 CONSOLE_PrintTextXY(6, 12,
2587 MUIGetString(STRING_HDDINFOUNK3),
2588 DiskSize,
2589 Unit,
2590 DiskEntry->DiskNumber,
2591 DiskEntry->Port,
2592 DiskEntry->Bus,
2593 DiskEntry->Id);
2594 }
2595
2596 while (TRUE)
2597 {
2598 CONSOLE_ConInKey(Ir);
2599
2600 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2601 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2602 {
2603 if (ConfirmQuit(Ir) != FALSE)
2604 return QUIT_PAGE;
2605
2606 break;
2607 }
2608 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2609 {
2610 return SELECT_PARTITION_PAGE;
2611 }
2612 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2613 {
2614 DeleteCurrentPartition(PartitionList);
2615
2616 return SELECT_PARTITION_PAGE;
2617 }
2618 }
2619
2620 return DELETE_PARTITION_PAGE;
2621 }
2622
2623
2624 /*
2625 * Displays the SelectFileSystemPage.
2626 *
2627 * Next pages:
2628 * CheckFileSystemPage (At once if RepairUpdate is selected)
2629 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2630 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2631 * SelectPartitionPage (If the user aborts)
2632 * FormatPartitionPage (Default)
2633 * QuitPage
2634 *
2635 * SIDEEFFECTS
2636 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2637 * Calls CheckActiveSystemPartition()
2638 *
2639 * RETURNS
2640 * Number of the next page.
2641 */
2642 static PAGE_NUMBER
2643 SelectFileSystemPage(PINPUT_RECORD Ir)
2644 {
2645 PDISKENTRY DiskEntry;
2646 PPARTENTRY PartEntry;
2647 ULONGLONG DiskSize;
2648 ULONGLONG PartSize;
2649 PCHAR DiskUnit;
2650 PCHAR PartUnit;
2651 CHAR PartTypeString[32];
2652 FORMATMACHINESTATE PreviousFormatState;
2653
2654 DPRINT("SelectFileSystemPage()\n");
2655
2656 if (PartitionList == NULL ||
2657 PartitionList->CurrentDisk == NULL ||
2658 PartitionList->CurrentPartition == NULL)
2659 {
2660 /* FIXME: show an error dialog */
2661 return QUIT_PAGE;
2662 }
2663
2664 /* Find or set the active system partition */
2665 CheckActiveSystemPartition(PartitionList);
2666 if (PartitionList->SystemPartition == NULL)
2667 {
2668 /* FIXME: show an error dialog */
2669 //
2670 // Error dialog should say that we cannot find a suitable
2671 // system partition and create one on the system. At this point,
2672 // it may be nice to ask the user whether he wants to continue,
2673 // or use an external drive as the system drive/partition
2674 // (e.g. floppy, USB drive, etc...)
2675 //
2676 return QUIT_PAGE;
2677 }
2678
2679 PreviousFormatState = FormatState;
2680 switch (FormatState)
2681 {
2682 case Start:
2683 {
2684 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2685 {
2686 TempPartition = PartitionList->SystemPartition;
2687 TempPartition->NeedsCheck = TRUE;
2688
2689 FormatState = FormatSystemPartition;
2690 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2691 }
2692 else
2693 {
2694 TempPartition = PartitionList->CurrentPartition;
2695 TempPartition->NeedsCheck = TRUE;
2696
2697 FormatState = FormatInstallPartition;
2698 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2699 }
2700 break;
2701 }
2702
2703 case FormatSystemPartition:
2704 {
2705 TempPartition = PartitionList->CurrentPartition;
2706 TempPartition->NeedsCheck = TRUE;
2707
2708 FormatState = FormatInstallPartition;
2709 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2710 break;
2711 }
2712
2713 case FormatInstallPartition:
2714 {
2715 if (GetNextUnformattedPartition(PartitionList,
2716 NULL,
2717 &TempPartition))
2718 {
2719 FormatState = FormatOtherPartition;
2720 TempPartition->NeedsCheck = TRUE;
2721 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2722 }
2723 else
2724 {
2725 FormatState = FormatDone;
2726 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2727 return CHECK_FILE_SYSTEM_PAGE;
2728 }
2729 break;
2730 }
2731
2732 case FormatOtherPartition:
2733 {
2734 if (GetNextUnformattedPartition(PartitionList,
2735 NULL,
2736 &TempPartition))
2737 {
2738 FormatState = FormatOtherPartition;
2739 TempPartition->NeedsCheck = TRUE;
2740 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2741 }
2742 else
2743 {
2744 FormatState = FormatDone;
2745 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2746 return CHECK_FILE_SYSTEM_PAGE;
2747 }
2748 break;
2749 }
2750
2751 default:
2752 {
2753 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2754 /* FIXME: show an error dialog */
2755 return QUIT_PAGE;
2756 }
2757 }
2758
2759 PartEntry = TempPartition;
2760 DiskEntry = PartEntry->DiskEntry;
2761
2762 /* Adjust disk size */
2763 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2764 if (DiskSize >= 10737418240) /* 10 GB */
2765 {
2766 DiskSize = DiskSize / 1073741824;
2767 DiskUnit = MUIGetString(STRING_GB);
2768 }
2769 else
2770 {
2771 DiskSize = DiskSize / 1048576;
2772 DiskUnit = MUIGetString(STRING_MB);
2773 }
2774
2775 /* Adjust partition size */
2776 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2777 if (PartSize >= 10737418240) /* 10 GB */
2778 {
2779 PartSize = PartSize / 1073741824;
2780 PartUnit = MUIGetString(STRING_GB);
2781 }
2782 else
2783 {
2784 PartSize = PartSize / 1048576;
2785 PartUnit = MUIGetString(STRING_MB);
2786 }
2787
2788 /* Adjust partition type */
2789 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2790 PartTypeString,
2791 ARRAYSIZE(PartTypeString));
2792
2793 if (PartEntry->AutoCreate != FALSE)
2794 {
2795 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2796
2797 #if 0
2798 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2799 PartEntry->PartitionNumber,
2800 PartSize,
2801 PartUnit,
2802 PartTypeString);
2803 #endif
2804
2805 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2806 DiskEntry->DiskNumber,
2807 DiskSize,
2808 DiskUnit,
2809 DiskEntry->Port,
2810 DiskEntry->Bus,
2811 DiskEntry->Id,
2812 &DiskEntry->DriverName);
2813
2814 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2815
2816 PartEntry->AutoCreate = FALSE;
2817 }
2818 else if (PartEntry->New != FALSE)
2819 {
2820 switch (FormatState)
2821 {
2822 case FormatSystemPartition:
2823 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2824 break;
2825
2826 case FormatInstallPartition:
2827 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2828 break;
2829
2830 case FormatOtherPartition:
2831 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2832 break;
2833
2834 default:
2835 break;
2836 }
2837
2838 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2839 }
2840 else
2841 {
2842 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2843
2844 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2845 {
2846 CONSOLE_PrintTextXY(8, 10,
2847 MUIGetString(STRING_HDDINFOUNK4),
2848 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2849 (PartEntry->DriveLetter == 0) ? '-' : ':',
2850 PartEntry->PartitionType,
2851 PartSize,
2852 PartUnit);
2853 }
2854 else
2855 {
2856 CONSOLE_PrintTextXY(8, 10,
2857 "%c%c %s %I64u %s",
2858 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2859 (PartEntry->DriveLetter == 0) ? '-' : ':',
2860 PartTypeString,
2861 PartSize,
2862 PartUnit);
2863 }
2864
2865 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2866 DiskEntry->DiskNumber,
2867 DiskSize,
2868 DiskUnit,
2869 DiskEntry->Port,
2870 DiskEntry->Bus,
2871 DiskEntry->Id,
2872 &DiskEntry->DriverName);
2873 }
2874
2875 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2876
2877 if (FileSystemList == NULL)
2878 {
2879 /* Create the file system list, and by default select the "FAT" file system */
2880 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2881 if (FileSystemList == NULL)
2882 {
2883 /* FIXME: show an error dialog */
2884 return QUIT_PAGE;
2885 }
2886 }
2887
2888 DrawFileSystemList(FileSystemList);
2889
2890 if (RepairUpdateFlag)
2891 {
2892 return CHECK_FILE_SYSTEM_PAGE;
2893 //return SELECT_PARTITION_PAGE;
2894 }
2895
2896 if (IsUnattendedSetup)
2897 {
2898 if (UnattendFormatPartition)
2899 {
2900 /*
2901 * We use whatever currently selected file system we have
2902 * (by default, this is "FAT", as per the initialization
2903 * performed above). Note that it may be interesting to specify
2904 * which file system to use in unattended installations, in the
2905 * txtsetup.sif file.
2906 */
2907 return FORMAT_PARTITION_PAGE;
2908 }
2909
2910 return CHECK_FILE_SYSTEM_PAGE;
2911 }
2912
2913 while (TRUE)
2914 {
2915 CONSOLE_ConInKey(Ir);
2916
2917 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2918 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2919 {
2920 if (ConfirmQuit(Ir) != FALSE)
2921 return QUIT_PAGE;
2922
2923 break;
2924 }
2925 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2926 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2927 {
2928 FormatState = Start;
2929 return SELECT_PARTITION_PAGE;
2930 }
2931 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2932 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2933 {
2934 ScrollDownFileSystemList(FileSystemList);
2935 }
2936 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2937 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2938 {
2939 ScrollUpFileSystemList(FileSystemList);
2940 }
2941 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2942 {
2943 if (!FileSystemList->Selected->FileSystem)
2944 return SELECT_FILE_SYSTEM_PAGE;
2945 else
2946 return FORMAT_PARTITION_PAGE;
2947 }
2948 }
2949
2950 FormatState = PreviousFormatState;
2951
2952 return SELECT_FILE_SYSTEM_PAGE;
2953 }
2954
2955
2956 /*
2957 * Displays the FormatPartitionPage.
2958 *
2959 * Next pages:
2960 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2961 * SelectPartitionPage (At once)
2962 * QuitPage
2963 *
2964 * SIDEEFFECTS
2965 * Sets PartitionList->CurrentPartition->FormatState
2966 * Sets DestinationRootPath
2967 *
2968 * RETURNS
2969 * Number of the next page.
2970 */
2971 static PAGE_NUMBER
2972 FormatPartitionPage(PINPUT_RECORD Ir)
2973 {
2974 UNICODE_STRING PartitionRootPath;
2975 WCHAR PathBuffer[MAX_PATH];
2976 PDISKENTRY DiskEntry;
2977 PPARTENTRY PartEntry;
2978 PFILE_SYSTEM_ITEM SelectedFileSystem;
2979 NTSTATUS Status;
2980
2981 #ifndef NDEBUG
2982 ULONG Line;
2983 ULONG i;
2984 PPARTITION_INFORMATION PartitionInfo;
2985 #endif
2986
2987 DPRINT("FormatPartitionPage()\n");
2988
2989 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2990
2991 if (PartitionList == NULL || TempPartition == NULL)
2992 {
2993 /* FIXME: show an error dialog */
2994 return QUIT_PAGE;
2995 }
2996
2997 PartEntry = TempPartition;
2998 DiskEntry = PartEntry->DiskEntry;
2999
3000 SelectedFileSystem = FileSystemList->Selected;
3001
3002 while (TRUE)
3003 {
3004 if (!IsUnattendedSetup)
3005 {
3006 CONSOLE_ConInKey(Ir);
3007 }
3008
3009 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3010 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3011 {
3012 if (ConfirmQuit(Ir) != FALSE)
3013 return QUIT_PAGE;
3014
3015 break;
3016 }
3017 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3018 {
3019 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3020
3021 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
3022 {
3023 /* FIXME: show an error dialog */
3024 return QUIT_PAGE;
3025 }
3026
3027 #ifndef NDEBUG
3028 CONSOLE_PrintTextXY(6, 12,
3029 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3030 DiskEntry->Cylinders,
3031 DiskEntry->TracksPerCylinder,
3032 DiskEntry->SectorsPerTrack,
3033 DiskEntry->BytesPerSector,
3034 DiskEntry->Dirty ? '*' : ' ');
3035
3036 Line = 13;
3037
3038 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3039 {
3040 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3041
3042 CONSOLE_PrintTextXY(6, Line,
3043 "%2u: %2lu %c %12I64u %12I64u %02x",
3044 i,
3045 PartitionInfo->PartitionNumber,
3046 PartitionInfo->BootIndicator ? 'A' : '-',
3047 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3048 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3049 PartitionInfo->PartitionType);
3050 Line++;
3051 }
3052 #endif
3053
3054 /* Commit the partition changes to the disk */
3055 if (!WritePartitionsToDisk(PartitionList))
3056 {
3057 DPRINT("WritePartitionsToDisk() failed\n");
3058 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3059 return QUIT_PAGE;
3060 }
3061
3062 /* Set PartitionRootPath */
3063 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3064 L"\\Device\\Harddisk%lu\\Partition%lu",
3065 DiskEntry->DiskNumber,
3066 PartEntry->PartitionNumber);
3067 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3068 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3069
3070 /* Format the partition */
3071 if (SelectedFileSystem->FileSystem)
3072 {
3073 Status = FormatPartition(&PartitionRootPath,
3074 SelectedFileSystem);
3075 if (!NT_SUCCESS(Status))
3076 {
3077 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3078 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3079 return QUIT_PAGE;
3080 }
3081
3082 PartEntry->FormatState = Formatted;
3083 // PartEntry->FileSystem = FileSystem;
3084 PartEntry->New = FALSE;
3085 }
3086
3087 #ifndef NDEBUG
3088 CONSOLE_SetStatusText(" Done. Press any key ...");
3089 CONSOLE_ConInKey(Ir);
3090 #endif
3091
3092 return SELECT_FILE_SYSTEM_PAGE;
3093 }
3094 }
3095
3096 return FORMAT_PARTITION_PAGE;
3097 }
3098
3099
3100 /*
3101 * Displays the CheckFileSystemPage.
3102 *
3103 * Next pages:
3104 * InstallDirectoryPage (At once)
3105 * QuitPage
3106 *
3107 * SIDEEFFECTS
3108 * Inits or reloads FileSystemList
3109 *
3110 * RETURNS
3111 * Number of the next page.
3112 */
3113 static PAGE_NUMBER
3114 CheckFileSystemPage(PINPUT_RECORD Ir)
3115 {
3116 PFILE_SYSTEM CurrentFileSystem;
3117 UNICODE_STRING PartitionRootPath;
3118 WCHAR PathBuffer[MAX_PATH];
3119 CHAR Buffer[MAX_PATH];
3120 PDISKENTRY DiskEntry;
3121 PPARTENTRY PartEntry;
3122 NTSTATUS Status;
3123
3124 if (PartitionList == NULL)
3125 {
3126 /* FIXME: show an error dialog */
3127 return QUIT_PAGE;
3128 }
3129
3130 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3131 {
3132 return INSTALL_DIRECTORY_PAGE;
3133 }
3134
3135 /* Set PartitionRootPath */
3136 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3137 L"\\Device\\Harddisk%lu\\Partition%lu",
3138 DiskEntry->DiskNumber,
3139 PartEntry->PartitionNumber);
3140 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3141 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3142
3143 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3144
3145 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3146
3147 CurrentFileSystem = PartEntry->FileSystem;
3148 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3149 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3150
3151 /* HACK: Do not try to check a partition with an unknown filesystem */
3152 if (CurrentFileSystem == NULL)
3153 {
3154 PartEntry->NeedsCheck = FALSE;
3155 return CHECK_FILE_SYSTEM_PAGE;
3156 }
3157
3158 if (CurrentFileSystem->ChkdskFunc == NULL)
3159 {
3160 sprintf(Buffer,
3161 "Setup is currently unable to check a partition formatted in %S.\n"
3162 "\n"
3163 " \x07 Press ENTER to continue Setup.\n"
3164 " \x07 Press F3 to quit Setup.",
3165 CurrentFileSystem->FileSystemName);
3166
3167 PopupError(Buffer,
3168 MUIGetString(STRING_QUITCONTINUE),
3169 NULL, POPUP_WAIT_NONE);
3170
3171 while (TRUE)
3172 {
3173 CONSOLE_ConInKey(Ir);
3174
3175 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3176 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3177 {
3178 if (ConfirmQuit(Ir))
3179 return QUIT_PAGE;
3180 else
3181 return CHECK_FILE_SYSTEM_PAGE;
3182 }
3183 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3184 {
3185 PartEntry->NeedsCheck = FALSE;
3186 return CHECK_FILE_SYSTEM_PAGE;
3187 }
3188 }
3189 }
3190 else
3191 {
3192 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3193 if (!NT_SUCCESS(Status))
3194 {
3195 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3196 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3197 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3198 "(Status 0x%08lx).\n", Status);
3199 PopupError(Buffer,
3200 // MUIGetString(STRING_REBOOTCOMPUTER),
3201 MUIGetString(STRING_CONTINUE),
3202 Ir, POPUP_WAIT_ENTER);
3203
3204 // return QUIT_PAGE;
3205 }
3206
3207 PartEntry->NeedsCheck = FALSE;
3208 return CHECK_FILE_SYSTEM_PAGE;
3209 }
3210 }
3211
3212
3213 static VOID
3214 BuildInstallPaths(PWSTR InstallDir,
3215 PDISKENTRY DiskEntry,
3216 PPARTENTRY PartEntry)
3217 {
3218 WCHAR PathBuffer[MAX_PATH];
3219
3220 /* Create 'InstallPath' string */
3221 RtlFreeUnicodeString(&InstallPath);
3222 RtlCreateUnicodeString(&InstallPath, InstallDir);
3223
3224 /* Create 'DestinationRootPath' string */
3225 RtlFreeUnicodeString(&DestinationRootPath);
3226 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3227 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3228 DiskEntry->DiskNumber,
3229 PartEntry->PartitionNumber);
3230 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3231 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3232
3233 /* Create 'DestinationPath' string */
3234 RtlFreeUnicodeString(&DestinationPath);
3235 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3236 DestinationRootPath.Buffer, InstallDir);
3237 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3238
3239 /* Create 'DestinationArcPath' */
3240 RtlFreeUnicodeString(&DestinationArcPath);
3241 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3242 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3243 DiskEntry->BiosDiskNumber,
3244 PartEntry->PartitionNumber);
3245 ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
3246 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3247 }
3248
3249
3250 /*
3251 * Displays the InstallDirectoryPage.
3252 *
3253 * Next pages:
3254 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3255 * QuitPage
3256 *
3257 * RETURNS
3258 * Number of the next page.
3259 */
3260 static PAGE_NUMBER
3261 InstallDirectoryPage(PINPUT_RECORD Ir)
3262 {
3263 PDISKENTRY DiskEntry;
3264 PPARTENTRY PartEntry;
3265 WCHAR InstallDir[51];
3266 WCHAR c;
3267 ULONG Length, Pos;
3268
3269 /* We do not need the filesystem list any more */
3270 if (FileSystemList != NULL)
3271 {
3272 DestroyFileSystemList(FileSystemList);
3273 FileSystemList = NULL;
3274 }
3275
3276 if (PartitionList == NULL ||
3277 PartitionList->CurrentDisk == NULL ||
3278 PartitionList->CurrentPartition == NULL)
3279 {
3280 /* FIXME: show an error dialog */
3281 return QUIT_PAGE;
3282 }
3283
3284 DiskEntry = PartitionList->CurrentDisk;
3285 PartEntry = PartitionList->CurrentPartition;
3286
3287 if (IsUnattendedSetup)
3288 {
3289 if (!IsValidPath(UnattendInstallationDirectory))
3290 {
3291 /* FIXME: Log the error? */
3292 return QUIT_PAGE;
3293 }
3294
3295 BuildInstallPaths(UnattendInstallationDirectory,
3296 DiskEntry,
3297 PartEntry);
3298
3299 return PREPARE_COPY_PAGE;
3300 }
3301
3302 wcscpy(InstallDir, L"\\ReactOS");
3303
3304 Length = wcslen(InstallDir);
3305 Pos = Length;
3306 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3307 CONSOLE_SetCursorXY(8 + Pos, 11);
3308 CONSOLE_SetCursorType(TRUE, TRUE);
3309 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3310
3311 while (TRUE)
3312 {
3313 CONSOLE_ConInKey(Ir);
3314
3315 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3316 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3317 {
3318 CONSOLE_SetCursorType(TRUE, FALSE);
3319
3320 if (ConfirmQuit(Ir) != FALSE)
3321 return QUIT_PAGE;
3322
3323 CONSOLE_SetCursorType(TRUE, TRUE);
3324 break;
3325 }
3326 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3327 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3328 {
3329 if (Pos < Length)
3330 {
3331 memmove(&InstallDir[Pos],
3332 &InstallDir[Pos + 1],
3333 (Length - Pos - 1) * sizeof(WCHAR));
3334 InstallDir[Length - 1] = UNICODE_NULL;
3335
3336 Length--;
3337 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3338 CONSOLE_SetCursorXY(8 + Pos, 11);
3339 }
3340 }
3341 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3342 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3343 {
3344 Pos = 0;
3345 CONSOLE_SetCursorXY(8 + Pos, 11);
3346 }
3347 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3348 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3349 {
3350 Pos = Length;
3351 CONSOLE_SetCursorXY(8 + Pos, 11);
3352 }
3353 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3354 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3355 {
3356 if (Pos > 0)
3357 {
3358 Pos--;
3359 CONSOLE_SetCursorXY(8 + Pos, 11);
3360 }
3361 }
3362 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3363 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3364 {
3365 if (Pos < Length)
3366 {
3367 Pos++;
3368 CONSOLE_SetCursorXY(8 + Pos, 11);
3369 }
3370 }
3371 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3372 {
3373 CONSOLE_SetCursorType(TRUE, FALSE);
3374
3375 /*
3376 * Check for the validity of the installation directory and pop up
3377 * an error if it is not the case. Then the user can fix its input.
3378 */
3379 if (!IsValidPath(InstallDir))
3380 {
3381 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3382 return INSTALL_DIRECTORY_PAGE;
3383 }
3384
3385 BuildInstallPaths(InstallDir,
3386 DiskEntry,
3387 PartEntry);
3388
3389 return PREPARE_COPY_PAGE;
3390 }
3391 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3392 {
3393 if (Pos > 0)
3394 {
3395 if (Pos < Length)
3396 memmove(&InstallDir[Pos - 1],
3397 &InstallDir[Pos],
3398 (Length - Pos) * sizeof(WCHAR));
3399 InstallDir[Length - 1] = UNICODE_NULL;
3400
3401 Pos--;
3402 Length--;
3403 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3404 CONSOLE_SetCursorXY(8 + Pos, 11);
3405 }
3406 }
3407 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3408 {
3409 if (Length < 50)
3410 {