xref: /reactos/base/setup/usetup/console.c (revision 139a3d66)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002 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/console.c
23  * PURPOSE:         Console support functions
24  * PROGRAMMER:
25  */
26 
27 /* INCLUDES ******************************************************************/
28 
29 #include <usetup.h>
30 /* Blue Driver Header */
31 #include <blue/ntddblue.h>
32 #include "keytrans.h"
33 
34 #define NDEBUG
35 #include <debug.h>
36 
37 /* DATA **********************************************************************/
38 
39 static BOOLEAN InputQueueEmpty;
40 static BOOLEAN WaitForInput;
41 static KEYBOARD_INPUT_DATA InputDataQueue; // Only one element!
42 static IO_STATUS_BLOCK InputIosb;
43 static UINT LastLoadedCodepage;
44 
45 /* FUNCTIONS *****************************************************************/
46 
47 typedef struct _CONSOLE_CABINET_CONTEXT
48 {
49     CABINET_CONTEXT CabinetContext;
50     PVOID Data;
51     ULONG Size;
52 } CONSOLE_CABINET_CONTEXT, *PCONSOLE_CABINET_CONTEXT;
53 
54 static PVOID
55 ConsoleCreateFileHandler(
56     IN PCABINET_CONTEXT CabinetContext,
57     IN ULONG FileSize)
58 {
59     PCONSOLE_CABINET_CONTEXT ConsoleCabinetContext;
60 
61     ConsoleCabinetContext = (PCONSOLE_CABINET_CONTEXT)CabinetContext;
62     ConsoleCabinetContext->Data = RtlAllocateHeap(ProcessHeap, 0, FileSize);
63     if (!ConsoleCabinetContext->Data)
64     {
65         DPRINT("Failed to allocate %d bytes\n", FileSize);
66         return NULL;
67     }
68     ConsoleCabinetContext->Size = FileSize;
69     return ConsoleCabinetContext->Data;
70 }
71 
72 BOOL
73 WINAPI
74 AllocConsole(VOID)
75 {
76     NTSTATUS Status;
77     UNICODE_STRING ScreenName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
78     UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
79     OBJECT_ATTRIBUTES ObjectAttributes;
80     IO_STATUS_BLOCK IoStatusBlock;
81     ULONG Enable;
82 
83     /* Open the screen */
84     InitializeObjectAttributes(&ObjectAttributes,
85                                &ScreenName,
86                                0,
87                                NULL,
88                                NULL);
89     Status = NtOpenFile(&StdOutput,
90                         FILE_ALL_ACCESS,
91                         &ObjectAttributes,
92                         &IoStatusBlock,
93                         FILE_OPEN,
94                         FILE_SYNCHRONOUS_IO_ALERT);
95     if (!NT_SUCCESS(Status))
96         return FALSE;
97 
98     /* Enable it */
99     Enable = TRUE;
100     Status = NtDeviceIoControlFile(StdOutput,
101                                    NULL,
102                                    NULL,
103                                    NULL,
104                                    &IoStatusBlock,
105                                    IOCTL_CONSOLE_RESET_SCREEN,
106                                    &Enable,
107                                    sizeof(Enable),
108                                    NULL,
109                                    0);
110     if (!NT_SUCCESS(Status))
111     {
112         NtClose(StdOutput);
113         return FALSE;
114     }
115 
116     /* Open the keyboard */
117     InitializeObjectAttributes(&ObjectAttributes,
118                                &KeyboardName,
119                                0,
120                                NULL,
121                                NULL);
122     Status = NtOpenFile(&StdInput,
123                         FILE_ALL_ACCESS,
124                         &ObjectAttributes,
125                         &IoStatusBlock,
126                         FILE_OPEN,
127                         0);
128     if (!NT_SUCCESS(Status))
129     {
130         NtClose(StdOutput);
131         return FALSE;
132     }
133 
134     /* Reset the queue state */
135     InputQueueEmpty = TRUE;
136     WaitForInput = FALSE;
137 
138     return TRUE;
139 }
140 
141 
142 BOOL
143 WINAPI
144 AttachConsole(
145     IN DWORD dwProcessId)
146 {
147     return FALSE;
148 }
149 
150 
151 BOOL
152 WINAPI
153 FreeConsole(VOID)
154 {
155     /* Reset the queue state */
156     InputQueueEmpty = TRUE;
157     WaitForInput = FALSE;
158 
159     if (StdInput != INVALID_HANDLE_VALUE)
160         NtClose(StdInput);
161 
162     if (StdOutput != INVALID_HANDLE_VALUE)
163         NtClose(StdOutput);
164 
165     return TRUE;
166 }
167 
168 
169 BOOL
170 WINAPI
171 WriteConsole(
172     IN HANDLE hConsoleOutput,
173     IN const VOID *lpBuffer,
174     IN DWORD nNumberOfCharsToWrite,
175     OUT LPDWORD lpNumberOfCharsWritten,
176     IN LPVOID lpReserved)
177 {
178     IO_STATUS_BLOCK IoStatusBlock;
179     NTSTATUS Status;
180 
181     Status = NtWriteFile(hConsoleOutput,
182                          NULL,
183                          NULL,
184                          NULL,
185                          &IoStatusBlock,
186                          (PVOID)lpBuffer,
187                          nNumberOfCharsToWrite,
188                          NULL,
189                          NULL);
190     if (!NT_SUCCESS(Status))
191         return FALSE;
192 
193     *lpNumberOfCharsWritten = IoStatusBlock.Information;
194     return TRUE;
195 }
196 
197 
198 HANDLE
199 WINAPI
200 GetStdHandle(
201     IN DWORD nStdHandle)
202 {
203     switch (nStdHandle)
204     {
205         case STD_INPUT_HANDLE:
206             return StdInput;
207         case STD_OUTPUT_HANDLE:
208             return StdOutput;
209         default:
210             return INVALID_HANDLE_VALUE;
211     }
212 }
213 
214 
215 BOOL
216 WINAPI
217 FlushConsoleInputBuffer(
218     IN HANDLE hConsoleInput)
219 {
220     NTSTATUS Status;
221     LARGE_INTEGER Offset, Timeout;
222     IO_STATUS_BLOCK IoStatusBlock;
223     KEYBOARD_INPUT_DATA InputData;
224 
225     /* Cancel any pending read */
226     if (WaitForInput)
227         NtCancelIoFile(hConsoleInput, &IoStatusBlock);
228 
229     /* Reset the queue state */
230     InputQueueEmpty = TRUE;
231     WaitForInput = FALSE;
232 
233     /* Flush the keyboard buffer */
234     do
235     {
236         Offset.QuadPart = 0;
237         Status = NtReadFile(hConsoleInput,
238                             NULL,
239                             NULL,
240                             NULL,
241                             &IoStatusBlock,
242                             &InputData,
243                             sizeof(InputData),
244                             &Offset,
245                             NULL);
246         if (Status == STATUS_PENDING)
247         {
248             Timeout.QuadPart = -100;
249             Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout);
250             if (Status == STATUS_TIMEOUT)
251             {
252                 NtCancelIoFile(hConsoleInput, &IoStatusBlock);
253                 return TRUE;
254             }
255         }
256     } while (NT_SUCCESS(Status));
257     return FALSE;
258 }
259 
260 
261 BOOL
262 WINAPI
263 PeekConsoleInput(
264     IN HANDLE hConsoleInput,
265     OUT PINPUT_RECORD lpBuffer,
266     IN DWORD nLength,
267     OUT LPDWORD lpNumberOfEventsRead)
268 {
269     NTSTATUS Status;
270     LARGE_INTEGER Offset, Timeout;
271     KEYBOARD_INPUT_DATA InputData;
272 
273     if (InputQueueEmpty)
274     {
275         /* Read the keyboard for an event, without waiting */
276         if (!WaitForInput)
277         {
278             Offset.QuadPart = 0;
279             Status = NtReadFile(hConsoleInput,
280                                 NULL,
281                                 NULL,
282                                 NULL,
283                                 &InputIosb,
284                                 &InputDataQueue,
285                                 sizeof(InputDataQueue),
286                                 &Offset,
287                                 NULL);
288             if (!NT_SUCCESS(Status))
289                 return FALSE;
290             if (Status == STATUS_PENDING)
291             {
292                 /* No input yet, we will have to wait next time */
293                 *lpNumberOfEventsRead = 0;
294                 WaitForInput = TRUE;
295                 return TRUE;
296             }
297         }
298         else
299         {
300             /*
301              * We already tried to read from the keyboard and are
302              * waiting for data, check whether something showed up.
303              */
304             Timeout.QuadPart = -100; // Wait just a little bit.
305             Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout);
306             if (Status == STATUS_TIMEOUT)
307             {
308                 /* Nothing yet, continue waiting next time */
309                 *lpNumberOfEventsRead = 0;
310                 WaitForInput = TRUE;
311                 return TRUE;
312             }
313             WaitForInput = FALSE;
314             if (!NT_SUCCESS(Status))
315                 return FALSE;
316         }
317 
318         /* We got something in the queue */
319         InputQueueEmpty = FALSE;
320         WaitForInput = FALSE;
321     }
322 
323     /* Fetch from the queue but keep it inside */
324     InputData = InputDataQueue;
325 
326     lpBuffer->EventType = KEY_EVENT;
327     Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent);
328     if (!NT_SUCCESS(Status))
329         return FALSE;
330 
331     *lpNumberOfEventsRead = 1;
332     return TRUE;
333 }
334 
335 
336 BOOL
337 WINAPI
338 ReadConsoleInput(
339     IN HANDLE hConsoleInput,
340     OUT PINPUT_RECORD lpBuffer,
341     IN DWORD nLength,
342     OUT LPDWORD lpNumberOfEventsRead)
343 {
344     NTSTATUS Status;
345     LARGE_INTEGER Offset;
346     KEYBOARD_INPUT_DATA InputData;
347 
348     if (InputQueueEmpty)
349     {
350         /* Read the keyboard and wait for an event, skipping the queue */
351         if (!WaitForInput)
352         {
353             Offset.QuadPart = 0;
354             Status = NtReadFile(hConsoleInput,
355                                 NULL,
356                                 NULL,
357                                 NULL,
358                                 &InputIosb,
359                                 &InputDataQueue,
360                                 sizeof(InputDataQueue),
361                                 &Offset,
362                                 NULL);
363             if (Status == STATUS_PENDING)
364             {
365                 /* Block and wait for input */
366                 WaitForInput = TRUE;
367                 Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
368                 WaitForInput = FALSE;
369                 Status = InputIosb.Status;
370             }
371             if (!NT_SUCCESS(Status))
372                 return FALSE;
373         }
374         else
375         {
376             /*
377              * We already tried to read from the keyboard and are
378              * waiting for data, block and wait for input.
379              */
380             Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
381             WaitForInput = FALSE;
382             Status = InputIosb.Status;
383             if (!NT_SUCCESS(Status))
384                 return FALSE;
385         }
386     }
387 
388     /* Fetch from the queue and empty it */
389     InputData = InputDataQueue;
390     InputQueueEmpty = TRUE;
391 
392     lpBuffer->EventType = KEY_EVENT;
393     Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent);
394     if (!NT_SUCCESS(Status))
395         return FALSE;
396 
397     *lpNumberOfEventsRead = 1;
398     return TRUE;
399 }
400 
401 
402 BOOL
403 WINAPI
404 WriteConsoleOutputCharacterA(
405     HANDLE hConsoleOutput,
406     IN LPCSTR lpCharacter,
407     IN DWORD nLength,
408     IN COORD dwWriteCoord,
409     OUT LPDWORD lpNumberOfCharsWritten)
410 {
411     IO_STATUS_BLOCK IoStatusBlock;
412     PCHAR Buffer;
413     COORD *pCoord;
414     PCHAR pText;
415     NTSTATUS Status;
416 
417     Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
418                                     0,
419                                     nLength + sizeof(COORD));
420     pCoord = (COORD *)Buffer;
421     pText = (PCHAR)(pCoord + 1);
422 
423     *pCoord = dwWriteCoord;
424     memcpy(pText, lpCharacter, nLength);
425 
426     Status = NtDeviceIoControlFile(hConsoleOutput,
427                                    NULL,
428                                    NULL,
429                                    NULL,
430                                    &IoStatusBlock,
431                                    IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
432                                    NULL,
433                                    0,
434                                    Buffer,
435                                    nLength + sizeof(COORD));
436 
437     RtlFreeHeap(ProcessHeap, 0, Buffer);
438     if (!NT_SUCCESS(Status))
439         return FALSE;
440 
441     *lpNumberOfCharsWritten = IoStatusBlock.Information;
442     return TRUE;
443 }
444 
445 
446 BOOL
447 WINAPI
448 WriteConsoleOutputCharacterW(
449     HANDLE hConsoleOutput,
450     IN LPCWSTR lpCharacter,
451     IN DWORD nLength,
452     IN COORD dwWriteCoord,
453     OUT LPDWORD lpNumberOfCharsWritten)
454 {
455     IO_STATUS_BLOCK IoStatusBlock;
456     PCHAR Buffer;
457     COORD *pCoord;
458     PCHAR pText;
459     NTSTATUS Status;
460 //    ULONG i;
461 
462     UNICODE_STRING UnicodeString;
463     OEM_STRING OemString;
464     ULONG OemLength;
465 
466     UnicodeString.Length = nLength * sizeof(WCHAR);
467     UnicodeString.MaximumLength = nLength * sizeof(WCHAR);
468     UnicodeString.Buffer = (PWSTR)lpCharacter;
469 
470     OemLength = RtlUnicodeStringToOemSize(&UnicodeString);
471 
472 
473     Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
474                                     0,
475                                     OemLength + sizeof(COORD));
476 //                                    nLength + sizeof(COORD));
477     if (Buffer== NULL)
478         return FALSE;
479 
480     pCoord = (COORD *)Buffer;
481     pText = (PCHAR)(pCoord + 1);
482 
483     *pCoord = dwWriteCoord;
484 
485     OemString.Length = 0;
486     OemString.MaximumLength = OemLength;
487     OemString.Buffer = pText;
488 
489     Status = RtlUnicodeStringToOemString(&OemString,
490                                          &UnicodeString,
491                                          FALSE);
492     if (!NT_SUCCESS(Status))
493         goto done;
494 
495     /* FIXME: use real unicode->oem conversion */
496 //    for (i = 0; i < nLength; i++)
497 //        pText[i] = (CHAR)lpCharacter[i];
498 
499     Status = NtDeviceIoControlFile(hConsoleOutput,
500                                    NULL,
501                                    NULL,
502                                    NULL,
503                                    &IoStatusBlock,
504                                    IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
505                                    NULL,
506                                    0,
507                                    Buffer,
508                                    nLength + sizeof(COORD));
509 
510 done:
511     RtlFreeHeap(ProcessHeap, 0, Buffer);
512     if (!NT_SUCCESS(Status))
513         return FALSE;
514 
515     *lpNumberOfCharsWritten = IoStatusBlock.Information;
516     return TRUE;
517 }
518 
519 
520 BOOL
521 WINAPI
522 FillConsoleOutputAttribute(
523     IN HANDLE hConsoleOutput,
524     IN WORD wAttribute,
525     IN DWORD nLength,
526     IN COORD dwWriteCoord,
527     OUT LPDWORD lpNumberOfAttrsWritten)
528 {
529     IO_STATUS_BLOCK IoStatusBlock;
530     OUTPUT_ATTRIBUTE Buffer;
531     NTSTATUS Status;
532 
533     Buffer.wAttribute = wAttribute;
534     Buffer.nLength    = nLength;
535     Buffer.dwCoord    = dwWriteCoord;
536 
537     Status = NtDeviceIoControlFile(hConsoleOutput,
538                                    NULL,
539                                    NULL,
540                                    NULL,
541                                    &IoStatusBlock,
542                                    IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
543                                    &Buffer,
544                                    sizeof(OUTPUT_ATTRIBUTE),
545                                    &Buffer,
546                                    sizeof(OUTPUT_ATTRIBUTE));
547     if (!NT_SUCCESS(Status))
548         return FALSE;
549 
550     *lpNumberOfAttrsWritten = Buffer.dwTransfered;
551     return TRUE;
552 }
553 
554 
555 BOOL
556 WINAPI
557 FillConsoleOutputCharacterA(
558     IN HANDLE hConsoleOutput,
559     IN CHAR cCharacter,
560     IN DWORD nLength,
561     IN COORD dwWriteCoord,
562     OUT LPDWORD lpNumberOfCharsWritten)
563 {
564     IO_STATUS_BLOCK IoStatusBlock;
565     OUTPUT_CHARACTER Buffer;
566     NTSTATUS Status;
567 
568     Buffer.cCharacter = cCharacter;
569     Buffer.nLength = nLength;
570     Buffer.dwCoord = dwWriteCoord;
571 
572     Status = NtDeviceIoControlFile(hConsoleOutput,
573                                    NULL,
574                                    NULL,
575                                    NULL,
576                                    &IoStatusBlock,
577                                    IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER,
578                                    &Buffer,
579                                    sizeof(OUTPUT_CHARACTER),
580                                    &Buffer,
581                                    sizeof(OUTPUT_CHARACTER));
582     if (!NT_SUCCESS(Status))
583         return FALSE;
584 
585     *lpNumberOfCharsWritten = Buffer.dwTransfered;
586     return TRUE;
587 }
588 
589 
590 BOOL
591 WINAPI
592 GetConsoleScreenBufferInfo(
593     IN HANDLE hConsoleOutput,
594     OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo)
595 {
596     IO_STATUS_BLOCK IoStatusBlock;
597     NTSTATUS Status;
598 
599     Status = NtDeviceIoControlFile(hConsoleOutput,
600                                    NULL,
601                                    NULL,
602                                    NULL,
603                                    &IoStatusBlock,
604                                    IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
605                                    NULL,
606                                    0,
607                                    lpConsoleScreenBufferInfo,
608                                    sizeof(CONSOLE_SCREEN_BUFFER_INFO));
609     return NT_SUCCESS(Status);
610 }
611 
612 
613 BOOL
614 WINAPI
615 SetConsoleCursorInfo(
616     IN HANDLE hConsoleOutput,
617     IN const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo)
618 {
619     IO_STATUS_BLOCK IoStatusBlock;
620     NTSTATUS Status;
621 
622     Status = NtDeviceIoControlFile(hConsoleOutput,
623                                    NULL,
624                                    NULL,
625                                    NULL,
626                                    &IoStatusBlock,
627                                    IOCTL_CONSOLE_SET_CURSOR_INFO,
628                                    (PCONSOLE_CURSOR_INFO)lpConsoleCursorInfo,
629                                    sizeof(CONSOLE_CURSOR_INFO),
630                                    NULL,
631                                    0);
632     return NT_SUCCESS(Status);
633 }
634 
635 
636 BOOL
637 WINAPI
638 SetConsoleCursorPosition(
639     IN HANDLE hConsoleOutput,
640     IN COORD dwCursorPosition)
641 {
642     CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
643     IO_STATUS_BLOCK IoStatusBlock;
644     NTSTATUS Status;
645 
646     Status = GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleScreenBufferInfo);
647     if (!NT_SUCCESS(Status))
648         return FALSE;
649 
650     ConsoleScreenBufferInfo.dwCursorPosition.X = dwCursorPosition.X;
651     ConsoleScreenBufferInfo.dwCursorPosition.Y = dwCursorPosition.Y;
652 
653     Status = NtDeviceIoControlFile(hConsoleOutput,
654                                    NULL,
655                                    NULL,
656                                    NULL,
657                                    &IoStatusBlock,
658                                    IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
659                                    &ConsoleScreenBufferInfo,
660                                    sizeof(CONSOLE_SCREEN_BUFFER_INFO),
661                                    NULL,
662                                    0);
663     return NT_SUCCESS(Status);
664 }
665 
666 
667 BOOL
668 WINAPI
669 SetConsoleTextAttribute(
670     IN HANDLE hConsoleOutput,
671     IN WORD wAttributes)
672 {
673     IO_STATUS_BLOCK IoStatusBlock;
674     NTSTATUS Status;
675 
676     Status = NtDeviceIoControlFile(hConsoleOutput,
677                                    NULL,
678                                    NULL,
679                                    NULL,
680                                    &IoStatusBlock,
681                                    IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
682                                    &wAttributes,
683                                    sizeof(USHORT),
684                                    NULL,
685                                    0);
686     return NT_SUCCESS(Status);
687 }
688 
689 
690 BOOL
691 WINAPI
692 SetConsoleOutputCP(
693     IN UINT wCodepage)
694 {
695     WCHAR FontName[100];
696     WCHAR FontFile[] = L"\\SystemRoot\\vgafonts.cab";
697     CONSOLE_CABINET_CONTEXT ConsoleCabinetContext;
698     PCABINET_CONTEXT CabinetContext = &ConsoleCabinetContext.CabinetContext;
699     CAB_SEARCH Search;
700     ULONG CabStatus;
701     HANDLE hConsoleOutput;
702     IO_STATUS_BLOCK IoStatusBlock;
703     NTSTATUS Status;
704 
705     if (wCodepage == LastLoadedCodepage)
706         return TRUE;
707 
708     hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
709 
710     CabinetInitialize(CabinetContext);
711     CabinetSetEventHandlers(CabinetContext,
712                             NULL, NULL, NULL, ConsoleCreateFileHandler);
713     CabinetSetCabinetName(CabinetContext, FontFile);
714 
715     CabStatus = CabinetOpen(CabinetContext);
716     if (CabStatus != CAB_STATUS_SUCCESS)
717     {
718         DPRINT("CabinetOpen('%S') returned 0x%08x\n", FontFile, CabStatus);
719         return FALSE;
720     }
721 
722     swprintf(FontName, L"%u-8x8.bin", wCodepage);
723     CabStatus = CabinetFindFirst(CabinetContext, FontName, &Search);
724     if (CabStatus != CAB_STATUS_SUCCESS)
725     {
726         DPRINT("CabinetFindFirst('%S', '%S') returned 0x%08x\n", FontFile, FontName, CabStatus);
727         CabinetClose(CabinetContext);
728         return FALSE;
729     }
730 
731     CabStatus = CabinetExtractFile(CabinetContext, &Search);
732     CabinetClose(CabinetContext);
733     if (CabStatus != CAB_STATUS_SUCCESS)
734     {
735         DPRINT("CabinetLoadFile('%S', '%S') returned 0x%08x\n", FontFile, FontName, CabStatus);
736         return FALSE;
737     }
738 
739     Status = NtDeviceIoControlFile(hConsoleOutput,
740                                    NULL,
741                                    NULL,
742                                    NULL,
743                                    &IoStatusBlock,
744                                    IOCTL_CONSOLE_SETFONT,
745                                    ConsoleCabinetContext.Data,
746                                    ConsoleCabinetContext.Size,
747                                    NULL,
748                                    0);
749     if (!NT_SUCCESS(Status))
750           return FALSE;
751 
752     LastLoadedCodepage = wCodepage;
753     return TRUE;
754 }
755 
756 
757 /* EOF */
758