[NTDLL]
[reactos.git] / reactos / win32ss / user / winsrv / consrv / console.c
index 0b7e2fa..b45828e 100644 (file)
 /* INCLUDES *******************************************************************/
 
 #include "consrv.h"
-#include "include/conio.h"
-#include "include/conio2.h"
-#include "handle.h"
-#include "procinit.h"
-#include "alias.h"
-#include "coninput.h"
-#include "conoutput.h"
-#include "lineinput.h"
-#include "include/settings.h"
-
-#include "frontends/gui/guiterm.h"
-#ifdef TUITERM_COMPILE
-#include "frontends/tui/tuiterm.h"
-#endif
 
-#include "include/console.h"
-#include "console.h"
-#include "resource.h"
+/* This is for COM usage */
+#define COBJMACROS
+#include <shlobj.h>
+
+
+#include <alias.h>
+#include <history.h>
+#include "procinit.h"
 
 #define NDEBUG
 #include <debug.h>
 
 /* 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,
-                      WaitAll,
+                      TRUE,
                       NULL,
                       NULL);
         if (!IsListEmpty(&Console->WriteWaitQueue))
@@ -132,53 +266,266 @@ 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)
 {
-    /* Just call the driver */
-    ConDrvReleaseConsole(Console, 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);
 }
 
 
-NTSTATUS WINAPI
+/* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
+
+VOID NTAPI
+ConSrvInitConsoleSupport(VOID)
+{
+    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_STATE_INFO ConsoleInfo,
+                   IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+                   IN HANDLE ConsoleLeaderProcessHandle);
+NTSTATUS NTAPI
+ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal);
+
+
+static BOOL
+LoadShellLinkConsoleInfo(IN OUT PCONSOLE_STATE_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")
+                                 (ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR));
+                    wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
+                    ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL;
+
+                    /* 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;
+            /*
+             * FIXME!! Because of a strange bug we have in PrivateExtractIconExW
+             * (see r65683 for more details), we cannot use this API to extract
+             * at the same time the large and small icons from the app.
+             * Instead we just use PrivateExtractIconsW.
+             *
+            PrivateExtractIconExW(IconPath,
+                                  ConsoleInitInfo->ConsoleStartInfo->IconIndex,
+                                  &hIcon,
+                                  &hIconSm,
+                                  1);
+             */
+            PrivateExtractIconsW(IconPath,
+                                 ConsoleInitInfo->ConsoleStartInfo->IconIndex,
+                                 32, 32,
+                                 &hIcon, NULL, 1, LR_COPYFROMRESOURCE);
+            PrivateExtractIconsW(IconPath,
+                                 ConsoleInitInfo->ConsoleStartInfo->IconIndex,
+                                 16, 16,
+                                 &hIconSm, NULL, 1, LR_COPYFROMRESOURCE);
+
+            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,
-                  IN ULONG ConsoleLeaderProcessId)
+                  OUT PCONSRV_CONSOLE* NewConsole,
+                  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+                  IN PCSR_PROCESS ConsoleLeaderProcess)
 {
     NTSTATUS Status;
     HANDLE ConsoleHandle;
-    PCONSOLE Console;
-    CONSOLE_INFO ConsoleInfo;
+    PCONSRV_CONSOLE Console;
+
+    BYTE ConsoleInfoBuffer[sizeof(CONSOLE_STATE_INFO) + MAX_PATH * sizeof(WCHAR)]; // CONSRV console information
+    PCONSOLE_STATE_INFO ConsoleInfo = (PCONSOLE_STATE_INFO)&ConsoleInfoBuffer;
+    CONSOLE_INFO DrvConsoleInfo; // Console information for CONDRV
+
     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;
@@ -186,60 +533,48 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     /*
      * Load the console settings
      */
+    RtlZeroMemory(ConsoleInfo, sizeof(ConsoleInfoBuffer));
+    ConsoleInfo->cbSize = sizeof(ConsoleInfoBuffer);
 
-    /* 1. Load the default settings */
-    ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId);
+    /* 1. Get the title of the console (initialize ConsoleInfo->ConsoleTitle) */
+    Length = min(ConsoleInitInfo->TitleLength,
+                 (ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR));
+    wcsncpy(ConsoleInfo->ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length);
+    ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL; // NULL-terminate it.
 
