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