[WINSRV] Don't try to remove messages from the queue without dispatching them. CORE...
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / guiterm.c
index f337874..e371ea4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS Console Server DLL
- * FILE:            consrv/frontends/gui/guiterm.c
+ * FILE:            win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
  * PURPOSE:         GUI Terminal Front-End
  * PROGRAMMERS:     Gé van Geldorp
  *                  Johannes Anderwald
 #define CONGUI_UPDATE_TIME    0
 #define CONGUI_UPDATE_TIMER   1
 
-#define PM_CREATE_CONSOLE       (WM_APP + 1)
-#define PM_DESTROY_CONSOLE      (WM_APP + 2)
+#define PM_CREATE_CONSOLE     (WM_APP + 1)
+#define PM_DESTROY_CONSOLE    (WM_APP + 2)
 
 
 /* GLOBALS ********************************************************************/
 
 typedef struct _GUI_INIT_INFO
 {
-    PCONSOLE_INFO ConsoleInfo;
-    PCONSOLE_START_INFO ConsoleStartInfo;
-    ULONG ProcessId;
+    HANDLE GuiThreadStartupEvent;
+    ULONG_PTR InputThreadId;
+    HWINSTA WinSta;
+    HDESK Desktop;
+    HICON hIcon;
+    HICON hIconSm;
     BOOLEAN IsWindowVisible;
+    GUI_CONSOLE_INFO TermInfo;
 } GUI_INIT_INFO, *PGUI_INIT_INFO;
 
-static BOOL    ConsInitialized = FALSE;
-static HANDLE  hInputThread = NULL;
-static DWORD   dwInputThreadId = 0;
+static BOOL ConsInitialized = FALSE;
 
 extern HICON   ghDefaultIcon;
 extern HICON   ghDefaultIconSm;
@@ -54,30 +56,6 @@ UnRegisterConWndClass(HINSTANCE hInstance);
 
 /* FUNCTIONS ******************************************************************/
 
-static VOID
-GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
-                         IN PGUI_CONSOLE_DATA GuiData,
-                         OUT PUINT WidthUnit,
-                         OUT PUINT HeightUnit)
-{
-    if (Buffer == NULL || GuiData == NULL ||
-        WidthUnit == NULL || HeightUnit == NULL)
-    {
-        return;
-    }
-
-    if (GetType(Buffer) == TEXTMODE_BUFFER)
-    {
-        *WidthUnit  = GuiData->CharWidth ;
-        *HeightUnit = GuiData->CharHeight;
-    }
-    else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
-    {
-        *WidthUnit  = 1;
-        *HeightUnit = 1;
-    }
-}
-
 VOID
 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
 {
@@ -93,20 +71,6 @@ GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
     }
 }
 
