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