[CONSRV]: More code cleaning.
[reactos.git] / win32ss / user / winsrv / consrv / console.c
index 441e07d..444631e 100644 (file)
 
 #include "consrv.h"
 
-#include <ndk/psfuncs.h>
+/* This is for COM usage */
+#define COBJMACROS
+#include <shlobj.h>
 
-#include "procinit.h"
 
-#ifdef TUITERM_COMPILE
-#include "frontends/tui/tuiterm.h"
-#endif
+#include <alias.h>
+#include <history.h>
+#include "procinit.h"
 
 #define NDEBUG
 #include <debug.h>
 
+// FIXME: Add this prototype to winternl.h / rtlfuncs.h / ...
+NTSTATUS NTAPI RtlGetLastNtStatus(VOID);
+
 /* GLOBALS ********************************************************************/
 
-/***************/
-#ifdef TUITERM_COMPILE
-NTSTATUS NTAPI
-TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
-                IN OUT PCONSOLE_INFO ConsoleInfo,
-                IN OUT PVOID ExtraConsoleInfo,
-                IN ULONG ProcessId);
-NTSTATUS NTAPI
-TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
-#endif
+/* The list of the ConSrv consoles */
+static ULONG ConsoleListSize;
+static PCONSRV_CONSOLE* ConsoleList;
+static RTL_RESOURCE ListLock;
 
-NTSTATUS NTAPI
-GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
-                IN OUT PCONSOLE_INFO ConsoleInfo,
-                IN OUT PVOID ExtraConsoleInfo,
-                IN ULONG ProcessId);
-NTSTATUS NTAPI
-GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
-/***************/
+#define ConSrvLockConsoleListExclusive()    \
+    RtlAcquireResourceExclusive(&ListLock, TRUE)
 
-typedef
-NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
-                                IN OUT PCONSOLE_INFO ConsoleInfo,
-                                IN OUT PVOID ExtraConsoleInfo,
-                                IN ULONG ProcessId);
+#define ConSrvLockConsoleListShared()       \
+    RtlAcquireResourceShared(&ListLock, TRUE)
 
-typedef
-NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
+#define ConSrvUnlockConsoleList()           \
+    RtlReleaseResource(&ListLock)
 
-/*
- * If we are not in GUI-mode, start the text-mode terminal emulator.
- * If we fail, try to start the GUI-mode terminal emulator.
- *
- * Try to open the GUI-mode terminal emulator. Two cases are possible:
- * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
- *   failed and we start GUI-mode terminal emulator.
- * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
- *   succeeded BUT we failed at starting text-mode terminal emulator.
- *   Then GuiMode was switched to TRUE in order to try to open the GUI-mode
- *   terminal emulator (Win32k will automatically switch to graphical mode,
- *   therefore no additional code is needed).
- */
 
-/*
- * NOTE: Each entry of the table should be retrieved when loading a front-end
- *       (examples of the CSR servers which register some data for CSRSS).
- */
-struct
+static NTSTATUS
+InsertConsole(OUT PHANDLE Handle,
+              IN PCONSRV_CONSOLE Console)
 {
-    CHAR            FrontEndName[80];
-    FRONTEND_LOAD   FrontEndLoad;
-    FRONTEND_UNLOAD FrontEndUnload;
-} FrontEndLoadingMethods[] =
+#define CONSOLE_HANDLES_INCREMENT   2 * 3
+
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG i = 0;
+    PCONSRV_CONSOLE* Block;
+
+    ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
+            (ConsoleList != NULL && ConsoleListSize != 0) );
+
+    /* All went right, so add the console to the list */
+    ConSrvLockConsoleListExclusive();
+    DPRINT("Insert in the list\n");
+
+    if (ConsoleList)
+    {
+        for (i = 0; i < ConsoleListSize; i++)
+        {
+            if (ConsoleList[i] == NULL) break;
+        }
+    }
+
+    if (i >= ConsoleListSize)
+    {
+        DPRINT("Creation of a new handles table\n");
+        /* Allocate a new handles table */
+        Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
+                                 (ConsoleListSize +
+                                    CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSRV_CONSOLE));
+        if (Block == NULL)
+        {
+            Status = STATUS_UNSUCCESSFUL;
+            goto Quit;
+        }
+
+        /* If we previously had a handles table, free it and use the new one */
+        if (ConsoleList)
+        {
+            /* Copy the handles from the old table to the new one */
+            RtlCopyMemory(Block,
+                          ConsoleList,
+                          ConsoleListSize * sizeof(PCONSRV_CONSOLE));
+            ConsoleFreeHeap(ConsoleList);
+        }
+        ConsoleList = Block;
+        ConsoleListSize += CONSOLE_HANDLES_INCREMENT;
+    }
+
+    ConsoleList[i] = Console;
+    *Handle = ULongToHandle((i << 2) | 0x3);
+
+Quit:
+    /* Unlock the console list and return status */
+    ConSrvUnlockConsoleList();
+    return Status;
+}
+
+/* Unused */
+#if 0
+static NTSTATUS
+RemoveConsoleByHandle(IN HANDLE Handle)
 {
-#ifdef TUITERM_COMPILE
-    {"TUI", TuiLoadFrontEnd,    TuiUnloadFrontEnd},
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSRV_CONSOLE Console;
+
+    BOOLEAN ValidHandle = ((HandleToULong(Handle) & 0x3) == 0x3);
+    ULONG Index = HandleToULong(Handle) >> 2;
+
+    if (!ValidHandle) return STATUS_INVALID_HANDLE;
+
+    ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
+            (ConsoleList != NULL && ConsoleListSize != 0) );
+
+    /* Remove the console from the list */
+    ConSrvLockConsoleListExclusive();
+
+    if (Index >= ConsoleListSize ||
+        (Console = ConsoleList[Index]) == NULL)
+    {
+        Status = STATUS_INVALID_HANDLE;
+        goto Quit;
+    }
+
+    ConsoleList[Index] = NULL;
+
+Quit:
+    /* Unlock the console list and return status */
+    ConSrvUnlockConsoleList();
+    return Status;
+}
 #endif
