[WIN32K:NTUSER] Make NtUserResolveDesktop() and IntResolveDesktop() work in a more...
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / guiterm.c
index e56e4c5..258b1e2 100644 (file)
@@ -13,9 +13,6 @@
 
 #include <consrv.h>
 
-#define COBJMACROS
-#include <shlobj.h>
-
 #define NDEBUG
 #include <debug.h>
 
 #define CONGUI_UPDATE_TIME    0
 #define CONGUI_UPDATE_TIMER   1
 
-#define PM_CREATE_CONSOLE       (WM_APP + 1)
-#define PM_DESTROY_CONSOLE      (WM_APP + 2)
-
-
-/* Not defined in any header file */
-extern VOID NTAPI PrivateCsrssManualGuiCheck(LONG Check);
-// See winsrv/usersrv/init.c line 234
+#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 HWND    NotifyWnd = NULL;
+static BOOL ConsInitialized = FALSE;
 
 extern HICON   ghDefaultIcon;
 extern HICON   ghDefaultIconSm;
@@ -60,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)
 {
@@ -99,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)
@@ -139,50 +97,81 @@ InvalidateCell(PGUI_CONSOLE_DATA GuiData,
  ******************************************************************************/
 
 VOID
-SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
+CreateSysMenu(HWND hWnd);
 
-static LRESULT CALLBACK
-GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static ULONG NTAPI
+GuiConsoleInputThread(PVOID Param)
 {
-    HWND NewWindow;
-    LONG WindowCount;
-    MSG Msg;
+    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;
 
-    switch (msg)
+    /*
+     * This thread dispatches all the console notifications to the
+     * 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(GuiInitInfo->GuiThreadStartupEvent, NULL);
+    Status = STATUS_SUCCESS;
+
+    while (GetMessageW(&msg, NULL, 0, 0))
     {
-        case WM_CREATE:
+        switch (msg.message)
         {
-            SetWindowLongW(hWnd, GWL_USERDATA, 0);
-            return 0;
-        }
-    
-        case PM_CREATE_CONSOLE:
-        {
-            PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
-            PCONSOLE Console = GuiData->Console;
-            RECT rcWnd;
-
-            DPRINT("PM_CREATE_CONSOLE -- creating window\n");
-
-            NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
-                                        GUI_CONWND_CLASS,
-                                        Console->Title.Buffer,
-                                        WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
-                                        CW_USEDEFAULT,
-                                        CW_USEDEFAULT,
-                                        CW_USEDEFAULT,
-                                        CW_USEDEFAULT,
-                                        NULL,
-                                        NULL,
-                                        ConSrvDllInstance,
-                                        (PVOID)GuiData);
-            if (NULL != NewWindow)
+            case PM_CREATE_CONSOLE:
             {
+                PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
+                PCONSRV_CONSOLE Console = GuiData->Console;
+                HWND NewWindow;
+                RECT rcWnd;
+
+                DPRINT("PM_CREATE_CONSOLE -- creating window\n");
+
+                NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
+                                            GUI_CONWND_CLASS,
+                                            Console->Title.Buffer,
+                                            WS_OVERLAPPEDWINDOW,
+                                            CW_USEDEFAULT,
+                                            CW_USEDEFAULT,
+                                            CW_USEDEFAULT,
+                                            CW_USEDEFAULT,
+                                            GuiData->IsWindowVisible ? HWND_DESKTOP : HWND_MESSAGE,
+                                            NULL,
+                                            ConSrvDllInstance,
+                                            (PVOID)GuiData);
+                if (NewWindow == NULL)
+                {
+                    DPRINT1("Failed to create a new console window\n");
+                    continue;
+                }
+
                 ASSERT(NewWindow == GuiData->hWindow);
 
-                WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
-                WindowCount++;
-                SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
+                InterlockedIncrement(&WindowCount);
 
                 //
                 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
@@ -194,193 +183,285 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
                 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
                 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
 
-                /* Move and resize the window to the user's values */
-                /* CAN WE DEADLOCK ?? */
-                GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
-                SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
-
-                /* Switch to full-screen mode if necessary */
-                // FIXME: Move elsewhere, it cause misdrawings of the window.
-                if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
+                if (GuiData->IsWindowVisible)
+                {
+                    /* Move and resize the window to the user's values */
+                    /* CAN WE DEADLOCK ?? */
+                    GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
+                    SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
+                }
 
-                DPRINT("PM_CREATE_CONSOLE -- showing window\n");
-                // ShowWindow(NewWindow, (int)wParam);
-                ShowWindowAsync(NewWindow, (int)wParam);
-                DPRINT("Window showed\n");
-            }
+                // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
+                CreateSysMenu(GuiData->hWindow);
 
-            return (LRESULT)NewWindow;
-        }
+                if (GuiData->IsWindowVisible)
+                {
+                    /* Switch to full-screen mode if necessary */
+                    // FIXME: Move elsewhere, it cause misdrawings of the window.
+                    if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
 
-        case PM_DESTROY_CONSOLE:
-        {
-            PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
+                    DPRINT("PM_CREATE_CONSOLE -- showing window\n");
+                    ShowWindowAsync(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
+                }
+                else
+                {
+                    DPRINT("PM_CREATE_CONSOLE -- hidden window\n");
+                    ShowWindowAsync(NewWindow, SW_HIDE);
+                }
 
-            /* Exit the full screen mode if it was already set */
-            // LeaveFullScreen(GuiData);
+                continue;
+            }
 
-            /*
-             * Window creation is done using a PostMessage(), so it's possible
-             * that the window that we want to destroy doesn't exist yet.
-             * So first empty the message queue.
-             */
-            /*
-            while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
+            case PM_DESTROY_CONSOLE:
             {
-                TranslateMessage(&Msg);
-                DispatchMessageW(&Msg);
-            }*/
-            while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
+                PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)msg.lParam;
+                MSG TempMsg;
+
+                /* Exit the full screen mode if it was already set */
+                // LeaveFullScreen(GuiData);
+
+                /*
+                 * Window creation is done using a PostMessage(), so it's possible
+                 * 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))
+                {
+                    DispatchMessageW(&TempMsg);
+                }
+
+                if (GuiData->hWindow == NULL) continue;
 
-            if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
-            {
                 DestroyWindow(GuiData->hWindow);
 
-                WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
-                WindowCount--;
-                SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
-                if (0 == WindowCount)
+                NtSetEvent(GuiData->hGuiTermEvent, NULL);
+
+                if (InterlockedDecrement(&WindowCount) == 0)
                 {
-                    NotifyWnd = NULL;
-                    DestroyWindow(hWnd);
-                    DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
-                    PostQuitMessage(0);
+                    DPRINT("CONSRV: Going to quit the Input Thread 0x%p\n", InputThreadId);
+                    goto Quit;
                 }
-            }
 
-            return 0;
+                continue;
+            }
         }
 
-        default:
-            return DefWindowProcW(hWnd, msg, wParam, lParam);
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    }
+
+Quit:
+    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);
+
+        CsrDereferenceThread(pcsrt);
     }
+
+    /* Exit the thread */
+    RtlExitUserThread(Status);
+    return 0;
 }
 
