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