-    /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
-    Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
-                 sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
-    wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
-    ConsoleInfo.ConsoleTitle[Length] = L'\0';
+    /* 2. Impersonate the caller in order to retrieve settings in its context */
+    if (!CsrImpersonateClient(NULL))
+        return STATUS_BAD_IMPERSONATION_LEVEL;
 
+    /* 3. Load the default settings */
+    ConCfgGetDefaultSettings(ConsoleInfo);
 
     /*
-     * Choose an adequate terminal front-end to load, and load it
+     * 4. 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.
+     * 5. 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,
          * or we failed to load shell-link console properties.
          * Therefore, load the console infos for the application from the registry.
          */
-        ConSrvReadUserSettings(&ConsoleInfo, ConsoleLeaderProcessId);
+        ConCfgReadUserSettings(ConsoleInfo, FALSE);
 
         /*
          * Now, update them with the properties the user might gave to us
@@ -247,47 +582,184 @@ 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->ScreenAttributes = (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->WindowSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize;
         }
+
+#if 0
+        /*
+         * 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 (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
+        {
+            ConsoleInfo->AutoPosition = FALSE;
+            ConsoleInfo->WindowPosition.x = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.X;
+            ConsoleInfo->WindowPosition.y = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.Y;
+        }
+        if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
+        {
+            ConsoleInfo->FullScreen = TRUE;
+        }
+#endif
     }
 
+    /* 6. Revert impersonation */
+    CsrRevertToSelf();
+
     /* Set-up the code page */
-    ConsoleInfo.CodePage = GetOEMCP();
-/******************************************************************************/
+    ConsoleInfo->CodePage = GetOEMCP();
 
-    Status = ConDrvInitConsole(&ConsoleHandle,
-                               &Console,
-                               &ConsoleInfo,
-                               ConsoleLeaderProcessId);
+    /*
+     * Initialize the ConSrv terminal and give it a chance to load
+     * its own settings and override the console settings.
+     */
+    Status = ConSrvInitTerminal(&Terminal,
+                                ConsoleInfo,
+                                ConsoleInitInfo,
+                                ConsoleLeaderProcess->ProcessHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status);
+        return Status;
+    }
+    DPRINT("CONSRV: Terminal initialized\n");
+
+    /* Initialize a new console via the driver */
+    // DrvConsoleInfo.InputBufferSize = 0;
+    DrvConsoleInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
+    DrvConsoleInfo.ConsoleSize = ConsoleInfo->WindowSize;
+    DrvConsoleInfo.CursorSize = ConsoleInfo->CursorSize;
+    // DrvConsoleInfo.CursorBlinkOn = ConsoleInfo->CursorBlinkOn;
+    DrvConsoleInfo.ScreenAttrib = ConsoleInfo->ScreenAttributes;
+    DrvConsoleInfo.PopupAttrib = ConsoleInfo->PopupAttributes;
+    DrvConsoleInfo.CodePage = ConsoleInfo->CodePage;
+    Status = ConDrvInitConsole(&Console, &DrvConsoleInfo);
     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] == UNICODE_NULL)