-    {"GUI", GuiLoadFrontEnd,    GuiUnloadFrontEnd},
 
-//  {"Not found", 0, NULL}
-};
+static NTSTATUS
+RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console)
+{
+    ULONG i = 0;
+
+    if (!Console) return STATUS_INVALID_PARAMETER;
+
+    ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
+            (ConsoleList != NULL && ConsoleListSize != 0) );
+
+    /* Remove the console from the list */
+    ConSrvLockConsoleListExclusive();
+
+    if (ConsoleList)
+    {
+        for (i = 0; i < ConsoleListSize; i++)
+        {
+            if (ConsoleList[i] == Console) ConsoleList[i] = NULL;
+        }
+    }
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
+    return STATUS_SUCCESS;
+}
+
+BOOLEAN NTAPI
+ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console,
+                      IN HANDLE ConsoleHandle,
+                      IN CONSOLE_STATE ExpectedState,
+                      IN BOOLEAN LockConsole)
+{
+    BOOLEAN RetVal = FALSE;
+    PCONSRV_CONSOLE ValidatedConsole;
+
+    BOOLEAN ValidHandle = ((HandleToULong(ConsoleHandle) & 0x3) == 0x3);
+    ULONG Index = HandleToULong(ConsoleHandle) >> 2;
+
+    if (!ValidHandle) return FALSE;
+
+    if (!Console) return FALSE;
+    *Console = NULL;
+
+    /*
+     * Forbid creation or deletion of consoles when
+     * checking for the existence of a console.
+     */
+    ConSrvLockConsoleListShared();
+
+    if (Index >= ConsoleListSize ||
+        (ValidatedConsole = ConsoleList[Index]) == NULL)
+    {
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return FALSE;
+    }
+
+    ValidatedConsole = ConsoleList[Index];
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
+
+    RetVal = ConDrvValidateConsoleUnsafe((PCONSOLE)ValidatedConsole,
+                                         ExpectedState,
+                                         LockConsole);
+    if (RetVal) *Console = ValidatedConsole;
+
+    return RetVal;
+}
 
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-#if 0000
-VOID FASTCALL
-ConioPause(PCONSOLE Console, UINT Flags)
+// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
+static BOOLEAN
+ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest,
+                           IN PCWSTR Source)
+{
+    SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR);
+    if (Size > MAXUSHORT) return FALSE;
+
+    UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
+    if (UniDest->Buffer == NULL) return FALSE;
+
+    RtlCopyMemory(UniDest->Buffer, Source, Size);
+    UniDest->MaximumLength = (USHORT)Size;
+    UniDest->Length = (USHORT)Size - sizeof(WCHAR);
+
+    return TRUE;
+}
+
+// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
+static VOID
+ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
+{
+    if (UnicodeString->Buffer)
+    {
+        ConsoleFreeHeap(UnicodeString->Buffer);
+        RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
+    }
+}
+
+VOID
+ConioPause(PCONSRV_CONSOLE Console, UINT Flags)
 {
     Console->PauseFlags |= Flags;
-    if (!Console->UnpauseEvent)
-        Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ConDrvPause((PCONSOLE)Console);
 }
 
-VOID FASTCALL
-ConioUnpause(PCONSOLE Console, UINT Flags)
+VOID
+ConioUnpause(PCONSRV_CONSOLE Console, UINT Flags)
 {
     Console->PauseFlags &= ~Flags;
 
     // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
-    if (Console->PauseFlags == 0 && Console->UnpauseEvent)
+    if (Console->PauseFlags == 0)
     {
-        SetEvent(Console->UnpauseEvent);
-        CloseHandle(Console->UnpauseEvent);
-        Console->UnpauseEvent = NULL;
+        ConDrvUnpause((PCONSOLE)Console);
 
         CsrNotifyWait(&Console->WriteWaitQueue,
                       TRUE,
@@ -121,53 +268,246 @@ ConioUnpause(PCONSOLE Console, UINT Flags)
         }
     }
 }
-#endif
 
-
-NTSTATUS FASTCALL
-ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
-                 PCONSOLE* Console,
-                 BOOL LockConsole)
+NTSTATUS
+ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData,
+                 OUT PCONSRV_CONSOLE* Console,
+                 IN BOOLEAN LockConsole)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
-    PCONSOLE ProcessConsole;
+    NTSTATUS Status = STATUS_INVALID_HANDLE;
+    PCONSRV_CONSOLE GrabConsole;
 
+    // if (Console == NULL) return STATUS_INVALID_PARAMETER;
     ASSERT(Console);
     *Console = NULL;
 
-    // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-
-    Status = ConDrvGetConsole(&ProcessConsole, ProcessData->ConsoleHandle, LockConsole);
-    if (NT_SUCCESS(Status)) *Console = ProcessConsole;
+    if (ConSrvValidateConsole(&GrabConsole,
+                              ProcessData->ConsoleHandle,
+                              CONSOLE_RUNNING,
+                              LockConsole))
+    {
+        InterlockedIncrement(&GrabConsole->ReferenceCount);
+        *Console = GrabConsole;
+        Status = STATUS_SUCCESS;
+    }
 
-    // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
     return Status;
 }
 