-static VOID
-SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
-{
-    PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
-    UINT WidthUnit, HeightUnit;
-
-    GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
-
-    Rect->left   = (SmallRect->Left       - Buffer->ViewOrigin.X) * WidthUnit ;
-    Rect->top    = (SmallRect->Top        - Buffer->ViewOrigin.Y) * HeightUnit;
-    Rect->right  = (SmallRect->Right  + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
-    Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
-}
-
 static VOID
 DrawRegion(PGUI_CONSOLE_DATA GuiData,
            SMALL_RECT* Region)
@@ -137,20 +101,44 @@ SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
 VOID
 CreateSysMenu(HWND hWnd);
 
-static DWORD NTAPI
+static ULONG NTAPI
 GuiConsoleInputThread(PVOID Param)
 {
-    PHANDLE GraphicsStartupEvent = (PHANDLE)Param;
+    NTSTATUS Status;
+    PCSR_THREAD pcsrt = NULL;
+    PGUI_INIT_INFO GuiInitInfo = (PGUI_INIT_INFO)Param;
+    DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
+    ULONG_PTR InputThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
+    HANDLE hThread = NULL;
+
     LONG WindowCount = 0;
     MSG msg;
 
     /*
      * This thread dispatches all the console notifications to the
-     * notification window. It is common for all the console windows.
+     * notification window. It is common for all the console windows
+     * in a given desktop in a window station.
      */
 
+    /* Assign this console input thread to this desktop */
+    DesktopConsoleThreadInfo.DesktopHandle = GuiInitInfo->Desktop; // Duplicated desktop handle
+    DesktopConsoleThreadInfo.ThreadId = InputThreadId;
+    Status = NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
+                                  &DesktopConsoleThreadInfo,
+                                  sizeof(DesktopConsoleThreadInfo));
+    if (!NT_SUCCESS(Status)) goto Quit;
+
+    /* Connect this CSR thread to the USER subsystem */
+    pcsrt = CsrConnectToUser();
+    if (pcsrt == NULL) goto Quit;
+    hThread = pcsrt->ThreadHandle;
+
+    /* Assign the desktop to this thread */
+    if (!SetThreadDesktop(DesktopConsoleThreadInfo.DesktopHandle)) goto Quit;
+
     /* The thread has been initialized, set the event */
-    NtSetEvent(*GraphicsStartupEvent, NULL);
+    NtSetEvent(GuiInitInfo->GuiThreadStartupEvent, NULL);
+    Status = STATUS_SUCCESS;
 
     while (GetMessageW(&msg, NULL, 0, 0))
     {
@@ -168,7 +156,7 @@ GuiConsoleInputThread(PVOID Param)
                 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
                                             GUI_CONWND_CLASS,
                                             Console->Title.Buffer,
-                                            WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
+                                            WS_OVERLAPPEDWINDOW,
                                             CW_USEDEFAULT,
                                             CW_USEDEFAULT,
                                             CW_USEDEFAULT,
@@ -241,13 +229,10 @@ GuiConsoleInputThread(PVOID Param)
                  * that the window that we want to destroy doesn't exist yet.
                  * So first empty the message queue.
                  */
-                /*
                 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
                 {
-                    TranslateMessage(&TempMsg);
                     DispatchMessageW(&TempMsg);
-                }*/
-                while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE)) ;
+                }
 
                 if (GuiData->hWindow == NULL) continue;
 
@@ -257,7 +242,7 @@ GuiConsoleInputThread(PVOID Param)
 
                 if (InterlockedDecrement(&WindowCount) == 0)
                 {
-                    DPRINT("CONSRV: Going to quit the Input Thread!!\n");
+                    DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
                     goto Quit;
                 }
 
@@ -270,19 +255,47 @@ GuiConsoleInputThread(PVOID Param)
     }
 
 Quit:
-    DPRINT("CONSRV: Quit the Input Thread!!\n");
+    DPRINT("CONSRV: Quit the Input Thread 0x%p, Status = 0x%08lx\n", InputThreadId, Status);
+
+    /* Remove this console input thread from this desktop */
+    // DesktopConsoleThreadInfo.DesktopHandle;
+    DesktopConsoleThreadInfo.ThreadId = 0;
+    NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
+                         &DesktopConsoleThreadInfo,
+                         sizeof(DesktopConsoleThreadInfo));
+
+    /* Close the duplicated desktop handle */
+    CloseDesktop(DesktopConsoleThreadInfo.DesktopHandle); // NtUserCloseDesktop
+
+    /* Cleanup CSR thread */
+    if (pcsrt)
+    {
+        if (hThread != pcsrt->ThreadHandle)
+            DPRINT1("WARNING!! hThread (0x%p) != pcsrt->ThreadHandle (0x%p), you may expect crashes soon!!\n", hThread, pcsrt->ThreadHandle);
 
-    hInputThread = NULL;
-    dwInputThreadId = 0;
+        CsrDereferenceThread(pcsrt);
+    }
 
-    return 1;
+    /* Exit the thread */
+    RtlExitUserThread(Status);
+    return 0;
 }
 
+// FIXME: Maybe return a NTSTATUS
 static BOOL