-static DWORD NTAPI
-GuiConsoleGuiThread(PVOID Data)
+// FIXME: Maybe return a NTSTATUS
+static BOOL
+GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
+        IN HANDLE ConsoleLeaderProcessHandle,
+        IN OUT PGUI_INIT_INFO GuiInitInfo)
 {
-    MSG msg;
-    PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
+    BOOL Success = TRUE;
+    UNICODE_STRING DesktopPath;
+    DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo;
+    HWINSTA hWinSta;
+    HDESK hDesk;
+
+    NTSTATUS Status;
+    HANDLE hInputThread;
+    CLIENT_ID ClientId;
 
     /*
-     * This thread dispatches all the console notifications to the notify window.
-     * It is common for all the console windows.
+     * Initialize and register the console window class, if needed.
      */
-
-    PrivateCsrssManualGuiCheck(+1);
-
-    NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
-                              L"",
-                              WS_OVERLAPPEDWINDOW,
-                              CW_USEDEFAULT,
-                              CW_USEDEFAULT,
-                              CW_USEDEFAULT,
-                              CW_USEDEFAULT,
-                              NULL,
-                              NULL,
-                              ConSrvDllInstance,
-                              NULL);
-    if (NULL == NotifyWnd)
+    if (!ConsInitialized)
     {
-        PrivateCsrssManualGuiCheck(-1);
-        SetEvent(*GraphicsStartupEvent);
-        return 1;
+        if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE;
+        ConsInitialized = TRUE;
     }
 
-    SetEvent(*GraphicsStartupEvent);
+    /*
+     * Set-up the console input thread. We have
+     * one console input thread per desktop.
+     */
+
+    if (!CsrImpersonateClient(NULL))
+        // return STATUS_BAD_IMPERSONATION_LEVEL;
+        return FALSE;
 