-VOID FASTCALL
-ConSrvReleaseConsole(PCONSOLE Console,
-                     BOOL WasConsoleLocked)
+VOID
+ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console,
+                     IN BOOLEAN WasConsoleLocked)
+{
+    LONG RefCount = 0;
+
+    if (!Console) return;
+    // if (Console->ReferenceCount == 0) return; // This shouldn't happen
+    ASSERT(Console->ReferenceCount > 0);
+
+    /* The console must be locked */
+    // ASSERT(Console_locked);
+
+    /*
+     * Decrement the reference count. Save the new value too,
+     * because Console->ReferenceCount might be modified after
+     * the console gets unlocked but before we check whether we
+     * can destroy it.
+     */
+    RefCount = _InterlockedDecrement(&Console->ReferenceCount);
+
+    /* Unlock the console if needed */
+    if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock);
+
+    /* Delete the console if needed */
+    if (RefCount <= 0) ConSrvDeleteConsole(Console);
+}
+
+
+/* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
+
+VOID NTAPI
+ConSrvInitConsoleSupport(VOID)
 {
-    /* Just call the driver */
-    ConDrvReleaseConsole(Console, WasConsoleLocked);
+    DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
+
+    /* Initialize the console list and its lock */
+    ConsoleListSize = 0;
+    ConsoleList = NULL;
+    RtlInitializeResource(&ListLock);
+
+    /* Should call LoadKeyboardLayout */
 }
 
+NTSTATUS NTAPI
+ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
+                   IN OUT PCONSOLE_INFO ConsoleInfo,
+                   IN OUT PVOID ExtraConsoleInfo,
+                   IN ULONG ProcessId);
+NTSTATUS NTAPI
+ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal);
+
+
+static BOOL
+LoadShellLinkConsoleInfo(IN OUT PCONSOLE_INFO ConsoleInfo,
+                         IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo)
+{
+#define PATH_SEPARATOR L'\\'
+
+    BOOL    RetVal   = FALSE;
+    HRESULT hRes     = S_OK;
+    SIZE_T  Length   = 0;
+    LPWSTR  LinkName = NULL;
+    LPWSTR  IconPath = NULL;
+    WCHAR   Buffer[MAX_PATH + 1];
+
+    ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
+
+    if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+    {
+        // return FALSE; // FIXME!! (for icon loading)
+        RetVal = TRUE;
+        goto Finish;
+    }
+
+    /* 1- Find the last path separator if any */
+    LinkName = wcsrchr(ConsoleInfo->ConsoleTitle, PATH_SEPARATOR);
+    if (LinkName == NULL)
+        LinkName = ConsoleInfo->ConsoleTitle;
+    else
+        ++LinkName; // Skip the path separator
+
+    /* 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;
+
+    /* 3- It may be a link. Try to retrieve some properties */
+    hRes = CoInitialize(NULL);
+    if (SUCCEEDED(hRes))
+    {
+        /* 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))
+        {
+            /* Get a pointer to the IPersistFile interface */
+            IPersistFile* ppf = NULL;
+            hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
+            if (SUCCEEDED(hRes))
+            {
+                /* Load the shortcut */
+                hRes = IPersistFile_Load(ppf, ConsoleInfo->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)) ConsoleInitInfo->ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
+
+                    /* Get the hotkey */
+                    // hRes = pshl->GetHotkey(&ShowCmd);
+                    // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey;
+
+                    /* Get the icon location, if any */
+                    hRes = IShellLinkW_GetIconLocation(pshl,
+                                                       Buffer,
+                                                       sizeof(Buffer)/sizeof(Buffer[0]) - 1, // == MAX_PATH
+                                                       &ConsoleInitInfo->ConsoleStartInfo->IconIndex);
+                    if (!SUCCEEDED(hRes))
+                    {
+                        ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
+                    }
+                    else
+                    {
+                        IconPath = Buffer;
+                    }
+
+                    // 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 = TRUE; // FALSE;
+                }
+                IPersistFile_Release(ppf);
+            }
+            IShellLinkW_Release(pshl);
+        }
+    }
+    CoUninitialize();
+
+Finish:
+
+    if (RetVal)
+    {
+        /* Get the associated icon, if any */
+        if (IconPath == NULL)
+        {
+            // Question: How to retrieve the full path name
+            // of the app we are going to run??
+            Length = RtlDosSearchPath_U(ConsoleInitInfo->CurDir,
+                                        ConsoleInitInfo->AppName,
+                                        NULL,
+                                        sizeof(Buffer),
+                                        Buffer,
+                                        NULL);
+            if (Length > 0 && Length < sizeof(Buffer))
+                IconPath = Buffer;
+            else
+                IconPath = ConsoleInitInfo->AppName;
+
+            // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
+        }
+        DPRINT("IconPath = '%S' ; IconIndex = %lu\n",
+               IconPath, ConsoleInitInfo->ConsoleStartInfo->IconIndex);
+        if (IconPath && *IconPath)
+        {
+            HICON hIcon = NULL, hIconSm = NULL;
+            PrivateExtractIconExW(IconPath,
+                                  ConsoleInitInfo->ConsoleStartInfo->IconIndex,
+                                  &hIcon,
+                                  &hIconSm,
+                                  1);
+            DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
+            if (hIcon   != NULL) ConsoleInitInfo->ConsoleStartInfo->hIcon   = hIcon;
+            if (hIconSm != NULL) ConsoleInitInfo->ConsoleStartInfo->hIconSm = hIconSm;
+        }
+    }
+
+    // FIXME: See the previous FIXME above.
+    RetVal = FALSE;
+
+    return RetVal;
+}
 
 NTSTATUS NTAPI
 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
