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