-    while (GetMessageW(&msg, NULL, 0, 0))
+    if (ConsoleInitInfo->DesktopLength)
     {
-        TranslateMessage(&msg);
-        DispatchMessageW(&msg);
+        DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength;
+        DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL);
+        DesktopPath.Buffer = ConsoleInitInfo->Desktop;
+    }
+    else
+    {
+        RtlInitUnicodeString(&DesktopPath, L"Default");
     }
 
-    DPRINT("CONSRV: Quit the Gui Thread!!\n");
-    PrivateCsrssManualGuiCheck(-1);
+    hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle,
+                                 &DesktopPath,
+                                 FALSE,
+                                 &hWinSta);
+    DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n",
+           &DesktopPath, hDesk, hWinSta);
 
-    return 1;
-}
+    CsrRevertToSelf();
 
-static BOOL
-GuiInit(VOID)
-{
-    WNDCLASSEXW wc;
+    if (hDesk == NULL) return FALSE;
 
-    /* Exit if we were already initialized */
-    // if (ConsInitialized) return TRUE;
+    /*
+     * 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);
 
     /*
-     * Initialize and register the different window classes, if needed.
+     * Save the opened window station and desktop handles in the initialization
+     * structure. They will be used later on, and released, by the GUI frontend.
      */
-    if (!ConsInitialized)
+    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)
     {
-        /* Initialize the notification window class */
-        wc.cbSize = sizeof(WNDCLASSEXW);
-        wc.lpszClassName = L"ConSrvCreateNotify";
-        wc.lpfnWndProc = GuiConsoleNotifyWndProc;
-        wc.style = 0;
-        wc.hInstance = ConSrvDllInstance;
-        wc.hIcon = NULL;
-        wc.hIconSm = NULL;
-        wc.hCursor = NULL;
-        wc.hbrBackground = NULL;
-        wc.lpszMenuName = NULL;
-        wc.cbClsExtra = 0;
-        wc.cbWndExtra = 0;
-        if (RegisterClassExW(&wc) == 0)
-        {
-            DPRINT1("Failed to register GUI notify wndproc\n");
-            return FALSE;
-        }
+        /* ... just use it... */
+        DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId);
+        GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId;
+        goto Quit;
+    }
 
-        /* Initialize the console window class */
-        if (!RegisterConWndClass(ConSrvDllInstance))
-            return FALSE;
+    /* ... otherwise create a new one. */
 
-        ConsInitialized = 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;
     }
 
     /*
-     * Set-up the notification window
+     * 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.
      */
-    if (NULL == NotifyWnd)
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               hDesk,
+                               NtCurrentProcess(),
+                               (PHANDLE)&GuiInitInfo->Desktop,
+                               0, 0, DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
     {
-        HANDLE ThreadHandle;
-        HANDLE GraphicsStartupEvent;
-
-        GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-        if (NULL == GraphicsStartupEvent) return FALSE;
-
-        ThreadHandle = CreateThread(NULL,
-                                    0,
-                                    GuiConsoleGuiThread,
-                                    (PVOID)&GraphicsStartupEvent,
-                                    0,
-                                    NULL);
-        if (NULL == ThreadHandle)
-        {
-            CloseHandle(GraphicsStartupEvent);
-            DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
-            return FALSE;
-        }
-        SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
-        CloseHandle(ThreadHandle);
+        Success = FALSE;
+        goto Quit;
+    }
 
-        WaitForSingleObject(GraphicsStartupEvent, INFINITE);
-        CloseHandle(GraphicsStartupEvent);
+    /* 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 (NULL == NotifyWnd)
-        {
-            DPRINT1("CONSRV: Failed to create notification window.\n");
-            return FALSE;
-        }
+    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;
     }
 
-    // ConsInitialized = TRUE;
+    /* No need to close hInputThread, this is done by CSR automatically */
 
