[CONSRV]: More code cleaning.
[reactos.git] / win32ss / user / winsrv / consrv / console.c
index e7bbc9e..444631e 100644 (file)
 
 #include "consrv.h"
 
-#include <ndk/psfuncs.h>
+/* This is for COM usage */
+#define COBJMACROS
+#include <shlobj.h>
+
 
 #include <alias.h>
+#include <history.h>
 #include "procinit.h"
 
 #define NDEBUG
@@ -25,8 +29,9 @@ NTSTATUS NTAPI RtlGetLastNtStatus(VOID);
 
 /* GLOBALS ********************************************************************/
 
+/* The list of the ConSrv consoles */
 static ULONG ConsoleListSize;
-static PCONSOLE* ConsoleList;   /* The list of the ConSrv consoles */
+static PCONSRV_CONSOLE* ConsoleList;
 static RTL_RESOURCE ListLock;
 
 #define ConSrvLockConsoleListExclusive()    \
@@ -41,20 +46,20 @@ static RTL_RESOURCE ListLock;
 
 static NTSTATUS
 InsertConsole(OUT PHANDLE Handle,
-              IN PCONSOLE Console)
+              IN PCONSRV_CONSOLE Console)
 {
 #define CONSOLE_HANDLES_INCREMENT   2 * 3
 
     NTSTATUS Status = STATUS_SUCCESS;
     ULONG i = 0;
-    PCONSOLE* Block;
+    PCONSRV_CONSOLE* Block;
 
     ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
             (ConsoleList != NULL && ConsoleListSize != 0) );
 
     /* All went right, so add the console to the list */
     ConSrvLockConsoleListExclusive();
-    DPRINT1("Insert in the list\n");
+    DPRINT("Insert in the list\n");
 
     if (ConsoleList)
     {
@@ -66,11 +71,11 @@ InsertConsole(OUT PHANDLE Handle,
 
     if (i >= ConsoleListSize)
     {
-        DPRINT1("Creation of a new handles table\n");
+        DPRINT("Creation of a new handles table\n");
         /* Allocate a new handles table */
         Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
                                  (ConsoleListSize +
-                                    CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSOLE));
+                                    CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSRV_CONSOLE));
         if (Block == NULL)
         {
             Status = STATUS_UNSUCCESSFUL;
@@ -83,7 +88,7 @@ InsertConsole(OUT PHANDLE Handle,
             /* Copy the handles from the old table to the new one */
             RtlCopyMemory(Block,
                           ConsoleList,
-                          ConsoleListSize * sizeof(PCONSOLE));
+                          ConsoleListSize * sizeof(PCONSRV_CONSOLE));
             ConsoleFreeHeap(ConsoleList);
         }
         ConsoleList = Block;
@@ -105,7 +110,7 @@ static NTSTATUS
 RemoveConsoleByHandle(IN HANDLE Handle)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     BOOLEAN ValidHandle = ((HandleToULong(Handle) & 0x3) == 0x3);
     ULONG Index = HandleToULong(Handle) >> 2;
@@ -135,7 +140,7 @@ Quit:
 #endif
 
 static NTSTATUS
-RemoveConsoleByPointer(IN PCONSOLE Console)
+RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console)
 {
     ULONG i = 0;
 
@@ -155,20 +160,19 @@ RemoveConsoleByPointer(IN PCONSOLE Console)
         }
     }
 
-    /* Unlock the console list */
+    /* Unlock the console list and return */
     ConSrvUnlockConsoleList();
-
     return STATUS_SUCCESS;
 }
 
 BOOLEAN NTAPI
