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