-    return TRUE;
-}
+    /* 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;
+}
 
 
 /******************************************************************************
@@ -390,133 +471,54 @@ GuiInit(VOID)
 static VOID NTAPI
 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
 
-NTSTATUS NTAPI
+static NTSTATUS NTAPI
 GuiInitFrontEnd(IN OUT PFRONTEND This,
-                IN PCONSOLE Console)
+                IN PCONSRV_CONSOLE Console)
 {
     PGUI_INIT_INFO GuiInitInfo;
-    PCONSOLE_INFO  ConsoleInfo;
-    PCONSOLE_START_INFO ConsoleStartInfo;
-
     PGUI_CONSOLE_DATA GuiData;
-    GUI_CONSOLE_INFO  TermInfo;
 
-    SIZE_T Length    = 0;
-    LPWSTR IconPath  = NULL;
-    INT    IconIndex = 0;
-
-    if (This == NULL || Console == NULL || This->OldData == NULL)
+    if (This == NULL || Console == NULL || This->Context2 == NULL)
         return STATUS_INVALID_PARAMETER;
 
     ASSERT(This->Console == Console);
 
-    GuiInitInfo = This->OldData;
-
-    if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
-        return STATUS_INVALID_PARAMETER;
-
-    ConsoleInfo      = GuiInitInfo->ConsoleInfo;
-    ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
-
-    IconPath  = ConsoleStartInfo->IconPath;
-    IconIndex = ConsoleStartInfo->IconIndex;
-
+    GuiInitInfo = This->Context2;
 
     /* 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->TermIFace.Data = (PVOID)GuiData; /* HACK */
+    /// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
     GuiData->Console      = Console;
     GuiData->ActiveBuffer = Console->ActiveBuffer;
     GuiData->hWindow = NULL;
+    GuiData->IsWindowVisible = GuiInitInfo->IsWindowVisible;
 
     /* The console can be resized */
     Console->FixedSize = FALSE;
 
     InitializeCriticalSection(&GuiData->Lock);
 
-
     /*
-     * Load terminal settings
+     * Set up GUI data
      */
+    RtlCopyMemory(&GuiData->GuiInfo, &GuiInitInfo->TermInfo, sizeof(GuiInitInfo->TermInfo));
 
-    /* 1. Load the default settings */
-    GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
-
-    /* 3. 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;
-        }
-    }
-
+    /* Initialize the icon handles */
+    if (GuiInitInfo->hIcon != NULL)
+        GuiData->hIcon = GuiInitInfo->hIcon;
+    else
+        GuiData->hIcon = ghDefaultIcon;
 
-    /*
-     * Set up GUI data
-     */
+    if (GuiInitInfo->hIconSm != NULL)
+        GuiData->hIconSm = GuiInitInfo->hIconSm;
+    else
+        GuiData->hIconSm = ghDefaultIconSm;
 
-    Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
-    wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
-    GuiData->GuiInfo.FaceName[Length] = L'\0';
-    GuiData->GuiInfo.FontFamily     = TermInfo.FontFamily;
-    GuiData->GuiInfo.FontSize       = TermInfo.FontSize;
-    GuiData->GuiInfo.FontWeight     = TermInfo.FontWeight;
-    GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
-    GuiData->GuiInfo.FullScreen     = TermInfo.FullScreen;
-    GuiData->GuiInfo.ShowWindow     = TermInfo.ShowWindow;
-    GuiData->GuiInfo.AutoPosition   = TermInfo.AutoPosition;
-    GuiData->GuiInfo.WindowOrigin   = TermInfo.WindowOrigin;
-
-    /* Initialize the icon handles to their default values */
-    GuiData->hIcon   = ghDefaultIcon;
-    GuiData->hIconSm = ghDefaultIconSm;
-
-    /* Get the associated icon, if any */
-    if (IconPath == NULL || IconPath[0] == L'\0')
-    {
-        IconPath  = ConsoleStartInfo->AppPath;
-        IconIndex = 0;
-    }
-    DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
-    if (IconPath && IconPath[0] != L'\0')
-    {
-        HICON hIcon = NULL, hIconSm = NULL;
-        PrivateExtractIconExW(IconPath,
-                              IconIndex,
-                              &hIcon,
-                              &hIconSm,
-                              1);
-        DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
-        if (hIcon   != NULL) GuiData->hIcon   = hIcon;
-        if (hIconSm != NULL) GuiData->hIconSm = hIconSm;
-    }
     ASSERT(GuiData->hIcon && GuiData->hIconSm);
 
     /* Mouse is shown by default with its default cursor shape */
@@ -525,6 +527,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;
@@ -533,8 +537,20 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
     GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
 
     /* Initialize the selection */
-    RtlZeroMemory(&GuiData->Selection, sizeof(CONSOLE_SELECTION_INFO));
+    RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
     GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
+    RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
+    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;
+    ConsoleFreeHeap(This->Context2);
+    This->Context2 = NULL;
 
     /*
      * We need to wait until the GUI has been fully initialized
@@ -542,17 +558,20 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
      * Ideally we could use SendNotifyMessage for this but its not
      * yet implemented.
      */