-                  OUT PCONSOLE* NewConsole,
-                  IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
+                  OUT PCONSRV_CONSOLE* NewConsole,
+                  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
                   IN ULONG ConsoleLeaderProcessId)
 {
     NTSTATUS Status;
     HANDLE ConsoleHandle;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
     CONSOLE_INFO ConsoleInfo;
     SIZE_T Length = 0;
-    ULONG i = 0;
-    FRONTEND FrontEnd;
 
-    if (NewConsole == NULL || ConsoleStartInfo == NULL)
+    TERMINAL Terminal; /* The ConSrv terminal for this console */
+
+    if (NewConsole == NULL || ConsoleInitInfo == NULL)
         return STATUS_INVALID_PARAMETER;
 
     *NewConsole = NULL;
@@ -180,48 +520,42 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId);
 
     /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
-    Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
+    Length = min(ConsoleInitInfo->TitleLength,
                  sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
-    wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
-    ConsoleInfo.ConsoleTitle[Length] = L'\0';
-
+    wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length);
+    ConsoleInfo.ConsoleTitle[Length] = L'\0'; // NULL-terminate it.
+
+    /* 3. Initialize the ConSrv terminal */
+    Status = ConSrvInitTerminal(&Terminal,
+                                &ConsoleInfo,
+                                ConsoleInitInfo,
+                                ConsoleLeaderProcessId);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status);
+        return Status;
+    }
+    DPRINT("CONSRV: Terminal initialized\n");
 
     /*
-     * Choose an adequate terminal front-end to load, and load it
+     * 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.
      */
-    Status = STATUS_SUCCESS;
-    for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i)
-    {
-        DPRINT("CONSRV: Trying to load %s terminal emulator...\n", FrontEndLoadingMethods[i].FrontEndName);
-        Status = FrontEndLoadingMethods[i].FrontEndLoad(&FrontEnd,
-                                                        &ConsoleInfo,
-                                                        ConsoleStartInfo,
-                                                        ConsoleLeaderProcessId);
-        if (NT_SUCCESS(Status))
-        {
-            DPRINT("CONSRV: %s terminal emulator loaded successfully\n", FrontEndLoadingMethods[i].FrontEndName);
-            break;
-        }
-        else
+    // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
+    {
+        if (!LoadShellLinkConsoleInfo(&ConsoleInfo, ConsoleInitInfo))
         {
-            DPRINT1("CONSRV: Loading %s terminal emulator failed, Status = 0x%08lx , continuing...\n", FrontEndLoadingMethods[i].FrontEndName, Status);
+            ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
         }
     }
 
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
-        return Status;
-    }
-
-    DPRINT("CONSRV: Frontend initialized\n");
-
-
-/******************************************************************************/
     /*
      * 4. Load the remaining console settings via the registry.
      */
-    if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+    if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
     {
         /*
          * Either we weren't created by an app launched via a shell-link,
@@ -236,47 +570,137 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
          * (and which was transmitted via the ConsoleStartInfo structure).
          * We therefore overwrite the values read in the registry.
          */
-        if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
+        if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
         {
-            ConsoleInfo.ScreenAttrib = (USHORT)ConsoleStartInfo->wFillAttribute;
+            ConsoleInfo.ScreenAttrib = (USHORT)ConsoleInitInfo->ConsoleStartInfo->wFillAttribute;
         }
-        if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
+        if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
         {
-            ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->dwScreenBufferSize;
+            ConsoleInfo.ScreenBufferSize = ConsoleInitInfo->ConsoleStartInfo->dwScreenBufferSize;
         }
-        if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
+        if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
         {
-            ConsoleInfo.ConsoleSize = ConsoleStartInfo->dwWindowSize;
+            ConsoleInfo.ConsoleSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize;
         }
     }
 
     /* Set-up the code page */
     ConsoleInfo.CodePage = GetOEMCP();
-/******************************************************************************/
 
-    Status = ConDrvInitConsole(&ConsoleHandle,
-                               &Console,
-                               &ConsoleInfo,
-                               ConsoleLeaderProcessId);
+    /* Initialize a new console via the driver */
+    Status = ConDrvInitConsole(&Console, &ConsoleInfo);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status);
-        FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
+        ConSrvDeinitTerminal(&Terminal);
         return Status;
     }
 
     ASSERT(Console);
     DPRINT("Console initialized\n");
 
