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