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