-    Status = ConDrvRegisterFrontEnd(Console, &FrontEnd);
+    /*** Register ConSrv features ***/
+
+    /* Initialize the console title */
+#if 0
+    WCHAR DefaultTitle[128];
+#endif
+    ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
+#if 0
+    if (ConsoleInfo.ConsoleTitle[0] == L'\0')
+    {
+        if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0])))
+        {
+            ConsoleCreateUnicodeString(&Console->Title, DefaultTitle);
+        }
+        else
+        {
+            ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console");
+        }
+    }
+    else
+    {
+#endif
+        ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
+#if 0
+    }
+#endif
+
+    /* Initialize process support */
+    InitializeListHead(&Console->ProcessList);
+    Console->NotifiedLastCloseProcess = NULL;
+    Console->NotifyLastClose = FALSE;
+
+    /* Initialize pausing support */
+    Console->PauseFlags = 0;
+    InitializeListHead(&Console->ReadWaitQueue);
+    InitializeListHead(&Console->WriteWaitQueue);
+
+    /* Initialize the alias and history buffers */
+    Console->Aliases = NULL;
+    InitializeListHead(&Console->HistoryBuffers);
+    Console->HistoryBufferSize      = ConsoleInfo.HistoryBufferSize;
+    Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
+    Console->HistoryNoDup           = ConsoleInfo.HistoryNoDup;
+
+    /* Initialize the Input Line Discipline */
+    Console->LineBuffer = NULL;
+    Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
+    Console->LineComplete = Console->LineUpPressed = FALSE;
+    // LineWakeupMask
+    Console->LineInsertToggle =
+    Console->InsertMode = ConsoleInfo.InsertMode;
+    Console->QuickEdit  = ConsoleInfo.QuickEdit;
+
+    /* Popup windows */
+    InitializeListHead(&Console->PopupWindows);
+
+    /* Colour table */
+    memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
+
+    /* Create the Initialization Events */
+    Status = NtCreateEvent(&Console->InitEvents[INIT_SUCCESS], EVENT_ALL_ACCESS,
+                           NULL, NotificationEvent, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
+        ConDrvDeleteConsole(Console);
+        ConSrvDeinitTerminal(&Terminal);
+        return Status;
+    }
+    Status = NtCreateEvent(&Console->InitEvents[INIT_FAILURE], EVENT_ALL_ACCESS,
+                           NULL, NotificationEvent, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
+        NtClose(Console->InitEvents[INIT_SUCCESS]);
+        ConDrvDeleteConsole(Console);
+        ConSrvDeinitTerminal(&Terminal);
+        return Status;
+    }
+
+    /*
+     * Attach the ConSrv terminal to the console.
+     * This call makes a copy of our local Terminal variable.
+     */
+    Status = ConDrvRegisterTerminal(Console, &Terminal);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to register frontend to the given console, Status = 0x%08lx\n", Status);
+        DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status);
+        NtClose(Console->InitEvents[INIT_FAILURE]);
+        NtClose(Console->InitEvents[INIT_SUCCESS]);
         ConDrvDeleteConsole(Console);
-        FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
+        ConSrvDeinitTerminal(&Terminal);
         return Status;
     }
-    DPRINT("FrontEnd registered\n");
+    DPRINT("Terminal registered\n");
+
+    /* All went right, so add the console to the list */
+    Status = InsertConsole(&ConsoleHandle, Console);
+
+    // FIXME! We do not support at all asynchronous console creation!
+    NtSetEvent(Console->InitEvents[INIT_SUCCESS], NULL);
+    // NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL);
 
     /* Return the newly created console to the caller and a success code too */
     *NewConsoleHandle = ConsoleHandle;
@@ -285,12 +709,174 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
 }
 
 VOID NTAPI
-ConSrvDeleteConsole(PCONSOLE Console)
+ConSrvDeleteConsole(PCONSRV_CONSOLE Console)
 {
     DPRINT("ConSrvDeleteConsole\n");
 
-    /* Just call the driver. ConSrvDeregisterFrontEnd is called on-demand. */
-    ConDrvDeleteConsole(Console);
+    // FIXME: Send a terminate message to all the processes owning this console
+
+    /* Remove the console from the list */
+    RemoveConsoleByPointer(Console);
+
+    /* Destroy the Initialization Events */
+    NtClose(Console->InitEvents[INIT_FAILURE]);
+    NtClose(Console->InitEvents[INIT_SUCCESS]);
+
+    /* Clean the Input Line Discipline */
+    if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer);
+
+    /* Clean aliases and history */
+    IntDeleteAllAliases(Console);
+    HistoryDeleteBuffers(Console);
+
+    /* Free the console title */
+    ConsoleFreeUnicodeString(&Console->OriginalTitle);
+    ConsoleFreeUnicodeString(&Console->Title);
+
+    /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */
+    ConDrvDeleteConsole((PCONSOLE)Console);
+
+    /* Deinit the ConSrv terminal */
+    // FIXME!!
+    // ConSrvDeinitTerminal(&Terminal);
+}
+
+
+
+
+
+
+static NTSTATUS
+ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
+                              IN PCONSOLE_PROCESS_DATA ProcessData,
+                              IN ULONG Timeout)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
+
+    if (ProcessData->CtrlRoutine)
+    {
+        _SEH2_TRY
+        {
+            HANDLE Thread = NULL;
+
+            _SEH2_TRY
+            {
+                Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
+                                            ProcessData->CtrlRoutine,
+                                            UlongToPtr(CtrlEvent), 0, NULL);
+                if (NULL == Thread)
+                {
+                    Status = RtlGetLastNtStatus();
+                    DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status);
+                }
+                else
+                {
+                    DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
+                           ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
+                    WaitForSingleObject(Thread, Timeout);
+                }
+            }
+            _SEH2_FINALLY
+            {
+                CloseHandle(Thread);
+            }
+            _SEH2_END;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+            DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status);
+        }
+        _SEH2_END;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent,
+                       IN PCONSOLE_PROCESS_DATA ProcessData)
+{
+    return ConSrvConsoleCtrlEventTimeout(CtrlEvent, ProcessData, 0);
+}
+
+PCONSOLE_PROCESS_DATA NTAPI
+ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console)
+{
+    if (Console == NULL) return NULL;
+
+    return CONTAINING_RECORD(Console->ProcessList.Blink,
+                             CONSOLE_PROCESS_DATA,
+                             ConsoleLink);
+}
+
+NTSTATUS NTAPI
+ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console,
+                            IN OUT PULONG ProcessIdsList,
+                            IN ULONG MaxIdListItems,
+                            OUT PULONG ProcessIdsTotal)
+{
+    PCONSOLE_PROCESS_DATA current;
+    PLIST_ENTRY current_entry;
+
+    if (Console == NULL || ProcessIdsList == NULL || ProcessIdsTotal == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    *ProcessIdsTotal = 0;
+
+    for (current_entry = Console->ProcessList.Flink;
+         current_entry != &Console->ProcessList;
+         current_entry = current_entry->Flink)
+    {
+        current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
+        if (++(*ProcessIdsTotal) <= MaxIdListItems)
+        {
+            *ProcessIdsList++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+// ConSrvGenerateConsoleCtrlEvent
+NTSTATUS NTAPI
+ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console,
+                              IN ULONG ProcessGroupId,
+                              IN ULONG CtrlEvent)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PLIST_ENTRY current_entry;
+    PCONSOLE_PROCESS_DATA current;
+
+    /* If the console is already being destroyed, just return */
+    if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING))
+        return STATUS_UNSUCCESSFUL;
+
+    /*
+     * Loop through the process list, from the most recent process
+     * (the active one) to the oldest one (the first created, i.e.
+     * the console leader process), and for each, send an event
+     * (new processes are inserted at the head of the console process list).
+     */
+    current_entry = Console->ProcessList.Flink;
+    while (current_entry != &Console->ProcessList)
+    {
+        current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
+        current_entry = current_entry->Flink;
+
+        /*
+         * Only processes belonging to the same process group are signaled.
+         * If the process group ID is zero, then all the processes are signaled.
+         */
+        if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId)
+        {
+            Status = ConSrvConsoleCtrlEvent(CtrlEvent, current);
+        }
+    }
+
+    return Status;
 }
 
 