-    GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+    NtCreateEvent(&GuiData->hGuiInitEvent, EVENT_ALL_ACCESS,
+                  NULL, SynchronizationEvent, FALSE);
+    NtCreateEvent(&GuiData->hGuiTermEvent, EVENT_ALL_ACCESS,
+                  NULL, SynchronizationEvent, FALSE);
 
     DPRINT("GUI - Checkpoint\n");
 
     /* Create the terminal window */
-    PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (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");
-    CloseHandle(GuiData->hGuiInitEvent);
+    NtClose(GuiData->hGuiInitEvent);
     GuiData->hGuiInitEvent = NULL;
 
     /* Check whether we really succeeded in initializing the terminal window */
@@ -563,20 +582,23 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
         return STATUS_UNSUCCESSFUL;
     }
 
-    /* Finally, finish to initialize the frontend structure */
-    This->Data = GuiData;
-    if (This->OldData) ConsoleFreeHeap(This->OldData);
-    This->OldData = NULL;
-
     return STATUS_SUCCESS;
 }
 
 static VOID NTAPI
 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
+    PostThreadMessageW(GuiData->InputThreadId, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
+    NtWaitForSingleObject(GuiData->hGuiTermEvent, FALSE, NULL);
+    DPRINT("hGuiTermEvent set\n");
+    NtClose(GuiData->hGuiTermEvent);
+    GuiData->hGuiTermEvent = NULL;
 
-    SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
+    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);
@@ -591,7 +613,7 @@ GuiDeinitFrontEnd(IN OUT PFRONTEND This)
         DestroyIcon(GuiData->hIconSm);
     }
 
-    This->Data = NULL;
+    This->Context = NULL;
     DeleteCriticalSection(&GuiData->Lock);
     ConsoleFreeHeap(GuiData);
 
@@ -602,7 +624,11 @@ static VOID NTAPI
 GuiDrawRegion(IN OUT PFRONTEND This,
               SMALL_RECT* Region)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
     DrawRegion(GuiData, Region);
 }
 
@@ -615,13 +641,16 @@ GuiWriteStream(IN OUT PFRONTEND This,
                PWCHAR Buffer,
                UINT Length)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     PCONSOLE_SCREEN_BUFFER Buff;
     SHORT CursorEndX, CursorEndY;
     RECT ScrollRect;
 
     if (NULL == GuiData || NULL == GuiData->hWindow) return;
 
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return;
+
     Buff = GuiData->ActiveBuffer;
     if (GetType(Buff) != TEXTMODE_BUFFER) return;
 
@@ -666,11 +695,23 @@ GuiWriteStream(IN OUT PFRONTEND This,
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
 }
 
