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