@@ -302,6 +888,7 @@ CSR_API(SrvAllocConsole)
     PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
     PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
+    CONSOLE_INIT_INFO ConsoleInitInfo;
 
     if (ProcessData->ConsoleHandle != NULL)
     {
@@ -309,33 +896,57 @@ CSR_API(SrvAllocConsole)
         return STATUS_ACCESS_DENIED;
     }
 
-    if (!CsrValidateMessageBuffer(ApiMessage,
-                                  (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
-                                  1,
-                                  sizeof(CONSOLE_START_INFO)))
+    if ( !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
+                                   1,
+                                   sizeof(CONSOLE_START_INFO))      ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&AllocConsoleRequest->ConsoleTitle,
+                                   AllocConsoleRequest->TitleLength,
+                                   sizeof(BYTE))                    ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&AllocConsoleRequest->Desktop,
+                                   AllocConsoleRequest->DesktopLength,
+                                   sizeof(BYTE))                    ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&AllocConsoleRequest->CurDir,
+                                   AllocConsoleRequest->CurDirLength,
+                                   sizeof(BYTE))                    ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&AllocConsoleRequest->AppName,
+                                   AllocConsoleRequest->AppNameLength,
+                                   sizeof(BYTE)) )
     {
         return STATUS_INVALID_PARAMETER;
     }
 
+    /* Initialize the console initialization info structure */
+    ConsoleInitInfo.ConsoleStartInfo = AllocConsoleRequest->ConsoleStartInfo;
+    ConsoleInitInfo.IsWindowVisible  = TRUE; // The console window is always visible.
+    ConsoleInitInfo.TitleLength      = AllocConsoleRequest->TitleLength;
+    ConsoleInitInfo.ConsoleTitle     = AllocConsoleRequest->ConsoleTitle;
+    ConsoleInitInfo.DesktopLength    = AllocConsoleRequest->DesktopLength;
+    ConsoleInitInfo.Desktop          = AllocConsoleRequest->Desktop;
+    ConsoleInitInfo.AppNameLength    = AllocConsoleRequest->AppNameLength;
+    ConsoleInitInfo.AppName          = AllocConsoleRequest->AppName;
+    ConsoleInitInfo.CurDirLength     = AllocConsoleRequest->CurDirLength;
+    ConsoleInitInfo.CurDir           = AllocConsoleRequest->CurDir;
+
     /* Initialize a new Console owned by the Console Leader Process */
     Status = ConSrvAllocateConsole(ProcessData,
-                                   &AllocConsoleRequest->InputHandle,
-                                   &AllocConsoleRequest->OutputHandle,
-                                   &AllocConsoleRequest->ErrorHandle,
-                                   AllocConsoleRequest->ConsoleStartInfo);
+                                   &AllocConsoleRequest->ConsoleStartInfo->InputHandle,
+                                   &AllocConsoleRequest->ConsoleStartInfo->OutputHandle,
+                                   &AllocConsoleRequest->ConsoleStartInfo->ErrorHandle,
+                                   &ConsoleInitInfo);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Console allocation failed\n");
         return Status;
     }
 
-    /* Return the console handle and the input wait handle to the caller */
-    AllocConsoleRequest->ConsoleHandle   = ProcessData->ConsoleHandle;
-    AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
-
     /* Set the Property-Dialog and Control-Dispatcher handlers */
-    ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
-    ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
+    ProcessData->PropRoutine = AllocConsoleRequest->PropRoutine;
+    ProcessData->CtrlRoutine = AllocConsoleRequest->CtrlRoutine;
 
     return STATUS_SUCCESS;
 }
@@ -357,6 +968,14 @@ CSR_API(SrvAttachConsole)
         return STATUS_ACCESS_DENIED;
     }
 
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&AttachConsoleRequest->ConsoleStartInfo,
+                                  1,
+                                  sizeof(CONSOLE_START_INFO)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /* Check whether we try to attach to the parent's console */
     if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
     {
@@ -371,7 +990,7 @@ CSR_API(SrvAttachConsole)
                                            Length, &Length);
         if (!NT_SUCCESS(Status))
         {
-            DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
+            DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = 0x%08lx\n", Status);
             return Status;
         }
 