+/* static */ VOID NTAPI
+GuiRingBell(IN OUT PFRONTEND This)
+{
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    /* Emit an error beep sound */
+    SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
+}
+
 static BOOL NTAPI
 GuiSetCursorInfo(IN OUT PFRONTEND This,
                  PCONSOLE_SCREEN_BUFFER Buff)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return TRUE;
 
     if (GuiData->ActiveBuffer == Buff)
     {
@@ -686,7 +727,10 @@ GuiSetScreenInfo(IN OUT PFRONTEND This,
                  SHORT OldCursorX,
                  SHORT OldCursorY)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return TRUE;
 
     if (GuiData->ActiveBuffer == Buff)
     {
@@ -702,7 +746,7 @@ GuiSetScreenInfo(IN OUT PFRONTEND This,
 static VOID NTAPI
 GuiResizeTerminal(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
     /* Resize the window to the user's values */
     PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
@@ -711,14 +755,14 @@ GuiResizeTerminal(IN OUT PFRONTEND This)
 static VOID NTAPI
 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;
     HPALETTE hPalette;
 
     EnterCriticalSection(&GuiData->Lock);
     GuiData->WindowSizeLock = TRUE;
 
-    InterlockedExchangePointer(&GuiData->ActiveBuffer,
+    InterlockedExchangePointer((PVOID*)&GuiData->ActiveBuffer,
                                ConDrvGetActiveScreenBuffer(GuiData->Console));
 
     GuiData->WindowSizeLock = FALSE;
@@ -728,15 +772,11 @@ GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
 
     /* Change the current palette */
     if (ActiveBuffer->PaletteHandle == NULL)
-    {
         hPalette = GuiData->hSysPalette;
-    }
     else
-    {
         hPalette = ActiveBuffer->PaletteHandle;
-    }
 
-    DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
+    DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
 
     /* Set the new palette for the framebuffer */
     SelectPalette(GuiData->hMemDC, hPalette, FALSE);
@@ -755,7 +795,7 @@ static VOID NTAPI
 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
                        IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
     /*
      * If we were notified to release a screen buffer that is not actually
@@ -788,32 +828,13 @@ 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);
     }
 }
 
-static BOOL NTAPI
-GuiProcessKeyCallback(IN OUT PFRONTEND This,
-                      MSG* msg,
-                      BYTE KeyStateMenu,
-                      DWORD ShiftState,
-                      UINT VirtualKeyCode,
-                      BOOL Down)
-{
-    if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
-        (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
-    {
-        DPRINT1("GuiProcessKeyCallback\n");
-        //DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
-        //return TRUE;
-    }
-
-    return FALSE;
-}
-
 static BOOL NTAPI
 GuiSetMouseCursor(IN OUT PFRONTEND This,
                   HCURSOR CursorHandle);
@@ -821,7 +842,7 @@ GuiSetMouseCursor(IN OUT PFRONTEND This,
 static VOID NTAPI
 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
     /* Update the console leader information held by the window */
     SetConWndConsoleLeaderCID(GuiData);
@@ -843,16 +864,16 @@ GuiRefreshInternalInfo(IN OUT PFRONTEND This)
 static VOID NTAPI
 GuiChangeTitle(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    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
 GuiChangeIcon(IN OUT PFRONTEND This,
               HICON IconHandle)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     HICON hIcon, hIconSm;
 
     if (IconHandle == NULL)
@@ -867,9 +888,7 @@ GuiChangeIcon(IN OUT PFRONTEND This,
     }
 
     if (hIcon == NULL)
-    {
         return FALSE;
-    }
 
     if (hIcon != GuiData->hIcon)
     {
@@ -896,7 +915,7 @@ GuiChangeIcon(IN OUT PFRONTEND This,
 static HWND NTAPI
 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     return GuiData->hWindow;
 }
 
@@ -904,56 +923,75 @@ static VOID NTAPI
 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
                                PCOORD pSize)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    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;
-    }
+        /* Default: graphics mode */
+        WidthUnit = HeightUnit = 1;
+#endif
 
-    width  = WorkArea.right;
-    height = WorkArea.bottom;
+    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
 GuiGetSelectionInfo(IN OUT PFRONTEND This,
                     PCONSOLE_SELECTION_INFO pSelectionInfo)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
     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;
 }
@@ -963,7 +1001,7 @@ GuiSetPalette(IN OUT PFRONTEND This,
               HPALETTE PaletteHandle,
               UINT PaletteUsage)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     HPALETTE OldPalette;
 
     // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
@@ -988,7 +1026,7 @@ GuiSetPalette(IN OUT PFRONTEND This,
 static ULONG NTAPI
 GuiGetDisplayMode(IN OUT PFRONTEND This)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     ULONG DisplayMode = 0;
 
     if (GuiData->GuiInfo.FullScreen)
@@ -1003,12 +1041,15 @@ static BOOL NTAPI
 GuiSetDisplayMode(IN OUT PFRONTEND This,
                   ULONG NewMode)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     BOOL FullScreen;
 
     if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
         return FALSE;
 
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return TRUE;
+
     FullScreen = ((NewMode & CONSOLE_FULLSCREEN_MODE) != 0);
 
     if (FullScreen != GuiData->GuiInfo.FullScreen)
@@ -1023,14 +1064,17 @@ static INT NTAPI
 GuiShowMouseCursor(IN OUT PFRONTEND This,
                    BOOL Show)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
-    /* Set the reference count */
-    if (Show) ++GuiData->MouseCursorRefCount;
-    else      --GuiData->MouseCursorRefCount;
+    if (GuiData->IsWindowVisible)
+    {
+        /* Set the reference count */
+        if (Show) ++GuiData->MouseCursorRefCount;
+        else      --GuiData->MouseCursorRefCount;
 
-    /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
-    PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
+        /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
+        PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
+    }
 
     return GuiData->MouseCursorRefCount;
 }
@@ -1039,7 +1083,10 @@ static BOOL NTAPI
 GuiSetMouseCursor(IN OUT PFRONTEND This,
                   HCURSOR CursorHandle)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
+
+    /* Do nothing if the window is hidden */
+    if (!GuiData->IsWindowVisible) return TRUE;
 
     /*
      * Set the cursor's handle. If the given handle is NULL,
@@ -1058,7 +1105,7 @@ GuiMenuControl(IN OUT PFRONTEND This,
                UINT CmdIdLow,
                UINT CmdIdHigh)
 {
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
 
     GuiData->CmdIdLow  = CmdIdLow ;
     GuiData->CmdIdHigh = CmdIdHigh;
@@ -1076,7 +1123,7 @@ GuiSetMenuClose(IN OUT PFRONTEND This,
      * for more information.
      */
 
-    PGUI_CONSOLE_DATA GuiData = This->Data;
+    PGUI_CONSOLE_DATA GuiData = This->Context;
     HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
 
     if (hSysMenu == NULL) return FALSE;
@@ -1093,12 +1140,12 @@ static FRONTEND_VTBL GuiVtbl =
     GuiDeinitFrontEnd,
     GuiDrawRegion,
     GuiWriteStream,
+    GuiRingBell,
     GuiSetCursorInfo,
     GuiSetScreenInfo,
     GuiResizeTerminal,
     GuiSetActiveScreenBuffer,
     GuiReleaseScreenBuffer,
-    GuiProcessKeyCallback,
     GuiRefreshInternalInfo,
     GuiChangeTitle,
     GuiChangeIcon,
@@ -1115,155 +1162,132 @@ static FRONTEND_VTBL GuiVtbl =
 };
 
 
-static BOOL
-LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
-                         IN OUT PCONSOLE_INFO ConsoleInfo)
+NTSTATUS NTAPI
+GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
+                IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+                IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+                IN HANDLE ConsoleLeaderProcessHandle)
 {
-#define PATH_SEPARATOR L'\\'
+    PCONSOLE_START_INFO ConsoleStartInfo;
+    PGUI_INIT_INFO GuiInitInfo;
+    USEROBJECTFLAGS UserObjectFlags;
 
-    BOOL    RetVal   = FALSE;
-    HRESULT hRes     = S_OK;
-    LPWSTR  LinkName = NULL;
-    SIZE_T  Length   = 0;
+    if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL)
+        return STATUS_INVALID_PARAMETER;
 
-    if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
-        return FALSE;
+    ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo;
 
-    ConsoleStartInfo->IconPath[0] = L'\0';
-    ConsoleStartInfo->IconIndex   = 0;
+    /*
+     * 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(*GuiInitInfo));
+    if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
 
-    /* 1- Find the last path separator if any */
-    LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
-    if (LinkName == NULL)
+    /* Initialize GUI terminal emulator common functionalities */
+    if (!GuiInit(ConsoleInitInfo, ConsoleLeaderProcessHandle, GuiInitInfo))
     {
-        LinkName = ConsoleStartInfo->ConsoleTitle;
+        ConsoleFreeHeap(GuiInitInfo);
+        return STATUS_UNSUCCESSFUL;
     }
-    else
+
+    GuiInitInfo->IsWindowVisible = ConsoleInitInfo->IsWindowVisible;
+    if (GuiInitInfo->IsWindowVisible)
     {
-        /* Skip the path separator */
-        ++LinkName;
+        /* Don't show the console if the window station is not interactive */
+        if (GetUserObjectInformationW(GuiInitInfo->WinSta,
+                                      UOI_FLAGS,
+                                      &UserObjectFlags,
+                                      sizeof(UserObjectFlags),
+                                      NULL))
+        {
+            if (!(UserObjectFlags.dwFlags & WSF_VISIBLE))
+                GuiInitInfo->IsWindowVisible = FALSE;
+        }
     }
 
-    /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
-    Length = wcslen(LinkName);
-    if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
-        return FALSE;
+    /*
+     * Load terminal settings
+     */
+#if 0
+    /* Impersonate the caller in order to retrieve settings in its context */
+    // if (!CsrImpersonateClient(NULL))
+        // return STATUS_UNSUCCESSFUL;
+    CsrImpersonateClient(NULL);
 
-    /* 3- It may be a link. Try to retrieve some properties */
-    hRes = CoInitialize(NULL);
-    if (SUCCEEDED(hRes))
+    /* 1. Load the default settings */
+    GuiConsoleGetDefaultSettings(&GuiInitInfo->TermInfo);
+#endif
+
+    GuiInitInfo->TermInfo.ShowWindow = SW_SHOWNORMAL;
+
+    if (GuiInitInfo->IsWindowVisible)
     {
-        /* Get a pointer to the IShellLink interface */
-        IShellLinkW* pshl = NULL;
-        hRes = CoCreateInstance(&CLSID_ShellLink,
-                                NULL, 
-                                CLSCTX_INPROC_SERVER,
-                                &IID_IShellLinkW,
-                                (LPVOID*)&pshl);
-        if (SUCCEEDED(hRes))
+        /* 2. Load the remaining console settings via the registry */
+        if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
         {
-            /* Get a pointer to the IPersistFile interface */
-            IPersistFile* ppf = NULL;
-            hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
-            if (SUCCEEDED(hRes))
+#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)
             {
-                /* Load the shortcut */
-                hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
-                if (SUCCEEDED(hRes))
-                {
-                    /*
-                     * Finally we can get the properties !
-                     * Update the old ones if needed.
-                     */
-                    INT ShowCmd = 0;
-                    // WORD HotKey = 0;
-
-                    /* Reset the name of the console with the name of the shortcut */
-                    Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
-                                 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
-                    wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
-                    ConsoleInfo->ConsoleTitle[Length] = L'\0';
-
-                    /* Get the window showing command */
-                    hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
-                    if (SUCCEEDED(hRes)) ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
-
-                    /* Get the hotkey */
-                    // hRes = pshl->GetHotkey(&ShowCmd);
-                    // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
-
-                    /* Get the icon location, if any */
-
-                    hRes = IShellLinkW_GetIconLocation(pshl,
-                                                       ConsoleStartInfo->IconPath,
-                                                       sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH
-                                                       &ConsoleStartInfo->IconIndex);
-                    if (!SUCCEEDED(hRes))
-                    {
-                        ConsoleStartInfo->IconPath[0] = L'\0';
-                        ConsoleStartInfo->IconIndex   = 0;
-                    }
-
-                    // FIXME: Since we still don't load console properties from the shortcut,
-                    // return false. When this will be done, we will return true instead.
-                    RetVal = FALSE;
-                }
-                IPersistFile_Release(ppf);
+                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;
             }
-            IShellLinkW_Release(pshl);
         }
     }
-    CoUninitialize();
 
-    return RetVal;
-}
-
-NTSTATUS NTAPI
-GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
-                IN OUT PCONSOLE_INFO ConsoleInfo,
-                IN OUT PVOID ExtraConsoleInfo,
-                IN ULONG ProcessId)
-{
-    PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo;
-    PGUI_INIT_INFO GuiInitInfo;
+#if 0
+    /* Revert impersonation */
+    CsrRevertToSelf();
+#endif
 
-    if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL)
-        return STATUS_INVALID_PARAMETER;
+    // 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;
 
