[USETUP] Moving around some code.
[reactos.git] / base / setup / usetup / usetup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 #include <usetup.h>
29 #include <math.h>
30
31 #include "bootsup.h"
32 #include "chkdsk.h"
33 #include "cmdcons.h"
34 #include "format.h"
35 #include "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 != INVALID_HANDLE_VALUE)
942 {
943 NtResumeThread(hPnpThread, NULL);
944 hPnpThread = INVALID_HANDLE_VALUE;
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 + 524288) / 1048576; /* 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 >= 10737418240) /* 10 GB */
2219 {
2220 DiskSize = DiskSize / 1073741824;
2221 Unit = MUIGetString(STRING_GB);
2222 }
2223 else
2224 #endif
2225 {
2226 DiskSize = DiskSize / 1048576;
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 / 1048576);
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) / 1048576; /* 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 * 1048576 / 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 >= 10737418240) /* 10 GB */
2378 {
2379 DiskSize = DiskSize / 1073741824;
2380 Unit = MUIGetString(STRING_GB);
2381 }
2382 else
2383 #endif
2384 {
2385 DiskSize = DiskSize / 1048576;
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 / 1048576);
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) / 1048576; /* 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 * 1048576 / 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 >= 10737418240) /* 10 GB */
2536 {
2537 DiskSize = DiskSize / 1073741824;
2538 Unit = MUIGetString(STRING_GB);
2539 }
2540 else
2541 #endif
2542 {
2543 DiskSize = DiskSize / 1048576;
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 / 1048576);
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) / 1048576; /* 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 * 1048576 / 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 >= 10737418240) /* 10 GB */
2734 {
2735 PartSize = PartSize / 1073741824;
2736 Unit = MUIGetString(STRING_GB);
2737 }
2738 else
2739 #endif
2740 if (PartSize >= 10485760) /* 10 MB */
2741 {
2742 PartSize = PartSize / 1048576;
2743 Unit = MUIGetString(STRING_MB);
2744 }
2745 else
2746 {
2747 PartSize = PartSize / 1024;
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 >= 10737418240) /* 10 GB */
2775 {
2776 DiskSize = DiskSize / 1073741824;
2777 Unit = MUIGetString(STRING_GB);
2778 }
2779 else
2780 #endif
2781 {
2782 DiskSize = DiskSize / 1048576;
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 >= 10737418240) /* 10 GB */
2984 {
2985 DiskSize = DiskSize / 1073741824;
2986 DiskUnit = MUIGetString(STRING_GB);
2987 }
2988 else
2989 {
2990 DiskSize = DiskSize / 1048576;
2991 DiskUnit = MUIGetString(STRING_MB);
2992 }
2993
2994 /* Adjust partition size */
2995 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2996 if (PartSize >= 10737418240) /* 10 GB */
2997 {
2998 PartSize = PartSize / 1073741824;
2999 PartUnit = MUIGetString(STRING_GB);
3000 }
3001 else
3002 {
3003 PartSize = PartSize / 1048576;
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 break;
3722 }
3723
3724 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3725 {
3726 /* FIXME: Handle error! */
3727 DPRINT1("INF_GetData() failed\n");
3728 break;
3729 }
3730
3731 if (!SetupQueueCopy(SetupFileQueue,
3732 SourceCabinet,
3733 SourceRootPath.Buffer,
3734 SourceRootDir.Buffer,
3735 FileKeyName,
3736 DirKeyValue,
3737 TargetFileName))
3738 {
3739 /* FIXME: Handle error! */
3740 DPRINT1("SetupQueueCopy() failed\n");
3741 }
3742 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3743
3744 return TRUE;
3745 }
3746
3747
3748 static BOOLEAN
3749 AddSectionToCopyQueue(HINF InfFile,
3750 PWCHAR SectionName,
3751 PWCHAR SourceCabinet,
3752 PCUNICODE_STRING DestinationPath,
3753 PINPUT_RECORD Ir)
3754 {
3755 INFCONTEXT FilesContext;
3756 INFCONTEXT DirContext;
3757 PWCHAR FileKeyName;
3758 PWCHAR FileKeyValue;
3759 PWCHAR DirKeyValue;
3760 PWCHAR TargetFileName;
3761 WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
3762
3763 if (SourceCabinet)
3764 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3765
3766 /*
3767 * This code enumerates the list of files in txtsetup.sif
3768 * that need to be installed in their respective directories.
3769 */
3770
3771 /* Search for the SectionName section */
3772 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3773 {
3774 CHAR Buffer[128];
3775 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3776 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3777 return FALSE;
3778 }
3779
3780 /*
3781 * Enumerate the files in the section and add them to the file queue.
3782 */
3783 do
3784 {
3785 /* Get source file name and target directory id */
3786 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3787 {
3788 /* FIXME: Handle error! */
3789 DPRINT1("INF_GetData() failed\n");
3790 break;
3791 }
3792
3793 /* Get target directory id */
3794 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3795 {
3796 /* FIXME: Handle error! */
3797 DPRINT1("INF_GetData() failed\n");
3798 break;
3799 }
3800
3801 /* Get optional target file name */
3802 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3803 TargetFileName = NULL;
3804 else if (!*TargetFileName)
3805 TargetFileName = NULL;
3806
3807 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3808
3809 /* Lookup target directory */
3810 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3811 {
3812 /* FIXME: Handle error! */
3813 DPRINT1("SetupFindFirstLine() failed\n");
3814 break;
3815 }
3816
3817 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3818 {
3819 /* FIXME: Handle error! */
3820 DPRINT1("INF_GetData() failed\n");
3821 break;
3822 }
3823
3824 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3825 {
3826 /* Installation path */
3827 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3828
3829 StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3830 SourceRootDir.Buffer);
3831
3832 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
3833 }
3834 else if (DirKeyValue[0] == L'\\')
3835 {
3836 /* Absolute path */
3837 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3838
3839 StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3840 DirKeyValue);
3841
3842 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
3843 }
3844 else // if (DirKeyValue[0] != L'\\')
3845 {
3846 /* Path relative to the installation path */
3847 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3848
3849 CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
3850 SourceRootDir.Buffer, DirKeyValue);
3851
3852 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
3853 }
3854
3855 if (!SetupQueueCopy(SetupFileQueue,
3856 SourceCabinet,
3857 SourceRootPath.Buffer,
3858 CompleteOrigDirName,
3859 FileKeyName,
3860 DirKeyValue,
3861 TargetFileName))
3862 {
3863 /* FIXME: Handle error! */
3864 DPRINT1("SetupQueueCopy() failed\n");
3865 }
3866 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3867
3868 return TRUE;
3869 }
3870
3871
3872 static BOOLEAN
3873 PrepareCopyPageInfFile(HINF InfFile,
3874 PWCHAR SourceCabinet,
3875 PINPUT_RECORD Ir)
3876 {
3877 NTSTATUS Status;
3878 INFCONTEXT DirContext;
3879 PWCHAR AdditionalSectionName = NULL;
3880 PWCHAR DirKeyValue;
3881 WCHAR PathBuffer[MAX_PATH];
3882
3883 /* Add common files */
3884 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
3885 return FALSE;
3886
3887 /* Add specific files depending of computer type */
3888 if (SourceCabinet == NULL)
3889 {
3890 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3891 return FALSE;
3892
3893 if (AdditionalSectionName)
3894 {
3895 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
3896 return FALSE;
3897 }
3898 }
3899
3900 /* Create directories */
3901
3902 /*
3903 * FIXME:
3904 * Copying files to DestinationRootPath should be done from within
3905 * the SystemPartitionFiles section.
3906 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3907 * For installing to DestinationPath specify just '\' .
3908 */
3909
3910 /* Get destination path */
3911 StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), DestinationPath.Buffer);
3912
3913 DPRINT("FullPath(1): '%S'\n", PathBuffer);
3914
3915 /* Create the install directory */
3916 Status = SetupCreateDirectory(PathBuffer);
3917 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3918 {
3919 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
3920 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3921 return FALSE;
3922 }
3923
3924 /* Search for the 'Directories' section */
3925 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3926 {
3927 if (SourceCabinet)
3928 {
3929 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3930 }
3931 else
3932 {
3933 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3934 }
3935
3936 return FALSE;
3937 }
3938
3939 /* Enumerate the directory values and create the subdirectories */
3940 do
3941 {
3942 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3943 {
3944 DPRINT1("break\n");
3945 break;
3946 }
3947
3948 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3949 {
3950 /* Installation path */
3951 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3952
3953 StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
3954 DestinationPath.Buffer);
3955
3956 DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
3957 }
3958 else if (DirKeyValue[0] == L'\\')
3959 {
3960 /* Absolute path */
3961 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3962
3963 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3964 DestinationRootPath.Buffer, DirKeyValue);
3965
3966 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
3967
3968 Status = SetupCreateDirectory(PathBuffer);
3969 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3970 {
3971 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3972 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3973 return FALSE;
3974 }
3975 }
3976 else // if (DirKeyValue[0] != L'\\')
3977 {
3978 /* Path relative to the installation path */
3979 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3980
3981 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3982 DestinationPath.Buffer, DirKeyValue);
3983
3984 DPRINT("RelativePath(2): '%S'\n", PathBuffer);
3985
3986 Status = SetupCreateDirectory(PathBuffer);
3987 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3988 {
3989 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3990 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3991 return FALSE;
3992 }
3993 }
3994 } while (SetupFindNextLine(&DirContext, &DirContext));
3995
3996 return TRUE;
3997 }
3998
3999
4000 /*
4001 * Displays the PrepareCopyPage.
4002 *
4003 * Next pages:
4004 * FileCopyPage(At once)
4005 * QuitPage
4006 *
4007 * SIDEEFFECTS
4008 * Inits SetupFileQueue
4009 * Calls PrepareCopyPageInfFile
4010 *
4011 * RETURNS
4012 * Number of the next page.
4013 */
4014 static PAGE_NUMBER
4015 PrepareCopyPage(PINPUT_RECORD Ir)
4016 {
4017 HINF InfHandle;
4018 WCHAR PathBuffer[MAX_PATH];
4019 INFCONTEXT CabinetsContext;
4020 ULONG InfFileSize;
4021 PWCHAR KeyValue;
4022 UINT ErrorLine;
4023 PVOID InfFileData;
4024
4025 MUIDisplayPage(PREPARE_COPY_PAGE);
4026
4027 /* Create the file queue */
4028 SetupFileQueue = SetupOpenFileQueue();
4029 if (SetupFileQueue == NULL)
4030 {
4031 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
4032 return QUIT_PAGE;
4033 }
4034
4035 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
4036 {
4037 /* FIXME: show an error dialog */
4038 return QUIT_PAGE;
4039 }
4040
4041 /* Search for the 'Cabinets' section */
4042 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
4043 {
4044 return FILE_COPY_PAGE;
4045 }
4046
4047 /*
4048 * Enumerate the directory values in the 'Cabinets'
4049 * section and parse their inf files.
4050 */
4051 do
4052 {
4053 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
4054 break;
4055
4056 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
4057 SourcePath.Buffer, KeyValue);
4058
4059 CabinetInitialize();
4060 CabinetSetEventHandlers(NULL, NULL, NULL);
4061 CabinetSetCabinetName(PathBuffer);
4062
4063 if (CabinetOpen() == CAB_STATUS_SUCCESS)
4064 {
4065 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
4066
4067 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
4068 if (InfFileData == NULL)
4069 {
4070 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
4071 return QUIT_PAGE;
4072 }
4073 }
4074 else
4075 {
4076 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
4077 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
4078 return QUIT_PAGE;
4079 }
4080
4081 InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
4082 InfFileSize,
4083 (const CHAR*) NULL,
4084 INF_STYLE_WIN4,
4085 LanguageId,
4086 &ErrorLine);
4087
4088 if (InfHandle == INVALID_HANDLE_VALUE)
4089 {
4090 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
4091 return QUIT_PAGE;
4092 }
4093
4094 CabinetCleanup();
4095
4096 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
4097 {
4098 /* FIXME: show an error dialog */
4099 return QUIT_PAGE;
4100 }
4101 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
4102
4103 return FILE_COPY_PAGE;
4104 }
4105
4106
4107 VOID
4108 NTAPI
4109 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
4110 IN BOOLEAN First)
4111 {
4112 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
4113
4114 /* Get the memory information from the system */
4115 NtQuerySystemInformation(SystemPerformanceInformation,
4116 &PerfInfo,
4117 sizeof(PerfInfo),
4118 NULL);
4119
4120 /* Check if this is initial setup */
4121 if (First)
4122 {
4123 /* Set maximum limits to be total RAM pages */
4124 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
4125 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
4126 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
4127 }
4128
4129 /* Set current values */
4130 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
4131 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
4132 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
4133 }
4134
4135
4136 static UINT
4137 CALLBACK
4138 FileCopyCallback(PVOID Context,
4139 UINT Notification,
4140 UINT_PTR Param1,
4141 UINT_PTR Param2)
4142 {
4143 PCOPYCONTEXT CopyContext;
4144
4145 CopyContext = (PCOPYCONTEXT)Context;
4146
4147 switch (Notification)
4148 {
4149 case SPFILENOTIFY_STARTSUBQUEUE:
4150 CopyContext->TotalOperations = (ULONG)Param2;
4151 ProgressSetStepCount(CopyContext->ProgressBar,
4152 CopyContext->TotalOperations);
4153 SetupUpdateMemoryInfo(CopyContext, TRUE);
4154 break;
4155
4156 case SPFILENOTIFY_STARTCOPY:
4157 /* Display copy message */
4158 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
4159 SetupUpdateMemoryInfo(CopyContext, FALSE);
4160 break;
4161
4162 case SPFILENOTIFY_ENDCOPY:
4163 CopyContext->CompletedOperations++;
4164
4165 /* SYSREG checkpoint */
4166 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
4167 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4168
4169 ProgressNextStep(CopyContext->ProgressBar);
4170 SetupUpdateMemoryInfo(CopyContext, FALSE);
4171 break;
4172 }
4173
4174 return 0;
4175 }
4176
4177
4178 /*
4179 * Displays the FileCopyPage.
4180 *
4181 * Next pages:
4182 * RegistryPage(At once)
4183 *
4184 * SIDEEFFECTS
4185 * Calls SetupCommitFileQueueW
4186 * Calls SetupCloseFileQueue
4187 *
4188 * RETURNS
4189 * Number of the next page.
4190 */
4191 static PAGE_NUMBER
4192 FileCopyPage(PINPUT_RECORD Ir)
4193 {
4194 COPYCONTEXT CopyContext;
4195 unsigned int mem_bar_width;
4196
4197 MUIDisplayPage(FILE_COPY_PAGE);
4198
4199 /* Create context for the copy process */
4200 CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
4201 CopyContext.InstallPath = InstallPath.Buffer;
4202 CopyContext.TotalOperations = 0;
4203 CopyContext.CompletedOperations = 0;
4204
4205 /* Create the progress bar as well */
4206 CopyContext.ProgressBar = CreateProgressBar(13,
4207 26,
4208 xScreen - 13,
4209 yScreen - 20,
4210 10,
4211 24,
4212 TRUE,
4213 MUIGetString(STRING_SETUPCOPYINGFILES));
4214
4215 // fit memory bars to screen width, distribute them uniform
4216 mem_bar_width = (xScreen - 26) / 5;
4217 mem_bar_width -= mem_bar_width % 2; // make even
4218 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4219 /* Create the paged pool progress bar */
4220 CopyContext.MemoryBars[0] = CreateProgressBar(13,
4221 40,
4222 13 + mem_bar_width,
4223 43,
4224 13,
4225 44,
4226 FALSE,
4227 "Kernel Pool");
4228
4229 /* Create the non paged pool progress bar */
4230 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
4231 40,
4232 (xScreen / 2) + (mem_bar_width / 2),
4233 43,
4234 (xScreen / 2)- (mem_bar_width / 2),
4235 44,
4236 FALSE,
4237 "Kernel Cache");
4238
4239 /* Create the global memory progress bar */
4240 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
4241 40,
4242 xScreen - 13,
4243 43,
4244 xScreen - 13 - mem_bar_width,
4245 44,
4246 FALSE,
4247 "Free Memory");
4248
4249 /* Do the file copying */
4250 SetupCommitFileQueueW(NULL,
4251 SetupFileQueue,
4252 FileCopyCallback,
4253 &CopyContext);
4254
4255 /* If we get here, we're done, so cleanup the queue and progress bar */
4256 SetupCloseFileQueue(SetupFileQueue);
4257 DestroyProgressBar(CopyContext.ProgressBar);
4258 DestroyProgressBar(CopyContext.MemoryBars[0]);
4259 DestroyProgressBar(CopyContext.MemoryBars[1]);
4260 DestroyProgressBar(CopyContext.MemoryBars[2]);
4261
4262 /* Go display the next page */
4263 return REGISTRY_PAGE;
4264 }
4265
4266
4267 /*
4268 * Displays the RegistryPage.
4269 *
4270 * Next pages:
4271 * SuccessPage (if RepairUpdate)
4272 * BootLoaderPage (default)
4273 * QuitPage
4274 *
4275 * SIDEEFFECTS
4276 * Calls RegInitializeRegistry
4277 * Calls ImportRegistryFile
4278 * Calls SetDefaultPagefile
4279 * Calls SetMountedDeviceValues
4280 *
4281 * RETURNS
4282 * Number of the next page.
4283 */
4284 static PAGE_NUMBER
4285 RegistryPage(PINPUT_RECORD Ir)
4286 {
4287 NTSTATUS Status;
4288 INFCONTEXT InfContext;
4289 PWSTR Action;
4290 PWSTR File;
4291 PWSTR Section;
4292 BOOLEAN Success;
4293 BOOLEAN ShouldRepairRegistry = FALSE;
4294 BOOLEAN Delete;
4295
4296 MUIDisplayPage(REGISTRY_PAGE);
4297
4298 if (RepairUpdateFlag)
4299 {
4300 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
4301
4302 /* Verify the registry hives and check whether we need to update or repair any of them */
4303 Status = VerifyRegistryHives(&DestinationPath, &ShouldRepairRegistry);
4304 if (!NT_SUCCESS(Status))
4305 {
4306 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
4307 ShouldRepairRegistry = FALSE;
4308 }
4309 if (!ShouldRepairRegistry)
4310 DPRINT1("No need to repair the registry\n");
4311 }
4312
4313 DoUpdate:
4314 /* Update the registry */
4315 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
4316
4317 /* Initialize the registry and setup the registry hives */
4318 Status = RegInitializeRegistry(&DestinationPath);
4319 if (!NT_SUCCESS(Status))
4320 {
4321 DPRINT1("RegInitializeRegistry() failed\n");
4322 /********** HACK!!!!!!!!!!! **********/
4323 if (Status == STATUS_NOT_IMPLEMENTED)
4324 {
4325 /* The hack was called, display its corresponding error */
4326 MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
4327 }
4328 else
4329 /*************************************/
4330 {
4331 /* Something else failed */
4332 MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
4333 }
4334 return QUIT_PAGE;
4335 }
4336
4337 if (!RepairUpdateFlag || ShouldRepairRegistry)
4338 {
4339 /*
4340 * We fully setup the hives, in case we are doing a fresh installation
4341 * (RepairUpdateFlag == FALSE), or in case we are doing an update
4342 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
4343 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
4344 */
4345
4346 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible
4347 if (!Success)
4348 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
4349
4350 if (!Success)
4351 {
4352 DPRINT1("SetupFindFirstLine() failed\n");
4353 MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
4354 goto Cleanup;
4355 }
4356 }
4357 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
4358 {
4359 /*
4360 * In case we are doing an update (RepairUpdateFlag == TRUE) and
4361 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
4362 * we only update the hives.
4363 */
4364
4365 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
4366 if (!Success)
4367 {
4368 /* Nothing to do for update! */
4369 DPRINT1("No update needed for the registry!\n");
4370 goto Cleanup;
4371 }
4372 }
4373
4374 do
4375 {
4376 INF_GetDataField(&InfContext, 0, &Action);
4377 INF_GetDataField(&InfContext, 1, &File);
4378 INF_GetDataField(&InfContext, 2, &Section);
4379
4380 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section);
4381
4382 if (Action == NULL)
4383 break; // Hackfix
4384
4385 if (!_wcsicmp(Action, L"AddReg"))
4386 Delete = FALSE;
4387 else if (!_wcsicmp(Action, L"DelReg"))
4388 Delete = TRUE;
4389 else
4390 {
4391 DPRINT1("Unrecognized registry INF action '%S'\n", Action);
4392 continue;
4393 }
4394
4395 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
4396
4397 if (!ImportRegistryFile(SourcePath.Buffer, File, Section, LanguageId, Delete))
4398 {
4399 DPRINT1("Importing %S failed\n", File);
4400 MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
4401 goto Cleanup;
4402 }
4403 } while (SetupFindNextLine(&InfContext, &InfContext));
4404
4405 if (!RepairUpdateFlag || ShouldRepairRegistry)
4406 {
4407 /* See the explanation for this test above */
4408
4409 /* Update display registry settings */
4410 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
4411 if (!ProcessDisplayRegistry(SetupInf, DisplayList))
4412 {
4413 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
4414 goto Cleanup;
4415 }
4416
4417 /* Set the locale */
4418 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
4419 if (!ProcessLocaleRegistry(LanguageList))
4420 {
4421 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
4422 goto Cleanup;
4423 }
4424
4425 /* Add keyboard layouts */
4426 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
4427 if (!AddKeyboardLayouts())
4428 {
4429 MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
4430 goto Cleanup;
4431 }
4432
4433 /* Set GeoID */
4434 if (!SetGeoID(MUIGetGeoID()))
4435 {
4436 MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
4437 goto Cleanup;
4438 }
4439
4440 if (!IsUnattendedSetup)
4441 {
4442 /* Update keyboard layout settings */
4443 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
4444 if (!ProcessKeyboardLayoutRegistry(LayoutList))
4445 {
4446 MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
4447 goto Cleanup;
4448 }
4449 }
4450
4451 /* Add codepage information to registry */
4452 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
4453 if (!AddCodePage())
4454 {
4455 MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
4456 goto Cleanup;
4457 }
4458
4459 /* Set the default pagefile entry */
4460 SetDefaultPagefile(DestinationDriveLetter);
4461
4462 /* Update the mounted devices list */
4463 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
4464 SetMountedDeviceValues(PartitionList);
4465 }
4466
4467 Cleanup:
4468 //
4469 // TODO: Unload all the registry stuff, perform cleanup,
4470 // and copy the created hive files into .sav files.
4471 //
4472 RegCleanupRegistry(&DestinationPath);
4473
4474 /*
4475 * Check whether we were in update/repair mode but we were actually
4476 * repairing the registry hives. If so, we have finished repairing them,
4477 * and we now reset the flag and run the proper registry update.
4478 * Otherwise we have finished the registry update!
4479 */
4480 if (RepairUpdateFlag && ShouldRepairRegistry)
4481 {
4482 ShouldRepairRegistry = FALSE;
4483 goto DoUpdate;
4484 }
4485
4486 if (NT_SUCCESS(Status))
4487 {
4488 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
4489 return BOOT_LOADER_PAGE;
4490 }
4491 else
4492 {
4493 return QUIT_PAGE;
4494 }
4495 }
4496
4497
4498 /*
4499 * Displays the BootLoaderPage.
4500 *
4501 * Next pages:
4502 * SuccessPage (if RepairUpdate)
4503 * BootLoaderHarddiskMbrPage
4504 * BootLoaderHarddiskVbrPage
4505 * BootLoaderFloppyPage
4506 * SuccessPage
4507 * QuitPage
4508 *
4509 * SIDEEFFECTS
4510 * Calls RegInitializeRegistry
4511 * Calls ImportRegistryFile
4512 * Calls SetDefaultPagefile
4513 * Calls SetMountedDeviceValues
4514 *
4515 * RETURNS
4516 * Number of the next page.
4517 */
4518 static PAGE_NUMBER
4519 BootLoaderPage(PINPUT_RECORD Ir)
4520 {
4521 UCHAR PartitionType;
4522 BOOLEAN InstallOnFloppy;
4523 USHORT Line = 12;
4524 WCHAR PathBuffer[MAX_PATH];
4525
4526 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4527
4528 RtlFreeUnicodeString(&SystemRootPath);
4529 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
4530 L"\\Device\\Harddisk%lu\\Partition%lu\\",
4531 PartitionList->SystemPartition->DiskEntry->DiskNumber,
4532 PartitionList->SystemPartition->PartitionNumber);
4533 RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
4534 DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath);
4535
4536 PartitionType = PartitionList->SystemPartition->PartitionType;
4537
4538 if (IsUnattendedSetup)
4539 {
4540 if (UnattendMBRInstallType == 0) /* skip MBR installation */
4541 {
4542 return SUCCESS_PAGE;
4543 }
4544 else if (UnattendMBRInstallType == 1) /* install on floppy */
4545 {
4546 return BOOT_LOADER_FLOPPY_PAGE;
4547 }
4548 }
4549
4550 if (PartitionType == PARTITION_ENTRY_UNUSED)
4551 {
4552 DPRINT("Error: system partition invalid (unused)\n");
4553 InstallOnFloppy = TRUE;
4554 }
4555 else if (PartitionType == PARTITION_OS2BOOTMGR)
4556 {
4557 /* OS/2 boot manager partition */
4558 DPRINT("Found OS/2 boot manager partition\n");
4559 InstallOnFloppy = TRUE;
4560 }
4561 else if (PartitionType == PARTITION_EXT2)
4562 {
4563 /* Linux EXT2 partition */
4564 DPRINT("Found Linux EXT2 partition\n");
4565 InstallOnFloppy = FALSE;
4566 }
4567 else if (PartitionType == PARTITION_IFS)
4568 {
4569 /* NTFS partition */
4570 DPRINT("Found NTFS partition\n");
4571
4572 // FIXME: Make it FALSE when we'll support NTFS installation!
4573 InstallOnFloppy = TRUE;
4574 }
4575 else if ((PartitionType == PARTITION_FAT_12) ||
4576 (PartitionType == PARTITION_FAT_16) ||
4577 (PartitionType == PARTITION_HUGE) ||
4578 (PartitionType == PARTITION_XINT13) ||
4579 (PartitionType == PARTITION_FAT32) ||
4580 (PartitionType == PARTITION_FAT32_XINT13))
4581 {
4582 DPRINT("Found FAT partition\n");
4583 InstallOnFloppy = FALSE;
4584 }
4585 else
4586 {
4587 /* Unknown partition */
4588 DPRINT("Unknown partition found\n");
4589 InstallOnFloppy = TRUE;
4590 }
4591
4592 if (InstallOnFloppy != FALSE)
4593 {
4594 return BOOT_LOADER_FLOPPY_PAGE;
4595 }
4596
4597 /* Unattended install on hdd? */
4598 if (IsUnattendedSetup && UnattendMBRInstallType == 2)
4599 {
4600 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4601 }
4602
4603 MUIDisplayPage(BOOT_LOADER_PAGE);
4604 CONSOLE_InvertTextXY(8, Line, 60, 1);
4605
4606 while (TRUE)
4607 {
4608 CONSOLE_ConInKey(Ir);
4609
4610 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4611 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4612 {
4613 CONSOLE_NormalTextXY(8, Line, 60, 1);
4614
4615 Line++;
4616 if (Line<12)
4617 Line=15;
4618
4619 if (Line>15)
4620 Line=12;
4621
4622 CONSOLE_InvertTextXY(8, Line, 60, 1);
4623 }
4624 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4625 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4626 {
4627 CONSOLE_NormalTextXY(8, Line, 60, 1);
4628
4629 Line--;
4630 if (Line<12)
4631 Line=15;
4632
4633 if (Line>15)
4634 Line=12;
4635
4636 CONSOLE_InvertTextXY(8, Line, 60, 1);
4637 }
4638 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4639 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4640 {
4641 if (ConfirmQuit(Ir) != FALSE)
4642 return QUIT_PAGE;
4643
4644 break;
4645 }
4646 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4647 {
4648 if (Line == 12)
4649 {
4650 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4651 }
4652 else if (Line == 13)
4653 {
4654 return BOOT_LOADER_HARDDISK_VBR_PAGE;
4655 }
4656 else if (Line == 14)
4657 {
4658 return BOOT_LOADER_FLOPPY_PAGE;
4659 }
4660 else if (Line == 15)
4661 {
4662 return SUCCESS_PAGE;
4663 }
4664
4665 return BOOT_LOADER_PAGE;
4666 }
4667 }
4668
4669 return BOOT_LOADER_PAGE;
4670 }
4671
4672
4673 /*
4674 * Displays the BootLoaderFloppyPage.
4675 *
4676 * Next pages:
4677 * SuccessPage (At once)
4678 * QuitPage
4679 *
4680 * SIDEEFFECTS
4681 * Calls InstallFatBootcodeToFloppy()
4682 *
4683 * RETURNS
4684 * Number of the next page.
4685 */
4686 static PAGE_NUMBER
4687 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4688 {
4689 NTSTATUS Status;
4690
4691 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4692
4693 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4694
4695 while (TRUE)
4696 {
4697 CONSOLE_ConInKey(Ir);
4698
4699 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4700 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4701 {
4702 if (ConfirmQuit(Ir) != FALSE)
4703 return QUIT_PAGE;
4704
4705 break;
4706 }
4707 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4708 {
4709 if (DoesPathExist(NULL, L"\\Device\\Floppy0\\") == FALSE)
4710 {
4711 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4712 return BOOT_LOADER_FLOPPY_PAGE;
4713 }
4714
4715 Status = InstallFatBootcodeToFloppy(&SourceRootPath, &DestinationArcPath);
4716 if (!NT_SUCCESS(Status))
4717 {
4718 /* Print error message */
4719 return BOOT_LOADER_FLOPPY_PAGE;
4720 }
4721
4722 return SUCCESS_PAGE;
4723 }
4724 }
4725
4726 return BOOT_LOADER_FLOPPY_PAGE;
4727 }
4728
4729
4730 /*
4731 * Displays the BootLoaderHarddiskVbrPage.
4732 *
4733 * Next pages:
4734 * SuccessPage (At once)
4735 * QuitPage
4736 *
4737 * SIDEEFFECTS
4738 * Calls InstallVBRToPartition()
4739 *
4740 * RETURNS
4741 * Number of the next page.
4742 */
4743 static PAGE_NUMBER
4744 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
4745 {
4746 NTSTATUS Status;
4747
4748 Status = InstallVBRToPartition(&SystemRootPath,
4749 &SourceRootPath,
4750 &DestinationArcPath,
4751 PartitionList->SystemPartition->PartitionType);
4752 if (!NT_SUCCESS(Status))
4753 {
4754 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4755 return QUIT_PAGE;
4756 }
4757
4758 return SUCCESS_PAGE;
4759 }
4760
4761
4762 /*
4763 * Displays the BootLoaderHarddiskMbrPage.
4764 *
4765 * Next pages:
4766 * SuccessPage (At once)
4767 * QuitPage
4768 *
4769 * SIDEEFFECTS
4770 * Calls InstallVBRToPartition()
4771 * Calls InstallMbrBootCodeToDisk()
4772 *
4773 * RETURNS
4774 * Number of the next page.
4775 */
4776 static PAGE_NUMBER
4777 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
4778 {
4779 NTSTATUS Status;
4780 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4781 WCHAR SourceMbrPathBuffer[MAX_PATH];
4782 WCHAR DstPath[MAX_PATH];
4783
4784 /* Step 1: Write the VBR */
4785 Status = InstallVBRToPartition(&SystemRootPath,
4786 &SourceRootPath,
4787 &DestinationArcPath,
4788 PartitionList->SystemPartition->PartitionType);
4789 if (!NT_SUCCESS(Status))
4790 {
4791 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4792 return QUIT_PAGE;
4793 }
4794
4795 /* Step 2: Write the MBR */
4796 StringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4797 L"\\Device\\Harddisk%d\\Partition0",
4798 PartitionList->SystemPartition->DiskEntry->DiskNumber);
4799
4800 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
4801
4802 if (IsThereAValidBootSector(DestinationDevicePathBuffer))
4803 {
4804 /* Save current MBR */
4805 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath.Buffer, L"mbr.old");
4806
4807 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
4808 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
4809 if (!NT_SUCCESS(Status))
4810 {
4811 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
4812 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4813 }
4814 }
4815
4816 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4817 SourceMbrPathBuffer, DestinationDevicePathBuffer);
4818 Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
4819 DestinationDevicePathBuffer);
4820 if (!NT_SUCCESS(Status))
4821 {
4822 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4823 Status);
4824 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
4825 return QUIT_PAGE;
4826 }
4827
4828 return SUCCESS_PAGE;
4829 }
4830
4831
4832 /**
4833 * @name ProgressTimeOutStringHandler
4834 *
4835 * Handles the generation (displaying) of the timeout
4836 * countdown to the screen dynamically.
4837 *
4838 * @param Bar
4839 * A pointer to a progress bar.
4840 *
4841 * @param AlwaysUpdate
4842 * Constantly update the progress bar (boolean type).
4843 *
4844 * @param Buffer
4845 * A pointer to a string buffer.
4846 *
4847 * @param cchBufferSize
4848 * The buffer's size in number of characters.
4849 *
4850 * @return
4851 * TRUE or FALSE on function termination.
4852 *
4853 */
4854 static
4855 BOOLEAN NTAPI
4856 ProgressTimeOutStringHandler(
4857 IN PPROGRESSBAR Bar,
4858 IN BOOLEAN AlwaysUpdate,
4859 OUT PSTR Buffer,
4860 IN SIZE_T cchBufferSize)
4861 {
4862 ULONG OldProgress = Bar->Progress;
4863
4864 if (Bar->StepCount == 0)
4865 {
4866 Bar->Progress = 0;
4867 }
4868 else
4869 {
4870 Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4871 }
4872
4873 /* Build the progress string if it has changed */
4874 if (Bar->ProgressFormatText &&
4875 (AlwaysUpdate || (Bar->Progress != OldProgress)))
4876 {
4877 RtlStringCchPrintfA(Buffer, cchBufferSize,
4878 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4879
4880 return TRUE;
4881 }
4882
4883 return FALSE;
4884 }
4885
4886 /**
4887 * @name ProgressCountdown
4888 *
4889 * Displays and draws a red-coloured progress bar with a countdown.
4890 * When the timeout is reached, the flush page is displayed for reboot.
4891 *
4892 * @param Ir
4893 * A pointer to an input keyboard record.
4894 *
4895 * @param TimeOut
4896 * Initial countdown value in seconds.
4897 *
4898 * @return
4899 * Nothing.
4900 *
4901 */
4902 static VOID
4903 ProgressCountdown(
4904 IN PINPUT_RECORD Ir,
4905 IN LONG TimeOut)
4906 {
4907 NTSTATUS Status;
4908 ULONG StartTime, BarWidth, TimerDiv;
4909 LONG TimeElapsed;
4910 LONG TimerValue, OldTimerValue;
4911 LARGE_INTEGER Timeout;
4912 PPROGRESSBAR ProgressBar;
4913 BOOLEAN RefreshProgress = TRUE;
4914
4915 /* Bail out if the timeout is already zero */
4916 if (TimeOut <= 0)
4917 return;
4918
4919 /* Create the timeout progress bar and set it up */
4920 ProgressBar = CreateProgressBarEx(13,
4921 26,
4922 xScreen - 13,
4923 yScreen - 20,
4924 10,
4925 24,
4926 TRUE,
4927 FOREGROUND_RED | BACKGROUND_BLUE,
4928 0,
4929 NULL,
4930 MUIGetString(STRING_REBOOTPROGRESSBAR),
4931 ProgressTimeOutStringHandler);
4932
4933 BarWidth = max(1, ProgressBar->Width);
4934 TimerValue = TimeOut * BarWidth;
4935 ProgressSetStepCount(ProgressBar, TimerValue);
4936
4937 StartTime = NtGetTickCount();
4938 CONSOLE_Flush();
4939
4940 TimerDiv = 1000 / BarWidth;
4941 TimerDiv = max(1, TimerDiv);
4942 OldTimerValue = TimerValue;
4943 while (TRUE)
4944 {
4945 /* Decrease the timer */
4946
4947 /*
4948 * Compute how much time the previous operations took.
4949 * This allows us in particular to take account for any time
4950 * elapsed if something slowed down.
4951 */
4952 TimeElapsed = NtGetTickCount() - StartTime;
4953 if (TimeElapsed >= TimerDiv)
4954 {
4955 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4956 TimeElapsed /= TimerDiv;
4957 StartTime += (TimerDiv * TimeElapsed);
4958
4959 if (TimeElapsed <= TimerValue)
4960 TimerValue -= TimeElapsed;
4961 else
4962 TimerValue = 0;
4963
4964 RefreshProgress = TRUE;
4965 }
4966
4967 if (RefreshProgress)
4968 {
4969 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4970 RefreshProgress = FALSE;
4971 }
4972
4973 /* Stop when the timer reaches zero */
4974 if (TimerValue <= 0)
4975 break;
4976
4977 /* Check for user key presses */
4978
4979 /*
4980 * If the timer is used, use a passive wait of maximum 1 second
4981 * while monitoring for incoming console input events, so that
4982 * we are still able to display the timing count.
4983 */
4984
4985 /* Wait a maximum of 1 second for input events */
4986 TimeElapsed = NtGetTickCount() - StartTime;
4987 if (TimeElapsed < TimerDiv)
4988 {
4989 /* Convert the time to NT Format */
4990 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4991 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
4992 }
4993 else
4994 {
4995 Status = STATUS_TIMEOUT;
4996 }
4997
4998 /* Check whether the input event has been signaled, or a timeout happened */
4999 if (Status == STATUS_TIMEOUT)
5000 {
5001 continue;
5002 }
5003 if (Status != STATUS_WAIT_0)
5004 {
5005 /* An error happened, bail out */
5006 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
5007 break;
5008 }
5009
5010 /* Check for an ENTER key press */
5011 while (CONSOLE_ConInKeyPeek(Ir))
5012 {
5013 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
5014 {
5015 /* Found it, stop waiting */
5016 goto Exit;
5017 }
5018 }
5019 }
5020
5021 Exit:
5022 /* Destroy the progress bar and quit */
5023 DestroyProgressBar(ProgressBar);
5024 }
5025
5026
5027 /*
5028 * Displays the QuitPage.
5029 *
5030 * Next pages:
5031 * FlushPage (At once)
5032 *
5033 * SIDEEFFECTS
5034 * Destroy the Lists
5035 *
5036 * RETURNS
5037 * Number of the next page.
5038 */
5039 static PAGE_NUMBER
5040 QuitPage(PINPUT_RECORD Ir)
5041 {
5042 MUIDisplayPage(QUIT_PAGE);
5043
5044 /* Destroy the NTOS installations list */
5045 if (NtOsInstallsList != NULL)
5046 {
5047 DestroyGenericList(NtOsInstallsList, TRUE);
5048 NtOsInstallsList = NULL;
5049 }
5050
5051 /* Destroy the partition list */
5052 if (PartitionList != NULL)
5053 {
5054 DestroyPartitionList(PartitionList);
5055 PartitionList = NULL;
5056 }
5057 TempPartition = NULL;
5058 FormatState = Start;
5059
5060 /* Destroy the filesystem list */
5061 if (FileSystemList != NULL)
5062 {
5063 DestroyFileSystemList(FileSystemList);
5064 FileSystemList = NULL;
5065 }
5066
5067 /* Destroy the computer settings list */
5068 if (ComputerList != NULL)
5069 {
5070 DestroyGenericList(ComputerList, TRUE);
5071 ComputerList = NULL;
5072 }
5073
5074 /* Destroy the display settings list */
5075 if (DisplayList != NULL)
5076 {
5077 DestroyGenericList(DisplayList, TRUE);
5078 DisplayList = NULL;
5079 }
5080
5081 /* Destroy the keyboard settings list */
5082 if (KeyboardList != NULL)
5083 {
5084 DestroyGenericList(KeyboardList, TRUE);
5085 KeyboardList = NULL;
5086 }
5087
5088 /* Destroy the keyboard layout list */
5089 if (LayoutList != NULL)
5090 {
5091 DestroyGenericList(LayoutList, TRUE);
5092 LayoutList = NULL;
5093 }
5094
5095 /* Destroy the languages list */
5096 if (LanguageList != NULL)
5097 {
5098 DestroyGenericList(LanguageList, FALSE);
5099 LanguageList = NULL;
5100 }
5101
5102 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
5103
5104 /* Wait for maximum 15 seconds or an ENTER key before quitting */
5105 ProgressCountdown(Ir, 15);
5106 return FLUSH_PAGE;
5107 }
5108
5109
5110 /*
5111 * Displays the SuccessPage.
5112 *
5113 * Next pages:
5114 * FlushPage (At once)
5115 *
5116 * SIDEEFFECTS
5117 * Destroy the Lists
5118 *
5119 * RETURNS
5120 * Number of the next page.
5121 */
5122 static PAGE_NUMBER
5123 SuccessPage(PINPUT_RECORD Ir)
5124 {
5125 MUIDisplayPage(SUCCESS_PAGE);
5126
5127 if (IsUnattendedSetup)
5128 return FLUSH_PAGE;
5129
5130 /* Wait for maximum 15 seconds or an ENTER key before quitting */
5131 ProgressCountdown(Ir, 15);
5132 return FLUSH_PAGE;
5133 }
5134
5135
5136 /*
5137 * Displays the FlushPage.
5138 *
5139 * Next pages:
5140 * RebootPage (At once)
5141 *
5142 * RETURNS
5143 * Number of the next page.
5144 */
5145 static PAGE_NUMBER
5146 FlushPage(PINPUT_RECORD Ir)
5147 {
5148 MUIDisplayPage(FLUSH_PAGE);
5149 return REBOOT_PAGE;
5150 }
5151
5152
5153 DWORD WINAPI
5154 PnpEventThread(IN LPVOID lpParameter);
5155
5156
5157 /*
5158 * The start routine and page management
5159 */
5160 NTSTATUS
5161 RunUSetup(VOID)
5162 {
5163 NTSTATUS Status;
5164 INPUT_RECORD Ir;
5165 PAGE_NUMBER Page;
5166 BOOLEAN Old;
5167
5168 InfSetHeap(ProcessHeap);
5169
5170 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
5171 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
5172 if (!NT_SUCCESS(Status))
5173 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
5174
5175 /* Create the PnP thread in suspended state */
5176 Status = RtlCreateUserThread(NtCurrentProcess(),
5177 NULL,
5178 TRUE,
5179 0,
5180 0,
5181 0,
5182 PnpEventThread,
5183 &SetupInf,
5184 &hPnpThread,
5185 NULL);
5186 if (!NT_SUCCESS(Status))
5187 hPnpThread = INVALID_HANDLE_VALUE;
5188
5189 if (!CONSOLE_Init())
5190 {
5191 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
5192 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
5193 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
5194
5195 /* We failed to initialize the video, just quit the installer */
5196 return STATUS_APP_INIT_FAILURE;
5197 }
5198
5199 /* Initialize global unicode strings */
5200 RtlInitUnicodeString(&SourcePath, NULL);
5201 RtlInitUnicodeString(&SourceRootPath, NULL);
5202 RtlInitUnicodeString(&SourceRootDir, NULL);
5203 RtlInitUnicodeString(&InstallPath, NULL);
5204 RtlInitUnicodeString(&DestinationPath, NULL);
5205 RtlInitUnicodeString(&DestinationArcPath, NULL);
5206 RtlInitUnicodeString(&DestinationRootPath, NULL);
5207 RtlInitUnicodeString(&SystemRootPath, NULL);
5208
5209 /* Hide the cursor */
5210 CONSOLE_SetCursorType(TRUE, FALSE);
5211
5212 /* Global Initialization page */
5213 CONSOLE_ClearScreen();
5214 CONSOLE_Flush();
5215 Page = SetupStartPage(&Ir);
5216
5217 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
5218 {
5219 CONSOLE_ClearScreen();
5220 CONSOLE_Flush();
5221
5222 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
5223 // CONSOLE_Flush();
5224
5225 switch (Page)
5226 {
5227 /* Language page */
5228 case LANGUAGE_PAGE:
5229 Page = LanguagePage(&Ir);
5230 break;
5231
5232 /* Welcome page */
5233 case WELCOME_PAGE:
5234 Page = WelcomePage(&Ir);
5235 break;
5236
5237 /* License page */
5238 case LICENSE_PAGE:
5239 Page = LicensePage(&Ir);
5240 break;
5241
5242 /* Install pages */
5243 case INSTALL_INTRO_PAGE:
5244 Page = InstallIntroPage(&Ir);
5245 break;
5246
5247 #if 0
5248 case SCSI_CONTROLLER_PAGE:
5249 Page = ScsiControllerPage(&Ir);
5250 break;
5251
5252 case OEM_DRIVER_PAGE:
5253 Page = OemDriverPage(&Ir);
5254 break;
5255 #endif
5256
5257 case DEVICE_SETTINGS_PAGE:
5258 Page = DeviceSettingsPage(&Ir);
5259 break;
5260
5261 case COMPUTER_SETTINGS_PAGE:
5262 Page = ComputerSettingsPage(&Ir);
5263 break;
5264
5265 case DISPLAY_SETTINGS_PAGE:
5266 Page = DisplaySettingsPage(&Ir);
5267 break;
5268
5269 case KEYBOARD_SETTINGS_PAGE:
5270 Page = KeyboardSettingsPage(&Ir);
5271 break;
5272
5273 case LAYOUT_SETTINGS_PAGE:
5274 Page = LayoutSettingsPage(&Ir);
5275 break;
5276
5277 case SELECT_PARTITION_PAGE:
5278 Page = SelectPartitionPage(&Ir);
5279 break;
5280
5281 case CREATE_PRIMARY_PARTITION_PAGE:
5282 Page = CreatePrimaryPartitionPage(&Ir);
5283 break;
5284
5285 case CREATE_EXTENDED_PARTITION_PAGE:
5286 Page = CreateExtendedPartitionPage(&Ir);
5287 break;
5288
5289 case CREATE_LOGICAL_PARTITION_PAGE:
5290 Page = CreateLogicalPartitionPage(&Ir);
5291 break;
5292
5293 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
5294 Page = ConfirmDeleteSystemPartitionPage(&Ir);
5295 break;
5296
5297 case DELETE_PARTITION_PAGE:
5298 Page = DeletePartitionPage(&Ir);
5299 break;
5300
5301 case SELECT_FILE_SYSTEM_PAGE:
5302 Page = SelectFileSystemPage(&Ir);
5303 break;
5304
5305 case FORMAT_PARTITION_PAGE:
5306 Page = FormatPartitionPage(&Ir);
5307 break;
5308
5309 case CHECK_FILE_SYSTEM_PAGE:
5310 Page = CheckFileSystemPage(&Ir);
5311 break;
5312
5313 case INSTALL_DIRECTORY_PAGE:
5314 Page = InstallDirectoryPage(&Ir);
5315 break;
5316
5317 case PREPARE_COPY_PAGE:
5318 Page = PrepareCopyPage(&Ir);
5319 break;
5320
5321 case FILE_COPY_PAGE:
5322 Page = FileCopyPage(&Ir);
5323 break;
5324
5325 case REGISTRY_PAGE:
5326 Page = RegistryPage(&Ir);
5327 break;
5328
5329 case BOOT_LOADER_PAGE:
5330 Page = BootLoaderPage(&Ir);
5331 break;
5332
5333 case BOOT_LOADER_FLOPPY_PAGE:
5334 Page = BootLoaderFloppyPage(&Ir);
5335 break;
5336
5337 case BOOT_LOADER_HARDDISK_MBR_PAGE:
5338 Page = BootLoaderHarddiskMbrPage(&Ir);
5339 break;
5340
5341 case BOOT_LOADER_HARDDISK_VBR_PAGE:
5342 Page = BootLoaderHarddiskVbrPage(&Ir);
5343 break;
5344
5345 /* Repair pages */
5346 case REPAIR_INTRO_PAGE:
5347 Page = RepairIntroPage(&Ir);
5348 break;
5349
5350 case UPGRADE_REPAIR_PAGE:
5351 Page = UpgradeRepairPage(&Ir);
5352 break;
5353
5354 case SUCCESS_PAGE:
5355 Page = SuccessPage(&Ir);
5356 break;
5357
5358 case FLUSH_PAGE:
5359 Page = FlushPage(&Ir);
5360 break;
5361
5362 case QUIT_PAGE:
5363 Page = QuitPage(&Ir);
5364 break;
5365
5366 case RECOVERY_PAGE:
5367 case REBOOT_PAGE:
5368 break;
5369 }
5370 }
5371
5372 if (Page == RECOVERY_PAGE)
5373 RecoveryConsole();
5374
5375 FreeConsole();
5376
5377 /* Reboot */
5378 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
5379 NtShutdownSystem(ShutdownReboot);
5380 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
5381
5382 return STATUS_SUCCESS;
5383 }
5384
5385
5386 VOID NTAPI
5387 NtProcessStartup(PPEB Peb)
5388 {
5389 NTSTATUS Status;
5390 LARGE_INTEGER Time;
5391
5392 RtlNormalizeProcessParams(Peb->ProcessParameters);
5393
5394 ProcessHeap = Peb->ProcessHeap;
5395
5396 NtQuerySystemTime(&Time);
5397
5398 Status = RunUSetup();
5399
5400 if (NT_SUCCESS(Status))
5401 {
5402 /*
5403 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5404 * a protective waiting.
5405 * This wait is needed because, since we are started as SMSS.EXE,
5406 * the NT kernel explicitly waits 5 seconds for the initial process
5407 * SMSS.EXE to initialize (as a protective measure), and otherwise
5408 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5409 */
5410 Time.QuadPart += 50000000;
5411 NtDelayExecution(FALSE, &Time);
5412 }
5413 else
5414 {
5415 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5416 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
5417 0, 0, NULL, 0, NULL);
5418 }
5419
5420 NtTerminateProcess(NtCurrentProcess(), Status);
5421 }
5422
5423 /* EOF */