+    {
+        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;
+    Console->HasFocus = 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 */
+    RtlCopyMemory(Console->Colors, ConsoleInfo->ColorTable,
+                  sizeof(ConsoleInfo->ColorTable));
+
+    /* 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("Failed to register frontend to the given console, Status = 0x%08lx\n", Status);
+        DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
+        NtClose(Console->InitEvents[INIT_SUCCESS]);
         ConDrvDeleteConsole(Console);
-        FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
+        ConSrvDeinitTerminal(&Terminal);
         return Status;
     }
-    DPRINT("FrontEnd registered\n");
+
+    /*
+     * Attach the ConSrv terminal to the console.
+     * This call makes a copy of our local Terminal variable.
+     */
+    Status = ConDrvAttachTerminal(Console, &Terminal);
+    if (!NT_SUCCESS(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);
+        ConSrvDeinitTerminal(&Terminal);
+        return Status;
+    }
+    DPRINT("Terminal attached\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;
@@ -295,13 +767,217 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     return STATUS_SUCCESS;
 }
 
-VOID WINAPI
-ConSrvDeleteConsole(PCONSOLE Console)
+VOID NTAPI
+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. ConDrvDetachTerminal 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);
+
+    /*
+     * Be sure we effectively have a control routine. It resides in kernel32.dll (client).
+     */
+    if (ProcessData->CtrlRoutine == NULL) return Status;
+
+    _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;
+}
+
+VOID
+ConSrvSetProcessFocus(IN PCSR_PROCESS CsrProcess,
+                      IN BOOLEAN SetForeground)
+{
+    // FIXME: Call NtUserSetInformationProcess (currently unimplemented!)
+    // for setting Win32 foreground/background flags.
+
+    if (SetForeground)
+        CsrSetForegroundPriority(CsrProcess);
+    else
+        CsrSetBackgroundPriority(CsrProcess);
+}
+
+NTSTATUS NTAPI
+ConSrvSetConsoleProcessFocus(IN PCONSRV_CONSOLE Console,
+                             IN BOOLEAN SetForeground)
+{
+    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
+     * to the oldest one, and for each, set its foreground priority.
+     */
+    current_entry = Console->ProcessList.Flink;
+    while (current_entry != &Console->ProcessList)
+    {
+        current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
+        current_entry = current_entry->Flink;
+
+        ConSrvSetProcessFocus(current->Process, SetForeground);
+    }
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -313,6 +989,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)
     {
@@ -320,33 +997,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;
 }
@@ -368,13 +1069,21 @@ 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))
     {
         PROCESS_BASIC_INFORMATION ProcessInfo;
         ULONG Length = sizeof(ProcessInfo);
 
-        /* Get the real parent's ID */
+        /* Get the real parent's PID */
 
         Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
                                            ProcessBasicInformation,
@@ -382,7 +1091,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;
         }
 
@@ -408,22 +1117,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;
 
@@ -435,8 +1141,7 @@ Quit:
 
 CSR_API(SrvFreeConsole)
 {
-    ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
-    return STATUS_SUCCESS;
+    return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
 }
 
 NTSTATUS NTAPI
@@ -449,13 +1154,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->ConsoleHandle,
+                             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->ConsoleMode);
+                                  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;
@@ -467,31 +1193,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->ConsoleHandle,
+                             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->ConsoleMode);
+                                  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 OUT PWCHAR Title,
-                      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,
@@ -504,27 +1262,55 @@ CSR_API(SrvGetConsoleTitle)
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
-    Status = ConDrvGetConsoleTitle(Console,
-                                   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)] = UNICODE_NULL;
+            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] = ANSI_NULL;
+            TitleRequest->Length = Length;
+        }
+        else
+        {
+            TitleRequest->Length = Console->Title.Length / sizeof(WCHAR);
+        }
+    }
 
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
 
-NTSTATUS NTAPI
-ConDrvSetConsoleTitle(IN PCONSOLE Console,
-                      IN PWCHAR Title,
-                      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,
@@ -537,16 +1323,60 @@ CSR_API(SrvSetConsoleTitle)
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
-    Status = ConDrvSetConsoleTitle(Console,
-                                   TitleRequest->Title,
-                                   TitleRequest->Length);
+    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);
 