-GuiInit(VOID)
+GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
+        IN HANDLE ConsoleLeaderProcessHandle,
+        IN OUT PGUI_INIT_INFO GuiInitInfo)
 {
-    /* Exit if we were already initialized */
-    // if (ConsInitialized) return TRUE;
+    BOOL Success = TRUE;
+    UNICODE_STRING DesktopPath;
+    DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
+    HWINSTA hWinSta;
+    HDESK hDesk;
+
+    NTSTATUS Status;
+    HANDLE hInputThread;
+    CLIENT_ID ClientId;
 
     /*
      * Initialize and register the console window class, if needed.
@@ -294,39 +307,164 @@ GuiInit(VOID)
     }
 
     /*
-     * Set-up the console input thread
+     * Set-up the console input thread. We have
+     * one console input thread per desktop.
      */
-    if (hInputThread == NULL)
+
+    if (!CsrImpersonateClient(NULL))
+        // return STATUS_BAD_IMPERSONATION_LEVEL;
+        return FALSE;
+
+    if (ConsoleInitInfo->DesktopLength)
     {
-        HANDLE GraphicsStartupEvent;
-        NTSTATUS Status;
-
-        Status = NtCreateEvent(&GraphicsStartupEvent, EVENT_ALL_ACCESS,
-                               NULL, SynchronizationEvent, FALSE);
-        if (!NT_SUCCESS(Status)) return FALSE;
-
-        hInputThread = CreateThread(NULL,
-                                    0,
-                                    GuiConsoleInputThread,
-                                    (PVOID)&GraphicsStartupEvent,
-                                    0,
-                                    &dwInputThreadId);
-        if (hInputThread == NULL)
-        {
-            NtClose(GraphicsStartupEvent);
-            DPRINT1("CONSRV: Failed to create graphics console thread.\n");
-            return FALSE;
-        }
-        SetThreadPriority(hInputThread, THREAD_PRIORITY_HIGHEST);
-        CloseHandle(hInputThread);
+        DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
+        DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
+        DesktopPath.Buffer = ConsoleInitInfo->Desktop;
+    }
+    else
+    {
+        RtlInitUnicodeString(&DesktopPath, L"Default");
+    }
+
+    hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle,
+                                 &DesktopPath,
+                                 0,
+                                 &hWinSta);
+    DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
+           &DesktopPath, hDesk, hWinSta);
+
+    CsrRevertToSelf();
+
+    if (hDesk == NULL) return FALSE;
+
+    /*
+     * We need to see whether we need to create a
+     * new console input thread for this desktop.
+     */
+    DesktopConsoleThreadInfo.DesktopHandle = hDesk;
+    DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID.
+    NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread,
+                         &DesktopConsoleThreadInfo,
+                         sizeof(DesktopConsoleThreadInfo));
+    DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
 
-        WaitForSingleObject(GraphicsStartupEvent, INFINITE);
-        NtClose(GraphicsStartupEvent);
+    /*
+     * Save the opened window station and desktop handles in the initialization
+     * structure. They will be used later on, and released, by the GUI frontend.
+     */
+    GuiInitInfo->WinSta  = hWinSta;
+    GuiInitInfo->Desktop = hDesk;
+
+    /* Here GuiInitInfo contains original handles */
+
+    /* If we already have a console input thread on this desktop... */
+    if (DesktopConsoleThreadInfo.ThreadId != 0)
+    {
+        /* ... just use it... */
+        DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
+        GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
+        goto Quit;
     }
 
-    // ConsInitialized = TRUE;
+    /* ... otherwise create a new one. */
 