@@ -397,22 +1016,19 @@ CSR_API(SrvAttachConsole)
     Status = ConSrvInheritConsole(TargetProcessData,
                                   SourceProcessData->ConsoleHandle,
                                   TRUE,
-                                  &AttachConsoleRequest->InputHandle,
-                                  &AttachConsoleRequest->OutputHandle,
-                                  &AttachConsoleRequest->ErrorHandle);
+                                  &AttachConsoleRequest->ConsoleStartInfo->InputHandle,
+                                  &AttachConsoleRequest->ConsoleStartInfo->OutputHandle,
+                                  &AttachConsoleRequest->ConsoleStartInfo->ErrorHandle,
+                                  AttachConsoleRequest->ConsoleStartInfo);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Console inheritance failed\n");
         goto Quit;
     }
 
-    /* Return the console handle and the input wait handle to the caller */
-    AttachConsoleRequest->ConsoleHandle   = TargetProcessData->ConsoleHandle;
-    AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
-
     /* Set the Property-Dialog and Control-Dispatcher handlers */
-    TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
-    TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
+    TargetProcessData->PropRoutine = AttachConsoleRequest->PropRoutine;
+    TargetProcessData->CtrlRoutine = AttachConsoleRequest->CtrlRoutine;
 
     Status = STATUS_SUCCESS;
 
@@ -424,8 +1040,7 @@ Quit:
 
 CSR_API(SrvFreeConsole)
 {
-    ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
-    return STATUS_SUCCESS;
+    return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
 }
 
 NTSTATUS NTAPI
@@ -438,13 +1053,34 @@ CSR_API(SrvGetConsoleMode)
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
     PCONSOLE_IO_OBJECT Object;
 
+    PULONG ConsoleMode = &ConsoleModeRequest->Mode;
+
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                              ConsoleModeRequest->Handle,
                              &Object, NULL, GENERIC_READ, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
+    /* Get the standard console modes */
     Status = ConDrvGetConsoleMode(Object->Console, Object,
-                                  &ConsoleModeRequest->Mode);
+                                  ConsoleMode);
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * If getting the console modes succeeds, then retrieve
+         * the extended CONSRV-specific input modes.
+         */
+        if (INPUT_BUFFER == Object->Type)
+        {
+            if (Object->Console->InsertMode || Object->Console->QuickEdit)
+            {
+                /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
+                *ConsoleMode |= ENABLE_EXTENDED_FLAGS;
+
+                if (Object->Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
+                if (Object->Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
+            }
+        }
+    }
 
     ConSrvReleaseObject(Object, TRUE);
     return Status;
@@ -456,32 +1092,63 @@ ConDrvSetConsoleMode(IN PCONSOLE Console,
                      IN ULONG ConsoleMode);
 CSR_API(SrvSetConsoleMode)
 {
+#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
+                                      ENABLE_INSERT_MODE    | ENABLE_QUICK_EDIT_MODE )
+
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
     PCONSOLE_IO_OBJECT Object;
 
+    ULONG ConsoleMode = ConsoleModeRequest->Mode;
+
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                              ConsoleModeRequest->Handle,
                              &Object, NULL, GENERIC_WRITE, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
+    /* Set the standard console modes (without the CONSRV-specific input modes) */
+    ConsoleMode &= ~CONSOLE_VALID_CONTROL_MODES; // Remove CONSRV-specific input modes.
     Status = ConDrvSetConsoleMode(Object->Console, Object,
-                                  ConsoleModeRequest->Mode);
+                                  ConsoleMode);
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * If setting the console modes succeeds, then set
+         * the extended CONSRV-specific input modes.
+         */
+        if (INPUT_BUFFER == Object->Type)
+        {
+            ConsoleMode = ConsoleModeRequest->Mode;
+
+            if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
+            {
+                /*
+                 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
+                 * then consider the flags invalid.
+                 */
+                if ((ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0)
+                {
+                    Status = STATUS_INVALID_PARAMETER;
+                }
+                else
+                {
+                    Object->Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
+                    Object->Console->QuickEdit  = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
+                }
+            }
+        }
+    }
 
     ConSrvReleaseObject(Object, TRUE);
     return Status;
 }
 
-NTSTATUS NTAPI
-ConDrvGetConsoleTitle(IN PCONSOLE Console,
-                      IN BOOLEAN Unicode,
-                      IN OUT PVOID TitleBuffer,
-                      IN OUT PULONG BufLength);
 CSR_API(SrvGetConsoleTitle)
 {
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
+    ULONG Length;
 
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&TitleRequest->Title,
@@ -498,25 +1165,51 @@ CSR_API(SrvGetConsoleTitle)
         return Status;
     }
 
