1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
5  * PURPOSE:         GUI Terminal Front-End
6  * PROGRAMMERS:     G� van Geldorp
7  *                  Johannes Anderwald
8  *                  Jeffrey Morlan
9  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include <consrv.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 #include "guiterm.h"
20 #include "resource.h"
21 
22 // HACK!! Remove it when the hack in GuiWriteStream is fixed
23 #define CONGUI_UPDATE_TIME    0
24 #define CONGUI_UPDATE_TIMER   1
25 
26 #define PM_CREATE_CONSOLE     (WM_APP + 1)
27 #define PM_DESTROY_CONSOLE    (WM_APP + 2)
28 
29 
30 /* GLOBALS ********************************************************************/
31 
32 typedef struct _GUI_INIT_INFO
33 {
34     HANDLE GuiThreadStartupEvent;
35     ULONG_PTR InputThreadId;
36     HWINSTA WinSta;
37     HDESK Desktop;
38     HICON hIcon;
39     HICON hIconSm;
40     BOOLEAN IsWindowVisible;
41     GUI_CONSOLE_INFO TermInfo;
42 } GUI_INIT_INFO, *PGUI_INIT_INFO;
43 
44 static BOOL ConsInitialized = FALSE;
45 
46 extern HICON   ghDefaultIcon;
47 extern HICON   ghDefaultIconSm;
48 extern HCURSOR ghDefaultCursor;
49 
50 VOID
51 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData);
52 BOOLEAN
53 RegisterConWndClass(IN HINSTANCE hInstance);
54 BOOLEAN
55 UnRegisterConWndClass(HINSTANCE hInstance);
56 
57 /* FUNCTIONS ******************************************************************/
58 
59 VOID
60 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
61 {
62     /* Move the window if needed (not positioned by the system) */
63     if (!GuiData->GuiInfo.AutoPosition)
64     {
65         SetWindowPos(GuiData->hWindow,
66                      NULL,
67                      GuiData->GuiInfo.WindowOrigin.x,
68                      GuiData->GuiInfo.WindowOrigin.y,
69                      0, 0,
70                      SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
71     }
72 }
73 
74 static VOID
75 DrawRegion(PGUI_CONSOLE_DATA GuiData,
76            SMALL_RECT* Region)
77 {
78     RECT RegionRect;
79 
80     SmallRectToRect(GuiData, &RegionRect, Region);
81     /* Do not erase the background: it speeds up redrawing and reduce flickering */
82     InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
83     /**UpdateWindow(GuiData->hWindow);**/
84 }
85 
86 VOID
87 InvalidateCell(PGUI_CONSOLE_DATA GuiData,
88                SHORT x, SHORT y)
89 {
90     SMALL_RECT CellRect = { x, y, x, y };
91     DrawRegion(GuiData, &CellRect);
92 }
93 
94 
95 /******************************************************************************
96  *                        GUI Terminal Initialization                         *
97  ******************************************************************************/
98 
99 VOID
100 CreateSysMenu(HWND hWnd);
101 
102 static ULONG NTAPI
103 GuiConsoleInputThread(PVOID Param)
104 {
105     NTSTATUS Status;
106     PCSR_THREAD pcsrt = NULL;
107     PGUI_INIT_INFO GuiInitInfo = (PGUI_INIT_INFO)Param;
108     DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
109     ULONG_PTR InputThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
110     HANDLE hThread = NULL;
111 
112     LONG WindowCount = 0;
113     MSG msg;
114 
115     /*
116      * This thread dispatches all the console notifications to the
117      * notification window. It is common for all the console windows
118      * in a given desktop in a window station.
119      */
120 
121     /* Assign this console input thread to this desktop */
122     DesktopConsoleThreadInfo.DesktopHandle = GuiInitInfo->Desktop; // Duplicated desktop handle
123     DesktopConsoleThreadInfo.ThreadId = InputThreadId;
124     Status = NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
125                                   &DesktopConsoleThreadInfo,
126                                   sizeof(DesktopConsoleThreadInfo));
127     if (!NT_SUCCESS(Status)) goto Quit;
128 
129     /* Connect this CSR thread to the USER subsystem */
130     pcsrt = CsrConnectToUser();
131     if (pcsrt == NULL) goto Quit;
132     hThread = pcsrt->ThreadHandle;
133 
134     /* Assign the desktop to this thread */
135     if (!SetThreadDesktop(DesktopConsoleThreadInfo.DesktopHandle)) goto Quit;
136 
137     /* The thread has been initialized, set the event */
138     NtSetEvent(GuiInitInfo->GuiThreadStartupEvent, NULL);
139     Status = STATUS_SUCCESS;
140 
141     while (GetMessageW(&msg, NULL, 0, 0))
142     {
143         switch (msg.message)
144         {
145             case PM_CREATE_CONSOLE:
146             {
147                 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
148                 PCONSRV_CONSOLE Console = GuiData->Console;
149                 HWND NewWindow;
150                 RECT rcWnd;
151 
152                 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
153 
154                 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
155                                             GUI_CONWND_CLASS,
156                                             Console->Title.Buffer,
157                                             WS_OVERLAPPEDWINDOW,
158                                             CW_USEDEFAULT,
159                                             CW_USEDEFAULT,
160                                             CW_USEDEFAULT,
161                                             CW_USEDEFAULT,
162                                             GuiData->IsWindowVisible ? HWND_DESKTOP : HWND_MESSAGE,
163                                             NULL,
164                                             ConSrvDllInstance,
165                                             (PVOID)GuiData);
166                 if (NewWindow == NULL)
167                 {
168                     DPRINT1("Failed to create a new console window\n");
169                     continue;
170                 }
171 
172                 ASSERT(NewWindow == GuiData->hWindow);
173 
174                 InterlockedIncrement(&WindowCount);
175 
176                 //
177                 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
178                 //
179 
180                 /* Retrieve our real position */
181                 // See conwnd.c!OnMove()
182                 GetWindowRect(GuiData->hWindow, &rcWnd);
183                 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
184                 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
185 
186                 if (GuiData->IsWindowVisible)
187                 {
188                     /* Move and resize the window to the user's values */
189                     /* CAN WE DEADLOCK ?? */
190                     GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
191                     SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
192                 }
193 
194                 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
195                 CreateSysMenu(GuiData->hWindow);
196 
197                 if (GuiData->IsWindowVisible)
198                 {
199                     /* Switch to full-screen mode if necessary */
200                     // FIXME: Move elsewhere, it cause misdrawings of the window.
201                     if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
202 
203                     DPRINT("PM_CREATE_CONSOLE -- showing window\n");
204                     ShowWindowAsync(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
205                 }
206                 else
207                 {
208                     DPRINT("PM_CREATE_CONSOLE -- hidden window\n");
209                     ShowWindowAsync(NewWindow, SW_HIDE);
210                 }
211 
212                 continue;
213             }
214 
215             case PM_DESTROY_CONSOLE:
216             {
217                 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
218                 MSG TempMsg;
219 
220                 /* Exit the full screen mode if it was already set */
221                 // LeaveFullScreen(GuiData);
222 
223                 /*
224                  * Window creation is done using a PostMessage(), so it's possible
225                  * that the window that we want to destroy doesn't exist yet.
226                  * So first empty the message queue.
227                  */
228                 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
229                 {
230                     DispatchMessageW(&TempMsg);
231                 }
232 
233                 if (GuiData->hWindow == NULL) continue;
234 
235                 DestroyWindow(GuiData->hWindow);
236 
237                 NtSetEvent(GuiData->hGuiTermEvent, NULL);
238 
239                 if (InterlockedDecrement(&WindowCount) == 0)
240                 {
241                     DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
242                     goto Quit;
243                 }
244 
245                 continue;
246             }
247         }
248 
249         TranslateMessage(&msg);
250         DispatchMessageW(&msg);
251     }
252 
253 Quit:
254     DPRINT("CONSRV: Quit the Input Thread 0x%p, Status = 0x%08lx\n", InputThreadId, Status);
255 
256     /* Remove this console input thread from this desktop */
257     // DesktopConsoleThreadInfo.DesktopHandle;
258     DesktopConsoleThreadInfo.ThreadId = 0;
259     NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
260                          &DesktopConsoleThreadInfo,
261                          sizeof(DesktopConsoleThreadInfo));
262 
263     /* Close the duplicated desktop handle */
264     CloseDesktop(DesktopConsoleThreadInfo.DesktopHandle); // NtUserCloseDesktop
265 
266     /* Cleanup CSR thread */
267     if (pcsrt)
268     {
269         if (hThread != pcsrt->ThreadHandle)
270             DPRINT1("WARNING!! hThread (0x%p) != pcsrt->ThreadHandle (0x%p), you may expect crashes soon!!\n", hThread, pcsrt->ThreadHandle);
271 
272         CsrDereferenceThread(pcsrt);
273     }
274 
275     /* Exit the thread */
276     RtlExitUserThread(Status);
277     return 0;
278 }
279 
280 // FIXME: Maybe return a NTSTATUS
281 static BOOL
282 GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
283         IN HANDLE ConsoleLeaderProcessHandle,
284         IN OUT PGUI_INIT_INFO GuiInitInfo)
285 {
286     BOOL Success = TRUE;
287     UNICODE_STRING DesktopPath;
288     DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
289     HWINSTA hWinSta;
290     HDESK hDesk;
291 
292     NTSTATUS Status;
293     HANDLE hInputThread;
294     CLIENT_ID ClientId;
295 
296     /*
297      * Initialize and register the console window class, if needed.
298      */
299     if (!ConsInitialized)
300     {
301         if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE;
302         ConsInitialized = TRUE;
303     }
304 
305     /*
306      * Set-up the console input thread. We have
307      * one console input thread per desktop.
308      */
309 
310     if (!CsrImpersonateClient(NULL))
311         // return STATUS_BAD_IMPERSONATION_LEVEL;
312         return FALSE;
313 
314     if (ConsoleInitInfo->DesktopLength)
315     {
316         DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
317         DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
318         DesktopPath.Buffer = ConsoleInitInfo->Desktop;
319     }
320     else
321     {
322         RtlInitUnicodeString(&DesktopPath, L"Default");
323     }
324 
325     hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle,
326                                  &DesktopPath,
327                                  FALSE,
328                                  &hWinSta);
329     DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
330            &DesktopPath, hDesk, hWinSta);
331 
332     CsrRevertToSelf();
333 
334     if (hDesk == NULL) return FALSE;
335 
336     /*
337      * We need to see whether we need to create a
338      * new console input thread for this desktop.
339      */
340     DesktopConsoleThreadInfo.DesktopHandle = hDesk;
341     DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID.
342     NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
343                          &DesktopConsoleThreadInfo,
344                          sizeof(DesktopConsoleThreadInfo));
345     DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
346 
347     /*
348      * Save the opened window station and desktop handles in the initialization
349      * structure. They will be used later on, and released, by the GUI frontend.
350      */
351     GuiInitInfo->WinSta  = hWinSta;
352     GuiInitInfo->Desktop = hDesk;
353 
354     /* Here GuiInitInfo contains original handles */
355 
356     /* If we already have a console input thread on this desktop... */
357     if (DesktopConsoleThreadInfo.ThreadId != 0)
358     {
359         /* ... just use it... */
360         DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
361         GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
362         goto Quit;
363     }
364 
365     /* ... otherwise create a new one. */
366 
367     /* Initialize a startup event for the thread to signal it */
368     Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS,
369                            NULL, SynchronizationEvent, FALSE);
370     if (!NT_SUCCESS(Status))
371     {
372         Success = FALSE;
373         goto Quit;
374     }
375 
376     /*
377      * Duplicate the desktop handle for the console input thread internal needs.
378      * If it happens to need also a window station handle in the future, then
379      * it is there that you also need to duplicate the window station handle!
380      *
381      * Note also that we are going to temporarily overwrite the stored handles
382      * in GuiInitInfo because it happens that we use also this structure to give
383      * the duplicated handles to the input thread that is going to initialize.
384      * After the input thread finishes its initialization, we restore the handles
385      * in GuiInitInfo to their old values.
386      */
387     Status = NtDuplicateObject(NtCurrentProcess(),
388                                hDesk,
389                                NtCurrentProcess(),
390                                (PHANDLE)&GuiInitInfo->Desktop,
391                                0, 0, DUPLICATE_SAME_ACCESS);
392     if (!NT_SUCCESS(Status))
393     {
394         Success = FALSE;
395         goto Quit;
396     }
397 
398     /* Here GuiInitInfo contains duplicated handles */
399 
400     Status = RtlCreateUserThread(NtCurrentProcess(),
401                                  NULL,
402                                  TRUE, // Start the thread in suspended state
403                                  0,
404                                  0,
405                                  0,
406                                  (PVOID)GuiConsoleInputThread,
407                                  (PVOID)GuiInitInfo,
408                                  &hInputThread,
409                                  &ClientId);
410     if (NT_SUCCESS(Status))
411     {
412         /* Add it as a static server thread and resume it */
413         CsrAddStaticServerThread(hInputThread, &ClientId, 0);
414         Status = NtResumeThread(hInputThread, NULL);
415     }
416     DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n",
417            hInputThread, ClientId.UniqueThread, Status);
418 
419     if (!NT_SUCCESS(Status) || hInputThread == NULL)
420     {
421         /* Close the thread's handle */
422         if (hInputThread) NtClose(hInputThread);
423 
424         /* We need to close here the duplicated desktop handle */
425         CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop
426 
427         /* Close the startup event and bail out */
428         NtClose(GuiInitInfo->GuiThreadStartupEvent);
429 
430         DPRINT1("CONSRV: Failed to create graphics console thread.\n");
431         Success = FALSE;
432         goto Quit;
433     }
434 
435     /* No need to close hInputThread, this is done by CSR automatically */
436 
437     /* Wait for the thread to finish its initialization, and close the startup event */
438     NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL);
439     NtClose(GuiInitInfo->GuiThreadStartupEvent);
440 
441     /*
442      * Save the input thread ID for later use, and restore the original handles.
443      * The copies are held by the console input thread.
444      */
445     GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread;
446     GuiInitInfo->WinSta  = hWinSta;
447     GuiInitInfo->Desktop = hDesk;
448 
449     /* Here GuiInitInfo contains again original handles */
450 
451 Quit:
452     if (!Success)
453     {
454         /*
455          * Close the original handles. Do not use the copies in GuiInitInfo
456          * because we may have failed in the middle of the duplicate operation
457          * and the handles stored in GuiInitInfo may have changed.
458          */
459         CloseDesktop(hDesk); // NtUserCloseDesktop
460         CloseWindowStation(hWinSta); // NtUserCloseWindowStation
461     }
462 
463     return Success;
464 }
465 
466 
467 /******************************************************************************
468  *                             GUI Console Driver                             *
469  ******************************************************************************/
470 
471 static VOID NTAPI
472 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
473 
474 static NTSTATUS NTAPI
475 GuiInitFrontEnd(IN OUT PFRONTEND This,
476                 IN PCONSRV_CONSOLE Console)
477 {
478     PGUI_INIT_INFO GuiInitInfo;
479     PGUI_CONSOLE_DATA GuiData;
480 
481     if (This == NULL || Console == NULL || This->Context2 == NULL)
482         return STATUS_INVALID_PARAMETER;
483 
484     ASSERT(This->Console == Console);
485 
486     GuiInitInfo = This->Context2;
487 
488     /* Terminal data allocation */
489     GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData));
490     if (!GuiData)
491     {
492         DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
493         return STATUS_UNSUCCESSFUL;
494     }
495     /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
496     GuiData->Console      = Console;
497     GuiData->ActiveBuffer = Console->ActiveBuffer;
498     GuiData->hWindow = NULL;
499     GuiData->IsWindowVisible = GuiInitInfo->IsWindowVisible;
500 
501     /* The console can be resized */
502     Console->FixedSize = FALSE;
503 
504     InitializeCriticalSection(&GuiData->Lock);
505 
506     /*
507      * Set up GUI data
508      */
509     RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo));
510 
511     /* Initialize the icon handles */
512     if (GuiInitInfo->hIcon != NULL)
513         GuiData->hIcon = GuiInitInfo->hIcon;
514     else
515         GuiData->hIcon = ghDefaultIcon;
516 
517     if (GuiInitInfo->hIconSm != NULL)
518         GuiData->hIconSm = GuiInitInfo->hIconSm;
519     else
520         GuiData->hIconSm = ghDefaultIconSm;
521 
522     ASSERT(GuiData->hIcon && GuiData->hIconSm);
523 
524     /* Mouse is shown by default with its default cursor shape */
525     GuiData->hCursor = ghDefaultCursor;
526     GuiData->MouseCursorRefCount = 0;
527 
528     /* A priori don't ignore mouse signals */
529     GuiData->IgnoreNextMouseSignal = FALSE;
530     /* Initialize HACK FOR CORE-8394. See conwnd.c!OnMouse for more details. */
531     GuiData->HackCORE8394IgnoreNextMove = FALSE;
532 
533     /* Close button and the corresponding system menu item are enabled by default */
534     GuiData->IsCloseButtonEnabled = TRUE;
535 
536     /* There is no user-reserved menu id range by default */
537     GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
538 
539     /* Initialize the selection */
540     RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
541     GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
542     RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
543     GuiData->LineSelection = FALSE; // Default to block selection
544     // TODO: Retrieve the selection mode via the registry.
545 
546     GuiData->InputThreadId = GuiInitInfo->InputThreadId;
547     GuiData->WinSta  = GuiInitInfo->WinSta;
548     GuiData->Desktop = GuiInitInfo->Desktop;
549 
550     /* Finally, finish to initialize the frontend structure */
551     This->Context  = GuiData;
552     ConsoleFreeHeap(This->Context2);
553     This->Context2 = NULL;
554 
555     /*
556      * We need to wait until the GUI has been fully initialized
557      * to retrieve custom settings i.e. WindowSize etc...
558      * Ideally we could use SendNotifyMessage for this but its not
559      * yet implemented.
560      */
561     NtCreateEvent(&GuiData->hGuiInitEvent, EVENT_ALL_ACCESS,
562                   NULL, SynchronizationEvent, FALSE);
563     NtCreateEvent(&GuiData->hGuiTermEvent, EVENT_ALL_ACCESS,
564                   NULL, SynchronizationEvent, FALSE);
565 
566     DPRINT("GUI - Checkpoint\n");
567 
568     /* Create the terminal window */
569     PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
570 
571     /* Wait until initialization has finished */
572     NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL);
573     DPRINT("OK we created the console window\n");
574     NtClose(GuiData->hGuiInitEvent);
575     GuiData->hGuiInitEvent = NULL;
576 
577     /* Check whether we really succeeded in initializing the terminal window */
578     if (GuiData->hWindow == NULL)
579     {
580         DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
581         GuiDeinitFrontEnd(This);
582         return STATUS_UNSUCCESSFUL;
583     }
584 
585     return STATUS_SUCCESS;
586 }
587 
588 static VOID NTAPI
589 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
590 {
591     PGUI_CONSOLE_DATA GuiData = This->Context;
592 
593     DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
594     PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
595     NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
596     DPRINT("hGuiTermEvent set\n");
597     NtClose(GuiData->hGuiTermEvent);
598     GuiData->hGuiTermEvent = NULL;
599 
600     CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop
601     CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation
602 
603     DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
604             GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
605     if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
606     {
607         DPRINT("Destroy hIcon\n");
608         DestroyIcon(GuiData->hIcon);
609     }
610     if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
611     {
612         DPRINT("Destroy hIconSm\n");
613         DestroyIcon(GuiData->hIconSm);
614     }
615 
616     This->Context = NULL;
617     DeleteCriticalSection(&GuiData->Lock);
618     ConsoleFreeHeap(GuiData);
619 
620     DPRINT("Quit GuiDeinitFrontEnd\n");
621 }
622 
623 static VOID NTAPI
624 GuiDrawRegion(IN OUT PFRONTEND This,
625               SMALL_RECT* Region)
626 {
627     PGUI_CONSOLE_DATA GuiData = This->Context;
628 
629     /* Do nothing if the window is hidden */
630     if (!GuiData->IsWindowVisible) return;
631 
632     DrawRegion(GuiData, Region);
633 }
634 
635 static VOID NTAPI
636 GuiWriteStream(IN OUT PFRONTEND This,
637                SMALL_RECT* Region,
638                SHORT CursorStartX,
639                SHORT CursorStartY,
640                UINT ScrolledLines,
641                PWCHAR Buffer,
642                UINT Length)
643 {
644     PGUI_CONSOLE_DATA GuiData = This->Context;
645     PCONSOLE_SCREEN_BUFFER Buff;
646     SHORT CursorEndX, CursorEndY;
647     RECT ScrollRect;
648 
649     if (NULL == GuiData || NULL == GuiData->hWindow) return;
650 
651     /* Do nothing if the window is hidden */
652     if (!GuiData->IsWindowVisible) return;
653 
654     Buff = GuiData->ActiveBuffer;
655     if (GetType(Buff) != TEXTMODE_BUFFER) return;
656 
657     if (0 != ScrolledLines)
658     {
659         ScrollRect.left = 0;
660         ScrollRect.top = 0;
661         ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
662         ScrollRect.bottom = Region->Top * GuiData->CharHeight;
663 
664         ScrollWindowEx(GuiData->hWindow,
665                        0,
666                        -(int)(ScrolledLines * GuiData->CharHeight),
667                        &ScrollRect,
668                        NULL,
669                        NULL,
670                        NULL,
671                        SW_INVALIDATE);
672     }
673 
674     DrawRegion(GuiData, Region);
675 
676     if (CursorStartX < Region->Left || Region->Right < CursorStartX
677             || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
678     {
679         InvalidateCell(GuiData, CursorStartX, CursorStartY);
680     }
681 
682     CursorEndX = Buff->CursorPosition.X;
683     CursorEndY = Buff->CursorPosition.Y;
684     if ((CursorEndX < Region->Left || Region->Right < CursorEndX
685             || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
686             && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
687     {
688         InvalidateCell(GuiData, CursorEndX, CursorEndY);
689     }
690 
691     // HACK!!
692     // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
693     // repaint the window without having it just freeze up and stay on the screen permanently.
694     Buff->CursorBlinkOn = TRUE;
695     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
696 }
697 
698 /* static */ VOID NTAPI
699 GuiRingBell(IN OUT PFRONTEND This)
700 {
701     PGUI_CONSOLE_DATA GuiData = This->Context;
702 
703     /* Emit an error beep sound */
704     SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
705 }
706 
707 static BOOL NTAPI
708 GuiSetCursorInfo(IN OUT PFRONTEND This,
709                  PCONSOLE_SCREEN_BUFFER Buff)
710 {
711     PGUI_CONSOLE_DATA GuiData = This->Context;
712 
713     /* Do nothing if the window is hidden */
714     if (!GuiData->IsWindowVisible) return TRUE;
715 
716     if (GuiData->ActiveBuffer == Buff)
717     {
718         InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
719     }
720 
721     return TRUE;
722 }
723 
724 static BOOL NTAPI
725 GuiSetScreenInfo(IN OUT PFRONTEND This,
726                  PCONSOLE_SCREEN_BUFFER Buff,
727                  SHORT OldCursorX,
728                  SHORT OldCursorY)
729 {
730     PGUI_CONSOLE_DATA GuiData = This->Context;
731 
732     /* Do nothing if the window is hidden */
733     if (!GuiData->IsWindowVisible) return TRUE;
734 
735     if (GuiData->ActiveBuffer == Buff)
736     {
737         /* Redraw char at old position (remove cursor) */
738         InvalidateCell(GuiData, OldCursorX, OldCursorY);
739         /* Redraw char at new position (show cursor) */
740         InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
741     }
742 
743     return TRUE;
744 }
745 
746 static VOID NTAPI
747 GuiResizeTerminal(IN OUT PFRONTEND This)
748 {
749     PGUI_CONSOLE_DATA GuiData = This->Context;
750 
751     /* Resize the window to the user's values */
752     PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
753 }
754 
755 static VOID NTAPI
756 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
757 {
758     PGUI_CONSOLE_DATA GuiData = This->Context;
759     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
760     HPALETTE hPalette;
761 
762     EnterCriticalSection(&GuiData->Lock);
763     GuiData->WindowSizeLock = TRUE;
764 
765     InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer,
766                                ConDrvGetActiveScreenBuffer(GuiData->Console));
767 
768     GuiData->WindowSizeLock = FALSE;
769     LeaveCriticalSection(&GuiData->Lock);
770 
771     ActiveBuffer = GuiData->ActiveBuffer;
772 
773     /* Change the current palette */
774     if (ActiveBuffer->PaletteHandle == NULL)
775         hPalette = GuiData->hSysPalette;
776     else
777         hPalette = ActiveBuffer->PaletteHandle;
778 
779     DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
780 
781     /* Set the new palette for the framebuffer */
782     SelectPalette(GuiData->hMemDC, hPalette, FALSE);
783 
784     /* Specify the use of the system palette for the framebuffer */
785     SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
786 
787     /* Realize the (logical) palette */
788     RealizePalette(GuiData->hMemDC);
789 
790     GuiResizeTerminal(This);
791     // ConioDrawConsole(Console);
792 }
793 
794 static VOID NTAPI
795 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
796                        IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
797 {
798     PGUI_CONSOLE_DATA GuiData = This->Context;
799 
800     /*
801      * If we were notified to release a screen buffer that is not actually
802      * ours, then just ignore the notification...
803      */
804     if (ScreenBuffer != GuiData->ActiveBuffer) return;
805 
806     /*
807      * ... else, we must release our active buffer. Two cases are present:
808      * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
809      *   active screen buffer, then we can safely switch to it.
810      * - If ScreenBuffer IS the console active screen buffer, we must release
811      *   it ONLY.
812      */
813 
814     /* Release the old active palette and set the default one */
815     if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
816     {
817         /* Set the new palette */
818         SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
819     }
820 
821     /* Set the adequate active screen buffer */
822     if (ScreenBuffer != GuiData->Console->ActiveBuffer)
823     {
824         GuiSetActiveScreenBuffer(This);
825     }
826     else
827     {
828         EnterCriticalSection(&GuiData->Lock);
829         GuiData->WindowSizeLock = TRUE;
830 
831         InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer, NULL);
832 
833         GuiData->WindowSizeLock = FALSE;
834         LeaveCriticalSection(&GuiData->Lock);
835     }
836 }
837 
838 static BOOL NTAPI
839 GuiSetMouseCursor(IN OUT PFRONTEND This,
840                   HCURSOR CursorHandle);
841 
842 static VOID NTAPI
843 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
844 {
845     PGUI_CONSOLE_DATA GuiData = This->Context;
846 
847     /* Update the console leader information held by the window */
848     SetConWndConsoleLeaderCID(GuiData);
849 
850     /*
851      * HACK:
852      * We reset the cursor here so that, when a console app quits, we reset
853      * the cursor to the default one. It's quite a hack since it doesn't proceed
854      * per - console process... This must be fixed.
855      *
856      * See GuiInitConsole(...) for more information.
857      */
858 
859     /* Mouse is shown by default with its default cursor shape */
860     GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
861     GuiSetMouseCursor(This, NULL);
862 }
863 
864 static VOID NTAPI
865 GuiChangeTitle(IN OUT PFRONTEND This)
866 {
867     PGUI_CONSOLE_DATA GuiData = This->Context;
868     PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
869 }
870 
871 static BOOL NTAPI
872 GuiChangeIcon(IN OUT PFRONTEND This,
873               HICON IconHandle)
874 {
875     PGUI_CONSOLE_DATA GuiData = This->Context;
876     HICON hIcon, hIconSm;
877 
878     if (IconHandle == NULL)
879     {
880         hIcon   = ghDefaultIcon;
881         hIconSm = ghDefaultIconSm;
882     }
883     else
884     {
885         hIcon   = CopyIcon(IconHandle);
886         hIconSm = CopyIcon(IconHandle);
887     }
888 
889     if (hIcon == NULL)
890         return FALSE;
891 
892     if (hIcon != GuiData->hIcon)
893     {
894         if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
895         {
896             DestroyIcon(GuiData->hIcon);
897         }
898         if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
899         {
900             DestroyIcon(GuiData->hIconSm);
901         }
902 
903         GuiData->hIcon   = hIcon;
904         GuiData->hIconSm = hIconSm;
905 
906         DPRINT("Set icons in GuiChangeIcon\n");
907         PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG  , (LPARAM)GuiData->hIcon  );
908         PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
909     }
910 
911     return TRUE;
912 }
913 
914 static HWND NTAPI
915 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
916 {
917     PGUI_CONSOLE_DATA GuiData = This->Context;
918     return GuiData->hWindow;
919 }
920 
921 static VOID NTAPI
922 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
923                                PCOORD pSize)
924 {
925     PGUI_CONSOLE_DATA GuiData = This->Context;
926     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
927     HMONITOR hMonitor;
928     MONITORINFO MonitorInfo;
929     LONG Width, Height;
930     UINT WidthUnit, HeightUnit;
931 
932     if (!pSize) return;
933 
934     /*
935      * Retrieve the monitor that is mostly covered by the current console window;
936      * default to primary monitor otherwise.
937      */
938     MonitorInfo.cbSize = sizeof(MonitorInfo);
939     hMonitor = MonitorFromWindow(GuiData->hWindow, MONITOR_DEFAULTTOPRIMARY);
940     if (hMonitor && GetMonitorInfoW(hMonitor, &MonitorInfo))
941     {
942         /* Retrieve the width and height of the client area of this monitor */
943         Width  = MonitorInfo.rcWork.right - MonitorInfo.rcWork.left;
944         Height = MonitorInfo.rcWork.bottom - MonitorInfo.rcWork.top;
945     }
946     else
947     {
948         /*
949          * Retrieve the width and height of the client area for a full-screen
950          * window on the primary display monitor.
951          */
952         Width  = GetSystemMetrics(SM_CXFULLSCREEN);
953         Height = GetSystemMetrics(SM_CYFULLSCREEN);
954 
955         // RECT WorkArea;
956         // SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0);
957         // Width  = WorkArea.right;
958         // Height = WorkArea.bottom;
959     }
960 
961     ActiveBuffer = GuiData->ActiveBuffer;
962 #if 0
963     // NOTE: This would be surprising if we wouldn't have an associated buffer...
964     if (ActiveBuffer)
965 #endif
966         GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
967 #if 0
968     else
969         /* Default: graphics mode */
970         WidthUnit = HeightUnit = 1;
971 #endif
972 
973     Width  -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
974     Height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
975 
976     if (Width  < 0) Width  = 0;
977     if (Height < 0) Height = 0;
978 
979     pSize->X = (SHORT)(Width  / (int)WidthUnit ) /* HACK */ + 2;
980     pSize->Y = (SHORT)(Height / (int)HeightUnit) /* HACK */ + 1;
981 }
982 
983 static BOOL NTAPI
984 GuiGetSelectionInfo(IN OUT PFRONTEND This,
985                     PCONSOLE_SELECTION_INFO pSelectionInfo)
986 {
987     PGUI_CONSOLE_DATA GuiData = This->Context;
988 
989     if (pSelectionInfo == NULL) return FALSE;
990 
991     ZeroMemory(pSelectionInfo, sizeof(*pSelectionInfo));
992     if (GuiData->Selection.dwFlags != CONSOLE_NO_SELECTION)
993         RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(*pSelectionInfo));
994 
995     return TRUE;
996 }
997 
998 static BOOL NTAPI
999 GuiSetPalette(IN OUT PFRONTEND This,
1000               HPALETTE PaletteHandle,
1001               UINT PaletteUsage)
1002 {
1003     PGUI_CONSOLE_DATA GuiData = This->Context;
1004     HPALETTE OldPalette;
1005 
1006     // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
1007     if (PaletteHandle == NULL) return FALSE;
1008 
1009     /* Set the new palette for the framebuffer */
1010     OldPalette = SelectPalette(GuiData->hMemDC, PaletteHandle, FALSE);
1011     if (OldPalette == NULL) return FALSE;
1012 
1013     /* Specify the use of the system palette for the framebuffer */
1014     SetSystemPaletteUse(GuiData->hMemDC, PaletteUsage);
1015 
1016     /* Realize the (logical) palette */
1017     RealizePalette(GuiData->hMemDC);
1018 
1019     /* Save the original system palette handle */
1020     if (GuiData->hSysPalette == NULL) GuiData->hSysPalette = OldPalette;
1021 
1022     return TRUE;
1023 }
1024 
1025 static ULONG NTAPI
1026 GuiGetDisplayMode(IN OUT PFRONTEND This)
1027 {
1028     PGUI_CONSOLE_DATA GuiData = This->Context;
1029     ULONG DisplayMode = 0;
1030 
1031     if (GuiData->GuiInfo.FullScreen)
1032         DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
1033     else
1034         DisplayMode |= CONSOLE_WINDOWED;
1035 
1036     return DisplayMode;
1037 }
1038 
1039 static BOOL NTAPI
1040 GuiSetDisplayMode(IN OUT PFRONTEND This,
1041                   ULONG NewMode)
1042 {
1043     PGUI_CONSOLE_DATA GuiData = This->Context;
1044     BOOL FullScreen;
1045 
1046     if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1047         return FALSE;
1048 
1049     /* Do nothing if the window is hidden */
1050     if (!GuiData->IsWindowVisible) return TRUE;
1051 
1052     FullScreen = ((NewMode & CONSOLE_FULLSCREEN_MODE) != 0);
1053 
1054     if (FullScreen != GuiData->GuiInfo.FullScreen)
1055     {
1056         SwitchFullScreen(GuiData, FullScreen);
1057     }
1058 
1059     return TRUE;
1060 }
1061 
1062 static INT NTAPI
1063 GuiShowMouseCursor(IN OUT PFRONTEND This,
1064                    BOOL Show)
1065 {
1066     PGUI_CONSOLE_DATA GuiData = This->Context;
1067 
1068     if (GuiData->IsWindowVisible)
1069     {
1070         /* Set the reference count */
1071         if (Show) ++GuiData->MouseCursorRefCount;
1072         else      --GuiData->MouseCursorRefCount;
1073 
1074         /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1075         PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1076     }
1077 
1078     return GuiData->MouseCursorRefCount;
1079 }
1080 
1081 static BOOL NTAPI
1082 GuiSetMouseCursor(IN OUT PFRONTEND This,
1083                   HCURSOR CursorHandle)
1084 {
1085     PGUI_CONSOLE_DATA GuiData = This->Context;
1086 
1087     /* Do nothing if the window is hidden */
1088     if (!GuiData->IsWindowVisible) return TRUE;
1089 
1090     /*
1091      * Set the cursor's handle. If the given handle is NULL,
1092      * then restore the default cursor.
1093      */
1094     GuiData->hCursor = (CursorHandle ? CursorHandle : ghDefaultCursor);
1095 
1096     /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1097     PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1098 
1099     return TRUE;
1100 }
1101 
1102 static HMENU NTAPI
1103 GuiMenuControl(IN OUT PFRONTEND This,
1104                UINT CmdIdLow,
1105                UINT CmdIdHigh)
1106 {
1107     PGUI_CONSOLE_DATA GuiData = This->Context;
1108 
1109     GuiData->CmdIdLow  = CmdIdLow ;
1110     GuiData->CmdIdHigh = CmdIdHigh;
1111 
1112     return GetSystemMenu(GuiData->hWindow, FALSE);
1113 }
1114 
1115 static BOOL NTAPI
1116 GuiSetMenuClose(IN OUT PFRONTEND This,
1117                 BOOL Enable)
1118 {
1119     /*
1120      * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1121      * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1122      * for more information.
1123      */
1124 
1125     PGUI_CONSOLE_DATA GuiData = This->Context;
1126     HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
1127 
1128     if (hSysMenu == NULL) return FALSE;
1129 
1130     GuiData->IsCloseButtonEnabled = Enable;
1131     EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
1132 
1133     return TRUE;
1134 }
1135 
1136 static FRONTEND_VTBL GuiVtbl =
1137 {
1138     GuiInitFrontEnd,
1139     GuiDeinitFrontEnd,
1140     GuiDrawRegion,
1141     GuiWriteStream,
1142     GuiRingBell,
1143     GuiSetCursorInfo,
1144     GuiSetScreenInfo,
1145     GuiResizeTerminal,
1146     GuiSetActiveScreenBuffer,
1147     GuiReleaseScreenBuffer,
1148     GuiRefreshInternalInfo,
1149     GuiChangeTitle,
1150     GuiChangeIcon,
1151     GuiGetConsoleWindowHandle,
1152     GuiGetLargestConsoleWindowSize,
1153     GuiGetSelectionInfo,
1154     GuiSetPalette,
1155     GuiGetDisplayMode,
1156     GuiSetDisplayMode,
1157     GuiShowMouseCursor,
1158     GuiSetMouseCursor,
1159     GuiMenuControl,
1160     GuiSetMenuClose,
1161 };
1162 
1163 
1164 NTSTATUS NTAPI
1165 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
1166                 IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
1167                 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
1168                 IN HANDLE ConsoleLeaderProcessHandle)
1169 {
1170     PCONSOLE_START_INFO ConsoleStartInfo;
1171     PGUI_INIT_INFO GuiInitInfo;
1172     USEROBJECTFLAGS UserObjectFlags;
1173 
1174     if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
1175         return STATUS_INVALID_PARAMETER;
1176 
1177     ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
1178 
1179     /*
1180      * Initialize a private initialization info structure for later use.
1181      * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1182      */
1183     GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo));
1184     if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
1185 
1186     /* Initialize GUI terminal emulator common functionalities */
1187     if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo))
1188     {
1189         ConsoleFreeHeap(GuiInitInfo);
1190         return STATUS_UNSUCCESSFUL;
1191     }
1192 
1193     GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
1194     if (GuiInitInfo->IsWindowVisible)
1195     {
1196         /* Don't show the console if the window station is not interactive */
1197         if (GetUserObjectInformationW(GuiInitInfo->WinSta,
1198                                       UOI_FLAGS,
1199                                       &UserObjectFlags,
1200                                       sizeof(UserObjectFlags),
1201                                       NULL))
1202         {
1203             if (!(UserObjectFlags.dwFlags & WSF_VISIBLE))
1204                 GuiInitInfo->IsWindowVisible = FALSE;
1205         }
1206     }
1207 
1208     /*
1209      * Load terminal settings
1210      */
1211 #if 0
1212     /* Impersonate the caller in order to retrieve settings in its context */
1213     // if (!CsrImpersonateClient(NULL))
1214         // return STATUS_UNSUCCESSFUL;
1215     CsrImpersonateClient(NULL);
1216 
1217     /* 1. Load the default settings */
1218     GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo);
1219 #endif
1220 
1221     GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL;
1222 
1223     if (GuiInitInfo->IsWindowVisible)
1224     {
1225         /* 2. Load the remaining console settings via the registry */
1226         if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
1227         {
1228 #if 0
1229             /* Load the terminal infos from the registry */
1230             GuiConsoleReadUserSettings(&GuiInitInfo->TermInfo);
1231 #endif
1232 
1233             /*
1234              * Now, update them with the properties the user might gave to us
1235              * via the STARTUPINFO structure before calling CreateProcess
1236              * (and which was transmitted via the ConsoleStartInfo structure).
1237              * We therefore overwrite the values read in the registry.
1238              */
1239             if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
1240             {
1241                 GuiInitInfo->TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
1242             }
1243             if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
1244             {
1245                 ConsoleInfo->AutoPosition = FALSE;
1246                 ConsoleInfo->WindowPosition.x = ConsoleStartInfo->dwWindowOrigin.X;
1247                 ConsoleInfo->WindowPosition.y = ConsoleStartInfo->dwWindowOrigin.Y;
1248             }
1249             if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
1250             {
1251                 ConsoleInfo->FullScreen = TRUE;
1252             }
1253         }
1254     }
1255 
1256 #if 0
1257     /* Revert impersonation */
1258     CsrRevertToSelf();
1259 #endif
1260 
1261     // Font data
1262     StringCchCopyNW(GuiInitInfo->TermInfo.FaceName, ARRAYSIZE(GuiInitInfo->TermInfo.FaceName),
1263                     ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName));
1264     GuiInitInfo->TermInfo.FontFamily = ConsoleInfo->FontFamily;
1265     GuiInitInfo->TermInfo.FontSize   = ConsoleInfo->FontSize;
1266     GuiInitInfo->TermInfo.FontWeight = ConsoleInfo->FontWeight;
1267 
1268     // Display
1269     GuiInitInfo->TermInfo.FullScreen   = ConsoleInfo->FullScreen;
1270     GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition;
1271     GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition;
1272 
1273     /* Initialize the icon handles */
1274     // if (ConsoleStartInfo->hIcon != NULL)
1275         GuiInitInfo->hIcon = ConsoleStartInfo->hIcon;
1276     // else
1277         // GuiInitInfo->hIcon = ghDefaultIcon;
1278 
1279     // if (ConsoleStartInfo->hIconSm != NULL)
1280         GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm;
1281     // else
1282         // GuiInitInfo->hIconSm = ghDefaultIconSm;
1283 
1284     // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm);
1285 
1286     /* Finally, initialize the frontend structure */
1287     FrontEnd->Vtbl     = &GuiVtbl;
1288     FrontEnd->Context  = NULL;
1289     FrontEnd->Context2 = GuiInitInfo;
1290 
1291     return STATUS_SUCCESS;
1292 }
1293 
1294 NTSTATUS NTAPI
1295 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
1296 {
1297     if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
1298 
1299     if (FrontEnd->Context ) GuiDeinitFrontEnd(FrontEnd);
1300     if (FrontEnd->Context2) ConsoleFreeHeap(FrontEnd->Context2);
1301 
1302     return STATUS_SUCCESS;
1303 }
1304 
1305 /* EOF */
1306