-    return TRUE;
+    /* Initialize a startup event for the thread to signal it */
+    Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS,
+                           NULL, SynchronizationEvent, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        Success = FALSE;
+        goto Quit;
+    }
+
+    /*
+     * Duplicate the desktop handle for the console input thread internal needs.
+     * If it happens to need also a window station handle in the future, then
+     * it is there that you also need to duplicate the window station handle!
+     *
+     * Note also that we are going to temporarily overwrite the stored handles
+     * in GuiInitInfo because it happens that we use also this structure to give
+     * the duplicated handles to the input thread that is going to initialize.
+     * After the input thread finishes its initialization, we restore the handles
+     * in GuiInitInfo to their old values.
+     */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               hDesk,
+                               NtCurrentProcess(),
+                               (PHANDLE)&GuiInitInfo->Desktop,
+                               0, 0, DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        Success = FALSE;
+        goto Quit;
+    }
+
+    /* Here GuiInitInfo contains duplicated handles */
+
+    Status = RtlCreateUserThread(NtCurrentProcess(),
+                                 NULL,
+                                 TRUE, // Start the thread in suspended state
+                                 0,
+                                 0,
+                                 0,
+                                 (PVOID)GuiConsoleInputThread,
+                                 (PVOID)GuiInitInfo,
+                                 &hInputThread,
+                                 &ClientId);
+    if (NT_SUCCESS(Status))
+    {
+        /* Add it as a static server thread and resume it */
+        CsrAddStaticServerThread(hInputThread, &ClientId, 0);
+        Status = NtResumeThread(hInputThread, NULL);
+    }
+    DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n",
+           hInputThread, ClientId.UniqueThread, Status);
+
+    if (!NT_SUCCESS(Status) || hInputThread == NULL)
+    {
+        /* Close the thread's handle */
+        if (hInputThread) NtClose(hInputThread);
+
+        /* We need to close here the duplicated desktop handle */
+        CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop
+
+        /* Close the startup event and bail out */
+        NtClose(GuiInitInfo->GuiThreadStartupEvent);
+
+        DPRINT1("CONSRV: Failed to create graphics console thread.\n");
+        Success = FALSE;
+        goto Quit;
+    }
+
+    /* No need to close hInputThread, this is done by CSR automatically */
+
+    /* Wait for the thread to finish its initialization, and close the startup event */
+    NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL);
+    NtClose(GuiInitInfo->GuiThreadStartupEvent);
+
+    /*
+     * Save the input thread ID for later use, and restore the original handles.
+     * The copies are held by the console input thread.
+     */
+    GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread;
+    GuiInitInfo->WinSta  = hWinSta;
+    GuiInitInfo->Desktop = hDesk;
+
+    /* Here GuiInitInfo contains again original handles */
+
+Quit:
+    if (!Success)
+    {
+        /*
+         * Close the original handles. Do not use the copies in GuiInitInfo
+         * because we may have failed in the middle of the duplicate operation
+         * and the handles stored in GuiInitInfo may have changed.
+         */
+        CloseDesktop(hDesk); // NtUserCloseDesktop
+        CloseWindowStation(hWinSta); // NtUserCloseWindowStation
+    }
+
+    return Success;
 }
 
 
@@ -342,11 +480,7 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
                 IN PCONSRV_CONSOLE Console)
 {
     PGUI_INIT_INFO GuiInitInfo;
-    PCONSOLE_INFO  ConsoleInfo;
-    PCONSOLE_START_INFO ConsoleStartInfo;
-
     PGUI_CONSOLE_DATA GuiData;
-    GUI_CONSOLE_INFO  TermInfo;
 
     if (This == NULL || Console == NULL || This->Context2 == NULL)
         return STATUS_INVALID_PARAMETER;
@@ -355,20 +489,14 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
 
     GuiInitInfo = This->Context2;
 
-    if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
-        return STATUS_INVALID_PARAMETER;
-
-    ConsoleInfo      = GuiInitInfo->ConsoleInfo;
-    ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
-
     /* Terminal data allocation */
-    GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
+    GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiData));
     if (!GuiData)
     {
         DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
         return STATUS_UNSUCCESSFUL;
     }
-    ///// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
+    /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
     GuiData->Console      = Console;
     GuiData->ActiveBuffer = Console->ActiveBuffer;
     GuiData->hWindow = NULL;
@@ -379,73 +507,19 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
 
     InitializeCriticalSection(&GuiData->Lock);
 
-
-    /*
-     * Load terminal settings
-     */
-
-    /* 1. Load the default settings */
-    GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
-
-    if (GuiData->IsWindowVisible)
-    {
-        /* 2. Load the remaining console settings via the registry */
-        if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
-        {
-            /* Load the terminal infos from the registry */
-            GuiConsoleReadUserSettings(&TermInfo,
-                                       ConsoleInfo->ConsoleTitle,
-                                       GuiInitInfo->ProcessId);
-
-            /*
-             * Now, update them with the properties the user might gave to us
-             * via the STARTUPINFO structure before calling CreateProcess
-             * (and which was transmitted via the ConsoleStartInfo structure).
-             * We therefore overwrite the values read in the registry.
-             */
-            if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
-            {
-                TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
-            }
-            if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
-            {
-                TermInfo.AutoPosition = FALSE;
-                TermInfo.WindowOrigin.x = ConsoleStartInfo->dwWindowOrigin.X;
-                TermInfo.WindowOrigin.y = ConsoleStartInfo->dwWindowOrigin.Y;
-            }
-            if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
-            {
-                TermInfo.FullScreen = TRUE;
-            }
-        }
-    }
-
-
     /*
      * Set up GUI data
      */
