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 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/partlist.c
23 * PURPOSE: Partition list functions
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 */
26
27 #include "usetup.h"
28
29 #define NDEBUG
30 #include <debug.h>
31
32 /* HELPERS FOR DISK AND PARTITION DESCRIPTIONS ******************************/
33
34 VOID
GetPartitionTypeString(IN PPARTENTRY PartEntry,OUT PSTR strBuffer,IN ULONG cchBuffer)35 GetPartitionTypeString(
36 IN PPARTENTRY PartEntry,
37 OUT PSTR strBuffer,
38 IN ULONG cchBuffer)
39 {
40 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED)
41 {
42 RtlStringCchCopyA(strBuffer, cchBuffer,
43 MUIGetString(STRING_FORMATUNUSED));
44 }
45 else if (IsContainerPartition(PartEntry->PartitionType))
46 {
47 RtlStringCchCopyA(strBuffer, cchBuffer,
48 MUIGetString(STRING_EXTENDED_PARTITION));
49 }
50 else
51 {
52 UINT i;
53
54 /* Do the table lookup */
55 if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_MBR)
56 {
57 for (i = 0; i < ARRAYSIZE(MbrPartitionTypes); ++i)
58 {
59 if (PartEntry->PartitionType == MbrPartitionTypes[i].Type)
60 {
61 RtlStringCchCopyA(strBuffer, cchBuffer,
62 MbrPartitionTypes[i].Description);
63 return;
64 }
65 }
66 }
67 #if 0 // TODO: GPT support!
68 else if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
69 {
70 for (i = 0; i < ARRAYSIZE(GptPartitionTypes); ++i)
71 {
72 if (IsEqualPartitionType(PartEntry->PartitionType,
73 GptPartitionTypes[i].Guid))
74 {
75 RtlStringCchCopyA(strBuffer, cchBuffer,
76 GptPartitionTypes[i].Description);
77 return;
78 }
79 }
80 }
81 #endif
82
83 /* We are here because the partition type is unknown */
84 if (cchBuffer > 0) *strBuffer = '\0';
85 }
86
87 if ((cchBuffer > 0) && (*strBuffer == '\0'))
88 {
89 RtlStringCchPrintfA(strBuffer, cchBuffer,
90 MUIGetString(STRING_PARTTYPE),
91 PartEntry->PartitionType);
92 }
93 }
94
95 VOID
PrettifySize1(IN OUT PULONGLONG Size,OUT PCSTR * Unit)96 PrettifySize1(
97 IN OUT PULONGLONG Size,
98 OUT PCSTR* Unit)
99 {
100 ULONGLONG DiskSize = *Size;
101
102 if (DiskSize >= 10 * GB) /* 10 GB */
103 {
104 DiskSize = RoundingDivide(DiskSize, GB);
105 *Unit = MUIGetString(STRING_GB);
106 }
107 else
108 {
109 DiskSize = RoundingDivide(DiskSize, MB);
110 if (DiskSize == 0)
111 DiskSize = 1;
112 *Unit = MUIGetString(STRING_MB);
113 }
114
115 *Size = DiskSize;
116 }
117
118 VOID
PrettifySize2(IN OUT PULONGLONG Size,OUT PCSTR * Unit)119 PrettifySize2(
120 IN OUT PULONGLONG Size,
121 OUT PCSTR* Unit)
122 {
123 ULONGLONG PartSize = *Size;
124
125 #if 0
126 if (PartSize >= 10 * GB) /* 10 GB */
127 {
128 PartSize = RoundingDivide(PartSize, GB);
129 *Unit = MUIGetString(STRING_GB);
130 }
131 else
132 #endif
133 if (PartSize >= 10 * MB) /* 10 MB */
134 {
135 PartSize = RoundingDivide(PartSize, MB);
136 *Unit = MUIGetString(STRING_MB);
137 }
138 else
139 {
140 PartSize = RoundingDivide(PartSize, KB);
141 *Unit = MUIGetString(STRING_KB);
142 }
143
144 *Size = PartSize;
145 }
146
147 VOID
PartitionDescription(IN PPARTENTRY PartEntry,OUT PSTR strBuffer,IN SIZE_T cchBuffer)148 PartitionDescription(
149 IN PPARTENTRY PartEntry,
150 OUT PSTR strBuffer,
151 IN SIZE_T cchBuffer)
152 {
153 PSTR pBuffer = strBuffer;
154 size_t cchBufferSize = cchBuffer;
155 ULONGLONG PartSize;
156 PCSTR Unit;
157 PVOLINFO VolInfo = (PartEntry->Volume ? &PartEntry->Volume->Info : NULL);
158
159 /* Get the partition size */
160 PartSize = GetPartEntrySizeInBytes(PartEntry);
161 PrettifySize2(&PartSize, &Unit);
162
163 if (PartEntry->IsPartitioned == FALSE)
164 {
165 /* Unpartitioned space: Just display the description and size */
166 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
167 &pBuffer, &cchBufferSize, 0,
168 " %s%-.30s",
169 PartEntry->LogicalPartition ? " " : "", // Optional indentation
170 MUIGetString(STRING_UNPSPACE));
171
172 RtlStringCchPrintfA(pBuffer, cchBufferSize,
173 "%*s%6I64u %s",
174 38 - min(strlen(strBuffer), 38), "", // Indentation
175 PartSize,
176 Unit);
177 return;
178 }
179
180 //
181 // NOTE: This could be done with the next case.
182 //
183 if ((PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_MBR) &&
184 IsContainerPartition(PartEntry->PartitionType))
185 {
186 /* Extended partition container: Just display the partition's type and size */
187 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
188 &pBuffer, &cchBufferSize, 0,
189 " %-.30s",
190 MUIGetString(STRING_EXTENDED_PARTITION));
191
192 RtlStringCchPrintfA(pBuffer, cchBufferSize,
193 "%*s%6I64u %s",
194 38 - min(strlen(strBuffer), 38), "", // Indentation
195 PartSize,
196 Unit);
197 return;
198 }
199
200 /*
201 * Not an extended partition container.
202 */
203
204 /* Drive letter and partition number */
205 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
206 &pBuffer, &cchBufferSize, 0,
207 "%c%c %c %s(%lu) ",
208 !(VolInfo && VolInfo->DriveLetter) ? '-' : (CHAR)VolInfo->DriveLetter,
209 !(VolInfo && VolInfo->DriveLetter) ? '-' : ':',
210 PartEntry->BootIndicator ? '*' : ' ',
211 PartEntry->LogicalPartition ? " " : "", // Optional indentation
212 PartEntry->PartitionNumber);
213
214 /*
215 * If the volume's file system is recognized, display the volume label
216 * (if any) and the file system name. Otherwise, display the partition
217 * type if it's not a new partition.
218 */
219 if (VolInfo && IsFormatted(VolInfo))
220 {
221 size_t cchLabelSize = 0;
222 if (*VolInfo->VolumeLabel)
223 {
224 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
225 &pBuffer, &cchLabelSize, 0,
226 "\"%-.11S\" ",
227 VolInfo->VolumeLabel);
228 cchLabelSize = cchBufferSize - cchLabelSize; // Actual length of the label part.
229 cchBufferSize -= cchLabelSize; // And reset cchBufferSize to what it should be.
230 }
231
232 // TODO: Group this part together with the similar one
233 // from below once the strings are in the same encoding...
234 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
235 &pBuffer, &cchBufferSize, 0,
236 "[%-.*S]",
237 /* The minimum length can be at most 11 since
238 * cchLabelSize can be at most == 11 + 3 == 14 */
239 25 - min(cchLabelSize, 25),
240 VolInfo->FileSystem);
241 }
242 else
243 {
244 CHAR PartTypeString[32];
245 PCSTR PartType = PartTypeString;
246
247 if (PartEntry->New)
248 {
249 /* Use this description if the partition is new (and thus, not formatted) */
250 PartType = MUIGetString(STRING_UNFORMATTED);
251 }
252 else
253 {
254 /* If the partition is not new but its file system is not recognized
255 * (or is not formatted), use the partition type description. */
256 GetPartitionTypeString(PartEntry,
257 PartTypeString,
258 ARRAYSIZE(PartTypeString));
259 PartType = PartTypeString;
260 }
261 if (!PartType || !*PartType)
262 {
263 PartType = MUIGetString(STRING_FORMATUNKNOWN);
264 }
265
266 // TODO: Group this part together with the similar one
267 // from above once the strings are in the same encoding...
268 RtlStringCchPrintfExA(pBuffer, cchBufferSize,
269 &pBuffer, &cchBufferSize, 0,
270 "[%-.*s]",
271 25,
272 PartType);
273 }
274
275 /* Show the remaining free space only if a FS is mounted */
276 // FIXME: We don't support that yet!
277 #if 0
278 if (VolInfo && *VolInfo->FileSystem)
279 {
280 RtlStringCchPrintfA(pBuffer, cchBufferSize,
281 "%*s%6I64u %s (%6I64u %s %s)",
282 38 - min(strlen(strBuffer), 38), "", // Indentation
283 PartSize,
284 Unit,
285 PartFreeSize,
286 Unit,
287 "free");
288 }
289 else
290 #endif
291 {
292 RtlStringCchPrintfA(pBuffer, cchBufferSize,
293 "%*s%6I64u %s",
294 38 - min(strlen(strBuffer), 38), "", // Indentation
295 PartSize,
296 Unit);
297 }
298 }
299
300 VOID
DiskDescription(IN PDISKENTRY DiskEntry,OUT PSTR strBuffer,IN SIZE_T cchBuffer)301 DiskDescription(
302 IN PDISKENTRY DiskEntry,
303 OUT PSTR strBuffer,
304 IN SIZE_T cchBuffer)
305 {
306 ULONGLONG DiskSize;
307 PCSTR Unit;
308
309 /* Get the disk size */
310 DiskSize = GetDiskSizeInBytes(DiskEntry);
311 PrettifySize1(&DiskSize, &Unit);
312
313 //
314 // FIXME: We *MUST* use TXTSETUP.SIF strings from section "DiskDriverMap" !!
315 //
316 if (DiskEntry->DriverName.Length > 0)
317 {
318 RtlStringCchPrintfA(strBuffer, cchBuffer,
319 MUIGetString(STRING_HDDINFO1),
320 DiskSize,
321 Unit,
322 DiskEntry->DiskNumber,
323 DiskEntry->Port,
324 DiskEntry->Bus,
325 DiskEntry->Id,
326 &DiskEntry->DriverName,
327 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
328 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
329 "RAW");
330 }
331 else
332 {
333 RtlStringCchPrintfA(strBuffer, cchBuffer,
334 MUIGetString(STRING_HDDINFO2),
335 DiskSize,
336 Unit,
337 DiskEntry->DiskNumber,
338 DiskEntry->Port,
339 DiskEntry->Bus,
340 DiskEntry->Id,
341 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
342 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
343 "RAW");
344 }
345 }
346
347
348 /* FUNCTIONS ****************************************************************/
349
350 VOID
InitPartitionListUi(IN OUT PPARTLIST_UI ListUi,IN PPARTLIST List,IN PPARTENTRY CurrentEntry OPTIONAL,IN SHORT Left,IN SHORT Top,IN SHORT Right,IN SHORT Bottom)351 InitPartitionListUi(
352 IN OUT PPARTLIST_UI ListUi,
353 IN PPARTLIST List,
354 IN PPARTENTRY CurrentEntry OPTIONAL,
355 IN SHORT Left,
356 IN SHORT Top,
357 IN SHORT Right,
358 IN SHORT Bottom)
359 {
360 ListUi->List = List;
361 // ListUi->FirstShown = NULL;
362 // ListUi->LastShown = NULL;
363
364 ListUi->Left = Left;
365 ListUi->Top = Top;
366 ListUi->Right = Right;
367 ListUi->Bottom = Bottom;
368
369 ListUi->Line = 0;
370 ListUi->Offset = 0;
371
372 // ListUi->Redraw = TRUE;
373
374 /* Search for first usable disk and partition */
375 if (!CurrentEntry)
376 {
377 ListUi->CurrentDisk = NULL;
378 ListUi->CurrentPartition = NULL;
379
380 if (!IsListEmpty(&List->DiskListHead))
381 {
382 ListUi->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
383 DISKENTRY, ListEntry);
384
385 if (!IsListEmpty(&ListUi->CurrentDisk->PrimaryPartListHead))
386 {
387 ListUi->CurrentPartition = CONTAINING_RECORD(ListUi->CurrentDisk->PrimaryPartListHead.Flink,
388 PARTENTRY, ListEntry);
389 }
390 }
391 }
392 else
393 {
394 /*
395 * The CurrentEntry must belong to the associated partition list,
396 * and the latter must therefore not be empty.
397 */
398 ASSERT(!IsListEmpty(&List->DiskListHead));
399 ASSERT(CurrentEntry->DiskEntry->PartList == List);
400
401 ListUi->CurrentPartition = CurrentEntry;
402 ListUi->CurrentDisk = CurrentEntry->DiskEntry;
403 }
404 }
405
406 static
407 VOID
PrintEmptyLine(IN PPARTLIST_UI ListUi)408 PrintEmptyLine(
409 IN PPARTLIST_UI ListUi)
410 {
411 COORD coPos;
412 ULONG Written;
413 USHORT Width;
414 USHORT Height;
415
416 Width = ListUi->Right - ListUi->Left - 1;
417 Height = ListUi->Bottom - ListUi->Top - 2;
418
419 coPos.X = ListUi->Left + 1;
420 coPos.Y = ListUi->Top + 1 + ListUi->Line;
421
422 if (ListUi->Line >= 0 && ListUi->Line <= Height)
423 {
424 FillConsoleOutputAttribute(StdOutput,
425 FOREGROUND_WHITE | BACKGROUND_BLUE,
426 Width,
427 coPos,
428 &Written);
429
430 FillConsoleOutputCharacterA(StdOutput,
431 ' ',
432 Width,
433 coPos,
434 &Written);
435 }
436
437 ListUi->Line++;
438 }
439
440 static
441 VOID
PrintPartitionData(IN PPARTLIST_UI ListUi,IN PDISKENTRY DiskEntry,IN PPARTENTRY PartEntry)442 PrintPartitionData(
443 IN PPARTLIST_UI ListUi,
444 IN PDISKENTRY DiskEntry,
445 IN PPARTENTRY PartEntry)
446 {
447 COORD coPos;
448 ULONG Written;
449 USHORT Width;
450 USHORT Height;
451 UCHAR Attribute;
452 CHAR LineBuffer[100];
453
454 PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer));
455
456 Width = ListUi->Right - ListUi->Left - 1;
457 Height = ListUi->Bottom - ListUi->Top - 2;
458
459 coPos.X = ListUi->Left + 1;
460 coPos.Y = ListUi->Top + 1 + ListUi->Line;
461
462 Attribute = (ListUi->CurrentDisk == DiskEntry &&
463 ListUi->CurrentPartition == PartEntry) ?
464 FOREGROUND_BLUE | BACKGROUND_WHITE :
465 FOREGROUND_WHITE | BACKGROUND_BLUE;
466
467 if (ListUi->Line >= 0 && ListUi->Line <= Height)
468 {
469 FillConsoleOutputCharacterA(StdOutput,
470 ' ',
471 Width,
472 coPos,
473 &Written);
474 }
475 coPos.X += 4;
476 Width -= 8;
477 if (ListUi->Line >= 0 && ListUi->Line <= Height)
478 {
479 FillConsoleOutputAttribute(StdOutput,
480 Attribute,
481 Width,
482 coPos,
483 &Written);
484 }
485 coPos.X++;
486 Width -= 2;
487 if (ListUi->Line >= 0 && ListUi->Line <= Height)
488 {
489 WriteConsoleOutputCharacterA(StdOutput,
490 LineBuffer,
491 min(strlen(LineBuffer), Width),
492 coPos,
493 &Written);
494 }
495
496 ListUi->Line++;
497 }
498
499 static
500 VOID
PrintDiskData(IN PPARTLIST_UI ListUi,IN PDISKENTRY DiskEntry)501 PrintDiskData(
502 IN PPARTLIST_UI ListUi,
503 IN PDISKENTRY DiskEntry)
504 {
505 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
506 PLIST_ENTRY PrimaryEntry, LogicalEntry;
507 COORD coPos;
508 ULONG Written;
509 USHORT Width;
510 USHORT Height;
511 CHAR LineBuffer[100];
512
513 DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer));
514
515 Width = ListUi->Right - ListUi->Left - 1;
516 Height = ListUi->Bottom - ListUi->Top - 2;
517
518 coPos.X = ListUi->Left + 1;
519 coPos.Y = ListUi->Top + 1 + ListUi->Line;
520
521 if (ListUi->Line >= 0 && ListUi->Line <= Height)
522 {
523 FillConsoleOutputAttribute(StdOutput,
524 FOREGROUND_WHITE | BACKGROUND_BLUE,
525 Width,
526 coPos,
527 &Written);
528
529 FillConsoleOutputCharacterA(StdOutput,
530 ' ',
531 Width,
532 coPos,
533 &Written);
534 }
535
536 coPos.X++;
537 if (ListUi->Line >= 0 && ListUi->Line <= Height)
538 {
539 WriteConsoleOutputCharacterA(StdOutput,
540 LineBuffer,
541 min((USHORT)strlen(LineBuffer), Width - 2),
542 coPos,
543 &Written);
544 }
545
546 ListUi->Line++;
547
548 /* Print separator line */
549 PrintEmptyLine(ListUi);
550
551 /* Print partition lines */
552 for (PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
553 PrimaryEntry != &DiskEntry->PrimaryPartListHead;
554 PrimaryEntry = PrimaryEntry->Flink)
555 {
556 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
557
558 PrintPartitionData(ListUi,
559 DiskEntry,
560 PrimaryPartEntry);
561
562 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
563 {
564 for (LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
565 LogicalEntry != &DiskEntry->LogicalPartListHead;
566 LogicalEntry = LogicalEntry->Flink)
567 {
568 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
569
570 PrintPartitionData(ListUi,
571 DiskEntry,
572 LogicalPartEntry);
573 }
574 }
575 }
576
577 /* Print separator line */
578 PrintEmptyLine(ListUi);
579 }
580
581 VOID
DrawPartitionList(IN PPARTLIST_UI ListUi)582 DrawPartitionList(
583 IN PPARTLIST_UI ListUi)
584 {
585 PPARTLIST List = ListUi->List;
586 PLIST_ENTRY Entry, Entry2;
587 PDISKENTRY DiskEntry;
588 PPARTENTRY PartEntry = NULL;
589 COORD coPos;
590 ULONG Written;
591 USHORT Width;
592 USHORT Height;
593 SHORT i;
594 SHORT CurrentDiskLine;
595 SHORT CurrentPartLine;
596 SHORT LastLine;
597 BOOLEAN CurrentPartLineFound = FALSE;
598 BOOLEAN CurrentDiskLineFound = FALSE;
599
600 Width = ListUi->Right - ListUi->Left - 1;
601 Height = ListUi->Bottom - ListUi->Top - 2;
602
603 /* Calculate the line of the current disk and partition */
604 CurrentDiskLine = 0;
605 CurrentPartLine = 0;
606 LastLine = 0;
607
608 for (Entry = List->DiskListHead.Flink;
609 Entry != &List->DiskListHead;
610 Entry = Entry->Flink)
611 {
612 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
613
614 LastLine += 2;
615 if (CurrentPartLineFound == FALSE)
616 {
617 CurrentPartLine += 2;
618 }
619
620 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
621 Entry2 != &DiskEntry->PrimaryPartListHead;
622 Entry2 = Entry2->Flink)
623 {
624 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
625 if (PartEntry == ListUi->CurrentPartition)
626 {
627 CurrentPartLineFound = TRUE;
628 }
629
630 if (CurrentPartLineFound == FALSE)
631 {
632 CurrentPartLine++;
633 }
634
635 LastLine++;
636 }
637
638 if (CurrentPartLineFound == FALSE)
639 {
640 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
641 Entry2 != &DiskEntry->LogicalPartListHead;
642 Entry2 = Entry2->Flink)
643 {
644 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
645 if (PartEntry == ListUi->CurrentPartition)
646 {
647 CurrentPartLineFound = TRUE;
648 }
649
650 if (CurrentPartLineFound == FALSE)
651 {
652 CurrentPartLine++;
653 }
654
655 LastLine++;
656 }
657 }
658
659 if (DiskEntry == ListUi->CurrentDisk)
660 {
661 CurrentDiskLineFound = TRUE;
662 }
663
664 if (Entry->Flink != &List->DiskListHead)
665 {
666 if (CurrentDiskLineFound == FALSE)
667 {
668 CurrentPartLine++;
669 CurrentDiskLine = CurrentPartLine;
670 }
671
672 LastLine++;
673 }
674 else
675 {
676 LastLine--;
677 }
678 }
679
680 /* If it possible, make the disk name visible */
681 if (CurrentPartLine < ListUi->Offset)
682 {
683 ListUi->Offset = CurrentPartLine;
684 }
685 else if (CurrentPartLine - ListUi->Offset > Height)
686 {
687 ListUi->Offset = CurrentPartLine - Height;
688 }
689
690 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < Height)
691 {
692 ListUi->Offset = CurrentDiskLine;
693 }
694
695 /* Draw upper left corner */
696 coPos.X = ListUi->Left;
697 coPos.Y = ListUi->Top;
698 FillConsoleOutputCharacterA(StdOutput,
699 CharUpperLeftCorner, // '+',
700 1,
701 coPos,
702 &Written);
703
704 /* Draw upper edge */
705 coPos.X = ListUi->Left + 1;
706 coPos.Y = ListUi->Top;
707 if (ListUi->Offset == 0)
708 {
709 FillConsoleOutputCharacterA(StdOutput,
710 CharHorizontalLine, // '-',
711 Width,
712 coPos,
713 &Written);
714 }
715 else
716 {
717 FillConsoleOutputCharacterA(StdOutput,
718 CharHorizontalLine, // '-',
719 Width - 4,
720 coPos,
721 &Written);
722 {
723 CHAR szBuff[] = "(.)"; // "(up)"
724 szBuff[1] = CharUpArrow;
725 coPos.X = ListUi->Right - 5;
726 WriteConsoleOutputCharacterA(StdOutput,
727 szBuff,
728 3,
729 coPos,
730 &Written);
731 }
732 coPos.X = ListUi->Right - 2;
733 FillConsoleOutputCharacterA(StdOutput,
734 CharHorizontalLine, // '-',
735 2,
736 coPos,
737 &Written);
738 }
739
740 /* Draw upper right corner */
741 coPos.X = ListUi->Right;
742 coPos.Y = ListUi->Top;
743 FillConsoleOutputCharacterA(StdOutput,
744 CharUpperRightCorner, // '+',
745 1,
746 coPos,
747 &Written);
748
749 /* Draw left and right edge */
750 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
751 {
752 coPos.X = ListUi->Left;
753 coPos.Y = i;
754 FillConsoleOutputCharacterA(StdOutput,
755 CharVerticalLine, // '|',
756 1,
757 coPos,
758 &Written);
759
760 coPos.X = ListUi->Right;
761 FillConsoleOutputCharacterA(StdOutput,
762 CharVerticalLine, //'|',
763 1,
764 coPos,
765 &Written);
766 }
767
768 /* Draw lower left corner */
769 coPos.X = ListUi->Left;
770 coPos.Y = ListUi->Bottom;
771 FillConsoleOutputCharacterA(StdOutput,
772 CharLowerLeftCorner, // '+',
773 1,
774 coPos,
775 &Written);
776
777 /* Draw lower edge */
778 coPos.X = ListUi->Left + 1;
779 coPos.Y = ListUi->Bottom;
780 if (LastLine - ListUi->Offset <= Height)
781 {
782 FillConsoleOutputCharacterA(StdOutput,
783 CharHorizontalLine, // '-',
784 Width,
785 coPos,
786 &Written);
787 }
788 else
789 {
790 FillConsoleOutputCharacterA(StdOutput,
791 CharHorizontalLine, // '-',
792 Width - 4,
793 coPos,
794 &Written);
795 {
796 CHAR szBuff[] = "(.)"; // "(down)"
797 szBuff[1] = CharDownArrow;
798 coPos.X = ListUi->Right - 5;
799 WriteConsoleOutputCharacterA(StdOutput,
800 szBuff,
801 3,
802 coPos,
803 &Written);
804 }
805 coPos.X = ListUi->Right - 2;
806 FillConsoleOutputCharacterA(StdOutput,
807 CharHorizontalLine, // '-',
808 2,
809 coPos,
810 &Written);
811 }
812
813 /* Draw lower right corner */
814 coPos.X = ListUi->Right;
815 coPos.Y = ListUi->Bottom;
816 FillConsoleOutputCharacterA(StdOutput,
817 CharLowerRightCorner, // '+',
818 1,
819 coPos,
820 &Written);
821
822 /* Print list entries */
823 ListUi->Line = -ListUi->Offset;
824
825 for (Entry = List->DiskListHead.Flink;
826 Entry != &List->DiskListHead;
827 Entry = Entry->Flink)
828 {
829 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
830
831 /* Print disk entry */
832 PrintDiskData(ListUi, DiskEntry);
833 }
834 }
835
836 /**
837 * @param[in] Direction
838 * TRUE or FALSE to scroll to the next (down) or previous (up) entry, respectively.
839 **/
840 VOID
ScrollUpDownPartitionList(_In_ PPARTLIST_UI ListUi,_In_ BOOLEAN Direction)841 ScrollUpDownPartitionList(
842 _In_ PPARTLIST_UI ListUi,
843 _In_ BOOLEAN Direction)
844 {
845 PPARTENTRY PartEntry =
846 (Direction ? GetNextPartition
847 : GetPrevPartition)(ListUi->List, ListUi->CurrentPartition);
848 if (PartEntry)
849 {
850 ListUi->CurrentPartition = PartEntry;
851 ListUi->CurrentDisk = PartEntry->DiskEntry;
852 DrawPartitionList(ListUi);
853 }
854 }
855
856 /* EOF */
857