-ConSrvValidateConsole(OUT PCONSOLE* Console,
+ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console,
                       IN HANDLE ConsoleHandle,
                       IN CONSOLE_STATE ExpectedState,
                       IN BOOLEAN LockConsole)
 {
     BOOLEAN RetVal = FALSE;
-    PCONSOLE ValidatedConsole;
+    PCONSRV_CONSOLE ValidatedConsole;
 
     BOOLEAN ValidHandle = ((HandleToULong(ConsoleHandle) & 0x3) == 0x3);
     ULONG Index = HandleToULong(ConsoleHandle) >> 2;
@@ -187,9 +191,8 @@ ConSrvValidateConsole(OUT PCONSOLE* Console,
     if (Index >= ConsoleListSize ||
         (ValidatedConsole = ConsoleList[Index]) == NULL)
     {
-        /* Unlock the console list */
+        /* Unlock the console list and return */
         ConSrvUnlockConsoleList();
-
         return FALSE;
     }
 
@@ -198,7 +201,7 @@ ConSrvValidateConsole(OUT PCONSOLE* Console,
     /* Unlock the console list and return */
     ConSrvUnlockConsoleList();
 
-    RetVal = ConDrvValidateConsoleUnsafe(ValidatedConsole,
+    RetVal = ConDrvValidateConsoleUnsafe((PCONSOLE)ValidatedConsole,
                                          ExpectedState,
                                          LockConsole);
     if (RetVal) *Console = ValidatedConsole;
@@ -209,22 +212,51 @@ ConSrvValidateConsole(OUT PCONSOLE* Console,
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
+// 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(PCONSOLE Console, UINT Flags)
+ConioPause(PCONSRV_CONSOLE Console, UINT Flags)
 {
     Console->PauseFlags |= Flags;
-    ConDrvPause(Console);
+    ConDrvPause((PCONSOLE)Console);
 }
 
 VOID
-ConioUnpause(PCONSOLE Console, UINT Flags)
+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)
     {
-        ConDrvUnpause(Console);
+        ConDrvUnpause((PCONSOLE)Console);
 
         CsrNotifyWait(&Console->WriteWaitQueue,
                       TRUE,
@@ -239,18 +271,16 @@ ConioUnpause(PCONSOLE Console, UINT Flags)
 
 NTSTATUS
 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData,
-                 OUT PCONSOLE* Console,
+                 OUT PCONSRV_CONSOLE* Console,
                  IN BOOLEAN LockConsole)
 {
     NTSTATUS Status = STATUS_INVALID_HANDLE;
-    PCONSOLE GrabConsole;
+    PCONSRV_CONSOLE GrabConsole;
 
     // if (Console == NULL) return STATUS_INVALID_PARAMETER;
     ASSERT(Console);
     *Console = NULL;
 
-    // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-
     if (ConSrvValidateConsole(&GrabConsole,
                               ProcessData->ConsoleHandle,
                               CONSOLE_RUNNING,
@@ -261,12 +291,11 @@ ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData,
         Status = STATUS_SUCCESS;
     }
 
-    // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
     return Status;
 }
 
 VOID
-ConSrvReleaseConsole(IN PCONSOLE Console,
+ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console,
                      IN BOOLEAN WasConsoleLocked)
 {
     LONG RefCount = 0;
@@ -317,21 +346,168 @@ ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
 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;
 
     TERMINAL Terminal; /* The ConSrv terminal for this console */
 
-    if (NewConsole == NULL || ConsoleStartInfo == NULL)
+    if (NewConsole == NULL || ConsoleInitInfo == NULL)
         return STATUS_INVALID_PARAMETER;
 
     *NewConsole = NULL;
@@ -344,15 +520,15 @@ 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,
-                                ConsoleStartInfo,
+                                ConsoleInitInfo,
                                 ConsoleLeaderProcessId);
     if (!NT_SUCCESS(Status))
     {
@@ -361,10 +537,25 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     }
     DPRINT("CONSRV: Terminal initialized\n");
 
+    /*
+     * Load per-application terminal settings.
+     *
+     * Check whether the process creating the console was launched via
+     * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
+     * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
+     */
+    // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
+    {
+        if (!LoadShellLinkConsoleInfo(&ConsoleInfo, ConsoleInitInfo))
+        {
+            ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
+        }
+    }
+
     /*
      * 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,
@@ -379,17 +570,17 @@ 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;
         }
     }
 
@@ -410,6 +601,31 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
 
     /*** 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;
@@ -427,13 +643,52 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
     Console->HistoryNoDup           = ConsoleInfo.HistoryNoDup;
 
-    Console->QuickEdit = ConsoleInfo.QuickEdit;
+    /* 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));
 
-    /* Attach the ConSrv terminal to the console */
+    /* 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 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;
@@ -443,6 +698,10 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     /* 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;
     *NewConsole       = Console;
@@ -450,7 +709,7 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
 }
 
 VOID NTAPI
-ConSrvDeleteConsole(PCONSOLE Console)
+ConSrvDeleteConsole(PCONSRV_CONSOLE Console)
 {
     DPRINT("ConSrvDeleteConsole\n");
 
@@ -459,12 +718,27 @@ ConSrvDeleteConsole(PCONSOLE 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(Console);
+    ConDrvDeleteConsole((PCONSOLE)Console);
+
+    /* Deinit the ConSrv terminal */
+    // FIXME!!
+    // ConSrvDeinitTerminal(&Terminal);
 }
 
 
@@ -481,7 +755,7 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
 
     DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
 
-    if (ProcessData->CtrlDispatcher)
+    if (ProcessData->CtrlRoutine)
     {
         _SEH2_TRY
         {
@@ -490,7 +764,7 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
             _SEH2_TRY
             {
                 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
-                                            ProcessData->CtrlDispatcher,
+                                            ProcessData->CtrlRoutine,
                                             UlongToPtr(CtrlEvent), 0, NULL);
                 if (NULL == Thread)
                 {
@@ -499,7 +773,8 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
                 }
                 else
                 {
-                    DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
+                    DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
+                           ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
                     WaitForSingleObject(Thread, Timeout);
                 }
             }
@@ -528,7 +803,7 @@ ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent,
 }
 
 PCONSOLE_PROCESS_DATA NTAPI
-ConSrvGetConsoleLeaderProcess(IN PCONSOLE Console)
+ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console)
 {
     if (Console == NULL) return NULL;
 
@@ -538,7 +813,7 @@ ConSrvGetConsoleLeaderProcess(IN PCONSOLE Console)
 }
 
 NTSTATUS NTAPI
-ConSrvGetConsoleProcessList(IN PCONSOLE Console,
+ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console,
                             IN OUT PULONG ProcessIdsList,
                             IN ULONG MaxIdListItems,
                             OUT PULONG ProcessIdsTotal)
@@ -567,7 +842,7 @@ ConSrvGetConsoleProcessList(IN PCONSOLE Console,
 
 // ConSrvGenerateConsoleCtrlEvent
 NTSTATUS NTAPI
-ConSrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
+ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console,
                               IN ULONG ProcessGroupId,
                               IN ULONG CtrlEvent)
 {
@@ -576,7 +851,7 @@ ConSrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
     PCONSOLE_PROCESS_DATA current;
 
     /* If the console is already being destroyed, just return */
-    if (!ConDrvValidateConsoleState(Console, CONSOLE_RUNNING))
+    if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING))
         return STATUS_UNSUCCESSFUL;
 
     /*
@@ -605,9 +880,6 @@ ConSrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
 }
 
 
-
-
-
 /* PUBLIC SERVER APIS *********************************************************/
 
 CSR_API(SrvAllocConsole)
@@ -616,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)
     {
@@ -623,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->InputWaitHandle;
-
     /* 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;
 }
@@ -671,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))
     {
@@ -685,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;
         }
 
@@ -711,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->InputWaitHandle;
-
     /* 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;
 
@@ -738,8 +1040,7 @@ Quit:
 
 CSR_API(SrvFreeConsole)
 {
-    ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
-    return STATUS_SUCCESS;
+    return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
 }
 
 NTSTATUS NTAPI
@@ -752,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;
@@ -770,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,
@@ -812,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,
@@ -847,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;
 }
@@ -865,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");
@@ -889,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");
@@ -909,7 +1332,7 @@ 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,
@@ -935,7 +1358,7 @@ 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;
@@ -952,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;
@@ -977,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)
@@ -989,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)