-    Status = ConDrvGetConsoleTitle(Console,
-                                   TitleRequest->Unicode,
-                                   TitleRequest->Title,
-                                   &TitleRequest->Length);
+    /* Copy title of the console to the user title buffer */
+    if (TitleRequest->Unicode)
+    {
+        if (TitleRequest->Length >= sizeof(WCHAR))
+        {
+            Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
+            RtlCopyMemory(TitleRequest->Title, Console->Title.Buffer, Length);
+            ((PWCHAR)TitleRequest->Title)[Length / sizeof(WCHAR)] = L'\0';
+            TitleRequest->Length = Length;
+        }
+        else
+        {
+            TitleRequest->Length = Console->Title.Length;
+        }
+    }
+    else
+    {
+        if (TitleRequest->Length >= sizeof(CHAR))
+        {
+            Length = min(TitleRequest->Length - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
+            Length = WideCharToMultiByte(Console->InputCodePage, 0,
+                                         Console->Title.Buffer, Length,
+                                         TitleRequest->Title, Length,
+                                         NULL, NULL);
+            ((PCHAR)TitleRequest->Title)[Length] = '\0';
+            TitleRequest->Length = Length;
+        }
+        else
+        {
+            TitleRequest->Length = Console->Title.Length / sizeof(WCHAR);
+        }
+    }
 
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
 
-NTSTATUS NTAPI
-ConDrvSetConsoleTitle(IN PCONSOLE Console,
-                      IN BOOLEAN Unicode,
-                      IN PVOID TitleBuffer,
-                      IN ULONG BufLength);
 CSR_API(SrvSetConsoleTitle)
 {
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
+
+    PWCHAR Buffer;
+    ULONG  Length;
 
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&TitleRequest->Title,
@@ -533,12 +1226,56 @@ CSR_API(SrvSetConsoleTitle)
         return Status;
     }
 
-    Status = ConDrvSetConsoleTitle(Console,
-                                   TitleRequest->Unicode,
-                                   TitleRequest->Title,
-                                   TitleRequest->Length);
-    if (NT_SUCCESS(Status)) TermChangeTitle(Console);
+    if (TitleRequest->Unicode)
+    {
+        /* Length is in bytes */
+        Length = TitleRequest->Length;
+    }
+    else
+    {
+        /* Use the console input CP for the conversion */
+        Length = MultiByteToWideChar(Console->InputCodePage, 0,
+                                     TitleRequest->Title, TitleRequest->Length,
+                                     NULL, 0);
+        /* The returned Length was in number of wchars, convert it in bytes */
+        Length *= sizeof(WCHAR);
+    }
+
+    /* Allocate a new buffer to hold the new title (NULL-terminated) */
+    Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
+    if (!Buffer)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quit;
+    }
+
+    /* Free the old title */
+    ConsoleFreeUnicodeString(&Console->Title);
+
+    /* Copy title to console */
+    Console->Title.Buffer = Buffer;
+    Console->Title.Length = Length;
+    Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
+
+    if (TitleRequest->Unicode)
+    {
+        RtlCopyMemory(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length);
+    }
+    else
+    {
+        MultiByteToWideChar(Console->InputCodePage, 0,
+                            TitleRequest->Title, TitleRequest->Length,
+                            Console->Title.Buffer,
+                            Console->Title.Length / sizeof(WCHAR));
+    }
+
+    /* NULL-terminate */
+    Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
 
+    TermChangeTitle(Console);
+    Status = STATUS_SUCCESS;
+
+Quit:
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
@@ -551,7 +1288,7 @@ CSR_API(SrvGetConsoleCP)
 {
     NTSTATUS Status;
     PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCPRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
             GetConsoleCPRequest->OutputCP ? "Output" : "Input");
@@ -575,7 +1312,7 @@ CSR_API(SrvSetConsoleCP)
 {
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
     PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCPRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
             SetConsoleCPRequest->OutputCP ? "Output" : "Input");
@@ -591,16 +1328,11 @@ CSR_API(SrvSetConsoleCP)
     return Status;
 }
 
-NTSTATUS NTAPI
-ConDrvGetConsoleProcessList(IN PCONSOLE Console,
-                            IN OUT PULONG ProcessIdsList,
-                            IN ULONG MaxIdListItems,
-                            OUT PULONG ProcessIdsTotal);
 CSR_API(SrvGetConsoleProcessList)
 {
     NTSTATUS Status;
     PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&GetProcessListRequest->ProcessIdsList,
@@ -613,7 +1345,7 @@ CSR_API(SrvGetConsoleProcessList)
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
-    Status = ConDrvGetConsoleProcessList(Console,
+    Status = ConSrvGetConsoleProcessList(Console,
                                          GetProcessListRequest->ProcessIdsList,
                                          GetProcessListRequest->ProcessCount,
                                          &GetProcessListRequest->ProcessCount);
@@ -626,12 +1358,12 @@ CSR_API(SrvGenerateConsoleCtrlEvent)
 {
     NTSTATUS Status;
     PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
-    Status = ConDrvConsoleProcessCtrlEvent(Console,
+    Status = ConSrvConsoleProcessCtrlEvent(Console,
                                            GenerateCtrlEventRequest->ProcessGroupId,
                                            GenerateCtrlEventRequest->CtrlEvent);
 
@@ -643,7 +1375,7 @@ CSR_API(SrvConsoleNotifyLastClose)
 {
     NTSTATUS Status;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
@@ -668,8 +1400,18 @@ CSR_API(SrvConsoleNotifyLastClose)
 
 CSR_API(SrvGetConsoleMouseInfo)
 {
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PCONSOLE_GETMOUSEINFO GetMouseInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetMouseInfoRequest;
+    PCONSRV_CONSOLE Console;
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Just retrieve the number of buttons of the mouse attached to this console */
+    GetMouseInfoRequest->NumButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return STATUS_SUCCESS;
 }
 
 CSR_API(SrvSetConsoleKeyShortcuts)
@@ -680,8 +1422,21 @@ CSR_API(SrvSetConsoleKeyShortcuts)
 
 CSR_API(SrvGetConsoleKeyboardLayoutName)
 {
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetKbdLayoutNameRequest;
+    PCONSRV_CONSOLE Console;
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Retrieve the keyboard layout name of the system */
+    if (GetKbdLayoutNameRequest->Ansi)
+        GetKeyboardLayoutNameA((PCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
+    else
+        GetKeyboardLayoutNameW((PWCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return STATUS_SUCCESS;
 }
 
 CSR_API(SrvGetConsoleCharType)