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