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