-    if (NT_SUCCESS(Status)) ConioChangeTitle(Console);
+    /* 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)] = UNICODE_NULL;
+
+    TermChangeTitle(Console);
+    Status = STATUS_SUCCESS;
+
+Quit:
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
@@ -554,22 +1384,22 @@ CSR_API(SrvSetConsoleTitle)
 NTSTATUS NTAPI
 ConDrvGetConsoleCP(IN PCONSOLE Console,
                    OUT PUINT CodePage,
-                   IN BOOLEAN InputCP);
+                   IN BOOLEAN OutputCP);
 CSR_API(SrvGetConsoleCP)
 {
     NTSTATUS Status;
-    PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
-    PCONSOLE Console;
+    PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCPRequest;
+    PCONSRV_CONSOLE Console;
 
     DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
-            ConsoleCPRequest->InputCP ? "Input" : "Output");
+            GetConsoleCPRequest->OutputCP ? "Output" : "Input");
 
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
     Status = ConDrvGetConsoleCP(Console,
-                                &ConsoleCPRequest->CodePage,
-                                ConsoleCPRequest->InputCP);
+                                &GetConsoleCPRequest->CodePage,
+                                GetConsoleCPRequest->OutputCP);
 
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
@@ -578,41 +1408,36 @@ CSR_API(SrvGetConsoleCP)
 NTSTATUS NTAPI
 ConDrvSetConsoleCP(IN PCONSOLE Console,
                    IN UINT CodePage,
-                   IN BOOLEAN InputCP);
+                   IN BOOLEAN OutputCP);
 CSR_API(SrvSetConsoleCP)
 {
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
-    PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
-    PCONSOLE Console;
+    PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCPRequest;
+    PCONSRV_CONSOLE Console;
 
     DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
-            ConsoleCPRequest->InputCP ? "Input" : "Output");
+            SetConsoleCPRequest->OutputCP ? "Output" : "Input");
 
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
     Status = ConDrvSetConsoleCP(Console,
-                                ConsoleCPRequest->CodePage,
-                                ConsoleCPRequest->InputCP);
+                                SetConsoleCPRequest->CodePage,
+                                SetConsoleCPRequest->OutputCP);
 
     ConSrvReleaseConsole(Console, TRUE);
     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->pProcessIds,
-                                  GetProcessListRequest->nMaxIds,
+                                  (PVOID)&GetProcessListRequest->ProcessIdsList,
+                                  GetProcessListRequest->ProcessCount,
                                   sizeof(DWORD)))
     {
         return STATUS_INVALID_PARAMETER;
@@ -621,10 +1446,10 @@ CSR_API(SrvGetConsoleProcessList)
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
-    Status = ConDrvGetConsoleProcessList(Console,
-                                         GetProcessListRequest->pProcessIds,
-                                         GetProcessListRequest->nMaxIds,
-                                         &GetProcessListRequest->nProcessIdsTotal);
+    Status = ConSrvGetConsoleProcessList(Console,
+                                         GetProcessListRequest->ProcessIdsList,
+                                         GetProcessListRequest->ProcessCount,
+                                         &GetProcessListRequest->ProcessCount);
 
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
@@ -634,14 +1459,14 @@ 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,
-                                           GenerateCtrlEventRequest->ProcessGroup,
-                                           GenerateCtrlEventRequest->Event);
+    Status = ConSrvConsoleProcessCtrlEvent(Console,
+                                           GenerateCtrlEventRequest->ProcessGroupId,
+                                           GenerateCtrlEventRequest->CtrlEvent);
 
     ConSrvReleaseConsole(Console, TRUE);
     return Status;
@@ -649,16 +1474,45 @@ CSR_API(SrvGenerateConsoleCtrlEvent)
 
 CSR_API(SrvConsoleNotifyLastClose)
 {
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSRV_CONSOLE Console;
+
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Only one process is allowed to be registered for last close notification */
+    if (!Console->NotifyLastClose)
+    {
+        Console->NotifyLastClose = TRUE;
+        Console->NotifiedLastCloseProcess = ProcessData;
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        Status = STATUS_ACCESS_DENIED;
+    }
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
 }
 
 
 
 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)
@@ -669,8 +1523,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)