1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002, 2003, 2004, 2005 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 /* COPYRIGHT: See COPYING in the top level directory 20 * PROJECT: ReactOS text-mode setup 21 * FILE: base/setup/usetup/partlist.c 22 * PURPOSE: Partition list functions 23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 24 */ 25 26 #include "usetup.h" 27 28 #define NDEBUG 29 #include <debug.h> 30 31 /* HELPERS FOR PARTITION TYPES **********************************************/ 32 33 typedef struct _PARTITION_TYPE 34 { 35 UCHAR Type; 36 PCHAR Description; 37 } PARTITION_TYPE, *PPARTITION_TYPE; 38 39 /* 40 * This partition type list was ripped off the kernelDisk.c module from: 41 * 42 * Visopsys Operating System 43 * Copyright (C) 1998-2015 J. Andrew McLaughlin 44 * 45 * This program is free software; you can redistribute it and/or modify it 46 * under the terms of the GNU General Public License as published by the Free 47 * Software Foundation; either version 2 of the License, or (at your option) 48 * any later version. 49 * 50 * This program is distributed in the hope that it will be useful, but 51 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 52 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 53 * for more details. 54 * 55 * You should have received a copy of the GNU General Public License along 56 * with this program; if not, write to the Free Software Foundation, Inc., 57 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 58 * 59 * 60 * See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs 61 * and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html 62 * for a complete list. 63 */ 64 65 /* This is a table for keeping known partition type codes and descriptions */ 66 static PARTITION_TYPE PartitionTypes[] = 67 { 68 { 0x00, "(Empty)" }, 69 { 0x01, "FAT12" }, 70 { 0x02, "XENIX root" }, 71 { 0x03, "XENIX /usr" }, 72 { 0x04, "FAT16 (small)" }, 73 { 0x05, "Extended" }, 74 { 0x06, "FAT16" }, 75 { 0x07, "NTFS/HPFS/exFAT" }, 76 { 0x08, "OS/2 or AIX boot" }, 77 { 0x09, "AIX data" }, 78 { 0x0A, "OS/2 Boot Manager" }, 79 { 0x0B, "FAT32" }, 80 { 0x0C, "FAT32 (LBA)" }, 81 { 0x0E, "FAT16 (LBA)" }, 82 { 0x0F, "Extended (LBA)" }, 83 { 0x11, "Hidden FAT12" }, 84 { 0x12, "FAT diagnostic" }, 85 { 0x14, "Hidden FAT16 (small)" }, 86 { 0x16, "Hidden FAT16" }, 87 { 0x17, "Hidden HPFS or NTFS" }, 88 { 0x1B, "Hidden FAT32" }, 89 { 0x1C, "Hidden FAT32 (LBA)" }, 90 { 0x1E, "Hidden FAT16 (LBA)" }, 91 { 0x35, "JFS" }, 92 { 0x39, "Plan 9" }, 93 { 0x3C, "PartitionMagic" }, 94 { 0x3D, "Hidden Netware" }, 95 { 0x41, "PowerPC PReP" }, 96 { 0x42, "Win2K dynamic extended" }, 97 { 0x43, "Old Linux" }, 98 { 0x44, "GoBack" }, 99 { 0x4D, "QNX4.x" }, 100 { 0x4D, "QNX4.x 2nd" }, 101 { 0x4D, "QNX4.x 3rd" }, 102 { 0x50, "Ontrack R/O" }, 103 { 0x51, "Ontrack R/W or Novell" }, 104 { 0x52, "CP/M" }, 105 { 0x63, "GNU HURD or UNIX SysV" }, 106 { 0x64, "Netware 2" }, 107 { 0x65, "Netware 3/4" }, 108 { 0x66, "Netware SMS" }, 109 { 0x67, "Novell" }, 110 { 0x68, "Novell" }, 111 { 0x69, "Netware 5+" }, 112 { 0x7E, "Veritas VxVM public" }, 113 { 0x7F, "Veritas VxVM private" }, 114 { 0x80, "Minix" }, 115 { 0x81, "Linux or Minix" }, 116 { 0x82, "Linux swap or Solaris" }, 117 { 0x83, "Linux" }, 118 { 0x84, "Hibernation" }, 119 { 0x85, "Linux extended" }, 120 { 0x86, "HPFS or NTFS mirrored" }, 121 { 0x87, "HPFS or NTFS mirrored" }, 122 { 0x8E, "Linux LVM" }, 123 { 0x93, "Hidden Linux" }, 124 { 0x96, "CDFS/ISO-9660" }, 125 { 0x9F, "BSD/OS" }, 126 { 0xA0, "Laptop hibernation" }, 127 { 0xA1, "Laptop hibernation" }, 128 { 0xA5, "BSD, NetBSD, FreeBSD" }, 129 { 0xA6, "OpenBSD" }, 130 { 0xA7, "NeXTSTEP" }, 131 { 0xA8, "OS-X UFS" }, 132 { 0xA9, "NetBSD" }, 133 { 0xAB, "OS-X boot" }, 134 { 0xAF, "OS-X HFS" }, 135 { 0xB6, "NT corrupt mirror" }, 136 { 0xB7, "BSDI" }, 137 { 0xB8, "BSDI swap" }, 138 { 0xBE, "Solaris 8 boot" }, 139 { 0xBF, "Solaris x86" }, 140 { 0xC0, "NTFT" }, 141 { 0xC1, "DR-DOS FAT12" }, 142 { 0xC2, "Hidden Linux" }, 143 { 0xC3, "Hidden Linux swap" }, 144 { 0xC4, "DR-DOS FAT16 (small)" }, 145 { 0xC5, "DR-DOS Extended" }, 146 { 0xC6, "DR-DOS FAT16" }, 147 { 0xC7, "HPFS mirrored" }, 148 { 0xCB, "DR-DOS FAT32" }, 149 { 0xCC, "DR-DOS FAT32 (LBA)" }, 150 { 0xCE, "DR-DOS FAT16 (LBA)" }, 151 { 0xD0, "MDOS" }, 152 { 0xD1, "MDOS FAT12" }, 153 { 0xD4, "MDOS FAT16 (small)" }, 154 { 0xD5, "MDOS Extended" }, 155 { 0xD6, "MDOS FAT16" }, 156 { 0xD8, "CP/M-86" }, 157 { 0xDF, "BootIt EMBRM(FAT16/32)" }, 158 { 0xEB, "BeOS BFS" }, 159 { 0xEE, "EFI GPT protective" }, 160 { 0xEF, "EFI filesystem" }, 161 { 0xF0, "Linux/PA-RISC boot" }, 162 { 0xF2, "DOS 3.3+ second" }, 163 { 0xFA, "Bochs" }, 164 { 0xFB, "VmWare" }, 165 { 0xFC, "VmWare swap" }, 166 { 0xFD, "Linux RAID" }, 167 { 0xFE, "NT hidden" }, 168 }; 169 170 VOID 171 GetPartTypeStringFromPartitionType( 172 IN UCHAR partitionType, 173 OUT PCHAR strPartType, 174 IN ULONG cchPartType) 175 { 176 /* Determine partition type */ 177 178 if (IsContainerPartition(partitionType)) 179 { 180 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION)); 181 } 182 else if (partitionType == PARTITION_ENTRY_UNUSED) 183 { 184 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED)); 185 } 186 else 187 { 188 UINT i; 189 190 /* Do the table lookup */ 191 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++) 192 { 193 if (partitionType == PartitionTypes[i].Type) 194 { 195 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description); 196 return; 197 } 198 } 199 200 /* We are here because the partition type is unknown */ 201 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN)); 202 } 203 } 204 205 206 /* FUNCTIONS ****************************************************************/ 207 208 VOID 209 InitPartitionListUi( 210 IN OUT PPARTLIST_UI ListUi, 211 IN PPARTLIST List, 212 IN SHORT Left, 213 IN SHORT Top, 214 IN SHORT Right, 215 IN SHORT Bottom) 216 { 217 ListUi->List = List; 218 // ListUi->FirstShown = NULL; 219 // ListUi->LastShown = NULL; 220 221 ListUi->Left = Left; 222 ListUi->Top = Top; 223 ListUi->Right = Right; 224 ListUi->Bottom = Bottom; 225 226 ListUi->Line = 0; 227 ListUi->Offset = 0; 228 229 // ListUi->Redraw = TRUE; 230 } 231 232 static 233 VOID 234 PrintEmptyLine( 235 IN PPARTLIST_UI ListUi) 236 { 237 COORD coPos; 238 ULONG Written; 239 USHORT Width; 240 USHORT Height; 241 242 Width = ListUi->Right - ListUi->Left - 1; 243 Height = ListUi->Bottom - ListUi->Top - 2; 244 245 coPos.X = ListUi->Left + 1; 246 coPos.Y = ListUi->Top + 1 + ListUi->Line; 247 248 if (ListUi->Line >= 0 && ListUi->Line <= Height) 249 { 250 FillConsoleOutputAttribute(StdOutput, 251 FOREGROUND_WHITE | BACKGROUND_BLUE, 252 Width, 253 coPos, 254 &Written); 255 256 FillConsoleOutputCharacterA(StdOutput, 257 ' ', 258 Width, 259 coPos, 260 &Written); 261 } 262 263 ListUi->Line++; 264 } 265 266 static 267 VOID 268 PrintPartitionData( 269 IN PPARTLIST_UI ListUi, 270 IN PDISKENTRY DiskEntry, 271 IN PPARTENTRY PartEntry) 272 { 273 PPARTLIST List = ListUi->List; 274 CHAR LineBuffer[128]; 275 COORD coPos; 276 ULONG Written; 277 USHORT Width; 278 USHORT Height; 279 LARGE_INTEGER PartSize; 280 PCHAR Unit; 281 UCHAR Attribute; 282 CHAR PartTypeString[32]; 283 PCHAR PartType = PartTypeString; 284 285 Width = ListUi->Right - ListUi->Left - 1; 286 Height = ListUi->Bottom - ListUi->Top - 2; 287 288 coPos.X = ListUi->Left + 1; 289 coPos.Y = ListUi->Top + 1 + ListUi->Line; 290 291 if (PartEntry->IsPartitioned == FALSE) 292 { 293 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 294 #if 0 295 if (PartSize.QuadPart >= 10737418240) /* 10 GB */ 296 { 297 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824); 298 Unit = MUIGetString(STRING_GB); 299 } 300 else 301 #endif 302 if (PartSize.QuadPart >= 10485760) /* 10 MB */ 303 { 304 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576); 305 Unit = MUIGetString(STRING_MB); 306 } 307 else 308 { 309 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024); 310 Unit = MUIGetString(STRING_KB); 311 } 312 313 sprintf(LineBuffer, 314 MUIGetString(STRING_UNPSPACE), 315 PartEntry->LogicalPartition ? " " : "", 316 PartEntry->LogicalPartition ? "" : " ", 317 PartSize.u.LowPart, 318 Unit); 319 } 320 else 321 { 322 /* Determine partition type */ 323 PartTypeString[0] = '\0'; 324 if (PartEntry->New != FALSE) 325 { 326 PartType = MUIGetString(STRING_UNFORMATTED); 327 } 328 else if (PartEntry->IsPartitioned != FALSE) 329 { 330 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, 331 PartTypeString, 332 ARRAYSIZE(PartTypeString)); 333 PartType = PartTypeString; 334 } 335 336 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 337 #if 0 338 if (PartSize.QuadPart >= 10737418240) /* 10 GB */ 339 { 340 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824); 341 Unit = MUIGetString(STRING_GB); 342 } 343 else 344 #endif 345 if (PartSize.QuadPart >= 10485760) /* 10 MB */ 346 { 347 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576); 348 Unit = MUIGetString(STRING_MB); 349 } 350 else 351 { 352 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024); 353 Unit = MUIGetString(STRING_KB); 354 } 355 356 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0) 357 { 358 sprintf(LineBuffer, 359 MUIGetString(STRING_HDDINFOUNK5), 360 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter, 361 (PartEntry->DriveLetter == 0) ? '-' : ':', 362 PartEntry->BootIndicator ? '*' : ' ', 363 PartEntry->LogicalPartition ? " " : "", 364 PartEntry->PartitionType, 365 PartEntry->LogicalPartition ? "" : " ", 366 PartSize.u.LowPart, 367 Unit); 368 } 369 else 370 { 371 sprintf(LineBuffer, 372 "%c%c %c %s%-24s%s %6lu %s", 373 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter, 374 (PartEntry->DriveLetter == 0) ? '-' : ':', 375 PartEntry->BootIndicator ? '*' : ' ', 376 PartEntry->LogicalPartition ? " " : "", 377 PartType, 378 PartEntry->LogicalPartition ? "" : " ", 379 PartSize.u.LowPart, 380 Unit); 381 } 382 } 383 384 Attribute = (List->CurrentDisk == DiskEntry && 385 List->CurrentPartition == PartEntry) ? 386 FOREGROUND_BLUE | BACKGROUND_WHITE : 387 FOREGROUND_WHITE | BACKGROUND_BLUE; 388 389 if (ListUi->Line >= 0 && ListUi->Line <= Height) 390 { 391 FillConsoleOutputCharacterA(StdOutput, 392 ' ', 393 Width, 394 coPos, 395 &Written); 396 } 397 coPos.X += 4; 398 Width -= 8; 399 if (ListUi->Line >= 0 && ListUi->Line <= Height) 400 { 401 FillConsoleOutputAttribute(StdOutput, 402 Attribute, 403 Width, 404 coPos, 405 &Written); 406 } 407 coPos.X++; 408 Width -= 2; 409 if (ListUi->Line >= 0 && ListUi->Line <= Height) 410 { 411 WriteConsoleOutputCharacterA(StdOutput, 412 LineBuffer, 413 min(strlen(LineBuffer), Width), 414 coPos, 415 &Written); 416 } 417 418 ListUi->Line++; 419 } 420 421 static 422 VOID 423 PrintDiskData( 424 IN PPARTLIST_UI ListUi, 425 IN PDISKENTRY DiskEntry) 426 { 427 // PPARTLIST List = ListUi->List; 428 PPARTENTRY PrimaryPartEntry, LogicalPartEntry; 429 PLIST_ENTRY PrimaryEntry, LogicalEntry; 430 CHAR LineBuffer[128]; 431 COORD coPos; 432 ULONG Written; 433 USHORT Width; 434 USHORT Height; 435 ULARGE_INTEGER DiskSize; 436 PCHAR Unit; 437 438 Width = ListUi->Right - ListUi->Left - 1; 439 Height = ListUi->Bottom - ListUi->Top - 2; 440 441 coPos.X = ListUi->Left + 1; 442 coPos.Y = ListUi->Top + 1 + ListUi->Line; 443 444 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 445 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */ 446 { 447 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824); 448 Unit = MUIGetString(STRING_GB); 449 } 450 else 451 { 452 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576); 453 if (DiskSize.QuadPart == 0) 454 DiskSize.QuadPart = 1; 455 Unit = MUIGetString(STRING_MB); 456 } 457 458 if (DiskEntry->DriverName.Length > 0) 459 { 460 sprintf(LineBuffer, 461 MUIGetString(STRING_HDINFOPARTSELECT), 462 DiskSize.u.LowPart, 463 Unit, 464 DiskEntry->DiskNumber, 465 DiskEntry->Port, 466 DiskEntry->Bus, 467 DiskEntry->Id, 468 DiskEntry->DriverName.Buffer); 469 } 470 else 471 { 472 sprintf(LineBuffer, 473 MUIGetString(STRING_HDDINFOUNK6), 474 DiskSize.u.LowPart, 475 Unit, 476 DiskEntry->DiskNumber, 477 DiskEntry->Port, 478 DiskEntry->Bus, 479 DiskEntry->Id); 480 } 481 482 if (ListUi->Line >= 0 && ListUi->Line <= Height) 483 { 484 FillConsoleOutputAttribute(StdOutput, 485 FOREGROUND_WHITE | BACKGROUND_BLUE, 486 Width, 487 coPos, 488 &Written); 489 490 FillConsoleOutputCharacterA(StdOutput, 491 ' ', 492 Width, 493 coPos, 494 &Written); 495 } 496 497 coPos.X++; 498 if (ListUi->Line >= 0 && ListUi->Line <= Height) 499 { 500 WriteConsoleOutputCharacterA(StdOutput, 501 LineBuffer, 502 min((USHORT)strlen(LineBuffer), Width - 2), 503 coPos, 504 &Written); 505 } 506 507 ListUi->Line++; 508 509 /* Print separator line */ 510 PrintEmptyLine(ListUi); 511 512 /* Print partition lines */ 513 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink; 514 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead) 515 { 516 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry); 517 518 PrintPartitionData(ListUi, 519 DiskEntry, 520 PrimaryPartEntry); 521 522 if (IsContainerPartition(PrimaryPartEntry->PartitionType)) 523 { 524 LogicalEntry = DiskEntry->LogicalPartListHead.Flink; 525 while (LogicalEntry != &DiskEntry->LogicalPartListHead) 526 { 527 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry); 528 529 PrintPartitionData(ListUi, 530 DiskEntry, 531 LogicalPartEntry); 532 533 LogicalEntry = LogicalEntry->Flink; 534 } 535 } 536 537 PrimaryEntry = PrimaryEntry->Flink; 538 } 539 540 /* Print separator line */ 541 PrintEmptyLine(ListUi); 542 } 543 544 VOID 545 DrawPartitionList( 546 IN PPARTLIST_UI ListUi) 547 { 548 PPARTLIST List = ListUi->List; 549 PLIST_ENTRY Entry, Entry2; 550 PDISKENTRY DiskEntry; 551 PPARTENTRY PartEntry = NULL; 552 COORD coPos; 553 ULONG Written; 554 SHORT i; 555 SHORT CurrentDiskLine; 556 SHORT CurrentPartLine; 557 SHORT LastLine; 558 BOOLEAN CurrentPartLineFound = FALSE; 559 BOOLEAN CurrentDiskLineFound = FALSE; 560 561 /* Calculate the line of the current disk and partition */ 562 CurrentDiskLine = 0; 563 CurrentPartLine = 0; 564 LastLine = 0; 565 566 Entry = List->DiskListHead.Flink; 567 while (Entry != &List->DiskListHead) 568 { 569 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 570 571 LastLine += 2; 572 if (CurrentPartLineFound == FALSE) 573 { 574 CurrentPartLine += 2; 575 } 576 577 Entry2 = DiskEntry->PrimaryPartListHead.Flink; 578 while (Entry2 != &DiskEntry->PrimaryPartListHead) 579 { 580 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 581 if (PartEntry == List->CurrentPartition) 582 { 583 CurrentPartLineFound = TRUE; 584 } 585 586 Entry2 = Entry2->Flink; 587 if (CurrentPartLineFound == FALSE) 588 { 589 CurrentPartLine++; 590 } 591 592 LastLine++; 593 } 594 595 if (CurrentPartLineFound == FALSE) 596 { 597 Entry2 = DiskEntry->LogicalPartListHead.Flink; 598 while (Entry2 != &DiskEntry->LogicalPartListHead) 599 { 600 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 601 if (PartEntry == List->CurrentPartition) 602 { 603 CurrentPartLineFound = TRUE; 604 } 605 606 Entry2 = Entry2->Flink; 607 if (CurrentPartLineFound == FALSE) 608 { 609 CurrentPartLine++; 610 } 611 612 LastLine++; 613 } 614 } 615 616 if (DiskEntry == List->CurrentDisk) 617 { 618 CurrentDiskLineFound = TRUE; 619 } 620 621 Entry = Entry->Flink; 622 if (Entry != &List->DiskListHead) 623 { 624 if (CurrentDiskLineFound == FALSE) 625 { 626 CurrentPartLine ++; 627 CurrentDiskLine = CurrentPartLine; 628 } 629 630 LastLine++; 631 } 632 else 633 { 634 LastLine--; 635 } 636 } 637 638 /* If it possible, make the disk name visible */ 639 if (CurrentPartLine < ListUi->Offset) 640 { 641 ListUi->Offset = CurrentPartLine; 642 } 643 else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2) 644 { 645 ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2); 646 } 647 648 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2) 649 { 650 ListUi->Offset = CurrentDiskLine; 651 } 652 653 /* Draw upper left corner */ 654 coPos.X = ListUi->Left; 655 coPos.Y = ListUi->Top; 656 FillConsoleOutputCharacterA(StdOutput, 657 0xDA, // '+', 658 1, 659 coPos, 660 &Written); 661 662 /* Draw upper edge */ 663 coPos.X = ListUi->Left + 1; 664 coPos.Y = ListUi->Top; 665 if (ListUi->Offset == 0) 666 { 667 FillConsoleOutputCharacterA(StdOutput, 668 0xC4, // '-', 669 ListUi->Right - ListUi->Left - 1, 670 coPos, 671 &Written); 672 } 673 else 674 { 675 FillConsoleOutputCharacterA(StdOutput, 676 0xC4, // '-', 677 ListUi->Right - ListUi->Left - 5, 678 coPos, 679 &Written); 680 coPos.X = ListUi->Right - 5; 681 WriteConsoleOutputCharacterA(StdOutput, 682 "(\x18)", // "(up)" 683 3, 684 coPos, 685 &Written); 686 coPos.X = ListUi->Right - 2; 687 FillConsoleOutputCharacterA(StdOutput, 688 0xC4, // '-', 689 2, 690 coPos, 691 &Written); 692 } 693 694 /* Draw upper right corner */ 695 coPos.X = ListUi->Right; 696 coPos.Y = ListUi->Top; 697 FillConsoleOutputCharacterA(StdOutput, 698 0xBF, // '+', 699 1, 700 coPos, 701 &Written); 702 703 /* Draw left and right edge */ 704 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++) 705 { 706 coPos.X = ListUi->Left; 707 coPos.Y = i; 708 FillConsoleOutputCharacterA(StdOutput, 709 0xB3, // '|', 710 1, 711 coPos, 712 &Written); 713 714 coPos.X = ListUi->Right; 715 FillConsoleOutputCharacterA(StdOutput, 716 0xB3, //'|', 717 1, 718 coPos, 719 &Written); 720 } 721 722 /* Draw lower left corner */ 723 coPos.X = ListUi->Left; 724 coPos.Y = ListUi->Bottom; 725 FillConsoleOutputCharacterA(StdOutput, 726 0xC0, // '+', 727 1, 728 coPos, 729 &Written); 730 731 /* Draw lower edge */ 732 coPos.X = ListUi->Left + 1; 733 coPos.Y = ListUi->Bottom; 734 if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2) 735 { 736 FillConsoleOutputCharacterA(StdOutput, 737 0xC4, // '-', 738 ListUi->Right - ListUi->Left - 1, 739 coPos, 740 &Written); 741 } 742 else 743 { 744 FillConsoleOutputCharacterA(StdOutput, 745 0xC4, // '-', 746 ListUi->Right - ListUi->Left - 5, 747 coPos, 748 &Written); 749 coPos.X = ListUi->Right - 5; 750 WriteConsoleOutputCharacterA(StdOutput, 751 "(\x19)", // "(down)" 752 3, 753 coPos, 754 &Written); 755 coPos.X = ListUi->Right - 2; 756 FillConsoleOutputCharacterA(StdOutput, 757 0xC4, // '-', 758 2, 759 coPos, 760 &Written); 761 } 762 763 /* Draw lower right corner */ 764 coPos.X = ListUi->Right; 765 coPos.Y = ListUi->Bottom; 766 FillConsoleOutputCharacterA(StdOutput, 767 0xD9, // '+', 768 1, 769 coPos, 770 &Written); 771 772 /* print list entries */ 773 ListUi->Line = - ListUi->Offset; 774 775 Entry = List->DiskListHead.Flink; 776 while (Entry != &List->DiskListHead) 777 { 778 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 779 780 /* Print disk entry */ 781 PrintDiskData(ListUi, DiskEntry); 782 783 Entry = Entry->Flink; 784 } 785 } 786 787 VOID 788 ScrollDownPartitionList( 789 IN PPARTLIST_UI ListUi) 790 { 791 if (GetNextPartition(ListUi->List)) 792 DrawPartitionList(ListUi); 793 } 794 795 VOID 796 ScrollUpPartitionList( 797 IN PPARTLIST_UI ListUi) 798 { 799 if (GetPrevPartition(ListUi->List)) 800 DrawPartitionList(ListUi); 801 } 802 803 /* EOF */ 804