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 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 25 * Hervé Poussineau (hpoussin@reactos.org) 26 */ 27 28 #include <usetup.h> 29 #include <math.h> 30 #include <ntstrsafe.h> 31 32 #include "cmdcons.h" 33 #include "devinst.h" 34 #include "fmtchk.h" 35 36 #define NDEBUG 37 #include <debug.h> 38 39 40 /* GLOBALS & LOCALS *********************************************************/ 41 42 HANDLE ProcessHeap; 43 BOOLEAN IsUnattendedSetup = FALSE; 44 45 static USETUP_DATA USetupData; 46 47 /* The partition where to perform the installation */ 48 static PPARTENTRY InstallPartition = NULL; 49 /* 50 * The system partition we will actually use. It can be different from 51 * PartitionList->SystemPartition in case we don't support it, or we install 52 * on a removable disk. 53 * We may indeed not support the original system partition in case we do not 54 * have write support on it. Please note that this situation is partly a HACK 55 * and MUST NEVER happen on architectures where real system partitions are 56 * mandatory (because then they are formatted in FAT FS and we support write 57 * operation on them). 58 */ 59 static PPARTENTRY SystemPartition = NULL; 60 61 62 /* OTHER Stuff *****/ 63 64 PCWSTR SelectedLanguageId; 65 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList 66 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList 67 68 static BOOLEAN RepairUpdateFlag = FALSE; 69 70 /* Global partition list on the system */ 71 static PPARTLIST PartitionList = NULL; 72 73 /* Currently selected partition entry in the list */ 74 static PPARTENTRY CurrentPartition = NULL; 75 static enum { 76 PartTypeData, // On MBR-disks, primary or logical partition 77 PartTypeExtended // MBR-disk container 78 } PartCreateType = PartTypeData; 79 80 /* Flag set in PARTENTRY::New when a partition is created automatically */ 81 #define PARTITION_NEW_AUTOCREATE 0x80 82 83 /* List of supported file systems for the partition to be formatted */ 84 static PFILE_SYSTEM_LIST FileSystemList = NULL; 85 86 /*****************************************************/ 87 88 static PNTOS_INSTALLATION CurrentInstallation = NULL; 89 static PGENERIC_LIST NtOsInstallsList = NULL; 90 91 #ifdef __REACTOS__ /* HACK */ 92 93 /* FONT SUBSTITUTION WORKAROUND *************************************************/ 94 95 /* For font file check */ 96 FONTSUBSTSETTINGS s_SubstSettings = { FALSE }; 97 98 static void 99 DoWatchDestFileName(LPCWSTR FileName) 100 { 101 if (FileName[0] == 'm' || FileName[0] == 'M') 102 { 103 if (wcsicmp(FileName, L"mingliu.ttc") == 0) 104 { 105 DPRINT("mingliu.ttc found\n"); 106 s_SubstSettings.bFoundFontMINGLIU = TRUE; 107 } 108 else if (wcsicmp(FileName, L"msgothic.ttc") == 0) 109 { 110 DPRINT("msgothic.ttc found\n"); 111 s_SubstSettings.bFoundFontMSGOTHIC = TRUE; 112 } 113 else if (wcsicmp(FileName, L"msmincho.ttc") == 0) 114 { 115 DPRINT("msmincho.ttc found\n"); 116 s_SubstSettings.bFoundFontMSMINCHO = TRUE; 117 } 118 else if (wcsicmp(FileName, L"mssong.ttf") == 0) 119 { 120 DPRINT("mssong.ttf found\n"); 121 s_SubstSettings.bFoundFontMSSONG = TRUE; 122 } 123 } 124 else 125 { 126 if (wcsicmp(FileName, L"simsun.ttc") == 0) 127 { 128 DPRINT("simsun.ttc found\n"); 129 s_SubstSettings.bFoundFontSIMSUN = TRUE; 130 } 131 else if (wcsicmp(FileName, L"gulim.ttc") == 0) 132 { 133 DPRINT("gulim.ttc found\n"); 134 s_SubstSettings.bFoundFontGULIM = TRUE; 135 } 136 else if (wcsicmp(FileName, L"batang.ttc") == 0) 137 { 138 DPRINT("batang.ttc found\n"); 139 s_SubstSettings.bFoundFontBATANG = TRUE; 140 } 141 } 142 } 143 #endif /* HACK */ 144 145 /* FUNCTIONS ****************************************************************/ 146 147 static VOID 148 PrintString(IN PCSTR fmt,...) 149 { 150 CHAR buffer[512]; 151 va_list ap; 152 UNICODE_STRING UnicodeString; 153 ANSI_STRING AnsiString; 154 155 va_start(ap, fmt); 156 vsprintf(buffer, fmt, ap); 157 va_end(ap); 158 159 RtlInitAnsiString(&AnsiString, buffer); 160 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); 161 NtDisplayString(&UnicodeString); 162 RtlFreeUnicodeString(&UnicodeString); 163 } 164 165 166 static VOID 167 DrawBox(IN SHORT xLeft, 168 IN SHORT yTop, 169 IN SHORT Width, 170 IN SHORT Height) 171 { 172 COORD coPos; 173 DWORD Written; 174 175 /* Draw upper left corner */ 176 coPos.X = xLeft; 177 coPos.Y = yTop; 178 FillConsoleOutputCharacterA(StdOutput, 179 CharUpperLeftCorner, // '+', 180 1, 181 coPos, 182 &Written); 183 184 /* Draw upper edge */ 185 coPos.X = xLeft + 1; 186 coPos.Y = yTop; 187 FillConsoleOutputCharacterA(StdOutput, 188 CharHorizontalLine, // '-', 189 Width - 2, 190 coPos, 191 &Written); 192 193 /* Draw upper right corner */ 194 coPos.X = xLeft + Width - 1; 195 coPos.Y = yTop; 196 FillConsoleOutputCharacterA(StdOutput, 197 CharUpperRightCorner, // '+', 198 1, 199 coPos, 200 &Written); 201 202 /* Draw right edge, inner space and left edge */ 203 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++) 204 { 205 coPos.X = xLeft; 206 FillConsoleOutputCharacterA(StdOutput, 207 CharVerticalLine, // '|', 208 1, 209 coPos, 210 &Written); 211 212 coPos.X = xLeft + 1; 213 FillConsoleOutputCharacterA(StdOutput, 214 ' ', 215 Width - 2, 216 coPos, 217 &Written); 218 219 coPos.X = xLeft + Width - 1; 220 FillConsoleOutputCharacterA(StdOutput, 221 CharVerticalLine, // '|', 222 1, 223 coPos, 224 &Written); 225 } 226 227 /* Draw lower left corner */ 228 coPos.X = xLeft; 229 coPos.Y = yTop + Height - 1; 230 FillConsoleOutputCharacterA(StdOutput, 231 CharLowerLeftCorner, // '+', 232 1, 233 coPos, 234 &Written); 235 236 /* Draw lower edge */ 237 coPos.X = xLeft + 1; 238 coPos.Y = yTop + Height - 1; 239 FillConsoleOutputCharacterA(StdOutput, 240 CharHorizontalLine, // '-', 241 Width - 2, 242 coPos, 243 &Written); 244 245 /* Draw lower right corner */ 246 coPos.X = xLeft + Width - 1; 247 coPos.Y = yTop + Height - 1; 248 FillConsoleOutputCharacterA(StdOutput, 249 CharLowerRightCorner, // '+', 250 1, 251 coPos, 252 &Written); 253 } 254 255 256 VOID 257 PopupError(PCCH Text, 258 PCCH Status, 259 PINPUT_RECORD Ir, 260 ULONG WaitEvent) 261 { 262 SHORT yTop; 263 SHORT xLeft; 264 COORD coPos; 265 DWORD Written; 266 ULONG Length; 267 ULONG MaxLength; 268 ULONG Lines; 269 PCHAR p; 270 PCCH pnext; 271 BOOLEAN LastLine; 272 SHORT Width; 273 SHORT Height; 274 275 /* Count text lines and longest line */ 276 MaxLength = 0; 277 Lines = 0; 278 pnext = Text; 279 280 while (TRUE) 281 { 282 p = strchr(pnext, '\n'); 283 284 if (p == NULL) 285 { 286 Length = strlen(pnext); 287 LastLine = TRUE; 288 } 289 else 290 { 291 Length = (ULONG)(p - pnext); 292 LastLine = FALSE; 293 } 294 295 Lines++; 296 297 if (Length > MaxLength) 298 MaxLength = Length; 299 300 if (LastLine) 301 break; 302 303 pnext = p + 1; 304 } 305 306 /* Check length of status line */ 307 if (Status != NULL) 308 { 309 Length = strlen(Status); 310 311 if (Length > MaxLength) 312 MaxLength = Length; 313 } 314 315 Width = MaxLength + 4; 316 Height = Lines + 2; 317 318 if (Status != NULL) 319 Height += 2; 320 321 yTop = (yScreen - Height) / 2; 322 xLeft = (xScreen - Width) / 2; 323 324 325 /* Set screen attributes */ 326 coPos.X = xLeft; 327 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++) 328 { 329 FillConsoleOutputAttribute(StdOutput, 330 FOREGROUND_RED | BACKGROUND_WHITE, 331 Width, 332 coPos, 333 &Written); 334 } 335 336 DrawBox(xLeft, yTop, Width, Height); 337 338 /* Print message text */ 339 coPos.Y = yTop + 1; 340 pnext = Text; 341 while (TRUE) 342 { 343 p = strchr(pnext, '\n'); 344 345 if (p == NULL) 346 { 347 Length = strlen(pnext); 348 LastLine = TRUE; 349 } 350 else 351 { 352 Length = (ULONG)(p - pnext); 353 LastLine = FALSE; 354 } 355 356 if (Length != 0) 357 { 358 coPos.X = xLeft + 2; 359 WriteConsoleOutputCharacterA(StdOutput, 360 pnext, 361 Length, 362 coPos, 363 &Written); 364 } 365 366 if (LastLine) 367 break; 368 369 coPos.Y++; 370 pnext = p + 1; 371 } 372 373 /* Print separator line and status text */ 374 if (Status != NULL) 375 { 376 coPos.Y = yTop + Height - 3; 377 coPos.X = xLeft; 378 FillConsoleOutputCharacterA(StdOutput, 379 CharVertLineAndRightHorizLine, // '+', 380 1, 381 coPos, 382 &Written); 383 384 coPos.X = xLeft + 1; 385 FillConsoleOutputCharacterA(StdOutput, 386 CharHorizontalLine, // '-', 387 Width - 2, 388 coPos, 389 &Written); 390 391 coPos.X = xLeft + Width - 1; 392 FillConsoleOutputCharacterA(StdOutput, 393 CharLeftHorizLineAndVertLine, // '+', 394 1, 395 coPos, 396 &Written); 397 398 coPos.Y++; 399 coPos.X = xLeft + 2; 400 WriteConsoleOutputCharacterA(StdOutput, 401 Status, 402 min(strlen(Status), (SIZE_T)Width - 4), 403 coPos, 404 &Written); 405 } 406 407 if (WaitEvent == POPUP_WAIT_NONE) 408 return; 409 410 while (TRUE) 411 { 412 CONSOLE_ConInKey(Ir); 413 414 if (WaitEvent == POPUP_WAIT_ANY_KEY || 415 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) 416 { 417 return; 418 } 419 } 420 } 421 422 423 /* 424 * Confirm quit setup 425 * RETURNS 426 * TRUE: Quit setup. 427 * FALSE: Don't quit setup. 428 */ 429 static BOOL 430 ConfirmQuit(PINPUT_RECORD Ir) 431 { 432 BOOL Result = FALSE; 433 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE); 434 435 while (TRUE) 436 { 437 CONSOLE_ConInKey(Ir); 438 439 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 440 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 441 { 442 Result = TRUE; 443 break; 444 } 445 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 446 { 447 Result = FALSE; 448 break; 449 } 450 } 451 452 return Result; 453 } 454 455 456 static VOID 457 UpdateKBLayout(VOID) 458 { 459 PGENERIC_LIST_ENTRY ListEntry; 460 KLID newLayout; 461 462 newLayout = MUIDefaultKeyboardLayout(SelectedLanguageId); 463 464 if (!USetupData.LayoutList) 465 { 466 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 467 if (!USetupData.LayoutList) 468 { 469 /* FIXME: Handle error! */ 470 return; 471 } 472 } 473 474 /* Search for default layout (if provided) */ 475 if (newLayout != 0) 476 { 477 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry; 478 ListEntry = GetNextListEntry(ListEntry)) 479 { 480 PCWSTR pszLayoutId = ((PGENENTRY)GetListEntryData(ListEntry))->Id; 481 KLID LayoutId = (KLID)(pszLayoutId ? wcstoul(pszLayoutId, NULL, 16) : 0); 482 if (newLayout == LayoutId) 483 { 484 SetCurrentListEntry(USetupData.LayoutList, ListEntry); 485 break; 486 } 487 } 488 } 489 } 490 491 492 static NTSTATUS 493 NTAPI 494 GetSettingDescription( 495 IN PGENERIC_LIST_ENTRY Entry, 496 OUT PSTR Buffer, 497 IN SIZE_T cchBufferSize) 498 { 499 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S", 500 ((PGENENTRY)GetListEntryData(Entry))->Value); 501 } 502 503 static NTSTATUS 504 NTAPI 505 GetNTOSInstallationName( 506 IN PGENERIC_LIST_ENTRY Entry, 507 OUT PSTR Buffer, 508 IN SIZE_T cchBufferSize) 509 { 510 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry); 511 PPARTENTRY PartEntry = NtOsInstall->PartEntry; 512 513 if (PartEntry && PartEntry->DriveLetter) 514 { 515 /* We have retrieved a partition that is mounted */ 516 return RtlStringCchPrintfA(Buffer, cchBufferSize, 517 "%C:%S \"%S\"", 518 PartEntry->DriveLetter, 519 NtOsInstall->PathComponent, 520 NtOsInstall->InstallationName); 521 } 522 else 523 { 524 /* We failed somewhere, just show the NT path */ 525 return RtlStringCchPrintfA(Buffer, cchBufferSize, 526 "%wZ \"%S\"", 527 &NtOsInstall->SystemNtPath, 528 NtOsInstall->InstallationName); 529 } 530 } 531 532 533 /* 534 * Start page 535 * 536 * Next pages: 537 * LanguagePage (at once, default) 538 * InstallIntroPage (at once, if unattended) 539 * QuitPage 540 * 541 * SIDEEFFECTS 542 * Init Sdi 543 * Init USetupData.SourcePath 544 * Init USetupData.SourceRootPath 545 * Init USetupData.SourceRootDir 546 * Init USetupData.SetupInf 547 * Init USetupData.RequiredPartitionDiskSpace 548 * Init IsUnattendedSetup 549 * If unattended, init *List and sets the Codepage 550 * If unattended, init SelectedLanguageId 551 * If unattended, init USetupData.LanguageId 552 * 553 * RETURNS 554 * Number of the next page. 555 */ 556 static PAGE_NUMBER 557 SetupStartPage(PINPUT_RECORD Ir) 558 { 559 ULONG Error; 560 PGENERIC_LIST_ENTRY ListEntry; 561 PCWSTR LocaleId; 562 563 MUIDisplayPage(SETUP_INIT_PAGE); 564 565 /* Initialize Setup, phase 1 */ 566 Error = InitializeSetup(&USetupData, 1); 567 if (Error != ERROR_SUCCESS) 568 { 569 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER); 570 return QUIT_PAGE; 571 } 572 573 /* Initialize the user-mode PnP manager */ 574 if (!EnableUserModePnpManager()) 575 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n"); 576 577 /* Wait for any immediate pending installations to finish */ 578 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0) 579 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n"); 580 581 CheckUnattendedSetup(&USetupData); 582 583 if (IsUnattendedSetup) 584 { 585 // TODO: Read options from inf 586 /* Load the hardware, language and keyboard layout lists */ 587 588 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf); 589 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf); 590 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf); 591 592 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage); 593 594 /* new part */ 595 SelectedLanguageId = DefaultLanguage; 596 wcscpy(DefaultLanguage, USetupData.LocaleID); 597 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 598 599 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 600 601 /* first we hack LanguageList */ 602 for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry; 603 ListEntry = GetNextListEntry(ListEntry)) 604 { 605 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id; 606 if (!wcsicmp(USetupData.LocaleID, LocaleId)) 607 { 608 DPRINT("found %S in LanguageList\n", LocaleId); 609 SetCurrentListEntry(USetupData.LanguageList, ListEntry); 610 break; 611 } 612 } 613 614 /* now LayoutList */ 615 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry; 616 ListEntry = GetNextListEntry(ListEntry)) 617 { 618 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id; 619 if (!wcsicmp(USetupData.LocaleID, LocaleId)) 620 { 621 DPRINT("found %S in LayoutList\n", LocaleId); 622 SetCurrentListEntry(USetupData.LayoutList, ListEntry); 623 break; 624 } 625 } 626 627 SetConsoleCodePage(); 628 629 return INSTALL_INTRO_PAGE; 630 } 631 632 return LANGUAGE_PAGE; 633 } 634 635 636 /* 637 * Displays the LanguagePage. 638 * 639 * Next pages: WelcomePage, QuitPage 640 * 641 * SIDEEFFECTS 642 * Init SelectedLanguageId 643 * Init USetupData.LanguageId 644 * 645 * RETURNS 646 * Number of the next page. 647 */ 648 static PAGE_NUMBER 649 LanguagePage(PINPUT_RECORD Ir) 650 { 651 GENERIC_LIST_UI ListUi; 652 PCWSTR NewLanguageId; 653 BOOL RefreshPage = FALSE; 654 655 /* Initialize the computer settings list */ 656 if (USetupData.LanguageList == NULL) 657 { 658 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage); 659 if (USetupData.LanguageList == NULL) 660 { 661 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE); 662 return WELCOME_PAGE; 663 } 664 } 665 666 SelectedLanguageId = DefaultLanguage; 667 USetupData.LanguageId = 0; 668 669 /* Load the font */ 670 SetConsoleCodePage(); 671 UpdateKBLayout(); 672 673 /* 674 * If there is no language or just a single one in the list, 675 * skip the language selection process altogether. 676 */ 677 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1) 678 { 679 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 680 return WELCOME_PAGE; 681 } 682 683 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription); 684 DrawGenericList(&ListUi, 685 2, 18, 686 xScreen - 3, 687 yScreen - 3); 688 689 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex()); 690 691 MUIDisplayPage(LANGUAGE_PAGE); 692 693 while (TRUE) 694 { 695 CONSOLE_ConInKey(Ir); 696 697 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 698 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 699 { 700 ScrollDownGenericList(&ListUi); 701 RefreshPage = TRUE; 702 } 703 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 704 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 705 { 706 ScrollUpGenericList(&ListUi); 707 RefreshPage = TRUE; 708 } 709 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 710 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */ 711 { 712 ScrollPageDownGenericList(&ListUi); 713 RefreshPage = TRUE; 714 } 715 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 716 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */ 717 { 718 ScrollPageUpGenericList(&ListUi); 719 RefreshPage = TRUE; 720 } 721 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 722 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 723 { 724 if (ConfirmQuit(Ir)) 725 return QUIT_PAGE; 726 else 727 RedrawGenericList(&ListUi); 728 } 729 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 730 { 731 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1); 732 733 SelectedLanguageId = 734 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id; 735 736 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 737 738 if (wcscmp(SelectedLanguageId, DefaultLanguage)) 739 { 740 UpdateKBLayout(); 741 } 742 743 /* Load the font */ 744 SetConsoleCodePage(); 745 746 return WELCOME_PAGE; 747 } 748 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) 749 { 750 /* a-z */ 751 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 752 RefreshPage = TRUE; 753 } 754 755 if (RefreshPage) 756 { 757 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1); 758 759 NewLanguageId = 760 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id; 761 762 if (wcscmp(SelectedLanguageId, NewLanguageId)) 763 { 764 /* Clear the language page */ 765 MUIClearPage(LANGUAGE_PAGE); 766 767 SelectedLanguageId = NewLanguageId; 768 769 /* Load the font */ 770 SetConsoleCodePage(); 771 772 /* Redraw the list */ 773 DrawGenericList(&ListUi, 774 2, 18, 775 xScreen - 3, 776 yScreen - 3); 777 778 /* Redraw language selection page in native language */ 779 MUIDisplayPage(LANGUAGE_PAGE); 780 } 781 782 RefreshPage = FALSE; 783 } 784 } 785 786 return WELCOME_PAGE; 787 } 788 789 790 /* 791 * Displays the WelcomePage. 792 * 793 * Next pages: 794 * InstallIntroPage (default) 795 * RepairIntroPage 796 * RecoveryPage 797 * LicensePage 798 * QuitPage 799 * 800 * RETURNS 801 * Number of the next page. 802 */ 803 static PAGE_NUMBER 804 WelcomePage(PINPUT_RECORD Ir) 805 { 806 MUIDisplayPage(WELCOME_PAGE); 807 808 while (TRUE) 809 { 810 CONSOLE_ConInKey(Ir); 811 812 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 813 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 814 { 815 if (ConfirmQuit(Ir)) 816 return QUIT_PAGE; 817 818 break; 819 } 820 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 821 { 822 return INSTALL_INTRO_PAGE; 823 } 824 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ 825 { 826 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE; 827 } 828 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */ 829 { 830 return LICENSE_PAGE; 831 } 832 } 833 834 return WELCOME_PAGE; 835 } 836 837 838 /* 839 * Displays the License page. 840 * 841 * Next page: 842 * WelcomePage (default) 843 * 844 * RETURNS 845 * Number of the next page. 846 */ 847 static PAGE_NUMBER 848 LicensePage(PINPUT_RECORD Ir) 849 { 850 MUIDisplayPage(LICENSE_PAGE); 851 852 while (TRUE) 853 { 854 CONSOLE_ConInKey(Ir); 855 856 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 857 { 858 return WELCOME_PAGE; 859 } 860 } 861 862 return LICENSE_PAGE; 863 } 864 865 866 /* 867 * Displays the RepairIntroPage. 868 * 869 * Next pages: 870 * RebootPage (default) 871 * InstallIntroPage 872 * RecoveryPage 873 * IntroPage 874 * 875 * RETURNS 876 * Number of the next page. 877 */ 878 static PAGE_NUMBER 879 RepairIntroPage(PINPUT_RECORD Ir) 880 { 881 MUIDisplayPage(REPAIR_INTRO_PAGE); 882 883 while (TRUE) 884 { 885 CONSOLE_ConInKey(Ir); 886 887 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 888 { 889 return REBOOT_PAGE; 890 } 891 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */ 892 { 893 RepairUpdateFlag = TRUE; 894 return INSTALL_INTRO_PAGE; 895 } 896 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ 897 { 898 return RECOVERY_PAGE; 899 } 900 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 901 { 902 return WELCOME_PAGE; 903 } 904 } 905 906 return REPAIR_INTRO_PAGE; 907 } 908 909 /* 910 * Displays the UpgradeRepairPage. 911 * 912 * Next pages: 913 * RebootPage (default) 914 * InstallIntroPage 915 * RecoveryPage 916 * WelcomePage 917 * 918 * RETURNS 919 * Number of the next page. 920 */ 921 static PAGE_NUMBER 922 UpgradeRepairPage(PINPUT_RECORD Ir) 923 { 924 GENERIC_LIST_UI ListUi; 925 926 /*** HACK!! ***/ 927 if (PartitionList == NULL) 928 { 929 PartitionList = CreatePartitionList(); 930 if (PartitionList == NULL) 931 { 932 /* FIXME: show an error dialog */ 933 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER); 934 return QUIT_PAGE; 935 } 936 else if (IsListEmpty(&PartitionList->DiskListHead)) 937 { 938 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); 939 return QUIT_PAGE; 940 } 941 } 942 /**************/ 943 944 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList); 945 if (!NtOsInstallsList) 946 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n"); 947 948 /* 949 * If there is no available installation (or just a single one??) that can 950 * be updated in the list, just continue with the regular installation. 951 */ 952 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0) 953 { 954 RepairUpdateFlag = FALSE; 955 956 // return INSTALL_INTRO_PAGE; 957 return DEVICE_SETTINGS_PAGE; 958 // return SCSI_CONTROLLER_PAGE; 959 } 960 961 MUIDisplayPage(UPGRADE_REPAIR_PAGE); 962 963 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName); 964 DrawGenericList(&ListUi, 965 2, 23, 966 xScreen - 3, 967 yScreen - 3); 968 969 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 970 while (TRUE) 971 { 972 CONSOLE_ConInKey(Ir); 973 974 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) 975 { 976 switch (Ir->Event.KeyEvent.wVirtualKeyCode) 977 { 978 case VK_DOWN: /* DOWN */ 979 ScrollDownGenericList(&ListUi); 980 break; 981 case VK_UP: /* UP */ 982 ScrollUpGenericList(&ListUi); 983 break; 984 case VK_NEXT: /* PAGE DOWN */ 985 ScrollPageDownGenericList(&ListUi); 986 break; 987 case VK_PRIOR: /* PAGE UP */ 988 ScrollPageUpGenericList(&ListUi); 989 break; 990 case VK_F3: /* F3 */ 991 { 992 if (ConfirmQuit(Ir)) 993 return QUIT_PAGE; 994 else 995 RedrawGenericList(&ListUi); 996 break; 997 } 998 #if 1 999 /* TODO: Temporarily kept until correct keyboard layout is in place. 1000 * (Actual AsciiChar of ESCAPE should be 0x1B instead of 0.) 1001 * Addendum to commit 8b94515b. 1002 */ 1003 case VK_ESCAPE: /* ESC */ 1004 { 1005 RestoreGenericListUiState(&ListUi); 1006 // return nextPage; // prevPage; 1007 1008 // return INSTALL_INTRO_PAGE; 1009 return DEVICE_SETTINGS_PAGE; 1010 // return SCSI_CONTROLLER_PAGE; 1011 } 1012 1013 #endif 1014 } 1015 } 1016 #if 0 1017 /* TODO: Restore this once correct keyboard layout is in place. */ 1018 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 1019 { 1020 RestoreGenericListUiState(&ListUi); 1021 // return nextPage; // prevPage; 1022 1023 // return INSTALL_INTRO_PAGE; 1024 return DEVICE_SETTINGS_PAGE; 1025 // return SCSI_CONTROLLER_PAGE; 1026 } 1027 #endif 1028 else 1029 { 1030 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar)) 1031 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1032 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */ 1033 { 1034 /* Retrieve the current installation */ 1035 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1); 1036 1037 CurrentInstallation = 1038 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList)); 1039 1040 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n", 1041 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber); 1042 1043 RepairUpdateFlag = TRUE; 1044 1045 // return nextPage; 1046 /***/return INSTALL_INTRO_PAGE;/***/ 1047 } 1048 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && 1049 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */ 1050 { 1051 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 1052 } 1053 } 1054 } 1055 1056 return UPGRADE_REPAIR_PAGE; 1057 } 1058 1059 1060 /* 1061 * Displays the InstallIntroPage. 1062 * 1063 * Next pages: 1064 * DeviceSettingsPage (At once if repair or update is selected) 1065 * SelectPartitionPage (At once if unattended setup) 1066 * DeviceSettingsPage (default) 1067 * QuitPage 1068 * 1069 * RETURNS 1070 * Number of the next page. 1071 */ 1072 static PAGE_NUMBER 1073 InstallIntroPage(PINPUT_RECORD Ir) 1074 { 1075 if (RepairUpdateFlag) 1076 { 1077 #if 1 /* Old code that looks good */ 1078 1079 // return SELECT_PARTITION_PAGE; 1080 return DEVICE_SETTINGS_PAGE; 1081 1082 #else /* Possible new code? */ 1083 1084 return DEVICE_SETTINGS_PAGE; 1085 // return SCSI_CONTROLLER_PAGE; 1086 1087 #endif 1088 } 1089 1090 if (IsUnattendedSetup) 1091 return SELECT_PARTITION_PAGE; 1092 1093 MUIDisplayPage(INSTALL_INTRO_PAGE); 1094 1095 while (TRUE) 1096 { 1097 CONSOLE_ConInKey(Ir); 1098 1099 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1100 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1101 { 1102 if (ConfirmQuit(Ir)) 1103 return QUIT_PAGE; 1104 1105 break; 1106 } 1107 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1108 { 1109 return UPGRADE_REPAIR_PAGE; 1110 } 1111 } 1112 1113 return INSTALL_INTRO_PAGE; 1114 } 1115 1116 1117 #if 0 1118 static PAGE_NUMBER 1119 ScsiControllerPage(PINPUT_RECORD Ir) 1120 { 1121 // MUIDisplayPage(SCSI_CONTROLLER_PAGE); 1122 1123 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:"); 1124 1125 /* FIXME: print loaded mass storage driver descriptions */ 1126 #if 0 1127 CONSOLE_SetTextXY(8, 10, "TEST device"); 1128 #endif 1129 1130 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit"); 1131 1132 while (TRUE) 1133 { 1134 CONSOLE_ConInKey(Ir); 1135 1136 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1137 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1138 { 1139 if (ConfirmQuit(Ir)) 1140 return QUIT_PAGE; 1141 1142 break; 1143 } 1144 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1145 { 1146 return DEVICE_SETTINGS_PAGE; 1147 } 1148 } 1149 1150 return SCSI_CONTROLLER_PAGE; 1151 } 1152 1153 static PAGE_NUMBER 1154 OemDriverPage(PINPUT_RECORD Ir) 1155 { 1156 // MUIDisplayPage(OEM_DRIVER_PAGE); 1157 1158 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!"); 1159 1160 /* FIXME: Implement!! */ 1161 1162 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit"); 1163 1164 while (TRUE) 1165 { 1166 CONSOLE_ConInKey(Ir); 1167 1168 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1169 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1170 { 1171 if (ConfirmQuit(Ir)) 1172 return QUIT_PAGE; 1173 1174 break; 1175 } 1176 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1177 { 1178 return DEVICE_SETTINGS_PAGE; 1179 } 1180 } 1181 1182 return OEM_DRIVER_PAGE; 1183 } 1184 #endif 1185 1186 1187 /* 1188 * Displays the DeviceSettingsPage. 1189 * 1190 * Next pages: 1191 * SelectPartitionPage (At once if repair or update is selected) 1192 * ComputerSettingsPage 1193 * DisplaySettingsPage 1194 * KeyboardSettingsPage 1195 * LayoutsettingsPage 1196 * SelectPartitionPage 1197 * QuitPage 1198 * 1199 * SIDEEFFECTS 1200 * Init USetupData.ComputerList 1201 * Init USetupData.DisplayList 1202 * Init USetupData.KeyboardList 1203 * Init USetupData.LayoutList 1204 * 1205 * RETURNS 1206 * Number of the next page. 1207 */ 1208 static PAGE_NUMBER 1209 DeviceSettingsPage(PINPUT_RECORD Ir) 1210 { 1211 static ULONG Line = 16; 1212 1213 /* Initialize the computer settings list */ 1214 if (USetupData.ComputerList == NULL) 1215 { 1216 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf); 1217 if (USetupData.ComputerList == NULL) 1218 { 1219 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER); 1220 return QUIT_PAGE; 1221 } 1222 } 1223 1224 /* Initialize the display settings list */ 1225 if (USetupData.DisplayList == NULL) 1226 { 1227 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf); 1228 if (USetupData.DisplayList == NULL) 1229 { 1230 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER); 1231 return QUIT_PAGE; 1232 } 1233 } 1234 1235 /* Initialize the keyboard settings list */ 1236 if (USetupData.KeyboardList == NULL) 1237 { 1238 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf); 1239 if (USetupData.KeyboardList == NULL) 1240 { 1241 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER); 1242 return QUIT_PAGE; 1243 } 1244 } 1245 1246 /* Initialize the keyboard layout list */ 1247 if (!USetupData.LayoutList) 1248 { 1249 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 1250 if (!USetupData.LayoutList) 1251 { 1252 /* FIXME: report error */ 1253 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER); 1254 return QUIT_PAGE; 1255 } 1256 } 1257 1258 if (RepairUpdateFlag) 1259 return SELECT_PARTITION_PAGE; 1260 1261 // if (IsUnattendedSetup) 1262 // return SELECT_PARTITION_PAGE; 1263 1264 MUIDisplayPage(DEVICE_SETTINGS_PAGE); 1265 1266 DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11); 1267 DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12); 1268 DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13); 1269 DrawGenericListCurrentItem(USetupData.LayoutList , GetSettingDescription, 25, 14); 1270 1271 CONSOLE_InvertTextXY(24, Line, 48, 1); 1272 1273 while (TRUE) 1274 { 1275 CONSOLE_ConInKey(Ir); 1276 1277 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1278 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1279 { 1280 CONSOLE_NormalTextXY(24, Line, 48, 1); 1281 1282 if (Line == 14) 1283 Line = 16; 1284 else if (Line == 16) 1285 Line = 11; 1286 else 1287 Line++; 1288 1289 CONSOLE_InvertTextXY(24, Line, 48, 1); 1290 } 1291 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1292 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1293 { 1294 CONSOLE_NormalTextXY(24, Line, 48, 1); 1295 1296 if (Line == 11) 1297 Line = 16; 1298 else if (Line == 16) 1299 Line = 14; 1300 else 1301 Line--; 1302 1303 CONSOLE_InvertTextXY(24, Line, 48, 1); 1304 } 1305 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1306 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1307 { 1308 if (ConfirmQuit(Ir)) 1309 return QUIT_PAGE; 1310 1311 break; 1312 } 1313 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1314 { 1315 if (Line == 11) 1316 return COMPUTER_SETTINGS_PAGE; 1317 else if (Line == 12) 1318 return DISPLAY_SETTINGS_PAGE; 1319 else if (Line == 13) 1320 return KEYBOARD_SETTINGS_PAGE; 1321 else if (Line == 14) 1322 return LAYOUT_SETTINGS_PAGE; 1323 else if (Line == 16) 1324 return SELECT_PARTITION_PAGE; 1325 } 1326 } 1327 1328 return DEVICE_SETTINGS_PAGE; 1329 } 1330 1331 1332 /* 1333 * Handles generic selection lists. 1334 * 1335 * PARAMS 1336 * GenericList: The list to handle. 1337 * nextPage: The page it needs to jump to after this page. 1338 * Ir: The PINPUT_RECORD 1339 */ 1340 static PAGE_NUMBER 1341 HandleGenericList(PGENERIC_LIST_UI ListUi, 1342 PAGE_NUMBER nextPage, 1343 PINPUT_RECORD Ir) 1344 { 1345 while (TRUE) 1346 { 1347 CONSOLE_ConInKey(Ir); 1348 1349 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1350 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1351 { 1352 ScrollDownGenericList(ListUi); 1353 } 1354 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1355 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1356 { 1357 ScrollUpGenericList(ListUi); 1358 } 1359 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1360 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */ 1361 { 1362 ScrollPageDownGenericList(ListUi); 1363 } 1364 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1365 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */ 1366 { 1367 ScrollPageUpGenericList(ListUi); 1368 } 1369 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1370 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1371 { 1372 if (ConfirmQuit(Ir)) 1373 return QUIT_PAGE; 1374 else 1375 RedrawGenericList(ListUi); 1376 } 1377 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 1378 { 1379 RestoreGenericListUiState(ListUi); 1380 return nextPage; // Use some "prevPage;" instead? 1381 } 1382 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1383 { 1384 return nextPage; 1385 } 1386 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) 1387 { 1388 /* a-z */ 1389 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 1390 } 1391 } 1392 } 1393 1394 1395 /* 1396 * Displays the ComputerSettingsPage. 1397 * 1398 * Next pages: 1399 * DeviceSettingsPage 1400 * QuitPage 1401 * 1402 * RETURNS 1403 * Number of the next page. 1404 */ 1405 static PAGE_NUMBER 1406 ComputerSettingsPage(PINPUT_RECORD Ir) 1407 { 1408 GENERIC_LIST_UI ListUi; 1409 MUIDisplayPage(COMPUTER_SETTINGS_PAGE); 1410 1411 InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription); 1412 DrawGenericList(&ListUi, 1413 2, 18, 1414 xScreen - 3, 1415 yScreen - 3); 1416 1417 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1418 } 1419 1420 1421 /* 1422 * Displays the DisplaySettingsPage. 1423 * 1424 * Next pages: 1425 * DeviceSettingsPage 1426 * QuitPage 1427 * 1428 * RETURNS 1429 * Number of the next page. 1430 */ 1431 static PAGE_NUMBER 1432 DisplaySettingsPage(PINPUT_RECORD Ir) 1433 { 1434 GENERIC_LIST_UI ListUi; 1435 MUIDisplayPage(DISPLAY_SETTINGS_PAGE); 1436 1437 InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription); 1438 DrawGenericList(&ListUi, 1439 2, 18, 1440 xScreen - 3, 1441 yScreen - 3); 1442 1443 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1444 } 1445 1446 1447 /* 1448 * Displays the KeyboardSettingsPage. 1449 * 1450 * Next pages: 1451 * DeviceSettingsPage 1452 * QuitPage 1453 * 1454 * RETURNS 1455 * Number of the next page. 1456 */ 1457 static PAGE_NUMBER 1458 KeyboardSettingsPage(PINPUT_RECORD Ir) 1459 { 1460 GENERIC_LIST_UI ListUi; 1461 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE); 1462 1463 InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription); 1464 DrawGenericList(&ListUi, 1465 2, 18, 1466 xScreen - 3, 1467 yScreen - 3); 1468 1469 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1470 } 1471 1472 1473 /* 1474 * Displays the LayoutSettingsPage. 1475 * 1476 * Next pages: 1477 * DeviceSettingsPage 1478 * QuitPage 1479 * 1480 * RETURNS 1481 * Number of the next page. 1482 */ 1483 static PAGE_NUMBER 1484 LayoutSettingsPage(PINPUT_RECORD Ir) 1485 { 1486 GENERIC_LIST_UI ListUi; 1487 MUIDisplayPage(LAYOUT_SETTINGS_PAGE); 1488 1489 InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription); 1490 DrawGenericList(&ListUi, 1491 2, 18, 1492 xScreen - 3, 1493 yScreen - 3); 1494 1495 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1496 } 1497 1498 1499 static BOOLEAN 1500 IsPartitionLargeEnough( 1501 _In_ PPARTENTRY PartEntry) 1502 { 1503 /* Retrieve the maximum size in MB (rounded up) */ 1504 ULONGLONG PartSize = RoundingDivide(GetPartEntrySizeInBytes(PartEntry), MB); 1505 1506 if (PartSize < USetupData.RequiredPartitionDiskSpace) 1507 { 1508 /* Partition is too small so ask for another one */ 1509 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", 1510 PartSize, USetupData.RequiredPartitionDiskSpace); 1511 return FALSE; 1512 } 1513 else 1514 { 1515 return TRUE; 1516 } 1517 } 1518 1519 1520 /* 1521 * Displays the SelectPartitionPage. 1522 * 1523 * Next pages: 1524 * SelectFileSystemPage (At once if unattended) 1525 * SelectFileSystemPage (Default if free space is selected) 1526 * CreatePartitionPage 1527 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set) 1528 * DeletePartitionPage 1529 * QuitPage 1530 * 1531 * SIDEEFFECTS 1532 * Set InstallShortcut (only if not unattended + free space is selected) 1533 * 1534 * RETURNS 1535 * Number of the next page. 1536 */ 1537 static PAGE_NUMBER 1538 SelectPartitionPage(PINPUT_RECORD Ir) 1539 { 1540 PARTLIST_UI ListUi; 1541 ULONG Error; 1542 1543 if (PartitionList == NULL) 1544 { 1545 PartitionList = CreatePartitionList(); 1546 if (PartitionList == NULL) 1547 { 1548 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER); 1549 return QUIT_PAGE; 1550 } 1551 else if (IsListEmpty(&PartitionList->DiskListHead)) 1552 { 1553 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); 1554 return QUIT_PAGE; 1555 } 1556 } 1557 1558 if (RepairUpdateFlag) 1559 { 1560 ASSERT(CurrentInstallation); 1561 1562 /* Determine the selected installation disk & partition */ 1563 InstallPartition = SelectPartition(PartitionList, 1564 CurrentInstallation->DiskNumber, 1565 CurrentInstallation->PartitionNumber); 1566 if (!InstallPartition) 1567 { 1568 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n"); 1569 ASSERT(FALSE); 1570 } 1571 ASSERT(!IsContainerPartition(InstallPartition->PartitionType)); 1572 1573 return START_PARTITION_OPERATIONS_PAGE; 1574 } 1575 1576 MUIDisplayPage(SELECT_PARTITION_PAGE); 1577 1578 InitPartitionListUi(&ListUi, PartitionList, 1579 CurrentPartition, 1580 2, 21, 1581 xScreen - 3, 1582 yScreen - 3); 1583 DrawPartitionList(&ListUi); 1584 1585 if (IsUnattendedSetup) 1586 { 1587 /* Determine the selected installation disk & partition */ 1588 InstallPartition = SelectPartition(PartitionList, 1589 USetupData.DestinationDiskNumber, 1590 USetupData.DestinationPartitionNumber); 1591 if (!InstallPartition) 1592 { 1593 CurrentPartition = ListUi.CurrentPartition; 1594 1595 if (USetupData.AutoPartition) 1596 { 1597 ASSERT(CurrentPartition != NULL); 1598 ASSERT(!IsContainerPartition(CurrentPartition->PartitionType)); 1599 1600 /* Automatically create the partition on the whole empty space; 1601 * it will be formatted later with default parameters */ 1602 CreatePartition(PartitionList, 1603 CurrentPartition, 1604 0ULL, 1605 0); 1606 CurrentPartition->New |= PARTITION_NEW_AUTOCREATE; 1607 1608 // FIXME?? Aren't we going to enter an infinite loop, if this test fails?? 1609 if (!IsPartitionLargeEnough(CurrentPartition)) 1610 { 1611 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1612 USetupData.RequiredPartitionDiskSpace); 1613 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1614 } 1615 1616 InstallPartition = CurrentPartition; 1617 return START_PARTITION_OPERATIONS_PAGE; 1618 } 1619 } 1620 else 1621 { 1622 ASSERT(!IsContainerPartition(InstallPartition->PartitionType)); 1623 1624 DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense... 1625 1626 // FIXME?? Aren't we going to enter an infinite loop, if this test fails?? 1627 if (!IsPartitionLargeEnough(InstallPartition)) 1628 { 1629 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1630 USetupData.RequiredPartitionDiskSpace); 1631 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1632 } 1633 1634 return START_PARTITION_OPERATIONS_PAGE; 1635 } 1636 } 1637 1638 while (TRUE) 1639 { 1640 ULONG uID; 1641 1642 CurrentPartition = ListUi.CurrentPartition; 1643 1644 /* Update status text */ 1645 if (CurrentPartition == NULL) 1646 { 1647 // FIXME: If we get a NULL current partition, this means that 1648 // the current disk is of unrecognized type. So we should display 1649 // instead a status string to initialize the disk with one of 1650 // the recognized partitioning schemes (MBR, later: GPT, etc.) 1651 // For the time being we don't have that, so use instead another 1652 // known string. 1653 uID = STRING_INSTALLCREATEPARTITION; 1654 } 1655 else 1656 { 1657 if (CurrentPartition->IsPartitioned) 1658 { 1659 uID = STRING_INSTALLDELETEPARTITION; 1660 if (!CurrentPartition->LogicalPartition && 1661 IsContainerPartition(CurrentPartition->PartitionType)) 1662 { 1663 uID = STRING_DELETEPARTITION; 1664 } 1665 } 1666 else 1667 { 1668 uID = STRING_INSTALLCREATEPARTITION; 1669 if (CurrentPartition->LogicalPartition) 1670 uID = STRING_INSTALLCREATELOGICAL; 1671 } 1672 } 1673 CONSOLE_SetStatusText(MUIGetString(uID)); 1674 1675 CONSOLE_ConInKey(Ir); 1676 1677 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1678 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1679 { 1680 if (ConfirmQuit(Ir)) 1681 { 1682 DestroyPartitionList(PartitionList); 1683 PartitionList = NULL; 1684 return QUIT_PAGE; 1685 } 1686 1687 break; 1688 } 1689 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1690 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1691 { 1692 ScrollUpDownPartitionList(&ListUi, TRUE); 1693 } 1694 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1695 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1696 { 1697 ScrollUpDownPartitionList(&ListUi, FALSE); 1698 } 1699 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 1700 { 1701 ASSERT(CurrentPartition != NULL); 1702 1703 if (IsContainerPartition(CurrentPartition->PartitionType)) 1704 continue; // return SELECT_PARTITION_PAGE; 1705 1706 /* 1707 * Check whether the user wants to install ReactOS on a disk that 1708 * is not recognized by the computer's firmware and if so, display 1709 * a warning since such disks may not be bootable. 1710 */ 1711 if (CurrentPartition->DiskEntry->MediaType == FixedMedia && 1712 !CurrentPartition->DiskEntry->BiosFound) 1713 { 1714 PopupError("The disk you have selected for installing ReactOS\n" 1715 "is not visible by the firmware of your computer,\n" 1716 "and so may not be bootable.\n" 1717 "Press ENTER to continue nonetheless.", 1718 MUIGetString(STRING_CONTINUE), 1719 Ir, POPUP_WAIT_ENTER); 1720 // return SELECT_PARTITION_PAGE; 1721 } 1722 1723 if (!CurrentPartition->IsPartitioned) 1724 { 1725 Error = PartitionCreationChecks(CurrentPartition); 1726 if (Error != NOT_AN_ERROR) 1727 { 1728 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1729 return SELECT_PARTITION_PAGE; 1730 } 1731 1732 /* Automatically create the partition on the whole empty space; 1733 * it will be formatted later with default parameters */ 1734 CreatePartition(PartitionList, 1735 CurrentPartition, 1736 0ULL, 1737 0); 1738 CurrentPartition->New |= PARTITION_NEW_AUTOCREATE; 1739 } 1740 1741 if (!IsPartitionLargeEnough(CurrentPartition)) 1742 { 1743 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1744 USetupData.RequiredPartitionDiskSpace); 1745 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1746 } 1747 1748 InstallPartition = CurrentPartition; 1749 return START_PARTITION_OPERATIONS_PAGE; 1750 } 1751 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'C') /* C */ 1752 { 1753 ASSERT(CurrentPartition != NULL); 1754 1755 Error = PartitionCreationChecks(CurrentPartition); 1756 if (Error != NOT_AN_ERROR) 1757 { 1758 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1759 return SELECT_PARTITION_PAGE; 1760 } 1761 1762 PartCreateType = PartTypeData; 1763 return CREATE_PARTITION_PAGE; 1764 } 1765 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */ 1766 { 1767 ASSERT(CurrentPartition != NULL); 1768 1769 if (CurrentPartition->LogicalPartition == FALSE) 1770 { 1771 Error = ExtendedPartitionCreationChecks(CurrentPartition); 1772 if (Error != NOT_AN_ERROR) 1773 { 1774 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1775 return SELECT_PARTITION_PAGE; 1776 } 1777 1778 PartCreateType = PartTypeExtended; 1779 return CREATE_PARTITION_PAGE; 1780 } 1781 } 1782 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */ 1783 { 1784 UNICODE_STRING CurrentPartitionU; 1785 WCHAR PathBuffer[MAX_PATH]; 1786 1787 ASSERT(CurrentPartition != NULL); 1788 1789 /* Ignore deletion in case this is not a partitioned entry */ 1790 if (!CurrentPartition->IsPartitioned) 1791 { 1792 continue; 1793 } 1794 1795 // TODO: Do something similar before trying to format the partition? 1796 if (!CurrentPartition->New && 1797 !IsContainerPartition(CurrentPartition->PartitionType) && 1798 CurrentPartition->FormatState != Unformatted) 1799 { 1800 ASSERT(CurrentPartition->PartitionNumber != 0); 1801 1802 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 1803 L"\\Device\\Harddisk%lu\\Partition%lu\\", 1804 CurrentPartition->DiskEntry->DiskNumber, 1805 CurrentPartition->PartitionNumber); 1806 RtlInitUnicodeString(&CurrentPartitionU, PathBuffer); 1807 1808 /* 1809 * Check whether the user attempts to delete the partition on which 1810 * the installation source is present. If so, fail with an error. 1811 */ 1812 // &USetupData.SourceRootPath 1813 if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE)) 1814 { 1815 MUIDisplayError(ERROR_SOURCE_PATH, Ir, POPUP_WAIT_ENTER); 1816 return SELECT_PARTITION_PAGE; 1817 } 1818 } 1819 1820 if (CurrentPartition == PartitionList->SystemPartition || 1821 IsPartitionActive(CurrentPartition)) 1822 { 1823 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE; 1824 } 1825 1826 return DELETE_PARTITION_PAGE; 1827 } 1828 } 1829 1830 return SELECT_PARTITION_PAGE; 1831 } 1832 1833 1834 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9 1835 /* Restriction for MaxSize */ 1836 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1) 1837 1838 static VOID 1839 ShowPartitionSizeInputBox(SHORT Left, 1840 SHORT Top, 1841 SHORT Right, 1842 SHORT Bottom, 1843 ULONG MaxSize, 1844 PWSTR InputBuffer, 1845 PBOOLEAN Quit, 1846 PBOOLEAN Cancel) 1847 { 1848 INPUT_RECORD Ir; 1849 COORD coPos; 1850 DWORD Written; 1851 CHAR Buffer[128]; 1852 INT Length, Pos; 1853 WCHAR ch; 1854 SHORT iLeft; 1855 SHORT iTop; 1856 1857 if (Quit != NULL) 1858 *Quit = FALSE; 1859 1860 if (Cancel != NULL) 1861 *Cancel = FALSE; 1862 1863 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1); 1864 1865 /* Print message */ 1866 coPos.X = Left + 2; 1867 coPos.Y = Top + 2; 1868 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE)); 1869 iLeft = coPos.X + (USHORT)strlen(Buffer) + 1; 1870 iTop = coPos.Y; 1871 1872 WriteConsoleOutputCharacterA(StdOutput, 1873 Buffer, 1874 strlen(Buffer), 1875 coPos, 1876 &Written); 1877 1878 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize); 1879 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1; 1880 coPos.Y = iTop; 1881 WriteConsoleOutputCharacterA(StdOutput, 1882 Buffer, 1883 strlen(Buffer), 1884 coPos, 1885 &Written); 1886 1887 swprintf(InputBuffer, L"%lu", MaxSize); 1888 Length = wcslen(InputBuffer); 1889 Pos = Length; 1890 CONSOLE_SetInputTextXY(iLeft, 1891 iTop, 1892 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1893 InputBuffer); 1894 CONSOLE_SetCursorXY(iLeft + Length, iTop); 1895 CONSOLE_SetCursorType(TRUE, TRUE); 1896 1897 while (TRUE) 1898 { 1899 CONSOLE_ConInKey(&Ir); 1900 1901 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1902 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1903 { 1904 if (Quit != NULL) 1905 *Quit = TRUE; 1906 1907 InputBuffer[0] = UNICODE_NULL; 1908 CONSOLE_SetCursorType(TRUE, FALSE); 1909 break; 1910 } 1911 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 1912 { 1913 CONSOLE_SetCursorType(TRUE, FALSE); 1914 break; 1915 } 1916 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 1917 { 1918 if (Cancel != NULL) 1919 *Cancel = TRUE; 1920 1921 InputBuffer[0] = UNICODE_NULL; 1922 CONSOLE_SetCursorType(TRUE, FALSE); 1923 break; 1924 } 1925 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1926 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 1927 { 1928 Pos = 0; 1929 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1930 } 1931 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1932 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 1933 { 1934 Pos = Length; 1935 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1936 } 1937 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1938 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */ 1939 { 1940 if (Pos > 0) 1941 { 1942 Pos--; 1943 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1944 } 1945 } 1946 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1947 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */ 1948 { 1949 if (Pos < Length) 1950 { 1951 Pos++; 1952 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1953 } 1954 } 1955 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1956 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */ 1957 { 1958 if (Pos < Length) 1959 { 1960 memmove(&InputBuffer[Pos], 1961 &InputBuffer[Pos + 1], 1962 (Length - Pos - 1) * sizeof(WCHAR)); 1963 InputBuffer[Length - 1] = UNICODE_NULL; 1964 1965 Length--; 1966 CONSOLE_SetInputTextXY(iLeft, 1967 iTop, 1968 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1969 InputBuffer); 1970 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1971 } 1972 } 1973 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */ 1974 { 1975 if (Pos > 0) 1976 { 1977 if (Pos < Length) 1978 memmove(&InputBuffer[Pos - 1], 1979 &InputBuffer[Pos], 1980 (Length - Pos) * sizeof(WCHAR)); 1981 InputBuffer[Length - 1] = UNICODE_NULL; 1982 1983 Pos--; 1984 Length--; 1985 CONSOLE_SetInputTextXY(iLeft, 1986 iTop, 1987 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1988 InputBuffer); 1989 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1990 } 1991 } 1992 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) 1993 { 1994 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1) 1995 { 1996 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar; 1997 1998 if ((ch >= L'0') && (ch <= L'9')) 1999 { 2000 if (Pos < Length) 2001 memmove(&InputBuffer[Pos + 1], 2002 &InputBuffer[Pos], 2003 (Length - Pos) * sizeof(WCHAR)); 2004 InputBuffer[Length + 1] = UNICODE_NULL; 2005 InputBuffer[Pos] = ch; 2006 2007 Pos++; 2008 Length++; 2009 CONSOLE_SetInputTextXY(iLeft, 2010 iTop, 2011 PARTITION_SIZE_INPUT_FIELD_LENGTH, 2012 InputBuffer); 2013 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 2014 } 2015 } 2016 } 2017 } 2018 } 2019 2020 2021 /* 2022 * Displays the CreatePartitionPage. 2023 * 2024 * Next pages: 2025 * SelectPartitionPage 2026 * SelectFileSystemPage (default) 2027 * QuitPage 2028 * 2029 * RETURNS 2030 * Number of the next page. 2031 */ 2032 static PAGE_NUMBER 2033 CreatePartitionPage(PINPUT_RECORD Ir) 2034 { 2035 PPARTENTRY PartEntry; 2036 PDISKENTRY DiskEntry; 2037 ULONG uID; 2038 ULONG MaxSize; 2039 ULONGLONG MaxPartSize, PartSize; 2040 BOOLEAN Quit, Cancel; 2041 WCHAR InputBuffer[50]; 2042 CHAR LineBuffer[100]; 2043 2044 if (PartitionList == NULL || CurrentPartition == NULL) 2045 { 2046 /* FIXME: show an error dialog */ 2047 return QUIT_PAGE; 2048 } 2049 2050 if (PartCreateType == PartTypeData) 2051 { 2052 uID = STRING_CHOOSE_NEW_PARTITION; 2053 if (CurrentPartition->LogicalPartition) 2054 uID = STRING_CHOOSE_NEW_LOGICAL_PARTITION; 2055 } 2056 else // if (PartCreateType == PartTypeExtended) 2057 { 2058 uID = STRING_CHOOSE_NEW_EXTENDED_PARTITION; 2059 } 2060 2061 CONSOLE_SetTextXY(6, 8, MUIGetString(uID)); 2062 2063 PartEntry = CurrentPartition; 2064 DiskEntry = CurrentPartition->DiskEntry; 2065 2066 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2067 CONSOLE_PrintTextXY(6, 10, MUIGetString(STRING_HDDISK1), 2068 LineBuffer); 2069 2070 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDPARTSIZE)); 2071 2072 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION)); 2073 2074 MaxPartSize = GetPartEntrySizeInBytes(PartEntry); 2075 2076 while (TRUE) 2077 { 2078 /* Retrieve the maximum size in MB (rounded up) 2079 * and cap it with what the user can enter */ 2080 MaxSize = (ULONG)RoundingDivide(MaxPartSize, MB); 2081 MaxSize = min(MaxSize, PARTITION_MAXSIZE); 2082 2083 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, 2084 MaxSize, InputBuffer, &Quit, &Cancel); 2085 if (Quit) 2086 { 2087 if (ConfirmQuit(Ir)) 2088 return QUIT_PAGE; 2089 break; 2090 } 2091 else if (Cancel) 2092 { 2093 return SELECT_PARTITION_PAGE; 2094 } 2095 2096 PartSize = _wcstoui64(InputBuffer, NULL, 10); 2097 2098 /* Retry if too small or too large */ 2099 if ((PartSize < 1) || (PartSize > MaxSize)) 2100 continue; 2101 2102 /* 2103 * If the input size, given in MB, specifies the maximum partition 2104 * size, it may slightly under- or over-estimate it due to rounding 2105 * error. In this case, use all of the unpartitioned disk space. 2106 * Otherwise, directly convert the size to bytes. 2107 */ 2108 if (PartSize == MaxSize) 2109 PartSize = MaxPartSize; 2110 else // if (PartSize < MaxSize) 2111 PartSize *= MB; 2112 DPRINT("Partition size: %I64u bytes\n", PartSize); 2113 2114 ASSERT(PartSize <= MaxPartSize); 2115 2116 CreatePartition(PartitionList, 2117 CurrentPartition, 2118 PartSize, 2119 (PartCreateType == PartTypeData) 2120 ? 0 2121 // (PartCreateType == PartTypeExtended) 2122 : PARTITION_EXTENDED); 2123 2124 return SELECT_PARTITION_PAGE; 2125 } 2126 2127 return CREATE_PARTITION_PAGE; 2128 } 2129 2130 2131 /* 2132 * Displays the ConfirmDeleteSystemPartitionPage. 2133 * 2134 * Next pages: 2135 * DeletePartitionPage (default) 2136 * SelectPartitionPage 2137 * 2138 * RETURNS 2139 * Number of the next page. 2140 */ 2141 static PAGE_NUMBER 2142 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir) 2143 { 2144 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE); 2145 2146 while (TRUE) 2147 { 2148 CONSOLE_ConInKey(Ir); 2149 2150 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2151 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2152 { 2153 if (ConfirmQuit(Ir)) 2154 return QUIT_PAGE; 2155 2156 break; 2157 } 2158 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 2159 { 2160 return DELETE_PARTITION_PAGE; 2161 } 2162 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2163 { 2164 return SELECT_PARTITION_PAGE; 2165 } 2166 } 2167 2168 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE; 2169 } 2170 2171 2172 /* 2173 * Displays the DeletePartitionPage. 2174 * 2175 * Next pages: 2176 * SelectPartitionPage (default) 2177 * QuitPage 2178 * 2179 * RETURNS 2180 * Number of the next page. 2181 */ 2182 static PAGE_NUMBER 2183 DeletePartitionPage(PINPUT_RECORD Ir) 2184 { 2185 PPARTENTRY PartEntry; 2186 PDISKENTRY DiskEntry; 2187 CHAR LineBuffer[100]; 2188 2189 if (PartitionList == NULL || CurrentPartition == NULL) 2190 { 2191 /* FIXME: show an error dialog */ 2192 return QUIT_PAGE; 2193 } 2194 2195 PartEntry = CurrentPartition; 2196 DiskEntry = CurrentPartition->DiskEntry; 2197 2198 MUIDisplayPage(DELETE_PARTITION_PAGE); 2199 2200 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2201 CONSOLE_SetTextXY(6, 10, LineBuffer); 2202 2203 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2204 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), 2205 LineBuffer); 2206 2207 while (TRUE) 2208 { 2209 CONSOLE_ConInKey(Ir); 2210 2211 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2212 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2213 { 2214 if (ConfirmQuit(Ir)) 2215 return QUIT_PAGE; 2216 2217 break; 2218 } 2219 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2220 { 2221 return SELECT_PARTITION_PAGE; 2222 } 2223 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */ 2224 { 2225 DeletePartition(PartitionList, 2226 CurrentPartition, 2227 &CurrentPartition); 2228 return SELECT_PARTITION_PAGE; 2229 } 2230 } 2231 2232 return DELETE_PARTITION_PAGE; 2233 } 2234 2235 2236 /* 2237 * Displays the SelectFileSystemPage. 2238 * 2239 * Next pages: 2240 * CheckFileSystemPage (At once if RepairUpdate is selected) 2241 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition) 2242 * FormatPartitionPage (Default, at once if Unattended and USetupData.FormatPartition) 2243 * SelectPartitionPage (If the user aborts) 2244 * QuitPage 2245 * 2246 * RETURNS 2247 * Number of the next page. 2248 */ 2249 // PFSVOL_CALLBACK 2250 static FSVOL_OP 2251 CALLBACK 2252 FsVolCallback( 2253 _In_opt_ PVOID Context, 2254 _In_ FSVOLNOTIFY FormatStatus, 2255 _In_ ULONG_PTR Param1, 2256 _In_ ULONG_PTR Param2); 2257 2258 typedef struct _FSVOL_CONTEXT 2259 { 2260 PINPUT_RECORD Ir; 2261 PAGE_NUMBER NextPageOnAbort; 2262 } FSVOL_CONTEXT, *PFSVOL_CONTEXT; 2263 2264 static PAGE_NUMBER 2265 StartPartitionOperationsPage(PINPUT_RECORD Ir) 2266 { 2267 FSVOL_CONTEXT FsVolContext = {Ir, QUIT_PAGE}; 2268 BOOLEAN Success; 2269 2270 if (PartitionList == NULL || InstallPartition == NULL) 2271 { 2272 /* FIXME: show an error dialog */ 2273 return QUIT_PAGE; 2274 } 2275 2276 /* Find or set the active system partition before starting formatting */ 2277 Success = InitSystemPartition(PartitionList, 2278 InstallPartition, 2279 &SystemPartition, 2280 FsVolCallback, 2281 &FsVolContext); 2282 if (!Success) 2283 return FsVolContext.NextPageOnAbort; 2284 // 2285 // FIXME?? If cannot use any system partition, install FreeLdr on floppy / removable media?? 2286 // 2287 2288 /* Set the AUTOCREATE flag if the system partition was automatically created */ 2289 if (SystemPartition->New) 2290 SystemPartition->New |= PARTITION_NEW_AUTOCREATE; 2291 2292 CONSOLE_ClearScreen(); 2293 CONSOLE_Flush(); 2294 2295 /* Apply all pending operations on partitions: formatting and checking */ 2296 Success = FsVolCommitOpsQueue(PartitionList, 2297 SystemPartition, 2298 InstallPartition, 2299 FsVolCallback, 2300 &FsVolContext); 2301 if (!Success) 2302 return FsVolContext.NextPageOnAbort; 2303 return BOOTLOADER_SELECT_PAGE; 2304 } 2305 2306 static BOOLEAN 2307 ChangeSystemPartitionPage( 2308 IN PINPUT_RECORD Ir, 2309 IN PPARTENTRY SystemPartition) 2310 { 2311 PPARTENTRY PartEntry; 2312 PDISKENTRY DiskEntry; 2313 CHAR LineBuffer[100]; 2314 2315 // CONSOLE_ClearScreen(); 2316 // CONSOLE_Flush(); 2317 MUIDisplayPage(CHANGE_SYSTEM_PARTITION); 2318 2319 PartEntry = PartitionList->SystemPartition; 2320 DiskEntry = PartEntry->DiskEntry; 2321 2322 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2323 CONSOLE_SetTextXY(8, 10, LineBuffer); 2324 2325 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2326 CONSOLE_PrintTextXY(8, 14, MUIGetString(STRING_HDDISK1), 2327 LineBuffer); 2328 2329 2330 PartEntry = SystemPartition; 2331 DiskEntry = PartEntry->DiskEntry; 2332 2333 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2334 CONSOLE_SetTextXY(8, 23, LineBuffer); 2335 2336 while (TRUE) 2337 { 2338 CONSOLE_ConInKey(Ir); 2339 2340 if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 2341 break; 2342 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2343 return FALSE; 2344 } 2345 2346 return TRUE; 2347 } 2348 2349 static VOID 2350 ResetFileSystemList(VOID) 2351 { 2352 if (!FileSystemList) 2353 return; 2354 2355 DestroyFileSystemList(FileSystemList); 2356 FileSystemList = NULL; 2357 } 2358 2359 static FSVOL_OP 2360 SelectFileSystemPage( 2361 IN PFSVOL_CONTEXT FsVolContext, 2362 IN PPARTENTRY PartEntry) 2363 { 2364 PINPUT_RECORD Ir = FsVolContext->Ir; 2365 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2366 PCWSTR DefaultFs; 2367 CHAR LineBuffer[100]; 2368 2369 DPRINT("SelectFileSystemPage()\n"); 2370 2371 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 2372 2373 Restart: 2374 /* Reset the file system list for each partition that is to be formatted */ 2375 ResetFileSystemList(); 2376 2377 CONSOLE_ClearScreen(); 2378 CONSOLE_Flush(); 2379 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE); 2380 2381 if (PartEntry->New & PARTITION_NEW_AUTOCREATE) 2382 { 2383 PartEntry->New &= ~PARTITION_NEW_AUTOCREATE; 2384 2385 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION)); 2386 } 2387 else if (PartEntry->New) 2388 { 2389 ULONG uID; 2390 2391 if (PartEntry == SystemPartition) // FormatSystemPartition 2392 uID = STRING_NONFORMATTEDSYSTEMPART; 2393 else if (PartEntry == InstallPartition) // FormatInstallPartition 2394 uID = STRING_NONFORMATTEDPART; 2395 else // FormatOtherPartition 2396 uID = STRING_NONFORMATTEDOTHERPART; 2397 2398 CONSOLE_SetTextXY(6, 8, MUIGetString(uID)); 2399 } 2400 else 2401 { 2402 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART)); 2403 } 2404 2405 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2406 CONSOLE_SetTextXY(6, 10, LineBuffer); 2407 2408 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2409 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), 2410 LineBuffer); 2411 2412 /* Show "This Partition will be formatted next" only if it is unformatted */ 2413 if (PartEntry->New || PartEntry->FormatState == Unformatted) 2414 CONSOLE_SetTextXY(6, 14, MUIGetString(STRING_PARTFORMAT)); 2415 2416 ASSERT(!FileSystemList); 2417 2418 if (IsUnattendedSetup) 2419 { 2420 ASSERT(USetupData.FormatPartition); 2421 2422 switch (USetupData.FsType) 2423 { 2424 /* 1 is for BtrFS */ 2425 case 1: 2426 DefaultFs = L"BTRFS"; 2427 break; 2428 2429 /* If we don't understand input, default to FAT */ 2430 default: 2431 DefaultFs = L"FAT"; 2432 break; 2433 } 2434 } 2435 else 2436 { 2437 /* By default select the "FAT" file system */ 2438 DefaultFs = L"FAT"; 2439 } 2440 2441 /* Create the file system list */ 2442 // TODO: Display only the FSes compatible with the selected partition! 2443 FileSystemList = CreateFileSystemList(6, 26, 2444 PartEntry->New || 2445 PartEntry->FormatState == Unformatted, 2446 DefaultFs); 2447 if (!FileSystemList) 2448 { 2449 /* FIXME: show an error dialog */ 2450 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2451 return FSVOL_ABORT; 2452 } 2453 2454 if (IsUnattendedSetup) 2455 { 2456 ASSERT(USetupData.FormatPartition); 2457 return FSVOL_DOIT; 2458 } 2459 2460 DrawFileSystemList(FileSystemList); 2461 2462 while (TRUE) 2463 { 2464 CONSOLE_ConInKey(Ir); 2465 2466 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2467 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2468 { 2469 if (ConfirmQuit(Ir)) 2470 { 2471 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2472 return FSVOL_ABORT; 2473 } 2474 2475 break; 2476 } 2477 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2478 { 2479 FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; 2480 return FSVOL_ABORT; 2481 } 2482 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2483 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 2484 { 2485 ScrollDownFileSystemList(FileSystemList); 2486 } 2487 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2488 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 2489 { 2490 ScrollUpFileSystemList(FileSystemList); 2491 } 2492 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 2493 { 2494 if (!FileSystemList->Selected->FileSystem) 2495 { 2496 ASSERT(!PartEntry->New && PartEntry->FormatState != Unformatted); 2497 2498 /* 2499 * Skip formatting this partition. We will also ignore 2500 * file system checks on it, unless it is either the 2501 * system or the installation partition. 2502 */ 2503 if (PartEntry != SystemPartition && 2504 PartEntry != InstallPartition) 2505 { 2506 PartEntry->NeedsCheck = FALSE; 2507 } 2508 return FSVOL_SKIP; 2509 } 2510 else 2511 { 2512 /* Format this partition */ 2513 return FSVOL_DOIT; 2514 } 2515 } 2516 } 2517 2518 goto Restart; 2519 } 2520 2521 static FSVOL_OP 2522 FormatPartitionPage( 2523 IN PFSVOL_CONTEXT FsVolContext, 2524 IN PPARTENTRY PartEntry) 2525 { 2526 PINPUT_RECORD Ir = FsVolContext->Ir; 2527 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2528 CHAR LineBuffer[100]; 2529 2530 Restart: 2531 CONSOLE_ClearScreen(); 2532 CONSOLE_Flush(); 2533 MUIDisplayPage(FORMAT_PARTITION_PAGE); 2534 2535 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2536 CONSOLE_SetTextXY(6, 10, LineBuffer); 2537 2538 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2539 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), 2540 LineBuffer); 2541 2542 while (TRUE) 2543 { 2544 if (!IsUnattendedSetup) 2545 CONSOLE_ConInKey(Ir); 2546 2547 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2548 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2549 { 2550 if (ConfirmQuit(Ir)) 2551 { 2552 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2553 return FSVOL_ABORT; 2554 } 2555 2556 goto Restart; 2557 } 2558 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */ 2559 { 2560 /* 2561 * Remove the "Press ENTER to continue" message prompt when the ENTER 2562 * key is pressed as the user wants to begin the partition formatting. 2563 */ 2564 MUIClearStyledText(FORMAT_PARTITION_PAGE, TEXT_ID_FORMAT_PROMPT, TEXT_TYPE_REGULAR); 2565 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 2566 2567 return FSVOL_DOIT; 2568 } 2569 } 2570 } 2571 2572 static VOID 2573 CheckFileSystemPage( 2574 IN PPARTENTRY PartEntry) 2575 { 2576 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 2577 CHAR LineBuffer[100]; 2578 2579 CONSOLE_ClearScreen(); 2580 CONSOLE_Flush(); 2581 MUIDisplayPage(CHECK_FILE_SYSTEM_PAGE); 2582 2583 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2584 CONSOLE_SetTextXY(6, 10, LineBuffer); 2585 2586 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); 2587 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), 2588 LineBuffer); 2589 } 2590 2591 // PFSVOL_CALLBACK 2592 static FSVOL_OP 2593 CALLBACK 2594 FsVolCallback( 2595 _In_opt_ PVOID Context, 2596 _In_ FSVOLNOTIFY FormatStatus, 2597 _In_ ULONG_PTR Param1, 2598 _In_ ULONG_PTR Param2) 2599 { 2600 PFSVOL_CONTEXT FsVolContext = (PFSVOL_CONTEXT)Context; 2601 PINPUT_RECORD Ir = FsVolContext->Ir; 2602 2603 switch (FormatStatus) 2604 { 2605 // FIXME: Deprecate! 2606 case ChangeSystemPartition: 2607 { 2608 PPARTENTRY SystemPartition = (PPARTENTRY)Param1; 2609 2610 FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; 2611 if (ChangeSystemPartitionPage(Ir, SystemPartition)) 2612 return FSVOL_DOIT; 2613 return FSVOL_ABORT; 2614 } 2615 2616 case FSVOLNOTIFY_PARTITIONERROR: 2617 { 2618 switch (Param1) 2619 { 2620 case STATUS_PARTITION_FAILURE: 2621 { 2622 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); 2623 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2624 break; 2625 } 2626 2627 case ERROR_SYSTEM_PARTITION_NOT_FOUND: 2628 { 2629 /* FIXME: improve the error dialog */ 2630 // 2631 // Error dialog should say that we cannot find a suitable 2632 // system partition and create one on the system. At this point, 2633 // it may be nice to ask the user whether he wants to continue, 2634 // or use an external drive as the system drive/partition 2635 // (e.g. floppy, USB drive, etc...) 2636 // 2637 PopupError("The ReactOS Setup could not find a supported system partition\n" 2638 "on your system or could not create a new one. Without such partition\n" 2639 "the Setup program cannot install ReactOS.\n" 2640 "Press ENTER to return to the partition selection list.", 2641 MUIGetString(STRING_CONTINUE), 2642 Ir, POPUP_WAIT_ENTER); 2643 2644 FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; 2645 break; 2646 } 2647 2648 default: 2649 break; 2650 } 2651 return FSVOL_ABORT; 2652 } 2653 2654 case FSVOLNOTIFY_STARTQUEUE: 2655 case FSVOLNOTIFY_ENDQUEUE: 2656 // NOTE: If needed, clear screen and flush input. 2657 return FSVOL_DOIT; 2658 2659 case FSVOLNOTIFY_STARTSUBQUEUE: 2660 { 2661 if ((FSVOL_OP)Param1 == FSVOL_FORMAT) 2662 { 2663 /* 2664 * In case we just repair an existing installation, or make 2665 * an unattended setup without formatting, just go to the 2666 * file system check step. 2667 */ 2668 if (RepairUpdateFlag) 2669 return FSVOL_SKIP; /** HACK!! **/ 2670 2671 if (IsUnattendedSetup && !USetupData.FormatPartition) 2672 return FSVOL_SKIP; /** HACK!! **/ 2673 } 2674 return FSVOL_DOIT; 2675 } 2676 2677 case FSVOLNOTIFY_ENDSUBQUEUE: 2678 return 0; 2679 2680 case FSVOLNOTIFY_FORMATERROR: 2681 { 2682 PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; 2683 CHAR Buffer[MAX_PATH]; 2684 2685 // FIXME: See also FSVOLNOTIFY_PARTITIONERROR 2686 if (FmtInfo->ErrorStatus == STATUS_PARTITION_FAILURE) 2687 { 2688 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); 2689 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2690 return FSVOL_ABORT; 2691 } 2692 else 2693 if (FmtInfo->ErrorStatus == STATUS_UNRECOGNIZED_VOLUME) 2694 { 2695 /* FIXME: show an error dialog */ 2696 // MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); 2697 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2698 return FSVOL_ABORT; 2699 } 2700 else 2701 if (FmtInfo->ErrorStatus == STATUS_NOT_SUPPORTED) 2702 { 2703 RtlStringCbPrintfA(Buffer, 2704 sizeof(Buffer), 2705 "Setup is currently unable to format a partition in %S.\n" 2706 "\n" 2707 " \x07 Press ENTER to continue Setup.\n" 2708 " \x07 Press F3 to quit Setup.", 2709 FmtInfo->FileSystemName); 2710 2711 PopupError(Buffer, 2712 MUIGetString(STRING_QUITCONTINUE), 2713 NULL, POPUP_WAIT_NONE); 2714 2715 while (TRUE) 2716 { 2717 CONSOLE_ConInKey(Ir); 2718 2719 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && 2720 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ 2721 { 2722 if (ConfirmQuit(Ir)) 2723 { 2724 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2725 return FSVOL_ABORT; 2726 } 2727 else 2728 { 2729 return FSVOL_RETRY; 2730 } 2731 } 2732 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ 2733 { 2734 return FSVOL_RETRY; 2735 } 2736 } 2737 } 2738 else if (!NT_SUCCESS(FmtInfo->ErrorStatus)) 2739 { 2740 WCHAR PathBuffer[MAX_PATH]; 2741 2742 /** HACK!! **/ 2743 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 2744 L"\\Device\\Harddisk%lu\\Partition%lu", 2745 FmtInfo->PartEntry->DiskEntry->DiskNumber, 2746 FmtInfo->PartEntry->PartitionNumber); 2747 2748 DPRINT1("FormatPartition() failed: Status 0x%08lx\n", FmtInfo->ErrorStatus); 2749 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); 2750 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2751 return FSVOL_ABORT; 2752 } 2753 return FSVOL_RETRY; 2754 } 2755 2756 case FSVOLNOTIFY_CHECKERROR: 2757 { 2758 PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; 2759 CHAR Buffer[MAX_PATH]; 2760 2761 if (ChkInfo->ErrorStatus == STATUS_NOT_SUPPORTED) 2762 { 2763 RtlStringCbPrintfA(Buffer, 2764 sizeof(Buffer), 2765 "Setup is currently unable to check a partition formatted in %S.\n" 2766 "\n" 2767 " \x07 Press ENTER to continue Setup.\n" 2768 " \x07 Press F3 to quit Setup.", 2769 ChkInfo->PartEntry->FileSystem); 2770 2771 PopupError(Buffer, 2772 MUIGetString(STRING_QUITCONTINUE), 2773 NULL, POPUP_WAIT_NONE); 2774 2775 while (TRUE) 2776 { 2777 CONSOLE_ConInKey(Ir); 2778 2779 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && 2780 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ 2781 { 2782 if (ConfirmQuit(Ir)) 2783 { 2784 FsVolContext->NextPageOnAbort = QUIT_PAGE; 2785 return FSVOL_ABORT; 2786 } 2787 else 2788 { 2789 return FSVOL_SKIP; 2790 } 2791 } 2792 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ 2793 { 2794 return FSVOL_SKIP; 2795 } 2796 } 2797 } 2798 else if (!NT_SUCCESS(ChkInfo->ErrorStatus)) 2799 { 2800 DPRINT1("ChkdskPartition() failed: Status 0x%08lx\n", ChkInfo->ErrorStatus); 2801 2802 RtlStringCbPrintfA(Buffer, 2803 sizeof(Buffer), 2804 "ChkDsk detected some disk errors.\n(Status 0x%08lx).\n", 2805 ChkInfo->ErrorStatus); 2806 2807 PopupError(Buffer, 2808 MUIGetString(STRING_CONTINUE), 2809 Ir, POPUP_WAIT_ENTER); 2810 return FSVOL_SKIP; 2811 } 2812 return FSVOL_SKIP; 2813 } 2814 2815 case FSVOLNOTIFY_STARTFORMAT: 2816 { 2817 PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; 2818 FSVOL_OP Result; 2819 2820 ASSERT((FSVOL_OP)Param2 == FSVOL_FORMAT); 2821 2822 /* Select the file system */ 2823 Result = SelectFileSystemPage(FsVolContext, FmtInfo->PartEntry); 2824 if (Result != FSVOL_DOIT) 2825 return Result; 2826 2827 /* Display the formatting page */ 2828 Result = FormatPartitionPage(FsVolContext, FmtInfo->PartEntry); 2829 if (Result != FSVOL_DOIT) 2830 return Result; 2831 2832 StartFormat(FmtInfo, FileSystemList->Selected); 2833 return FSVOL_DOIT; 2834 } 2835 2836 case FSVOLNOTIFY_ENDFORMAT: 2837 { 2838 PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; 2839 EndFormat(FmtInfo->ErrorStatus); 2840 2841 /* Reset the file system list */ 2842 ResetFileSystemList(); 2843 return 0; 2844 } 2845 2846 case FSVOLNOTIFY_STARTCHECK: 2847 { 2848 PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; 2849 2850 ASSERT((FSVOL_OP)Param2 == FSVOL_CHECK); 2851 2852 CheckFileSystemPage(ChkInfo->PartEntry); 2853 StartCheck(ChkInfo); 2854 return FSVOL_DOIT; 2855 } 2856 2857 case FSVOLNOTIFY_ENDCHECK: 2858 { 2859 PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; 2860 EndCheck(ChkInfo->ErrorStatus); 2861 return 0; 2862 } 2863 } 2864 2865 return 0; 2866 } 2867 2868 2869 static BOOLEAN 2870 IsValidPath( 2871 IN PCWSTR InstallDir) 2872 { 2873 UINT i, Length; 2874 2875 Length = wcslen(InstallDir); 2876 2877 // TODO: Add check for 8.3 too. 2878 2879 /* Path must be at least 2 characters long */ 2880 // if (Length < 2) 2881 // return FALSE; 2882 2883 /* Path must start with a backslash */ 2884 // if (InstallDir[0] != L'\\') 2885 // return FALSE; 2886 2887 /* Path must not end with a backslash */ 2888 if (InstallDir[Length - 1] == L'\\') 2889 return FALSE; 2890 2891 /* Path must not contain whitespace characters */ 2892 for (i = 0; i < Length; i++) 2893 { 2894 if (iswspace(InstallDir[i])) 2895 return FALSE; 2896 } 2897 2898 /* Path component must not end with a dot */ 2899 for (i = 0; i < Length; i++) 2900 { 2901 if (InstallDir[i] == L'\\' && i > 0) 2902 { 2903 if (InstallDir[i - 1] == L'.') 2904 return FALSE; 2905 } 2906 } 2907 2908 if (InstallDir[Length - 1] == L'.') 2909 return FALSE; 2910 2911 return TRUE; 2912 } 2913 2914 2915 /* 2916 * Displays the InstallDirectoryPage. 2917 * 2918 * Next pages: 2919 * PrepareCopyPage 2920 * QuitPage 2921 * 2922 * RETURNS 2923 * Number of the next page. 2924 */ 2925 static PAGE_NUMBER 2926 InstallDirectoryPage(PINPUT_RECORD Ir) 2927 { 2928 NTSTATUS Status; 2929 ULONG Length, Pos; 2930 WCHAR c; 2931 WCHAR InstallDir[MAX_PATH]; 2932 2933 if (PartitionList == NULL || InstallPartition == NULL) 2934 { 2935 /* FIXME: show an error dialog */ 2936 return QUIT_PAGE; 2937 } 2938 2939 // if (IsUnattendedSetup) 2940 if (RepairUpdateFlag) 2941 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath 2942 else if (USetupData.InstallationDirectory[0]) 2943 wcscpy(InstallDir, USetupData.InstallationDirectory); 2944 else 2945 wcscpy(InstallDir, L"\\ReactOS"); 2946 2947 /* 2948 * Check the validity of the predefined 'InstallDir'. If we are either 2949 * in unattended setup or in update/repair mode, and the installation path 2950 * is valid, just perform the installation. Otherwise (either in the case 2951 * of an invalid path, or we are in regular setup), display the UI and allow 2952 * the user to specify a new installation path. 2953 */ 2954 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir)) 2955 { 2956 Status = InitDestinationPaths(&USetupData, InstallDir, InstallPartition); 2957 if (!NT_SUCCESS(Status)) 2958 { 2959 DPRINT1("InitDestinationPaths() failed: Status 0x%lx\n", Status); 2960 MUIDisplayError(ERROR_NO_BUILD_PATH, Ir, POPUP_WAIT_ENTER); 2961 return QUIT_PAGE; 2962 } 2963 2964 /* 2965 * Check whether the user attempts to install ReactOS within the 2966 * installation source directory, or in a subdirectory thereof. 2967 * If so, fail with an error. 2968 */ 2969 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE)) 2970 { 2971 MUIDisplayError(ERROR_SOURCE_DIR, Ir, POPUP_WAIT_ENTER); 2972 return INSTALL_DIRECTORY_PAGE; 2973 } 2974 2975 return PREPARE_COPY_PAGE; 2976 } 2977 2978 Length = wcslen(InstallDir); 2979 Pos = Length; 2980 2981 MUIDisplayPage(INSTALL_DIRECTORY_PAGE); 2982 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 2983 CONSOLE_SetCursorXY(8 + Pos, 11); 2984 CONSOLE_SetCursorType(TRUE, TRUE); 2985 2986 while (TRUE) 2987 { 2988 CONSOLE_ConInKey(Ir); 2989 2990 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2991 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2992 { 2993 CONSOLE_SetCursorType(TRUE, FALSE); 2994 2995 if (ConfirmQuit(Ir)) 2996 return QUIT_PAGE; 2997 2998 CONSOLE_SetCursorType(TRUE, TRUE); 2999 break; 3000 } 3001 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3002 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */ 3003 { 3004 if (Pos < Length) 3005 { 3006 memmove(&InstallDir[Pos], 3007 &InstallDir[Pos + 1], 3008 (Length - Pos - 1) * sizeof(WCHAR)); 3009 InstallDir[Length - 1] = UNICODE_NULL; 3010 3011 Length--; 3012 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3013 CONSOLE_SetCursorXY(8 + Pos, 11); 3014 } 3015 } 3016 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3017 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 3018 { 3019 Pos = 0; 3020 CONSOLE_SetCursorXY(8 + Pos, 11); 3021 } 3022 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3023 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 3024 { 3025 Pos = Length; 3026 CONSOLE_SetCursorXY(8 + Pos, 11); 3027 } 3028 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3029 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */ 3030 { 3031 if (Pos > 0) 3032 { 3033 Pos--; 3034 CONSOLE_SetCursorXY(8 + Pos, 11); 3035 } 3036 } 3037 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3038 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */ 3039 { 3040 if (Pos < Length) 3041 { 3042 Pos++; 3043 CONSOLE_SetCursorXY(8 + Pos, 11); 3044 } 3045 } 3046 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 3047 { 3048 CONSOLE_SetCursorType(TRUE, FALSE); 3049 3050 /* 3051 * Check for the validity of the installation directory and pop up 3052 * an error if it is not the case. Then the user can fix its input. 3053 */ 3054 if (!IsValidPath(InstallDir)) 3055 { 3056 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER); 3057 return INSTALL_DIRECTORY_PAGE; 3058 } 3059 3060 Status = InitDestinationPaths(&USetupData, InstallDir, InstallPartition); 3061 if (!NT_SUCCESS(Status)) 3062 { 3063 DPRINT1("InitDestinationPaths() failed: Status 0x%lx\n", Status); 3064 MUIDisplayError(ERROR_NO_BUILD_PATH, Ir, POPUP_WAIT_ENTER); 3065 return QUIT_PAGE; 3066 } 3067 3068 /* 3069 * Check whether the user attempts to install ReactOS within the 3070 * installation source directory, or in a subdirectory thereof. 3071 * If so, fail with an error. 3072 */ 3073 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE)) 3074 { 3075 MUIDisplayError(ERROR_SOURCE_DIR, Ir, POPUP_WAIT_ENTER); 3076 return INSTALL_DIRECTORY_PAGE; 3077 } 3078 3079 return PREPARE_COPY_PAGE; 3080 } 3081 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */ 3082 { 3083 if (Pos > 0) 3084 { 3085 if (Pos < Length) 3086 memmove(&InstallDir[Pos - 1], 3087 &InstallDir[Pos], 3088 (Length - Pos) * sizeof(WCHAR)); 3089 InstallDir[Length - 1] = UNICODE_NULL; 3090 3091 Pos--; 3092 Length--; 3093 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3094 CONSOLE_SetCursorXY(8 + Pos, 11); 3095 } 3096 } 3097 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar)) 3098 { 3099 if (Length < 50) 3100 { 3101 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar; 3102 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_') 3103 { 3104 if (Pos < Length) 3105 memmove(&InstallDir[Pos + 1], 3106 &InstallDir[Pos], 3107 (Length - Pos) * sizeof(WCHAR)); 3108 InstallDir[Length + 1] = UNICODE_NULL; 3109 InstallDir[Pos] = c; 3110 3111 Pos++; 3112 Length++; 3113 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3114 CONSOLE_SetCursorXY(8 + Pos, 11); 3115 } 3116 } 3117 } 3118 } 3119 3120 return INSTALL_DIRECTORY_PAGE; 3121 } 3122 3123 3124 // PSETUP_ERROR_ROUTINE 3125 static VOID 3126 __cdecl 3127 USetupErrorRoutine( 3128 IN PUSETUP_DATA pSetupData, 3129 ...) 3130 { 3131 INPUT_RECORD Ir; 3132 va_list arg_ptr; 3133 3134 va_start(arg_ptr, pSetupData); 3135 3136 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS && 3137 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE) 3138 { 3139 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber... 3140 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr); 3141 } 3142 3143 va_end(arg_ptr); 3144 } 3145 3146 /* 3147 * Displays the PrepareCopyPage. 3148 * 3149 * Next pages: 3150 * FileCopyPage(At once) 3151 * QuitPage 3152 * 3153 * SIDEEFFECTS 3154 * Calls PrepareFileCopy 3155 * 3156 * RETURNS 3157 * Number of the next page. 3158 */ 3159 static PAGE_NUMBER 3160 PrepareCopyPage(PINPUT_RECORD Ir) 3161 { 3162 // ERROR_NUMBER ErrorNumber; 3163 BOOLEAN Success; 3164 3165 MUIDisplayPage(PREPARE_COPY_PAGE); 3166 3167 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL); 3168 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success) 3169 { 3170 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER); 3171 return QUIT_PAGE; 3172 } 3173 3174 return FILE_COPY_PAGE; 3175 } 3176 3177 typedef struct _COPYCONTEXT 3178 { 3179 ULONG TotalOperations; 3180 ULONG CompletedOperations; 3181 PPROGRESSBAR ProgressBar; 3182 PPROGRESSBAR MemoryBars[4]; 3183 } COPYCONTEXT, *PCOPYCONTEXT; 3184 3185 static VOID 3186 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext, 3187 IN BOOLEAN First) 3188 { 3189 SYSTEM_PERFORMANCE_INFORMATION PerfInfo; 3190 3191 /* Get the memory information from the system */ 3192 NtQuerySystemInformation(SystemPerformanceInformation, 3193 &PerfInfo, 3194 sizeof(PerfInfo), 3195 NULL); 3196 3197 /* Check if this is initial setup */ 3198 if (First) 3199 { 3200 /* Set maximum limits to be total RAM pages */ 3201 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit); 3202 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit); 3203 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit); 3204 } 3205 3206 /* Set current values */ 3207 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages); 3208 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage); 3209 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages); 3210 } 3211 3212 static UINT 3213 CALLBACK 3214 FileCopyCallback(PVOID Context, 3215 UINT Notification, 3216 UINT_PTR Param1, 3217 UINT_PTR Param2) 3218 { 3219 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context; 3220 PFILEPATHS_W FilePathInfo; 3221 PCWSTR SrcFileName, DstFileName; 3222 3223 switch (Notification) 3224 { 3225 case SPFILENOTIFY_STARTSUBQUEUE: 3226 { 3227 CopyContext->TotalOperations = (ULONG)Param2; 3228 CopyContext->CompletedOperations = 0; 3229 ProgressSetStepCount(CopyContext->ProgressBar, 3230 CopyContext->TotalOperations); 3231 SetupUpdateMemoryInfo(CopyContext, TRUE); 3232 break; 3233 } 3234 3235 case SPFILENOTIFY_STARTDELETE: 3236 case SPFILENOTIFY_STARTRENAME: 3237 case SPFILENOTIFY_STARTCOPY: 3238 { 3239 FilePathInfo = (PFILEPATHS_W)Param1; 3240 3241 if (Notification == SPFILENOTIFY_STARTDELETE) 3242 { 3243 /* Display delete message */ 3244 ASSERT(Param2 == FILEOP_DELETE); 3245 3246 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3247 if (DstFileName) ++DstFileName; 3248 else DstFileName = FilePathInfo->Target; 3249 3250 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING), 3251 DstFileName); 3252 } 3253 else if (Notification == SPFILENOTIFY_STARTRENAME) 3254 { 3255 /* Display move/rename message */ 3256 ASSERT(Param2 == FILEOP_RENAME); 3257 3258 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\'); 3259 if (SrcFileName) ++SrcFileName; 3260 else SrcFileName = FilePathInfo->Source; 3261 3262 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3263 if (DstFileName) ++DstFileName; 3264 else DstFileName = FilePathInfo->Target; 3265 3266 if (!wcsicmp(SrcFileName, DstFileName)) 3267 Param2 = STRING_MOVING; 3268 else 3269 Param2 = STRING_RENAMING; 3270 3271 CONSOLE_SetStatusText(MUIGetString(Param2), 3272 SrcFileName, DstFileName); 3273 } 3274 else if (Notification == SPFILENOTIFY_STARTCOPY) 3275 { 3276 static PCSTR s_pszCopying = NULL; /* Cached for speed */ 3277 3278 /* Display copy message */ 3279 ASSERT(Param2 == FILEOP_COPY); 3280 3281 /* NOTE: When extracting from CABs the Source is the CAB name */ 3282 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3283 if (DstFileName) ++DstFileName; 3284 else DstFileName = FilePathInfo->Target; 3285 3286 if (!s_pszCopying) 3287 s_pszCopying = MUIGetString(STRING_COPYING); 3288 CONSOLE_SetStatusText(s_pszCopying, DstFileName); 3289 #ifdef __REACTOS__ /* HACK */ 3290 DoWatchDestFileName(DstFileName); 3291 #endif 3292 } 3293 3294 SetupUpdateMemoryInfo(CopyContext, FALSE); 3295 break; 3296 } 3297 3298 case SPFILENOTIFY_COPYERROR: 3299 { 3300 FilePathInfo = (PFILEPATHS_W)Param1; 3301 3302 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n", 3303 FilePathInfo->Target, FilePathInfo->Win32Error); 3304 return FILEOP_SKIP; 3305 } 3306 3307 case SPFILENOTIFY_ENDDELETE: 3308 case SPFILENOTIFY_ENDRENAME: 3309 case SPFILENOTIFY_ENDCOPY: 3310 { 3311 CopyContext->CompletedOperations++; 3312 3313 /* SYSREG checkpoint */ 3314 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations) 3315 DPRINT1("CHECKPOINT:HALF_COPIED\n"); 3316 3317 ProgressNextStep(CopyContext->ProgressBar); 3318 SetupUpdateMemoryInfo(CopyContext, FALSE); 3319 break; 3320 } 3321 } 3322 3323 return FILEOP_DOIT; 3324 } 3325 3326 3327 /* 3328 * Displays the FileCopyPage. 3329 * 3330 * Next pages: 3331 * RegistryPage(At once) 3332 * 3333 * SIDEEFFECTS 3334 * Calls DoFileCopy 3335 * 3336 * RETURNS 3337 * Number of the next page. 3338 */ 3339 static PAGE_NUMBER 3340 FileCopyPage(PINPUT_RECORD Ir) 3341 { 3342 COPYCONTEXT CopyContext; 3343 UINT MemBarWidth; 3344 3345 MUIDisplayPage(FILE_COPY_PAGE); 3346 3347 /* Create context for the copy process */ 3348 CopyContext.TotalOperations = 0; 3349 CopyContext.CompletedOperations = 0; 3350 3351 /* Create the progress bar as well */ 3352 CopyContext.ProgressBar = CreateProgressBar(13, 3353 26, 3354 xScreen - 13, 3355 yScreen - 20, 3356 10, 3357 24, 3358 TRUE, 3359 MUIGetString(STRING_SETUPCOPYINGFILES)); 3360 3361 // fit memory bars to screen width, distribute them uniform 3362 MemBarWidth = (xScreen - 26) / 5; 3363 MemBarWidth -= MemBarWidth % 2; // make even 3364 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */ 3365 /* Create the paged pool progress bar */ 3366 CopyContext.MemoryBars[0] = CreateProgressBar(13, 3367 40, 3368 13 + MemBarWidth, 3369 43, 3370 13, 3371 44, 3372 FALSE, 3373 "Kernel Pool"); 3374 3375 /* Create the non paged pool progress bar */ 3376 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2), 3377 40, 3378 (xScreen / 2) + (MemBarWidth / 2), 3379 43, 3380 (xScreen / 2)- (MemBarWidth / 2), 3381 44, 3382 FALSE, 3383 "Kernel Cache"); 3384 3385 /* Create the global memory progress bar */ 3386 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth, 3387 40, 3388 xScreen - 13, 3389 43, 3390 xScreen - 13 - MemBarWidth, 3391 44, 3392 FALSE, 3393 "Free Memory"); 3394 3395 /* Do the file copying */ 3396 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext); 3397 3398 /* If we get here, we're done, so cleanup the progress bar */ 3399 DestroyProgressBar(CopyContext.ProgressBar); 3400 DestroyProgressBar(CopyContext.MemoryBars[0]); 3401 DestroyProgressBar(CopyContext.MemoryBars[1]); 3402 DestroyProgressBar(CopyContext.MemoryBars[2]); 3403 3404 /* Create the $winnt$.inf file */ 3405 InstallSetupInfFile(&USetupData); 3406 3407 /* Go display the next page */ 3408 return REGISTRY_PAGE; 3409 } 3410 3411 3412 static VOID 3413 __cdecl 3414 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...) 3415 { 3416 /* WARNING: Please keep this lookup table in sync with the resources! */ 3417 static const UINT StringIDs[] = 3418 { 3419 STRING_DONE, /* Success */ 3420 STRING_REGHIVEUPDATE, /* RegHiveUpdate */ 3421 STRING_IMPORTFILE, /* ImportRegHive */ 3422 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */ 3423 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */ 3424 STRING_ADDKBLAYOUTS, /* KeybLayouts */ 3425 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */ 3426 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */ 3427 }; 3428 3429 va_list args; 3430 3431 if (RegStatus < ARRAYSIZE(StringIDs)) 3432 { 3433 va_start(args, RegStatus); 3434 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args); 3435 va_end(args); 3436 } 3437 else 3438 { 3439 CONSOLE_SetStatusText("Unknown status %d", RegStatus); 3440 } 3441 } 3442 3443 /* 3444 * Displays the RegistryPage. 3445 * 3446 * Next pages: 3447 * BootLoaderSelectPage 3448 * QuitPage 3449 * 3450 * SIDEEFFECTS 3451 * Calls UpdateRegistry 3452 * 3453 * RETURNS 3454 * Number of the next page. 3455 */ 3456 static PAGE_NUMBER 3457 RegistryPage(PINPUT_RECORD Ir) 3458 { 3459 ULONG Error; 3460 3461 MUIDisplayPage(REGISTRY_PAGE); 3462 3463 Error = UpdateRegistry(&USetupData, 3464 RepairUpdateFlag, 3465 PartitionList, 3466 InstallPartition->DriveLetter, 3467 SelectedLanguageId, 3468 RegistryStatus, 3469 &s_SubstSettings); 3470 if (Error != ERROR_SUCCESS) 3471 { 3472 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER); 3473 return QUIT_PAGE; 3474 } 3475 else 3476 { 3477 CONSOLE_SetStatusText(MUIGetString(STRING_DONE)); 3478 return BOOTLOADER_INSTALL_PAGE; 3479 } 3480 } 3481 3482 3483 /* 3484 * Displays the BootLoaderSelectPage. 3485 * 3486 * Next pages: 3487 * SuccessPage 3488 * QuitPage 3489 * 3490 * RETURNS 3491 * Number of the next page. 3492 */ 3493 static PAGE_NUMBER 3494 BootLoaderSelectPage(PINPUT_RECORD Ir) 3495 { 3496 USHORT Line = 12; 3497 3498 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 3499 3500 /* We must have a supported system partition by now */ 3501 ASSERT(SystemPartition && SystemPartition->IsPartitioned && SystemPartition->PartitionNumber != 0); 3502 3503 /* 3504 * If we repair an existing installation and we made it up to here, 3505 * this means a valid bootloader and boot entry have been found. 3506 * Thus, there is no need to re-install it: skip its installation. 3507 */ 3508 if (RepairUpdateFlag) 3509 { 3510 USetupData.MBRInstallType = 0; 3511 goto Quit; 3512 } 3513 3514 /* For unattended setup, skip MBR installation or install on removable disk if needed */ 3515 if (IsUnattendedSetup) 3516 { 3517 if ((USetupData.MBRInstallType == 0) || 3518 (USetupData.MBRInstallType == 1)) 3519 { 3520 goto Quit; 3521 } 3522 } 3523 3524 #if 0 // Deprecated code, whose global logic may need to be moved elsewhere... 3525 /* 3526 * We may install an MBR or VBR, but before that, check whether 3527 * we need to actually install the VBR on removable disk if the 3528 * system partition is not recognized. 3529 */ 3530 if ((SystemPartition->DiskEntry->DiskStyle != PARTITION_STYLE_MBR) || 3531 !IsRecognizedPartition(SystemPartition->PartitionType)) 3532 { 3533 USetupData.MBRInstallType = 1; 3534 goto Quit; 3535 } 3536 #endif 3537 3538 /* Is it an unattended install on hdd? */ 3539 if (IsUnattendedSetup) 3540 { 3541 if ((USetupData.MBRInstallType == 2) || 3542 (USetupData.MBRInstallType == 3)) 3543 { 3544 goto Quit; 3545 } 3546 } 3547 3548 MUIDisplayPage(BOOTLOADER_SELECT_PAGE); 3549 CONSOLE_InvertTextXY(8, Line, 60, 1); 3550 3551 while (TRUE) 3552 { 3553 CONSOLE_ConInKey(Ir); 3554 3555 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3556 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 3557 { 3558 CONSOLE_NormalTextXY(8, Line, 60, 1); 3559 3560 Line++; 3561 if (Line < 12) 3562 Line = 15; 3563 3564 if (Line > 15) 3565 Line = 12; 3566 3567 CONSOLE_InvertTextXY(8, Line, 60, 1); 3568 } 3569 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3570 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 3571 { 3572 CONSOLE_NormalTextXY(8, Line, 60, 1); 3573 3574 Line--; 3575 if (Line < 12) 3576 Line = 15; 3577 3578 if (Line > 15) 3579 Line = 12; 3580 3581 CONSOLE_InvertTextXY(8, Line, 60, 1); 3582 } 3583 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3584 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 3585 { 3586 CONSOLE_NormalTextXY(8, Line, 60, 1); 3587 3588 Line = 12; 3589 3590 CONSOLE_InvertTextXY(8, Line, 60, 1); 3591 } 3592 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3593 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 3594 { 3595 CONSOLE_NormalTextXY(8, Line, 60, 1); 3596 3597 Line = 15; 3598 3599 CONSOLE_InvertTextXY(8, Line, 60, 1); 3600 } 3601 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3602 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 3603 { 3604 if (ConfirmQuit(Ir)) 3605 return QUIT_PAGE; 3606 3607 break; 3608 } 3609 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 3610 { 3611 if (Line == 12) 3612 { 3613 /* Install on both MBR and VBR */ 3614 USetupData.MBRInstallType = 2; 3615 break; 3616 } 3617 else if (Line == 13) 3618 { 3619 /* Install on VBR only */ 3620 USetupData.MBRInstallType = 3; 3621 break; 3622 } 3623 else if (Line == 14) 3624 { 3625 /* Install on removable disk */ 3626 USetupData.MBRInstallType = 1; 3627 break; 3628 } 3629 else if (Line == 15) 3630 { 3631 /* Skip installation */ 3632 USetupData.MBRInstallType = 0; 3633 break; 3634 } 3635 3636 return BOOTLOADER_SELECT_PAGE; 3637 } 3638 } 3639 3640 Quit: 3641 /* Continue the installation; the bootloader is installed at the end */ 3642 return INSTALL_DIRECTORY_PAGE; 3643 } 3644 3645 3646 /* 3647 * Installs the bootloader on removable disk. 3648 */ 3649 static BOOLEAN 3650 BootLoaderRemovableDiskPage(PINPUT_RECORD Ir) 3651 { 3652 NTSTATUS Status; 3653 3654 Retry: 3655 CONSOLE_ClearScreen(); 3656 CONSOLE_Flush(); 3657 MUIDisplayPage(BOOTLOADER_REMOVABLE_DISK_PAGE); 3658 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 3659 3660 while (TRUE) 3661 { 3662 CONSOLE_ConInKey(Ir); 3663 3664 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3665 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 3666 { 3667 if (ConfirmQuit(Ir)) 3668 return FALSE; 3669 3670 break; 3671 } 3672 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 3673 { 3674 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, 3675 &USetupData.DestinationArcPath); 3676 if (!NT_SUCCESS(Status)) 3677 { 3678 if (Status == STATUS_DEVICE_NOT_READY) 3679 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER); 3680 3681 /* TODO: Print error message */ 3682 goto Retry; 3683 } 3684 3685 return TRUE; 3686 } 3687 } 3688 3689 goto Retry; 3690 } 3691 3692 /* 3693 * Installs the bootloader on hard-disk. 3694 */ 3695 static BOOLEAN 3696 BootLoaderHardDiskPage(PINPUT_RECORD Ir) 3697 { 3698 NTSTATUS Status; 3699 WCHAR DestinationDevicePathBuffer[MAX_PATH]; 3700 3701 if (USetupData.MBRInstallType == 2) 3702 { 3703 /* Step 1: Write the VBR */ 3704 Status = InstallVBRToPartition(&USetupData.SystemRootPath, 3705 &USetupData.SourceRootPath, 3706 &USetupData.DestinationArcPath, 3707 SystemPartition->FileSystem); 3708 if (!NT_SUCCESS(Status)) 3709 { 3710 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, 3711 SystemPartition->FileSystem); 3712 return FALSE; 3713 } 3714 3715 /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */ 3716 if (!IsSuperFloppy(SystemPartition->DiskEntry)) 3717 { 3718 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), 3719 L"\\Device\\Harddisk%d\\Partition0", 3720 SystemPartition->DiskEntry->DiskNumber); 3721 Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath, 3722 &USetupData.SourceRootPath, 3723 DestinationDevicePathBuffer); 3724 if (!NT_SUCCESS(Status)) 3725 { 3726 DPRINT1("InstallMbrBootCodeToDisk() failed: Status 0x%lx\n", Status); 3727 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR"); 3728 return FALSE; 3729 } 3730 } 3731 } 3732 else 3733 { 3734 Status = InstallVBRToPartition(&USetupData.SystemRootPath, 3735 &USetupData.SourceRootPath, 3736 &USetupData.DestinationArcPath, 3737 SystemPartition->FileSystem); 3738 if (!NT_SUCCESS(Status)) 3739 { 3740 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, 3741 SystemPartition->FileSystem); 3742 return FALSE; 3743 } 3744 } 3745 3746 return TRUE; 3747 } 3748 3749 /* 3750 * Actually installs the bootloader at the end of the installation. 3751 * The bootloader installation place has already been chosen before, 3752 * see BootLoaderSelectPage(). 3753 * 3754 * Next pages: 3755 * SuccessPage (At once) 3756 * QuitPage 3757 * 3758 * RETURNS 3759 * Number of the next page. 3760 */ 3761 static PAGE_NUMBER 3762 BootLoaderInstallPage(PINPUT_RECORD Ir) 3763 { 3764 WCHAR PathBuffer[MAX_PATH]; 3765 3766 // /* We must have a supported system partition by now */ 3767 // ASSERT(SystemPartition && SystemPartition->IsPartitioned && SystemPartition->PartitionNumber != 0); 3768 3769 RtlFreeUnicodeString(&USetupData.SystemRootPath); 3770 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 3771 L"\\Device\\Harddisk%lu\\Partition%lu\\", 3772 SystemPartition->DiskEntry->DiskNumber, 3773 SystemPartition->PartitionNumber); 3774 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer); 3775 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath); 3776 3777 if (USetupData.MBRInstallType != 0) 3778 MUIDisplayPage(BOOTLOADER_INSTALL_PAGE); 3779 3780 switch (USetupData.MBRInstallType) 3781 { 3782 /* Skip installation */ 3783 case 0: 3784 return SUCCESS_PAGE; 3785 3786 /* Install on removable disk */ 3787 case 1: 3788 return BootLoaderRemovableDiskPage(Ir) ? SUCCESS_PAGE : QUIT_PAGE; 3789 3790 /* Install on hard-disk (both MBR and VBR, or VBR only) */ 3791 case 2: 3792 case 3: 3793 return BootLoaderHardDiskPage(Ir) ? SUCCESS_PAGE : QUIT_PAGE; 3794 3795 default: 3796 return SUCCESS_PAGE; 3797 } 3798 } 3799 3800 3801 /** 3802 * @name ProgressTimeOutStringHandler 3803 * 3804 * Handles the generation (displaying) of the timeout 3805 * countdown to the screen dynamically. 3806 * 3807 * @param Bar 3808 * A pointer to a progress bar. 3809 * 3810 * @param AlwaysUpdate 3811 * Constantly update the progress bar (boolean type). 3812 * 3813 * @param Buffer 3814 * A pointer to a string buffer. 3815 * 3816 * @param cchBufferSize 3817 * The buffer's size in number of characters. 3818 * 3819 * @return 3820 * TRUE or FALSE on function termination. 3821 * 3822 */ 3823 static 3824 BOOLEAN NTAPI 3825 ProgressTimeOutStringHandler( 3826 IN PPROGRESSBAR Bar, 3827 IN BOOLEAN AlwaysUpdate, 3828 OUT PSTR Buffer, 3829 IN SIZE_T cchBufferSize) 3830 { 3831 ULONG OldProgress = Bar->Progress; 3832 3833 if (Bar->StepCount == 0) 3834 { 3835 Bar->Progress = 0; 3836 } 3837 else 3838 { 3839 Bar->Progress = Bar->StepCount - Bar->CurrentStep; 3840 } 3841 3842 /* Build the progress string if it has changed */ 3843 if (Bar->ProgressFormatText && 3844 (AlwaysUpdate || (Bar->Progress != OldProgress))) 3845 { 3846 RtlStringCchPrintfA(Buffer, cchBufferSize, 3847 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1); 3848 3849 return TRUE; 3850 } 3851 3852 return FALSE; 3853 } 3854 3855 /** 3856 * @name ProgressCountdown 3857 * 3858 * Displays and draws a red-coloured progress bar with a countdown. 3859 * When the timeout is reached, the flush page is displayed for reboot. 3860 * 3861 * @param Ir 3862 * A pointer to an input keyboard record. 3863 * 3864 * @param TimeOut 3865 * Initial countdown value in seconds. 3866 * 3867 * @return 3868 * Nothing. 3869 * 3870 */ 3871 static VOID 3872 ProgressCountdown( 3873 IN PINPUT_RECORD Ir, 3874 IN LONG TimeOut) 3875 { 3876 NTSTATUS Status; 3877 ULONG StartTime, BarWidth, TimerDiv; 3878 LONG TimeElapsed; 3879 LONG TimerValue, OldTimerValue; 3880 LARGE_INTEGER Timeout; 3881 PPROGRESSBAR ProgressBar; 3882 BOOLEAN RefreshProgress = TRUE; 3883 3884 /* Bail out if the timeout is already zero */ 3885 if (TimeOut <= 0) 3886 return; 3887 3888 /* Create the timeout progress bar and set it up */ 3889 ProgressBar = CreateProgressBarEx(13, 3890 26, 3891 xScreen - 13, 3892 yScreen - 20, 3893 10, 3894 24, 3895 TRUE, 3896 FOREGROUND_RED | BACKGROUND_BLUE, 3897 0, 3898 NULL, 3899 MUIGetString(STRING_REBOOTPROGRESSBAR), 3900 ProgressTimeOutStringHandler); 3901 3902 BarWidth = max(1, ProgressBar->Width); 3903 TimerValue = TimeOut * BarWidth; 3904 ProgressSetStepCount(ProgressBar, TimerValue); 3905 3906 StartTime = NtGetTickCount(); 3907 CONSOLE_Flush(); 3908 3909 TimerDiv = 1000 / BarWidth; 3910 TimerDiv = max(1, TimerDiv); 3911 OldTimerValue = TimerValue; 3912 while (TRUE) 3913 { 3914 /* Decrease the timer */ 3915 3916 /* 3917 * Compute how much time the previous operations took. 3918 * This allows us in particular to take account for any time 3919 * elapsed if something slowed down. 3920 */ 3921 TimeElapsed = NtGetTickCount() - StartTime; 3922 if (TimeElapsed >= TimerDiv) 3923 { 3924 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */ 3925 TimeElapsed /= TimerDiv; 3926 StartTime += (TimerDiv * TimeElapsed); 3927 3928 if (TimeElapsed <= TimerValue) 3929 TimerValue -= TimeElapsed; 3930 else 3931 TimerValue = 0; 3932 3933 RefreshProgress = TRUE; 3934 } 3935 3936 if (RefreshProgress) 3937 { 3938 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue); 3939 RefreshProgress = FALSE; 3940 } 3941 3942 /* Stop when the timer reaches zero */ 3943 if (TimerValue <= 0) 3944 break; 3945 3946 /* Check for user key presses */ 3947 3948 /* 3949 * If the timer is used, use a passive wait of maximum 1 second 3950 * while monitoring for incoming console input events, so that 3951 * we are still able to display the timing count. 3952 */ 3953 3954 /* Wait a maximum of 1 second for input events */ 3955 TimeElapsed = NtGetTickCount() - StartTime; 3956 if (TimeElapsed < TimerDiv) 3957 { 3958 /* Convert the time to NT format */ 3959 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL; 3960 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout); 3961 } 3962 else 3963 { 3964 Status = STATUS_TIMEOUT; 3965 } 3966 3967 /* Check whether the input event has been signaled, or a timeout happened */ 3968 if (Status == STATUS_TIMEOUT) 3969 { 3970 continue; 3971 } 3972 if (Status != STATUS_WAIT_0) 3973 { 3974 /* An error happened, bail out */ 3975 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status); 3976 break; 3977 } 3978 3979 /* Check for an ENTER key press */ 3980 while (CONSOLE_ConInKeyPeek(Ir)) 3981 { 3982 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 3983 { 3984 /* Found it, stop waiting */ 3985 goto Exit; 3986 } 3987 } 3988 } 3989 3990 Exit: 3991 /* Destroy the progress bar and quit */ 3992 DestroyProgressBar(ProgressBar); 3993 } 3994 3995 3996 /* 3997 * Displays the QuitPage. 3998 * 3999 * Next pages: 4000 * FlushPage (At once) 4001 * 4002 * SIDEEFFECTS 4003 * Destroy the Lists 4004 * 4005 * RETURNS 4006 * Number of the next page. 4007 */ 4008 static PAGE_NUMBER 4009 QuitPage(PINPUT_RECORD Ir) 4010 { 4011 MUIDisplayPage(QUIT_PAGE); 4012 4013 /* Destroy the NTOS installations list */ 4014 if (NtOsInstallsList != NULL) 4015 { 4016 DestroyGenericList(NtOsInstallsList, TRUE); 4017 NtOsInstallsList = NULL; 4018 } 4019 4020 /* Destroy the partition list */ 4021 if (PartitionList != NULL) 4022 { 4023 DestroyPartitionList(PartitionList); 4024 PartitionList = NULL; 4025 } 4026 4027 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2)); 4028 4029 /* Wait for maximum 15 seconds or an ENTER key before quitting */ 4030 ProgressCountdown(Ir, 15); 4031 return FLUSH_PAGE; 4032 } 4033 4034 4035 /* 4036 * Displays the SuccessPage. 4037 * 4038 * Next pages: 4039 * FlushPage (At once) 4040 * 4041 * SIDEEFFECTS 4042 * Destroy the Lists 4043 * 4044 * RETURNS 4045 * Number of the next page. 4046 */ 4047 static PAGE_NUMBER 4048 SuccessPage(PINPUT_RECORD Ir) 4049 { 4050 MUIDisplayPage(SUCCESS_PAGE); 4051 4052 if (IsUnattendedSetup) 4053 return FLUSH_PAGE; 4054 4055 /* Wait for maximum 15 seconds or an ENTER key before quitting */ 4056 ProgressCountdown(Ir, 15); 4057 return FLUSH_PAGE; 4058 } 4059 4060 4061 /* 4062 * Displays the FlushPage. 4063 * 4064 * Next pages: 4065 * RebootPage (At once) 4066 * 4067 * RETURNS 4068 * Number of the next page. 4069 */ 4070 static PAGE_NUMBER 4071 FlushPage(PINPUT_RECORD Ir) 4072 { 4073 MUIDisplayPage(FLUSH_PAGE); 4074 return REBOOT_PAGE; 4075 } 4076 4077 4078 /* 4079 * The start routine and page management 4080 */ 4081 NTSTATUS 4082 RunUSetup(VOID) 4083 { 4084 NTSTATUS Status; 4085 INPUT_RECORD Ir; 4086 PAGE_NUMBER Page; 4087 BOOLEAN Old; 4088 4089 InfSetHeap(ProcessHeap); 4090 4091 /* Tell the Cm this is a setup boot, and it has to behave accordingly */ 4092 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP); 4093 if (!NT_SUCCESS(Status)) 4094 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status); 4095 4096 /* Initialize the user-mode PnP manager */ 4097 Status = InitializeUserModePnpManager(&USetupData.SetupInf); 4098 if (!NT_SUCCESS(Status)) 4099 { 4100 // PrintString(??); 4101 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status); 4102 } 4103 4104 if (!CONSOLE_Init()) 4105 { 4106 PrintString(MUIGetString(STRING_CONSOLEFAIL1)); 4107 PrintString(MUIGetString(STRING_CONSOLEFAIL2)); 4108 PrintString(MUIGetString(STRING_CONSOLEFAIL3)); 4109 4110 /* We failed to initialize the video, just quit the installer */ 4111 return STATUS_APP_INIT_FAILURE; 4112 } 4113 4114 /* Initialize Setup, phase 0 */ 4115 InitializeSetup(&USetupData, 0); 4116 USetupData.ErrorRoutine = USetupErrorRoutine; 4117 4118 /* Hide the cursor and clear the screen and keyboard buffer */ 4119 CONSOLE_SetCursorType(TRUE, FALSE); 4120 CONSOLE_ClearScreen(); 4121 CONSOLE_Flush(); 4122 4123 /* Global Initialization page */ 4124 Page = SetupStartPage(&Ir); 4125 4126 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE) 4127 { 4128 CONSOLE_ClearScreen(); 4129 CONSOLE_Flush(); 4130 4131 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup "); 4132 4133 switch (Page) 4134 { 4135 /* Language page */ 4136 case LANGUAGE_PAGE: 4137 Page = LanguagePage(&Ir); 4138 break; 4139 4140 /* Welcome page */ 4141 case WELCOME_PAGE: 4142 Page = WelcomePage(&Ir); 4143 break; 4144 4145 /* License page */ 4146 case LICENSE_PAGE: 4147 Page = LicensePage(&Ir); 4148 break; 4149 4150 /* Install pages */ 4151 case INSTALL_INTRO_PAGE: 4152 Page = InstallIntroPage(&Ir); 4153 break; 4154 4155 #if 0 4156 case SCSI_CONTROLLER_PAGE: 4157 Page = ScsiControllerPage(&Ir); 4158 break; 4159 4160 case OEM_DRIVER_PAGE: 4161 Page = OemDriverPage(&Ir); 4162 break; 4163 #endif 4164 4165 case DEVICE_SETTINGS_PAGE: 4166 Page = DeviceSettingsPage(&Ir); 4167 break; 4168 4169 case COMPUTER_SETTINGS_PAGE: 4170 Page = ComputerSettingsPage(&Ir); 4171 break; 4172 4173 case DISPLAY_SETTINGS_PAGE: 4174 Page = DisplaySettingsPage(&Ir); 4175 break; 4176 4177 case KEYBOARD_SETTINGS_PAGE: 4178 Page = KeyboardSettingsPage(&Ir); 4179 break; 4180 4181 case LAYOUT_SETTINGS_PAGE: 4182 Page = LayoutSettingsPage(&Ir); 4183 break; 4184 4185 /* Partitioning pages */ 4186 case SELECT_PARTITION_PAGE: 4187 Page = SelectPartitionPage(&Ir); 4188 break; 4189 4190 case CREATE_PARTITION_PAGE: 4191 Page = CreatePartitionPage(&Ir); 4192 break; 4193 4194 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE: 4195 Page = ConfirmDeleteSystemPartitionPage(&Ir); 4196 break; 4197 4198 case DELETE_PARTITION_PAGE: 4199 Page = DeletePartitionPage(&Ir); 4200 break; 4201 4202 /* File system partition operations pages */ 4203 case START_PARTITION_OPERATIONS_PAGE: 4204 Page = StartPartitionOperationsPage(&Ir); 4205 break; 4206 4207 /* Bootloader selection page */ 4208 case BOOTLOADER_SELECT_PAGE: 4209 Page = BootLoaderSelectPage(&Ir); 4210 break; 4211 4212 /* Installation pages */ 4213 case INSTALL_DIRECTORY_PAGE: 4214 Page = InstallDirectoryPage(&Ir); 4215 break; 4216 4217 case PREPARE_COPY_PAGE: 4218 Page = PrepareCopyPage(&Ir); 4219 break; 4220 4221 case FILE_COPY_PAGE: 4222 Page = FileCopyPage(&Ir); 4223 break; 4224 4225 case REGISTRY_PAGE: 4226 Page = RegistryPage(&Ir); 4227 break; 4228 4229 /* Bootloader installation page */ 4230 case BOOTLOADER_INSTALL_PAGE: 4231 // case BOOTLOADER_REMOVABLE_DISK_PAGE: 4232 Page = BootLoaderInstallPage(&Ir); 4233 break; 4234 4235 /* Repair pages */ 4236 case REPAIR_INTRO_PAGE: 4237 Page = RepairIntroPage(&Ir); 4238 break; 4239 4240 case UPGRADE_REPAIR_PAGE: 4241 Page = UpgradeRepairPage(&Ir); 4242 break; 4243 4244 case SUCCESS_PAGE: 4245 Page = SuccessPage(&Ir); 4246 break; 4247 4248 case FLUSH_PAGE: 4249 Page = FlushPage(&Ir); 4250 break; 4251 4252 case QUIT_PAGE: 4253 Page = QuitPage(&Ir); 4254 break; 4255 4256 /* Virtual pages */ 4257 case SETUP_INIT_PAGE: 4258 case SELECT_FILE_SYSTEM_PAGE: 4259 case FORMAT_PARTITION_PAGE: 4260 // case CHECK_FILE_SYSTEM_PAGE: 4261 case REBOOT_PAGE: 4262 case RECOVERY_PAGE: 4263 break; 4264 4265 default: 4266 break; 4267 } 4268 } 4269 4270 /* Terminate the user-mode PnP manager */ 4271 TerminateUserModePnpManager(); 4272 4273 /* Setup has finished */ 4274 FinishSetup(&USetupData); 4275 4276 if (Page == RECOVERY_PAGE) 4277 RecoveryConsole(); 4278 4279 FreeConsole(); 4280 4281 /* Reboot */ 4282 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old); 4283 NtShutdownSystem(ShutdownReboot); 4284 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old); 4285 4286 return STATUS_SUCCESS; 4287 } 4288 4289 4290 VOID NTAPI 4291 NtProcessStartup(PPEB Peb) 4292 { 4293 NTSTATUS Status; 4294 LARGE_INTEGER Time; 4295 4296 RtlNormalizeProcessParams(Peb->ProcessParameters); 4297 4298 ProcessHeap = Peb->ProcessHeap; 4299 4300 NtQuerySystemTime(&Time); 4301 4302 Status = RunUSetup(); 4303 4304 if (NT_SUCCESS(Status)) 4305 { 4306 /* 4307 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing 4308 * a protective waiting. 4309 * This wait is needed because, since we are started as SMSS.EXE, 4310 * the NT kernel explicitly waits 5 seconds for the initial process 4311 * SMSS.EXE to initialize (as a protective measure), and otherwise 4312 * bugchecks with the code SESSION5_INITIALIZATION_FAILED. 4313 */ 4314 Time.QuadPart += 50000000; 4315 NtDelayExecution(FALSE, &Time); 4316 } 4317 else 4318 { 4319 /* The installer failed to start: raise a hard error (crash the system/BSOD) */ 4320 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 4321 0, 0, NULL, 0, NULL); 4322 } 4323 4324 NtTerminateProcess(NtCurrentProcess(), Status); 4325 } 4326 4327 /* EOF */ 4328