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