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