-
-    // Font data
-    wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
-    GuiData->GuiInfo.FaceName[LF_FACESIZE - 1] = UNICODE_NULL;
-    GuiData->GuiInfo.FontFamily     = TermInfo.FontFamily;
-    GuiData->GuiInfo.FontSize       = TermInfo.FontSize;
-    GuiData->GuiInfo.FontWeight     = TermInfo.FontWeight;
-
-    // Display
-    GuiData->GuiInfo.FullScreen     = TermInfo.FullScreen;
-    GuiData->GuiInfo.ShowWindow     = TermInfo.ShowWindow;
-    GuiData->GuiInfo.AutoPosition   = TermInfo.AutoPosition;
-    GuiData->GuiInfo.WindowOrigin   = TermInfo.WindowOrigin;
+    RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo));
 
     /* Initialize the icon handles */
-    if (ConsoleStartInfo->hIcon != NULL)
-        GuiData->hIcon = ConsoleStartInfo->hIcon;
+    if (GuiInitInfo->hIcon != NULL)
+        GuiData->hIcon = GuiInitInfo->hIcon;
     else
         GuiData->hIcon = ghDefaultIcon;
 
-    if (ConsoleStartInfo->hIconSm != NULL)
-        GuiData->hIconSm = ConsoleStartInfo->hIconSm;
+    if (GuiInitInfo->hIconSm != NULL)
+        GuiData->hIconSm = GuiInitInfo->hIconSm;
     else
         GuiData->hIconSm = ghDefaultIconSm;
 
@@ -457,6 +531,8 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
 
     /* A priori don't ignore mouse signals */
     GuiData->IgnoreNextMouseSignal = FALSE;
+    /* Initialize HACK FOR CORE-8394. See conwnd.c!OnMouse for more details. */
+    GuiData->HackCORE8394IgnoreNextMove = FALSE;
 
     /* Close button and the corresponding system menu item are enabled by default */
     GuiData->IsCloseButtonEnabled = TRUE;
@@ -471,9 +547,13 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
     GuiData->LineSelection = FALSE; // Default to block selection
     // TODO: Retrieve the selection mode via the registry.
 
+    GuiData->InputThreadId = GuiInitInfo->InputThreadId;
+    GuiData->WinSta  = GuiInitInfo->WinSta;
+    GuiData->Desktop = GuiInitInfo->Desktop;
+
     /* Finally, finish to initialize the frontend structure */
     This->Context  = GuiData;
-    if (This->Context2) ConsoleFreeHeap(This->Context2);
+    ConsoleFreeHeap(This->Context2);
     This->Context2 = NULL;
 
     /*
@@ -490,10 +570,10 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
     DPRINT("GUI - Checkpoint\n");
 
     /* Create the terminal window */
-    PostThreadMessageW(dwInputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
+    PostThreadMessageW(GuiData->InputThreadId, PM_CREATE_CONSOLE, 0, (LPARAM)GuiData);
 
     /* Wait until initialization has finished */
-    WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
+    NtWaitForSingleObject(GuiData->hGuiInitEvent, FALSE, NULL);
     DPRINT("OK we created the console window\n");
     NtClose(GuiData->hGuiInitEvent);
     GuiData->hGuiInitEvent = NULL;
@@ -515,12 +595,15 @@ GuiDeinitFrontEnd(IN OUT PFRONTEND This)
     PGUI_CONSOLE_DATA GuiData = This->Context;
 
     DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
-    PostThreadMessageW(dwInputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
-    WaitForSingleObject(GuiData->hGuiTermEvent, INFINITE);
+    PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
+    NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
     DPRINT("hGuiTermEvent set\n");
     NtClose(GuiData->hGuiTermEvent);
     GuiData->hGuiTermEvent = NULL;
 
+    CloseDesktop(GuiData->Desktop); // NtUserCloseDesktop
+    CloseWindowStation(GuiData->WinSta); // NtUserCloseWindowStation
+
     DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
             GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
     if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
@@ -683,7 +766,7 @@ GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
     EnterCriticalSection(&GuiData->Lock);
     GuiData->WindowSizeLock = TRUE;
 
-    InterlockedExchangePointer(&GuiData->ActiveBuffer,
+    InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer,
                                ConDrvGetActiveScreenBuffer(GuiData->Console));
 
     GuiData->WindowSizeLock = FALSE;
@@ -693,13 +776,9 @@ GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
 
     /* Change the current palette */
     if (ActiveBuffer->PaletteHandle == NULL)
-    {
         hPalette = GuiData->hSysPalette;
-    }
     else
-    {
         hPalette = ActiveBuffer->PaletteHandle;
-    }
 
     DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
 
@@ -753,7 +832,7 @@ GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
         EnterCriticalSection(&GuiData->Lock);
         GuiData->WindowSizeLock = TRUE;
 
-        InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
+        InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer, NULL);
 
         GuiData->WindowSizeLock = FALSE;
         LeaveCriticalSection(&GuiData->Lock);
@@ -791,7 +870,7 @@ GuiChangeTitle(IN OUT PFRONTEND This)
 {
     PGUI_CONSOLE_DATA GuiData = This->Context;
     // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
-    SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
+    SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer);
 }
 
 static BOOL NTAPI