-    /* Initialize GUI terminal emulator common functionalities */
-    if (!GuiInit()) return STATUS_UNSUCCESSFUL;
+    // Display
+    GuiInitInfo->TermInfo.FullScreen   = ConsoleInfo->FullScreen;
+    GuiInitInfo->TermInfo.AutoPosition = ConsoleInfo->AutoPosition;
+    GuiInitInfo->TermInfo.WindowOrigin = ConsoleInfo->WindowPosition;
 
-    /*
-     * Load per-application terminal settings.
-     *
-     * Check whether the process creating the console was launched via
-     * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
-     * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
-     */
-    if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
-    {
-        if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo))
-        {
-            ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
-        }
-    }
+    /* Initialize the icon handles */
+    // if (ConsoleStartInfo->hIcon != NULL)
+        GuiInitInfo->hIcon = ConsoleStartInfo->hIcon;
+    // else
+        // GuiInitInfo->hIcon = ghDefaultIcon;
 
-    /*
-     * 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));
-    if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
+    // if (ConsoleStartInfo->hIconSm != NULL)
+        GuiInitInfo->hIconSm = ConsoleStartInfo->hIconSm;
+    // else
+        // GuiInitInfo->hIconSm = ghDefaultIconSm;
 
-    // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
-    GuiInitInfo->ConsoleInfo      = ConsoleInfo;
-    GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo;
-    GuiInitInfo->ProcessId        = ProcessId;
+    // ASSERT(GuiInitInfo->hIcon && GuiInitInfo->hIconSm);
 
     /* Finally, initialize the frontend structure */
-    FrontEnd->Vtbl    = &GuiVtbl;
-    FrontEnd->Data    = NULL;
-    FrontEnd->OldData = GuiInitInfo;
+    FrontEnd->Vtbl     = &GuiVtbl;
+    FrontEnd->Context  = NULL;
+    FrontEnd->Context2 = GuiInitInfo;
 
     return STATUS_SUCCESS;
 }
@@ -1273,8 +1297,8 @@ GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
 {
     if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
 
-    if (FrontEnd->Data)    GuiDeinitFrontEnd(FrontEnd);
-    if (FrontEnd->OldData) ConsoleFreeHeap(FrontEnd->OldData);
+    if (FrontEnd->Context ) GuiDeinitFrontEnd(FrontEnd);
+    if (FrontEnd->Context2) ConsoleFreeHeap(FrontEnd->Context2);
 
     return STATUS_SUCCESS;
 }