1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c
5  * PURPOSE:         TUI Terminal Front-End - Virtual Consoles...
6  * PROGRAMMERS:     David Welch
7  *                  Gé van Geldorp
8  *                  Jeffrey Morlan
9  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10  */
11 
12 #ifdef TUITERM_COMPILE
13 
14 #include <consrv.h>
15 
16 // #include "include/conio.h"
17 #include "include/console.h"
18 #include "include/settings.h"
19 #include "tuiterm.h"
20 
21 #include <ndk/iofuncs.h>
22 #include <ndk/setypes.h>
23 #include <drivers/blue/ntddblue.h>
24 
25 #define NDEBUG
26 #include <debug.h>
27 
28 
29 /* CAB FILE STRUCTURES ******************************************************/
30 
31 typedef struct _CFHEADER
32 {
33     ULONG Signature;        // File signature 'MSCF' (CAB_SIGNATURE)
34     ULONG Reserved1;        // Reserved field
35     ULONG CabinetSize;      // Cabinet file size
36     ULONG Reserved2;        // Reserved field
37     ULONG FileTableOffset;  // Offset of first CFFILE
38     ULONG Reserved3;        // Reserved field
39     USHORT Version;         // Cabinet version (CAB_VERSION)
40     USHORT FolderCount;     // Number of folders
41     USHORT FileCount;       // Number of files
42     USHORT Flags;           // Cabinet flags (CAB_FLAG_*)
43     USHORT SetID;           // Cabinet set id
44     USHORT CabinetNumber;   // Zero-based cabinet number
45 } CFHEADER, *PCFHEADER;
46 
47 typedef struct _CFFILE
48 {
49     ULONG FileSize;         // Uncompressed file size in bytes
50     ULONG FileOffset;       // Uncompressed offset of file in the folder
51     USHORT FileControlID;   // File control ID (CAB_FILE_*)
52     USHORT FileDate;        // File date stamp, as used by DOS
53     USHORT FileTime;        // File time stamp, as used by DOS
54     USHORT Attributes;      // File attributes (CAB_ATTRIB_*)
55     /* After this is the NULL terminated filename */
56     // CHAR FileName[ANYSIZE_ARRAY];
57 } CFFILE, *PCFFILE;
58 
59 #define CAB_SIGNATURE       0x4643534D // "MSCF"
60 #define CAB_VERSION         0x0103
61 
62 
63 /* GLOBALS ******************************************************************/
64 
65 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \
66 do { \
67     ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
68     WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
69 } while (0)
70 
71 /* TUI Console Window Class name */
72 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
73 
74 typedef struct _TUI_CONSOLE_DATA
75 {
76     CRITICAL_SECTION Lock;
77     LIST_ENTRY Entry;           /* Entry in the list of virtual consoles */
78     // HANDLE hTuiInitEvent;
79     // HANDLE hTuiTermEvent;
80 
81     HWND hWindow;               /* Handle to the console's window (used for the window's procedure) */
82 
83     PCONSRV_CONSOLE Console;           /* Pointer to the owned console */
84     PCONSOLE_SCREEN_BUFFER ActiveBuffer;    /* Pointer to the active screen buffer (then maybe the previous Console member is redundant?? Or not...) */
85     // TUI_CONSOLE_INFO TuiInfo;   /* TUI terminal settings */
86 } TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA;
87 
88 #define GetNextConsole(Console) \
89     CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry)
90 
91 #define GetPrevConsole(Console) \
92     CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry)
93 
94 
95 /* List of the maintained virtual consoles and its lock */
96 static LIST_ENTRY VirtConsList;
97 static PTUI_CONSOLE_DATA ActiveConsole; /* The active console on screen */
98 static CRITICAL_SECTION ActiveVirtConsLock;
99 
100 static COORD PhysicalConsoleSize;
101 static HANDLE ConsoleDeviceHandle;
102 
103 static BOOL ConsInitialized = FALSE;
104 
105 /******************************************************************************\
106 |** BlueScreen Driver management                                             **|
107 \**/
108 /* Code taken and adapted from base/system/services/driver.c */
109 static DWORD
ScmLoadDriver(LPCWSTR lpServiceName)110 ScmLoadDriver(LPCWSTR lpServiceName)
111 {
112     NTSTATUS Status = STATUS_SUCCESS;
113     BOOLEAN WasPrivilegeEnabled = FALSE;
114     PWSTR pszDriverPath;
115     UNICODE_STRING DriverPath;
116 
117     /* Build the driver path */
118     /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
119     pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
120                                      (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
121     if (pszDriverPath == NULL)
122         return ERROR_NOT_ENOUGH_MEMORY;
123 
124     wcscpy(pszDriverPath,
125            L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
126     wcscat(pszDriverPath,
127            lpServiceName);
128 
129     RtlInitUnicodeString(&DriverPath,
130                          pszDriverPath);
131 
132     DPRINT("  Path: %wZ\n", &DriverPath);
133 
134     /* Acquire driver-loading privilege */
135     Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
136                                 TRUE,
137                                 FALSE,
138                                 &WasPrivilegeEnabled);
139     if (!NT_SUCCESS(Status))
140     {
141         /* We encountered a failure, exit properly */
142         DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status);
143         goto done;
144     }
145 
146     Status = NtLoadDriver(&DriverPath);
147 
148     /* Release driver-loading privilege */
149     RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
150                        WasPrivilegeEnabled,
151                        FALSE,
152                        &WasPrivilegeEnabled);
153 
154 done:
155     ConsoleFreeHeap(pszDriverPath);
156     return RtlNtStatusToDosError(Status);
157 }
158 
159 #ifdef BLUESCREEN_DRIVER_UNLOADING
160 static DWORD
ScmUnloadDriver(LPCWSTR lpServiceName)161 ScmUnloadDriver(LPCWSTR lpServiceName)
162 {
163     NTSTATUS Status = STATUS_SUCCESS;
164     BOOLEAN WasPrivilegeEnabled = FALSE;
165     PWSTR pszDriverPath;
166     UNICODE_STRING DriverPath;
167 
168     /* Build the driver path */
169     /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
170     pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
171                                      (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
172     if (pszDriverPath == NULL)
173         return ERROR_NOT_ENOUGH_MEMORY;
174 
175     wcscpy(pszDriverPath,
176            L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
177     wcscat(pszDriverPath,
178            lpServiceName);
179 
180     RtlInitUnicodeString(&DriverPath,
181                          pszDriverPath);
182 
183     DPRINT("  Path: %wZ\n", &DriverPath);
184 
185     /* Acquire driver-unloading privilege */
186     Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
187                                 TRUE,
188                                 FALSE,
189                                 &WasPrivilegeEnabled);
190     if (!NT_SUCCESS(Status))
191     {
192         /* We encountered a failure, exit properly */
193         DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status);
194         goto done;
195     }
196 
197     Status = NtUnloadDriver(&DriverPath);
198 
199     /* Release driver-unloading privilege */
200     RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
201                        WasPrivilegeEnabled,
202                        FALSE,
203                        &WasPrivilegeEnabled);
204 
205 done:
206     ConsoleFreeHeap(pszDriverPath);
207     return RtlNtStatusToDosError(Status);
208 }
209 #endif
210 /**\
211 \******************************************************************************/
212 
213 #if 0
214 static BOOL
215 TuiSwapConsole(INT Next)
216 {
217     static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */
218     DWORD BytesReturned;
219     ANSI_STRING Title;
220     PVOID Buffer;
221     PCOORD pos;
222 
223     if (0 != Next)
224     {
225         /*
226          * Alt-Tab, swap consoles.
227          * move SwapConsole to next console, and print its title.
228          */
229         EnterCriticalSection(&ActiveVirtConsLock);
230         if (!SwapConsole) SwapConsole = ActiveConsole;
231 
232         SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole));
233         Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title);
234         Title.Length = 0;
235         Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength);
236         pos = (PCOORD)Buffer;
237         Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD));
238 
239         RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE);
240         pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
241         pos->Y = PhysicalConsoleSize.Y / 2;
242         /* Redraw the console to clear off old title */
243         ConioDrawConsole(ActiveConsole->Console);
244         if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
245                              NULL, 0, Buffer, sizeof(COORD) + Title.Length,
246                              &BytesReturned, NULL))
247         {
248             DPRINT1( "Error writing to console\n" );
249         }
250         ConsoleFreeHeap(Buffer);
251         LeaveCriticalSection(&ActiveVirtConsLock);
252 
253         return TRUE;
254     }
255     else if (NULL != SwapConsole)
256     {
257         EnterCriticalSection(&ActiveVirtConsLock);
258         if (SwapConsole != ActiveConsole)
259         {
260             /* First remove swapconsole from the list */
261             SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink;
262             SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink;
263             /* Now insert before activeconsole */
264             SwapConsole->Entry.Flink = &ActiveConsole->Entry;
265             SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink;
266             ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry;
267             ActiveConsole->Entry.Blink = &SwapConsole->Entry;
268         }
269         ActiveConsole = SwapConsole;
270         SwapConsole = NULL;
271         ConioDrawConsole(ActiveConsole->Console);
272         LeaveCriticalSection(&ActiveVirtConsLock);
273         return TRUE;
274     }
275     else
276     {
277         return FALSE;
278     }
279 }
280 #endif
281 
282 static VOID
TuiCopyRect(PCHAR Dest,PTEXTMODE_SCREEN_BUFFER Buff,SMALL_RECT * Region)283 TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region)
284 {
285     UINT SrcDelta, DestDelta;
286     LONG i;
287     PCHAR_INFO Src, SrcEnd;
288 
289     Src = ConioCoordToPointer(Buff, Region->Left, Region->Top);
290     SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
291     SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
292     DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */;
293     for (i = Region->Top; i <= Region->Bottom; i++)
294     {
295         ConsoleOutputUnicodeToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar);
296         *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes;
297 
298         Src += SrcDelta;
299         if (SrcEnd <= Src)
300         {
301             Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
302         }
303         Dest += DestDelta;
304     }
305 }
306 
307 static LRESULT CALLBACK
TuiConsoleWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)308 TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
309 {
310 /*
311     PTUI_CONSOLE_DATA TuiData = NULL;
312     PCONSRV_CONSOLE Console = NULL;
313 
314     TuiData = TuiGetGuiData(hWnd);
315     if (TuiData == NULL) return 0;
316 */
317 
318     switch (msg)
319     {
320         case WM_CHAR:
321         case WM_SYSCHAR:
322         case WM_KEYDOWN:
323         case WM_SYSKEYDOWN:
324         case WM_KEYUP:
325         case WM_SYSKEYUP:
326         {
327 #if 0
328             if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_TAB)
329             {
330                 // if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT)
331                     TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
332 
333                 break;
334             }
335             else if (wParam == VK_MENU /* && !Down */)
336             {
337                 TuiSwapConsole(0);
338                 break;
339             }
340 #endif
341 
342             if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
343             {
344                 MSG Message;
345                 Message.hwnd = hWnd;
346                 Message.message = msg;
347                 Message.wParam = wParam;
348                 Message.lParam = lParam;
349 
350                 ConioProcessKey(ActiveConsole->Console, &Message);
351                 LeaveCriticalSection(&ActiveConsole->Console->Lock);
352             }
353             break;
354         }
355 
356         case WM_ACTIVATE:
357         {
358             if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
359             {
360                 if (LOWORD(wParam) != WA_INACTIVE)
361                 {
362                     SetFocus(hWnd);
363                     ConioDrawConsole(ActiveConsole->Console);
364                 }
365                 LeaveCriticalSection(&ActiveConsole->Console->Lock);
366             }
367             break;
368         }
369 
370         default:
371             break;
372     }
373 
374     return DefWindowProcW(hWnd, msg, wParam, lParam);
375 }
376 
377 static DWORD NTAPI
TuiConsoleThread(PVOID Param)378 TuiConsoleThread(PVOID Param)
379 {
380     PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Param;
381     PCONSRV_CONSOLE Console = TuiData->Console;
382     HWND NewWindow;
383     MSG msg;
384 
385     NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS,
386                               Console->Title.Buffer,
387                               0,
388                               -32000, -32000, 0, 0,
389                               NULL, NULL,
390                               ConSrvDllInstance,
391                               (PVOID)Console);
392     if (NULL == NewWindow)
393     {
394         DPRINT1("CONSRV: Unable to create console window\n");
395         return 1;
396     }
397     TuiData->hWindow = NewWindow;
398 
399     SetForegroundWindow(TuiData->hWindow);
400     NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0);
401 
402     while (GetMessageW(&msg, NULL, 0, 0))
403     {
404         TranslateMessage(&msg);
405         DispatchMessageW(&msg);
406     }
407 
408     return 0;
409 }
410 
411 static BOOLEAN
TuiSetConsoleOutputCP(IN HANDLE hNtConddHandle,IN UINT CodePage)412 TuiSetConsoleOutputCP(
413     IN HANDLE hNtConddHandle,
414     IN UINT CodePage)
415 {
416     static UINT LastLoadedCodepage = 0;
417     UNICODE_STRING FontFile = RTL_CONSTANT_STRING(L"\\SystemRoot\\vgafonts.cab");
418     CHAR FontName[20];
419 
420     NTSTATUS Status;
421     HANDLE FileHandle;
422     OBJECT_ATTRIBUTES ObjectAttributes;
423     IO_STATUS_BLOCK IoStatusBlock;
424     // ULONG ReadCP;
425     PUCHAR FontBitField = NULL;
426 
427     /* CAB-specific data */
428     HANDLE FileSectionHandle;
429     PUCHAR FileBuffer = NULL;
430     SIZE_T FileSize = 0;
431     PCFHEADER CabFileHeader;
432     union
433     {
434         PCFFILE CabFile;
435         PVOID Buffer;
436     } Data;
437     PCFFILE FoundFile = NULL;
438     PSTR FileName;
439     USHORT Index;
440 
441     if (CodePage == LastLoadedCodepage)
442         return TRUE;
443 
444     /*
445      * Open the *uncompressed* fonts archive file.
446      */
447     InitializeObjectAttributes(&ObjectAttributes,
448                                &FontFile,
449                                OBJ_CASE_INSENSITIVE,
450                                NULL,
451                                NULL);
452 
453     Status = NtOpenFile(&FileHandle,
454                         GENERIC_READ | SYNCHRONIZE,
455                         &ObjectAttributes,
456                         &IoStatusBlock,
457                         FILE_SHARE_READ,
458                         FILE_SYNCHRONOUS_IO_NONALERT);
459     if (!NT_SUCCESS(Status))
460     {
461         DPRINT1("Error: Cannot open '%wZ' (0x%lx)\n", &FontFile, Status);
462         return FALSE;
463     }
464 
465     /*
466      * Load it.
467      */
468     Status = NtCreateSection(&FileSectionHandle,
469                              SECTION_ALL_ACCESS,
470                              0, 0,
471                              PAGE_READONLY,
472                              SEC_COMMIT,
473                              FileHandle);
474     if (!NT_SUCCESS(Status))
475     {
476         DPRINT1("NtCreateSection failed (0x%lx)\n", Status);
477         goto Exit;
478     }
479 
480     Status = NtMapViewOfSection(FileSectionHandle,
481                                 NtCurrentProcess(),
482                                 (PVOID*)&FileBuffer,
483                                 0, 0, NULL,
484                                 &FileSize,
485                                 ViewUnmap,
486                                 0,
487                                 PAGE_READONLY);
488     if (!NT_SUCCESS(Status))
489     {
490         DPRINT1("NtMapViewOfSection failed (0x%lx)\n", Status);
491         goto Exit;
492     }
493 
494     /* Wrap in SEH to protect against ill-formed file */
495     _SEH2_TRY
496     {
497         DPRINT("Cabinet file '%wZ' opened and mapped to 0x%p\n",
498                &FontFile, FileBuffer);
499 
500         CabFileHeader = (PCFHEADER)FileBuffer;
501 
502         /* Validate the CAB file */
503         if (FileSize <= sizeof(CFHEADER) ||
504             CabFileHeader->Signature != CAB_SIGNATURE ||
505             CabFileHeader->Version != CAB_VERSION ||
506             CabFileHeader->FolderCount == 0 ||
507             CabFileHeader->FileCount == 0 ||
508             CabFileHeader->FileTableOffset < sizeof(CFHEADER))
509         {
510             DPRINT1("Cabinet file '%wZ' has an invalid header\n", &FontFile);
511             Status = STATUS_UNSUCCESSFUL;
512             _SEH2_YIELD(goto Exit);
513         }
514 
515         /*
516          * Find the font file within the archive.
517          */
518         RtlStringCbPrintfA(FontName, sizeof(FontName),
519                            "%u-8x8.bin", CodePage);
520 
521         /* Read the file table, find the file of interest and the end of the table */
522         Data.CabFile = (PCFFILE)(FileBuffer + CabFileHeader->FileTableOffset);
523         for (Index = 0; Index < CabFileHeader->FileCount; ++Index)
524         {
525             FileName = (PSTR)(Data.CabFile + 1);
526 
527             if (!FoundFile)
528             {
529                 // Status = RtlCharToInteger(FileName, 0, &ReadCP);
530                 // if (NT_SUCCESS(Status) && (ReadCP == CodePage))
531                 if (_stricmp(FontName, FileName) == 0)
532                 {
533                     /* We've got the correct file. Save the offset and
534                      * loop through the rest of the file table to find
535                      * the position, where the actual data starts. */
536                     FoundFile = Data.CabFile;
537                 }
538             }
539 
540             /* Move to the next file (go past the filename NULL terminator) */
541             Data.CabFile = (PCFFILE)(strchr(FileName, 0) + 1);
542         }
543 
544         if (!FoundFile)
545         {
546             DPRINT("File '%S' not found in cabinet '%wZ'\n",
547                    FontName, &FontFile);
548             Status = STATUS_OBJECT_NAME_NOT_FOUND;
549             _SEH2_YIELD(goto Exit);
550         }
551 
552         /*
553          * Extract the font file.
554          */
555         /* Verify the font file size; we only support a fixed 256-char 8-bit font */
556         if (FoundFile->FileSize != 256 * 8)
557         {
558             DPRINT1("File of size %lu is not of the expected size %lu\n",
559                     FoundFile->FileSize, 256 * 8);
560             Status = STATUS_INVALID_BUFFER_SIZE;
561             _SEH2_YIELD(goto Exit);
562         }
563 
564         FontBitField = RtlAllocateHeap(RtlGetProcessHeap(), 0, FoundFile->FileSize);
565         if (!FontBitField)
566         {
567             DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", FoundFile->FileSize);
568             Status = STATUS_NO_MEMORY;
569             _SEH2_YIELD(goto Exit);
570         }
571 
572         /* 8 = Size of a CFFOLDER structure (see cabman). As we don't need
573          * the values of that structure, just increase the offset here. */
574         Data.Buffer = (PVOID)((ULONG_PTR)Data.Buffer + 8); // sizeof(CFFOLDER);
575         Data.Buffer = (PVOID)((ULONG_PTR)Data.Buffer + FoundFile->FileOffset);
576 
577         /* Data.Buffer now points to the actual data of the RAW font */
578         RtlCopyMemory(FontBitField, Data.Buffer, FoundFile->FileSize);
579         Status = STATUS_SUCCESS;
580     }
581     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
582     {
583         Status = _SEH2_GetExceptionCode();
584         DPRINT1("TuiSetConsoleOutputCP - Caught an exception, Status = 0x%08lx\n", Status);
585     }
586     _SEH2_END;
587 
588     /*
589      * Load the font.
590      */
591     if (NT_SUCCESS(Status))
592     {
593         ASSERT(FoundFile);
594         ASSERT(FontBitField);
595         Status = NtDeviceIoControlFile(hNtConddHandle,
596                                        NULL,
597                                        NULL,
598                                        NULL,
599                                        &IoStatusBlock,
600                                        IOCTL_CONSOLE_LOADFONT,
601                                        FontBitField,
602                                        FoundFile->FileSize,
603                                        NULL,
604                                        0);
605     }
606 
607     if (FontBitField)
608         RtlFreeHeap(RtlGetProcessHeap(), 0, FontBitField);
609 
610 Exit:
611     if (FileBuffer)
612         NtUnmapViewOfSection(NtCurrentProcess(), FileBuffer);
613 
614     if (FileSectionHandle)
615         NtClose(FileSectionHandle);
616 
617     NtClose(FileHandle);
618 
619     if (NT_SUCCESS(Status))
620         LastLoadedCodepage = CodePage;
621 
622     return NT_SUCCESS(Status);
623 }
624 
625 static BOOL
TuiInit(IN UINT OemCP)626 TuiInit(IN UINT OemCP)
627 {
628     BOOL Success;
629     CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
630     DWORD BytesReturned;
631     WNDCLASSEXW wc;
632     ATOM ConsoleClassAtom;
633     USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
634 
635     /* Exit if we were already initialized */
636     if (ConsInitialized) return TRUE;
637 
638     /*
639      * Initialize the TUI front-end:
640      * - load the console driver,
641      * - open BlueScreen device and enable it,
642      * - set default screen attributes,
643      * - grab the console size.
644      */
645     ScmLoadDriver(L"Blue");
646 
647     ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen",
648                                       FILE_ALL_ACCESS,
649                                       0, NULL,
650                                       OPEN_EXISTING,
651                                       0, NULL);
652     if (ConsoleDeviceHandle == INVALID_HANDLE_VALUE)
653     {
654         DPRINT1("Failed to open BlueScreen.\n");
655         return FALSE;
656     }
657 
658     Success = TRUE;
659     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_RESET_SCREEN,
660                          &Success, sizeof(Success), NULL, 0,
661                          &BytesReturned, NULL))
662     {
663         DPRINT1("Failed to enable the screen.\n");
664         CloseHandle(ConsoleDeviceHandle);
665         return FALSE;
666     }
667 
668     if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle, OemCP))
669     {
670         DPRINT1("Failed to load the font for codepage %d\n", OemCP);
671         /* Let's suppose the font is good enough to continue */
672     }
673 
674     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
675                          &TextAttribute, sizeof(TextAttribute), NULL, 0,
676                          &BytesReturned, NULL))
677     {
678         DPRINT1("Failed to set text attribute.\n");
679     }
680 
681     ActiveConsole = NULL;
682     InitializeListHead(&VirtConsList);
683     InitializeCriticalSection(&ActiveVirtConsLock);
684 
685     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
686                          NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
687     {
688         DPRINT1("Failed to get console info.\n");
689         Success = FALSE;
690         goto Quit;
691     }
692     PhysicalConsoleSize = ScrInfo.dwSize;
693 
694     /* Register the TUI notification window class */
695     RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
696     wc.cbSize = sizeof(WNDCLASSEXW);
697     wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS;
698     wc.lpfnWndProc = TuiConsoleWndProc;
699     wc.cbWndExtra = 0;
700     wc.hInstance = ConSrvDllInstance;
701 
702     ConsoleClassAtom = RegisterClassExW(&wc);
703     if (ConsoleClassAtom == 0)
704     {
705         DPRINT1("Failed to register TUI console wndproc.\n");
706         Success = FALSE;
707     }
708     else
709     {
710         Success = TRUE;
711     }
712 
713 Quit:
714     if (!Success)
715     {
716         DeleteCriticalSection(&ActiveVirtConsLock);
717         CloseHandle(ConsoleDeviceHandle);
718     }
719 
720     ConsInitialized = Success;
721     return Success;
722 }
723 
724 
725 
726 /******************************************************************************
727  *                             TUI Console Driver                             *
728  ******************************************************************************/
729 
730 static VOID NTAPI
731 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*,
732                   IN PCONSRV_CONSOLE Console */);
733 
734 static NTSTATUS NTAPI
TuiInitFrontEnd(IN OUT PFRONTEND This,IN PCONSRV_CONSOLE Console)735 TuiInitFrontEnd(IN OUT PFRONTEND This,
736                 IN PCONSRV_CONSOLE Console)
737 {
738     PTUI_CONSOLE_DATA TuiData;
739     HANDLE ThreadHandle;
740 
741     if (This == NULL || Console == NULL)
742         return STATUS_INVALID_PARAMETER;
743 
744     if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER)
745         return STATUS_INVALID_PARAMETER;
746 
747     TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA));
748     if (!TuiData)
749     {
750         DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n");
751         return STATUS_UNSUCCESSFUL;
752     }
753     // Console->FrontEndIFace.Context = (PVOID)TuiData;
754     TuiData->Console      = Console;
755     TuiData->ActiveBuffer = Console->ActiveBuffer;
756     TuiData->hWindow = NULL;
757 
758     InitializeCriticalSection(&TuiData->Lock);
759 
760     /*
761      * HACK: Resize the console since we don't support for now changing
762      * the console size when we display it with the hardware.
763      */
764     // Console->ConsoleSize = PhysicalConsoleSize;
765     // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize);
766 
767     // /* The console cannot be resized anymore */
768     // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !!
769     // // TermResizeTerminal(Console);
770 
771     /*
772      * Contrary to what we do in the GUI front-end, here we create
773      * an input thread for each console. It will dispatch all the
774      * input messages to the proper console (on the GUI it is done
775      * via the default GUI dispatch thread).
776      */
777     ThreadHandle = CreateThread(NULL,
778                                 0,
779                                 TuiConsoleThread,
780                                 (PVOID)TuiData,
781                                 0,
782                                 NULL);
783     if (NULL == ThreadHandle)
784     {
785         DPRINT1("CONSRV: Unable to create console thread\n");
786         // TuiDeinitFrontEnd(Console);
787         TuiDeinitFrontEnd(This);
788         return STATUS_UNSUCCESSFUL;
789     }
790     CloseHandle(ThreadHandle);
791 
792     /*
793      * Insert the newly created console in the list of virtual consoles
794      * and activate it (give it the focus).
795      */
796     EnterCriticalSection(&ActiveVirtConsLock);
797     InsertTailList(&VirtConsList, &TuiData->Entry);
798     ActiveConsole = TuiData;
799     LeaveCriticalSection(&ActiveVirtConsLock);
800 
801     /* Finally, initialize the frontend structure */
802     This->Context  = TuiData;
803     This->Context2 = NULL;
804 
805     return STATUS_SUCCESS;
806 }
807 
808 static VOID NTAPI
TuiDeinitFrontEnd(IN OUT PFRONTEND This)809 TuiDeinitFrontEnd(IN OUT PFRONTEND This)
810 {
811     // PCONSRV_CONSOLE Console = This->Console;
812     PTUI_CONSOLE_DATA TuiData = This->Context;
813 
814     /* Close the notification window */
815     DestroyWindow(TuiData->hWindow);
816 
817     /*
818      * Set the active console to the next one
819      * and remove the console from the list.
820      */
821     EnterCriticalSection(&ActiveVirtConsLock);
822     ActiveConsole = GetNextConsole(TuiData);
823     RemoveEntryList(&TuiData->Entry);
824 
825     // /* Switch to next console */
826     // if (ActiveConsole == TuiData)
827     // if (ActiveConsole->Console == Console)
828     // {
829         // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL);
830     // }
831 
832     // if (GetNextConsole(TuiData) != TuiData)
833     // {
834         // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink;
835         // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink;
836     // }
837 
838     LeaveCriticalSection(&ActiveVirtConsLock);
839 
840     /* Switch to the next console */
841     if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console);
842 
843     This->Context = NULL;
844     DeleteCriticalSection(&TuiData->Lock);
845     ConsoleFreeHeap(TuiData);
846 }
847 
848 static VOID NTAPI
TuiDrawRegion(IN OUT PFRONTEND This,SMALL_RECT * Region)849 TuiDrawRegion(IN OUT PFRONTEND This,
850               SMALL_RECT* Region)
851 {
852     PTUI_CONSOLE_DATA TuiData = This->Context;
853     PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer;
854     PCONSOLE_DRAW ConsoleDraw;
855     DWORD BytesReturned;
856     UINT ConsoleDrawSize;
857 
858     if (TuiData != ActiveConsole) return;
859     if (GetType(Buff) != TEXTMODE_BUFFER) return;
860 
861     ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
862                       (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
863     ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize);
864     if (NULL == ConsoleDraw)
865     {
866         DPRINT1("ConsoleAllocHeap failed\n");
867         return;
868     }
869     ConsoleDraw->X = Region->Left;
870     ConsoleDraw->Y = Region->Top;
871     ConsoleDraw->SizeX = ConioRectWidth(Region);
872     ConsoleDraw->SizeY = ConioRectHeight(Region);
873     ConsoleDraw->CursorX = Buff->CursorPosition.X;
874     ConsoleDraw->CursorY = Buff->CursorPosition.Y;
875 
876     TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region);
877 
878     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
879                          NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
880     {
881         DPRINT1("Failed to draw console\n");
882         ConsoleFreeHeap(ConsoleDraw);
883         return;
884     }
885 
886     ConsoleFreeHeap(ConsoleDraw);
887 }
888 
889 static VOID NTAPI
TuiWriteStream(IN OUT PFRONTEND This,SMALL_RECT * Region,SHORT CursorStartX,SHORT CursorStartY,UINT ScrolledLines,PWCHAR Buffer,UINT Length)890 TuiWriteStream(IN OUT PFRONTEND This,
891                SMALL_RECT* Region,
892                SHORT CursorStartX,
893                SHORT CursorStartY,
894                UINT ScrolledLines,
895                PWCHAR Buffer,
896                UINT Length)
897 {
898     PTUI_CONSOLE_DATA TuiData = This->Context;
899     PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer;
900     PCHAR NewBuffer;
901     ULONG NewLength;
902     DWORD BytesWritten;
903 
904     if (TuiData != ActiveConsole) return;
905     if (GetType(Buff) != TEXTMODE_BUFFER) return;
906 
907     NewLength = WideCharToMultiByte(TuiData->Console->OutputCodePage, 0,
908                                     Buffer, Length,
909                                     NULL, 0, NULL, NULL);
910     NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR));
911     if (!NewBuffer) return;
912 
913     WideCharToMultiByte(TuiData->Console->OutputCodePage, 0,
914                         Buffer, Length,
915                         NewBuffer, NewLength, NULL, NULL);
916 
917     if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL))
918     {
919         DPRINT1("Error writing to BlueScreen\n");
920     }
921 
922     RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
923 }
924 
925 static VOID NTAPI
TuiRingBell(IN OUT PFRONTEND This)926 TuiRingBell(IN OUT PFRONTEND This)
927 {
928     Beep(800, 200);
929 }
930 
931 static BOOL NTAPI
TuiSetCursorInfo(IN OUT PFRONTEND This,PCONSOLE_SCREEN_BUFFER Buff)932 TuiSetCursorInfo(IN OUT PFRONTEND This,
933                  PCONSOLE_SCREEN_BUFFER Buff)
934 {
935     PTUI_CONSOLE_DATA TuiData = This->Context;
936     CONSOLE_CURSOR_INFO Info;
937     DWORD BytesReturned;
938 
939     if (TuiData != ActiveConsole) return TRUE;
940     if (TuiData->Console->ActiveBuffer != Buff) return TRUE;
941     if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE;
942 
943     Info.dwSize = ConioEffectiveCursorSize(TuiData->Console, 100);
944     Info.bVisible = Buff->CursorInfo.bVisible;
945 
946     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
947                          &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
948     {
949         DPRINT1( "Failed to set cursor info\n" );
950         return FALSE;
951     }
952 
953     return TRUE;
954 }
955 
956 static BOOL NTAPI
TuiSetScreenInfo(IN OUT PFRONTEND This,PCONSOLE_SCREEN_BUFFER Buff,SHORT OldCursorX,SHORT OldCursorY)957 TuiSetScreenInfo(IN OUT PFRONTEND This,
958                  PCONSOLE_SCREEN_BUFFER Buff,
959                  SHORT OldCursorX,
960                  SHORT OldCursorY)
961 {
962     PTUI_CONSOLE_DATA TuiData = This->Context;
963     CONSOLE_SCREEN_BUFFER_INFO Info;
964     DWORD BytesReturned;
965 
966     if (TuiData != ActiveConsole) return TRUE;
967     if (TuiData->Console->ActiveBuffer != Buff) return TRUE;
968     if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE;
969 
970     Info.dwCursorPosition = Buff->CursorPosition;
971     Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib;
972 
973     if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
974                          &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
975                          &BytesReturned, NULL))
976     {
977         DPRINT1( "Failed to set cursor position\n" );
978         return FALSE;
979     }
980 
981     return TRUE;
982 }
983 
984 static VOID NTAPI
TuiResizeTerminal(IN OUT PFRONTEND This)985 TuiResizeTerminal(IN OUT PFRONTEND This)
986 {
987 }
988 
989 static VOID NTAPI
TuiSetActiveScreenBuffer(IN OUT PFRONTEND This)990 TuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
991 {
992     // PGUI_CONSOLE_DATA GuiData = This->Context;
993     // PCONSOLE_SCREEN_BUFFER ActiveBuffer;
994     // HPALETTE hPalette;
995 
996     // EnterCriticalSection(&GuiData->Lock);
997     // GuiData->WindowSizeLock = TRUE;
998 
999     // InterlockedExchangePointer(&GuiData->ActiveBuffer,
1000                                // ConDrvGetActiveScreenBuffer(GuiData->Console));
1001 
1002     // GuiData->WindowSizeLock = FALSE;
1003     // LeaveCriticalSection(&GuiData->Lock);
1004 
1005     // ActiveBuffer = GuiData->ActiveBuffer;
1006 
1007     // /* Change the current palette */
1008     // if (ActiveBuffer->PaletteHandle == NULL)
1009     // {
1010         // hPalette = GuiData->hSysPalette;
1011     // }
1012     // else
1013     // {
1014         // hPalette = ActiveBuffer->PaletteHandle;
1015     // }
1016 
1017     // DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
1018 
1019     // /* Set the new palette for the framebuffer */
1020     // SelectPalette(GuiData->hMemDC, hPalette, FALSE);
1021 
1022     // /* Specify the use of the system palette for the framebuffer */
1023     // SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
1024 
1025     // /* Realize the (logical) palette */
1026     // RealizePalette(GuiData->hMemDC);
1027 
1028     // GuiResizeTerminal(This);
1029     // // ConioDrawConsole(Console);
1030 }
1031 
1032 static VOID NTAPI
TuiReleaseScreenBuffer(IN OUT PFRONTEND This,IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)1033 TuiReleaseScreenBuffer(IN OUT PFRONTEND This,
1034                        IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
1035 {
1036     // PGUI_CONSOLE_DATA GuiData = This->Context;
1037 
1038     // /*
1039      // * If we were notified to release a screen buffer that is not actually
1040      // * ours, then just ignore the notification...
1041      // */
1042     // if (ScreenBuffer != GuiData->ActiveBuffer) return;
1043 
1044     // /*
1045      // * ... else, we must release our active buffer. Two cases are present:
1046      // * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
1047      // *   active screen buffer, then we can safely switch to it.
1048      // * - If ScreenBuffer IS the console active screen buffer, we must release
1049      // *   it ONLY.
1050      // */
1051 
1052     // /* Release the old active palette and set the default one */
1053     // if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
1054     // {
1055         // /* Set the new palette */
1056         // SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
1057     // }
1058 
1059     // /* Set the adequate active screen buffer */
1060     // if (ScreenBuffer != GuiData->Console->ActiveBuffer)
1061     // {
1062         // GuiSetActiveScreenBuffer(This);
1063     // }
1064     // else
1065     // {
1066         // EnterCriticalSection(&GuiData->Lock);
1067         // GuiData->WindowSizeLock = TRUE;
1068 
1069         // InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
1070 
1071         // GuiData->WindowSizeLock = FALSE;
1072         // LeaveCriticalSection(&GuiData->Lock);
1073     // }
1074 }
1075 
1076 static VOID NTAPI
TuiRefreshInternalInfo(IN OUT PFRONTEND This)1077 TuiRefreshInternalInfo(IN OUT PFRONTEND This)
1078 {
1079 }
1080 
1081 static VOID NTAPI
TuiChangeTitle(IN OUT PFRONTEND This)1082 TuiChangeTitle(IN OUT PFRONTEND This)
1083 {
1084 }
1085 
1086 static BOOL NTAPI
TuiChangeIcon(IN OUT PFRONTEND This,HICON IconHandle)1087 TuiChangeIcon(IN OUT PFRONTEND This,
1088               HICON IconHandle)
1089 {
1090     return TRUE;
1091 }
1092 
1093 static HDESK NTAPI
TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This)1094 TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This)
1095 {
1096     // PTUI_CONSOLE_DATA TuiData = This->Context;
1097     return NULL;
1098 }
1099 
1100 static HWND NTAPI
TuiGetConsoleWindowHandle(IN OUT PFRONTEND This)1101 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
1102 {
1103     PTUI_CONSOLE_DATA TuiData = This->Context;
1104     return TuiData->hWindow;
1105 }
1106 
1107 static VOID NTAPI
TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,PCOORD pSize)1108 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
1109                                PCOORD pSize)
1110 {
1111     if (!pSize) return;
1112     *pSize = PhysicalConsoleSize;
1113 }
1114 
1115 static BOOL NTAPI
TuiGetSelectionInfo(IN OUT PFRONTEND This,PCONSOLE_SELECTION_INFO pSelectionInfo)1116 TuiGetSelectionInfo(IN OUT PFRONTEND This,
1117                     PCONSOLE_SELECTION_INFO pSelectionInfo)
1118 {
1119     return TRUE;
1120 }
1121 
1122 static BOOL NTAPI
TuiSetPalette(IN OUT PFRONTEND This,HPALETTE PaletteHandle,UINT PaletteUsage)1123 TuiSetPalette(IN OUT PFRONTEND This,
1124               HPALETTE PaletteHandle,
1125               UINT PaletteUsage)
1126 {
1127     return TRUE;
1128 }
1129 
1130 static BOOL NTAPI
TuiSetCodePage(IN OUT PFRONTEND This,UINT CodePage)1131 TuiSetCodePage(IN OUT PFRONTEND This,
1132                UINT CodePage)
1133 {
1134     // PTUI_CONSOLE_DATA TuiData = This->Context;
1135 
1136     // TODO: Verify that the console is the visible one.
1137     // Only then can we change the output code page font.
1138 
1139     if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle, CodePage))
1140     {
1141         DPRINT1("Failed to load the font for codepage %d\n", CodePage);
1142         /* Let's suppose the font is good enough to continue */
1143         return FALSE;
1144     }
1145 
1146     return TRUE;
1147 }
1148 
1149 static ULONG NTAPI
TuiGetDisplayMode(IN OUT PFRONTEND This)1150 TuiGetDisplayMode(IN OUT PFRONTEND This)
1151 {
1152     return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN;
1153 }
1154 
1155 static BOOL NTAPI
TuiSetDisplayMode(IN OUT PFRONTEND This,ULONG NewMode)1156 TuiSetDisplayMode(IN OUT PFRONTEND This,
1157                   ULONG NewMode)
1158 {
1159     // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1160     //     return FALSE;
1161     return TRUE;
1162 }
1163 
1164 static INT NTAPI
TuiShowMouseCursor(IN OUT PFRONTEND This,BOOL Show)1165 TuiShowMouseCursor(IN OUT PFRONTEND This,
1166                    BOOL Show)
1167 {
1168     return 0;
1169 }
1170 
1171 static BOOL NTAPI
TuiSetMouseCursor(IN OUT PFRONTEND This,HCURSOR CursorHandle)1172 TuiSetMouseCursor(IN OUT PFRONTEND This,
1173                   HCURSOR CursorHandle)
1174 {
1175     return TRUE;
1176 }
1177 
1178 static HMENU NTAPI
TuiMenuControl(IN OUT PFRONTEND This,UINT CmdIdLow,UINT CmdIdHigh)1179 TuiMenuControl(IN OUT PFRONTEND This,
1180                UINT CmdIdLow,
1181                UINT CmdIdHigh)
1182 {
1183     return NULL;
1184 }
1185 
1186 static BOOL NTAPI
TuiSetMenuClose(IN OUT PFRONTEND This,BOOL Enable)1187 TuiSetMenuClose(IN OUT PFRONTEND This,
1188                 BOOL Enable)
1189 {
1190     return TRUE;
1191 }
1192 
1193 static FRONTEND_VTBL TuiVtbl =
1194 {
1195     TuiInitFrontEnd,
1196     TuiDeinitFrontEnd,
1197     TuiDrawRegion,
1198     TuiWriteStream,
1199     TuiRingBell,
1200     TuiSetCursorInfo,
1201     TuiSetScreenInfo,
1202     TuiResizeTerminal,
1203     TuiSetActiveScreenBuffer,
1204     TuiReleaseScreenBuffer,
1205     TuiRefreshInternalInfo,
1206     TuiChangeTitle,
1207     TuiChangeIcon,
1208     TuiGetThreadConsoleDesktop,
1209     TuiGetConsoleWindowHandle,
1210     TuiGetLargestConsoleWindowSize,
1211     TuiGetSelectionInfo,
1212     TuiSetPalette,
1213     TuiSetCodePage,
1214     TuiGetDisplayMode,
1215     TuiSetDisplayMode,
1216     TuiShowMouseCursor,
1217     TuiSetMouseCursor,
1218     TuiMenuControl,
1219     TuiSetMenuClose,
1220 };
1221 
1222 static BOOLEAN
IsConsoleMode(VOID)1223 IsConsoleMode(VOID)
1224 {
1225     return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE);
1226 }
1227 
1228 NTSTATUS NTAPI
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,IN OUT PCONSOLE_STATE_INFO ConsoleInfo,IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,IN HANDLE ConsoleLeaderProcessHandle)1229 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
1230                 IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
1231                 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
1232                 IN HANDLE ConsoleLeaderProcessHandle)
1233 {
1234     if (FrontEnd == NULL || ConsoleInfo == NULL)
1235         return STATUS_INVALID_PARAMETER;
1236 
1237     /* We must be in console mode already */
1238     if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL;
1239 
1240     /* Initialize the TUI terminal emulator */
1241     if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL;
1242 
1243     /* Finally, initialize the frontend structure */
1244     FrontEnd->Vtbl     = &TuiVtbl;
1245     FrontEnd->Context  = NULL;
1246     FrontEnd->Context2 = NULL;
1247 
1248     return STATUS_SUCCESS;
1249 }
1250 
1251 NTSTATUS NTAPI
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)1252 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
1253 {
1254     if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
1255     if (FrontEnd->Context) TuiDeinitFrontEnd(FrontEnd);
1256 
1257     return STATUS_SUCCESS;
1258 }
1259 
1260 #endif
1261 
1262 /* EOF */
1263