@@ -813,9 +892,7 @@ GuiChangeIcon(IN OUT PFRONTEND This,
     }
 
     if (hIcon == NULL)
-    {
         return FALSE;
-    }
 
     if (hIcon != GuiData->hIcon)
     {
@@ -852,41 +929,60 @@ GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
 {
     PGUI_CONSOLE_DATA GuiData = This->Context;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
-    RECT WorkArea;
-    LONG width, height;
+    HMONITOR hMonitor;
+    MONITORINFO MonitorInfo;
+    LONG Width, Height;
     UINT WidthUnit, HeightUnit;
 
     if (!pSize) return;
 
-    if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0))
+    /*
+     * Retrieve the monitor that is mostly covered by the current console window;
+     * default to primary monitor otherwise.
+     */
+    MonitorInfo.cbSize = sizeof(MonitorInfo);
+    hMonitor = MonitorFromWindow(GuiData->hWindow, MONITOR_DEFAULTTOPRIMARY);
+    if (hMonitor && GetMonitorInfoW(hMonitor, &MonitorInfo))
+    {
+        /* Retrieve the width and height of the client area of this monitor */
+        Width  = MonitorInfo.rcWork.right - MonitorInfo.rcWork.left;
+        Height = MonitorInfo.rcWork.bottom - MonitorInfo.rcWork.top;
+    }
+    else
     {
-        DPRINT1("SystemParametersInfoW failed - What to do ??\n");
-        return;
+        /*
+         * Retrieve the width and height of the client area for a full-screen
+         * window on the primary display monitor.
+         */
+        Width  = GetSystemMetrics(SM_CXFULLSCREEN);
+        Height = GetSystemMetrics(SM_CYFULLSCREEN);
+
+        // RECT WorkArea;
+        // SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0);
+        // Width  = WorkArea.right;
+        // Height = WorkArea.bottom;
     }
 
     ActiveBuffer = GuiData->ActiveBuffer;
+#if 0
+    // NOTE: This would be surprising if we wouldn't have an associated buffer...
     if (ActiveBuffer)
-    {
+#endif
         GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
-    }
+#if 0
     else
-    {
-        /* Default: text mode */
-        WidthUnit  = GuiData->CharWidth ;
-        HeightUnit = GuiData->CharHeight;
-    }
-
-    width  = WorkArea.right;
-    height = WorkArea.bottom;
+        /* Default: graphics mode */
+        WidthUnit = HeightUnit = 1;
+#endif
 
-    width  -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
-    height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
+    Width  -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
+    Height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
 
-    if (width  < 0) width  = 0;
-    if (height < 0) height = 0;
+    if (Width  < 0) Width  = 0;
+    if (Height < 0) Height = 0;
 
-    pSize->X = (SHORT)(width  / (int)WidthUnit ) /* HACK */ + 2;
-    pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1;
+    pSize->X = (SHORT)(Width  / (int)WidthUnit ) /* HACK */ + 2;
+    pSize->Y = (SHORT)(Height / (int)HeightUnit) /* HACK */ + 1;
 }
 
 static BOOL NTAPI
@@ -897,9 +993,9 @@ GuiGetSelectionInfo(IN OUT PFRONTEND This,
 
     if (pSelectionInfo == NULL) return FALSE;
 
-    ZeroMemory(pSelectionInfo, sizeof(CONSOLE_SELECTION_INFO));
+    ZeroMemory(pSelectionInfo, sizeof(*pSelectionInfo));
     if (GuiData->Selection.dwFlags != CONSOLE_NO_SELECTION)
-        RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(CONSOLE_SELECTION_INFO));
+        RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(*pSelectionInfo));
 
     return TRUE;
 }
