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