@@ -1072,32 +1168,112 @@ static FRONTEND_VTBL GuiVtbl =
 
 NTSTATUS NTAPI
 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
-                IN OUT PCONSOLE_INFO ConsoleInfo,
-                IN OUT PVOID ExtraConsoleInfo,
-                IN ULONG ProcessId)
+                IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+                IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+                IN HANDLE ConsoleLeaderProcessHandle)
 {
-    PCONSOLE_INIT_INFO ConsoleInitInfo = ExtraConsoleInfo;
+    PCONSOLE_START_INFO ConsoleStartInfo;
     PGUI_INIT_INFO GuiInitInfo;
 
     if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
         return STATUS_INVALID_PARAMETER;
 
-    /* Initialize GUI terminal emulator common functionalities */
-    if (!GuiInit()) return STATUS_UNSUCCESSFUL;
+    ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
 
     /*
      * Initialize a private initialization info structure for later use.
      * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
      */
-    GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO));
+    GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*GuiInitInfo));
     if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
 
-    // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
-    // If not, then copy exactly what we need in GuiInitInfo.
-    GuiInitInfo->ConsoleInfo      = ConsoleInfo;
-    GuiInitInfo->ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
-    GuiInitInfo->ProcessId        = ProcessId;
-    GuiInitInfo->IsWindowVisible  = ConsoleInitInfo->IsWindowVisible;
+    /* Initialize GUI terminal emulator common functionalities */
+    if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo))
+    {
+        ConsoleFreeHeap(GuiInitInfo);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /*
+     * Load terminal settings
+     */
+#if 0
+    /* Impersonate the caller in order to retrieve settings in its context */
+    // if (!CsrImpersonateClient(NULL))
+        // return STATUS_UNSUCCESSFUL;
+    CsrImpersonateClient(NULL);
+
+    /* 1. Load the default settings */
+    GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo);
+#endif
+
+    GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL;
+
+    if (ConsoleInitInfo->IsWindowVisible)
+    {
+        /* 2. Load the remaining console settings via the registry */
+        if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+        {
+#if 0
+            /* Load the terminal infos from the registry */
+            GuiConsoleReadUserSettings(&GuiInitInfo->TermInfo);
+#endif
+
+            /*
+             * Now, update them with the properties the user might gave to us
+             * via the STARTUPINFO structure before calling CreateProcess
+             * (and which was transmitted via the ConsoleStartInfo structure).
+             * We therefore overwrite the values read in the registry.
+             */
+            if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
+            {
+                GuiInitInfo->TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
+            }
+            if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
+            {
+                ConsoleInfo->AutoPosition = FALSE;
+                ConsoleInfo->WindowPosition.x = ConsoleStartInfo->dwWindowOrigin.X;
+                ConsoleInfo->WindowPosition.y = ConsoleStartInfo->dwWindowOrigin.Y;
+            }
+            if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
+            {
+                ConsoleInfo->FullScreen = TRUE;
+            }
+        }
+    }
+
+#if 0
+    /* Revert impersonation */
+    CsrRevertToSelf();
+#endif
+
+    // Font data
+    StringCchCopyNW(GuiInitInfo->TermInfo.FaceName, ARRAYSIZE(GuiInitInfo->TermInfo.FaceName),
+                    ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName));
+    GuiInitInfo->TermInfo.FontFamily = ConsoleInfo->FontFamily;
+    GuiInitInfo->TermInfo.FontSize   = ConsoleInfo->FontSize;
+    GuiInitInfo->TermInfo.FontWeight = ConsoleInfo->FontWeight;
+
+    // Display
+    GuiInitInfo->TermInfo.FullScreen   = ConsoleInfo->FullScreen;
+    // GuiInitInfo->TermInfo.ShowWindow;
+    GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition;
+    GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition;
+
+    /* Initialize the icon handles */
+    // if (ConsoleStartInfo->hIcon != NULL)
+        GuiInitInfo->hIcon = ConsoleStartInfo->hIcon;
+    // else
+        // GuiInitInfo->hIcon = ghDefaultIcon;
+
+    // if (ConsoleStartInfo->hIconSm != NULL)
+        GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm;
+    // else
+        // GuiInitInfo->hIconSm = ghDefaultIconSm;
+
+    // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm);
+
+    GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
 
     /* Finally, initialize the frontend structure */
     FrontEnd->Vtbl     = &GuiVtbl;