[BASESRV-CONSRV-WINSRV]
[reactos.git] / win32ss / user / consrv / console.c
index 7605b61..870432c 100644 (file)
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS Console Server DLL
  * FILE:            win32ss/user/consrv/console.c
- * PURPOSE:         Console I/O functions
- * PROGRAMMERS:
+ * PURPOSE:         Console Management Functions
+ * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
+
+#define COBJMACROS
+#define NONAMELESSUNION
 
 #include "consrv.h"
-#include "guiconsole.h"
-#include "tuiconsole.h"
+#include "include/conio.h"
+#include "conio.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 TUI_CONSOLE
+    #include "frontends/tui/tuiterm.h"
+#endif
+
+#include "include/console.h"
+#include "console.h"
+#include "resource.h"
+
+#include <shlwapi.h>
+#include <shlobj.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS *****************************************************************/
+/* GLOBALS ********************************************************************/
 
-/*** Taken from win32ss/user/win32csr/desktopbg.c ***/
-BOOL FASTCALL
+static LIST_ENTRY ConsoleList;  /* The list of all the allocated consoles */
+static RTL_RESOURCE ListLock;
+
+#define ConSrvLockConsoleListExclusive()    \
+    RtlAcquireResourceExclusive(&ListLock, TRUE)
+
+#define ConSrvLockConsoleListShared()       \
+    RtlAcquireResourceShared(&ListLock, TRUE)
+
+#define ConSrvUnlockConsoleList()           \
+    RtlReleaseResource(&ListLock)
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+#ifdef TUI_CONSOLE
+static BOOL
 DtbgIsDesktopVisible(VOID)
 {
-    HWND VisibleDesktopWindow = GetDesktopWindow(); // DESKTOPWNDPROC
+    return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
+}
+#endif
+
+static ULONG
+ConSrvConsoleCtrlEventTimeout(DWORD Event,
+                              PCONSOLE_PROCESS_DATA ProcessData,
+                              DWORD Timeout)
+{
+    ULONG Status = ERROR_SUCCESS;
 
-    if (VisibleDesktopWindow != NULL &&
-            !IsWindowVisible(VisibleDesktopWindow))
+    DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
+
+    if (ProcessData->CtrlDispatcher)
     {
-        VisibleDesktopWindow = NULL;
+        _SEH2_TRY
+        {
+            HANDLE Thread = NULL;
+
+            _SEH2_TRY
+            {
+                Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
+                                            ProcessData->CtrlDispatcher,
+                                            UlongToPtr(Event), 0, NULL);
+                if (NULL == Thread)
+                {
+                    Status = GetLastError();
+                    DPRINT1("Failed thread creation (Error: 0x%x)\n", Status);
+                }
+                else
+                {
+                    DPRINT("ProcessData->CtrlDispatcher 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 = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
+            DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status);
+        }
+        _SEH2_END;
     }
 
-    return VisibleDesktopWindow != NULL;
+    return Status;
 }
-/****************************************************/
 
-NTSTATUS FASTCALL
-ConioConsoleFromProcessData(PCSR_PROCESS ProcessData, PCSRSS_CONSOLE *Console)
+static ULONG
+ConSrvConsoleCtrlEvent(DWORD Event,
+                       PCONSOLE_PROCESS_DATA ProcessData)
 {
-    PCSRSS_CONSOLE ProcessConsole;
+    return ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
+}
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    ProcessConsole = ProcessData->Console;
+ULONG FASTCALL
+ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
+                              ULONG ProcessGroupId,
+                              DWORD Event)
+{
+    ULONG Status = ERROR_SUCCESS;
+    PLIST_ENTRY current_entry;
+    PCONSOLE_PROCESS_DATA current;
+
+    /* If the console is already being destroyed, just return */
+    if (!ConSrvValidateConsole(Console, CONSOLE_RUNNING, FALSE))
+        return STATUS_UNSUCCESSFUL;
 
-    if (!ProcessConsole)
+    /*
+     * 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)
     {
-        *Console = NULL;
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_INVALID_HANDLE;
+        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(Event, current);
+        }
     }
 
-    InterlockedIncrement(&ProcessConsole->ReferenceCount);
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-    EnterCriticalSection(&(ProcessConsole->Lock));
-    *Console = ProcessConsole;
-
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 VOID FASTCALL
-ConioConsoleCtrlEventTimeout(DWORD Event, PCSR_PROCESS ProcessData, DWORD Timeout)
+ConioPause(PCONSOLE Console, UINT Flags)
 {
-    HANDLE Thread;
+    Console->PauseFlags |= Flags;
+    if (!Console->UnpauseEvent)
+        Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
 
-    DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ClientId.UniqueProcess);
+VOID FASTCALL
+ConioUnpause(PCONSOLE Console, UINT Flags)
+{
+    Console->PauseFlags &= ~Flags;
 
-    if (ProcessData->CtrlDispatcher)
+    // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
+    if (Console->PauseFlags == 0 && Console->UnpauseEvent)
     {
+        SetEvent(Console->UnpauseEvent);
+        CloseHandle(Console->UnpauseEvent);
+        Console->UnpauseEvent = NULL;
 
-        Thread = CreateRemoteThread(ProcessData->ProcessHandle, NULL, 0,
-                                    (LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
-                                    UlongToPtr(Event), 0, NULL);
-        if (NULL == Thread)
+        CsrNotifyWait(&Console->WriteWaitQueue,
+                      WaitAll,
+                      NULL,
+                      NULL);
+        if (!IsListEmpty(&Console->WriteWaitQueue))
         {
-            DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
-            return;
+            CsrDereferenceWait(&Console->WriteWaitQueue);
         }
-        WaitForSingleObject(Thread, Timeout);
-        CloseHandle(Thread);
     }
 }
 
-VOID FASTCALL
-ConioConsoleCtrlEvent(DWORD Event, PCSR_PROCESS ProcessData)
+BOOL FASTCALL
+ConSrvValidateConsolePointer(PCONSOLE Console)
 {
-    ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
+    PLIST_ENTRY ConsoleEntry;
+    PCONSOLE CurrentConsole = NULL;
+
+    if (!Console) return FALSE;
+
+    /* The console list must be locked */
+    // ASSERT(Console_list_locked);
+
+    ConsoleEntry = ConsoleList.Flink;
+    while (ConsoleEntry != &ConsoleList)
+    {
+        CurrentConsole = CONTAINING_RECORD(ConsoleEntry, CONSOLE, Entry);
+        ConsoleEntry = ConsoleEntry->Flink;
+        if (CurrentConsole == Console) return TRUE;
+    }
+
+    return FALSE;
 }
 
-static NTSTATUS WINAPI
-CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
+BOOL FASTCALL
+ConSrvValidateConsoleState(PCONSOLE Console,
+                           CONSOLE_STATE ExpectedState)
 {
-    NTSTATUS Status;
-    SECURITY_ATTRIBUTES SecurityAttributes;
-    PCSRSS_SCREEN_BUFFER NewBuffer;
-    BOOL GuiMode;
-    WCHAR Title[255];
-    HINSTANCE hInst;
+    // if (!Console) return FALSE;
 
-    Console->Title.MaximumLength = Console->Title.Length = 0;
-    Console->Title.Buffer = NULL;
+    /* The console must be locked */
+    // ASSERT(Console_locked);
 
-    hInst = GetModuleHandleW(L"win32csr");
-    if (LoadStringW(hInst,IDS_COMMAND_PROMPT,Title,sizeof(Title)/sizeof(Title[0])))
+    return (Console->State == ExpectedState);
+}
+
+BOOL FASTCALL
+ConSrvValidateConsoleUnsafe(PCONSOLE Console,
+                            CONSOLE_STATE ExpectedState,
+                            BOOL LockConsole)
+{
+    if (!Console) return FALSE;
+
+    /*
+     * Lock the console to forbid possible console's state changes
+     * (which must be done when the console is already locked).
+     * If we don't want to lock it, it's because the lock is already
+     * held. So there must be no problems.
+     */
+    if (LockConsole) EnterCriticalSection(&Console->Lock);
+
+    // ASSERT(Console_locked);
+
+    /* Check whether the console's state is what we expect */
+    if (!ConSrvValidateConsoleState(Console, ExpectedState))
     {
-        RtlCreateUnicodeString(&Console->Title, Title);
+        if (LockConsole) LeaveCriticalSection(&Console->Lock);
+        return FALSE;
     }
-    else
+
+    return TRUE;
+}
+
+BOOL FASTCALL
+ConSrvValidateConsole(PCONSOLE Console,
+                      CONSOLE_STATE ExpectedState,
+                      BOOL LockConsole)
+{
+    BOOL RetVal = FALSE;
+
+    if (!Console) return FALSE;
+
+    /*
+     * Forbid creation or deletion of consoles when
+     * checking for the existence of a console.
+     */
+    ConSrvLockConsoleListShared();
+
+    if (ConSrvValidateConsolePointer(Console))
     {
-        RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
+        RetVal = ConSrvValidateConsoleUnsafe(Console,
+                                             ExpectedState,
+                                             LockConsole);
     }
 
-    Console->ReferenceCount = 0;
-    Console->LineBuffer = NULL;
-    Console->Header.Type = CONIO_CONSOLE_MAGIC;
-    Console->Header.Console = Console;
-    Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
-    InitializeListHead(&Console->BufferList);
-    Console->ActiveBuffer = NULL;
-    InitializeListHead(&Console->InputEvents);
-    InitializeListHead(&Console->HistoryBuffers);
-    Console->CodePage = GetOEMCP();
-    Console->OutputCodePage = GetOEMCP();
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
+    return RetVal;
+}
 
-    SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
-    SecurityAttributes.lpSecurityDescriptor = NULL;
-    SecurityAttributes.bInheritHandle = TRUE;
+NTSTATUS
+FASTCALL
+ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
+                 PCONSOLE* Console,
+                 BOOL LockConsole)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSOLE ProcessConsole;
+
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    ProcessConsole = ProcessData->Console;
 
-    Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
-    if (NULL == Console->ActiveEvent)
+    if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
     {
-        RtlFreeUnicodeString(&Console->Title);
-        return STATUS_UNSUCCESSFUL;
+        InterlockedIncrement(&ProcessConsole->ReferenceCount);
+        *Console = ProcessConsole;
+    }
+    else
+    {
+        *Console = NULL;
+        Status = STATUS_INVALID_HANDLE;
     }
-    Console->PrivateData = NULL;
-    InitializeCriticalSection(&Console->Lock);
 
-    GuiMode = DtbgIsDesktopVisible();
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+    return Status;
+}
+
+VOID FASTCALL
+ConSrvReleaseConsole(PCONSOLE Console,
+                     BOOL 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);
 
-    /* allocate console screen buffer */
-    NewBuffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
-    if (NULL == NewBuffer)
+    /* Delete the console if needed */
+    if (RefCount <= 0) ConSrvDeleteConsole(Console);
+}
+
+VOID WINAPI
+ConSrvInitConsoleSupport(VOID)
+{
+    DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
+
+    /* Initialize the console list and its lock */
+    InitializeListHead(&ConsoleList);
+    RtlInitializeResource(&ListLock);
+
+    /* Should call LoadKeyboardLayout */
+}
+
+static BOOL
+LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
+                         IN OUT PCONSOLE_INFO ConsoleInfo,
+                         OUT LPWSTR IconPath,
+                         IN SIZE_T IconPathLength,
+                         OUT PINT piIcon)
+{
+#define PATH_SEPARATOR L'\\'
+
+    BOOL   RetVal = FALSE;
+    LPWSTR LinkName = NULL;
+    SIZE_T Length = 0;
+
+    if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
+        return FALSE;
+
+    if (IconPath == NULL || piIcon == NULL)
+        return FALSE;
+
+    IconPath[0] = L'\0';
+    *piIcon = 0;
+
+    /* 1- Find the last path separator if any */
+    LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
+    if (LinkName == NULL)
     {
-        RtlFreeUnicodeString(&Console->Title);
-        DeleteCriticalSection(&Console->Lock);
-        CloseHandle(Console->ActiveEvent);
-        return STATUS_INSUFFICIENT_RESOURCES;
+        LinkName = ConsoleStartInfo->ConsoleTitle;
     }
-    /* init screen buffer with defaults */
-    NewBuffer->CursorInfo.bVisible = TRUE;
-    NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
-    /* make console active, and insert into console list */
-    Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
+    else
+    {
+        /* Skip the path separator */
+        ++LinkName;
+    }
+
+    /* 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;
 
-    if (! GuiMode)
+    /* 3- It may be a link. Try to retrieve some properties */
+    HRESULT hRes = CoInitialize(NULL);
+    if (SUCCEEDED(hRes))
     {
-        Status = TuiInitConsole(Console);
-        if (! NT_SUCCESS(Status))
+        /* 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))
         {
-            DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
-            GuiMode = TRUE;
+            /* 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, ConsoleStartInfo->ConsoleTitle, STGM_READ);
+                if (SUCCEEDED(hRes))
+                {
+                    /*
+                     * Finally we can get the properties !
+                     * Update the old ones if needed.
+                     */
+                    INT ShowCmd = 0;
+                    // WORD HotKey = 0;
+
+                    /* Reset the name of the console with the name of the shortcut */
+                    Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
+                                 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
+                    wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
+                    ConsoleInfo->ConsoleTitle[Length] = L'\0';
+
+                    /* Get the window showing command */
+                    hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
+                    if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd;
+
+                    /* Get the hotkey */
+                    // hRes = pshl->GetHotkey(&ShowCmd);
+                    // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
+
+                    /* Get the icon location, if any */
+                    hRes = IShellLinkW_GetIconLocation(pshl, IconPath, IconPathLength, piIcon);
+                    if (!SUCCEEDED(hRes))
+                    {
+                        IconPath[0] = L'\0';
+                    }
+
+                    // FIXME: Since we still don't load console properties from the shortcut,
+                    // return false. When this will be done, we will return true instead.
+                    RetVal = FALSE;
+                }
+                IPersistFile_Release(ppf);
+            }
+            IShellLinkW_Release(pshl);
         }
     }
-    else /* GuiMode */
+    CoUninitialize();
+
+    return RetVal;
+}
+
+NTSTATUS WINAPI
+ConSrvInitConsole(OUT PCONSOLE* NewConsole,
+                  IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
+                  IN PCSR_PROCESS ConsoleLeaderProcess)
+{
+    NTSTATUS Status;
+    SECURITY_ATTRIBUTES SecurityAttributes;
+    CONSOLE_INFO ConsoleInfo;
+    SIZE_T Length = 0;
+    DWORD ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess);
+    PCONSOLE Console;
+    PCONSOLE_SCREEN_BUFFER NewBuffer;
+    BOOL GuiMode;
+    WCHAR Title[128];
+    WCHAR IconPath[MAX_PATH + 1] = L"";
+    INT iIcon = 0;
+
+    if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
+    *NewConsole = NULL;
+
+    /*
+     * Allocate a console structure
+     */
+    Console = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE));
+    if (NULL == Console)
     {
-        Status = GuiInitConsole(Console, ShowCmd);
-        if (! NT_SUCCESS(Status))
+        DPRINT1("Not enough memory for console creation.\n");
+        return STATUS_NO_MEMORY;
+    }
+
+    /*
+     * Load the console settings
+     */
+
+    /* 1. Load the default settings */
+    ConSrvGetDefaultSettings(&ConsoleInfo, ProcessId);
+
+    /* 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';
+
+    /*
+     * 3. Check whether the process creating the console was launched
+     *    via a shell-link. ConsoleInfo.ConsoleTitle may be updated by
+     *    the name of the shortcut.
+     */
+    if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
+    {
+        if (!LoadShellLinkConsoleInfo(ConsoleStartInfo,
+                                      &ConsoleInfo,
+                                      IconPath,
+                                      MAX_PATH,
+                                      &iIcon))
         {
-            HeapFree(ConSrvHeap,0, NewBuffer);
-            RtlFreeUnicodeString(&Console->Title);
-            DeleteCriticalSection(&Console->Lock);
-            CloseHandle(Console->ActiveEvent);
-            DPRINT1("GuiInitConsole: failed\n");
-            return Status;
+            ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
         }
     }
 
-    Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
-    if (! NT_SUCCESS(Status))
+    /*
+     * 4. Load the remaining console settings via the registry.
+     */
+    if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
     {
-        ConioCleanupConsole(Console);
-        RtlFreeUnicodeString(&Console->Title);
-        DeleteCriticalSection(&Console->Lock);
-        CloseHandle(Console->ActiveEvent);
-        HeapFree(ConSrvHeap, 0, NewBuffer);
-        DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
-        return Status;
+        /*
+         * 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, ProcessId);
+
+        /*
+         * Now, update them with the properties the user might gave to us
+         * via the STARTUPINFO structure before calling CreateProcess
+         * (and which was transmitted via the ConsoleStartInfo structure).
+         * We therefore overwrite the values read in the registry.
+         */
+        if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
+        {
+            ConsoleInfo.ScreenAttrib = ConsoleStartInfo->FillAttribute;
+        }
+        if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
+        {
+            ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
+        }
+        if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
+        {
+            // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
+            ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx;
+            ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy;
+        }
+        /*
+        if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
+        {
+            ConsoleInfo.FullScreen = TRUE;
+        }
+        */
     }
 
-    /* copy buffer contents to screen */
-    ConioDrawConsole(Console);
-
-    return STATUS_SUCCESS;
-}
-
-CSR_API(SrvAllocConsole)
-{
-    PCSRSS_ALLOC_CONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    NTSTATUS Status = STATUS_SUCCESS;
-    BOOLEAN NewConsole = FALSE;
+    /*
+     * Initialize the console
+     */
+    Console->State = CONSOLE_INITIALIZING;
+    InitializeCriticalSection(&Console->Lock);
+    Console->ReferenceCount = 0;
+    InitializeListHead(&Console->ProcessList);
+    memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
+    Console->ConsoleSize = ConsoleInfo.ConsoleSize;
 
-    DPRINT("SrvAllocConsole\n");
+    /*
+     * Initialize the input buffer
+     */
+    Console->InputBuffer.Header.Type = INPUT_BUFFER;
+    Console->InputBuffer.Header.Console = Console;
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    if (ProcessData->Console)
+    SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+    SecurityAttributes.lpSecurityDescriptor = NULL;
+    SecurityAttributes.bInheritHandle = TRUE;
+    Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
+    if (NULL == Console->InputBuffer.ActiveEvent)
     {
-        DPRINT1("Process already has a console\n");
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_INVALID_PARAMETER;
+        DeleteCriticalSection(&Console->Lock);
+        RtlFreeHeap(ConSrvHeap, 0, Console);
+        return STATUS_UNSUCCESSFUL;
     }
 
-    /* If we don't need a console, then get out of here */
-    if (!AllocConsoleRequest->ConsoleNeeded)
+    Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+                                ENABLE_ECHO_INPUT      | ENABLE_MOUSE_INPUT;
+    Console->QuickEdit  = ConsoleInfo.QuickEdit;
+    Console->InsertMode = ConsoleInfo.InsertMode;
+    InitializeListHead(&Console->InputBuffer.ReadWaitQueue);
+    InitializeListHead(&Console->InputBuffer.InputEvents);
+    Console->LineBuffer = NULL;
+    Console->CodePage = GetOEMCP();
+    Console->OutputCodePage = GetOEMCP();
+
+    /* Initialize a new screen buffer with default settings */
+    InitializeListHead(&Console->BufferList);
+    Status = ConSrvCreateScreenBuffer(Console,
+                                      &NewBuffer,
+                                      ConsoleInfo.ScreenBufferSize,
+                                      ConsoleInfo.ScreenAttrib,
+                                      ConsoleInfo.PopupAttrib,
+                                      (ConsoleInfo.FullScreen ? CONSOLE_FULLSCREEN_MODE
+                                                              : CONSOLE_WINDOWED_MODE),
+                                      TRUE,
+                                      ConsoleInfo.CursorSize);
+    if (!NT_SUCCESS(Status))
     {
-        DPRINT("No console needed\n");
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_SUCCESS;
+        DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
+        CloseHandle(Console->InputBuffer.ActiveEvent);
+        DeleteCriticalSection(&Console->Lock);
+        RtlFreeHeap(ConSrvHeap, 0, Console);
+        return Status;
     }
+    /* Make the new screen buffer active */
+    Console->ActiveBuffer = NewBuffer;
+    InitializeListHead(&Console->WriteWaitQueue);
 
-    /* If we already have one, then don't create a new one... */
-    if (!AllocConsoleRequest->Console ||
-            AllocConsoleRequest->Console != ProcessData->ParentConsole)
+    /*
+     * Initialize the history buffers
+     */
+    InitializeListHead(&Console->HistoryBuffers);
+    Console->HistoryBufferSize = ConsoleInfo.HistoryBufferSize;
+    Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
+    Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
+
+    /* Initialize the console title */
+    RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
+    if (ConsoleInfo.ConsoleTitle[0] == L'\0')
     {
-        /* Allocate a console structure */
-        NewConsole = TRUE;
-        Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
-        if (NULL == Console)
+        if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, Title, sizeof(Title) / sizeof(Title[0])))
         {
-            DPRINT1("Not enough memory for console\n");
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return STATUS_NO_MEMORY;
+            RtlCreateUnicodeString(&Console->Title, Title);
         }
-        /* initialize list head */
-        InitializeListHead(&Console->ProcessList);
-        /* insert process data required for GUI initialization */
-        InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
-        /* Initialize the Console */
-        Status = CsrInitConsole(Console, AllocConsoleRequest->ShowCmd);
-        if (!NT_SUCCESS(Status))
+        else
         {
-            DPRINT1("Console init failed\n");
-            HeapFree(ConSrvHeap, 0, Console);
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
+            RtlCreateUnicodeString(&Console->Title, L"ReactOS Console");
         }
     }
     else
     {
-        /* Reuse our current console */
-        Console = AllocConsoleRequest->Console;
+        RtlCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
     }
 
-    /* Set the Process Console */
-    ProcessData->Console = Console;
-
-    /* Return it to the caller */
-    AllocConsoleRequest->Console = Console;
+    /* Lock the console until its initialization is finished */
+    // EnterCriticalSection(&Console->Lock);
 
-    /* Add a reference count because the process is tied to the console */
-    _InterlockedIncrement(&Console->ReferenceCount);
+    /*
+     * If we are not in GUI-mode, start the text-mode terminal emulator.
+     * If we fail, try to start the GUI-mode terminal emulator.
+     */
+#ifdef TUI_CONSOLE
+    GuiMode = DtbgIsDesktopVisible();
+#else
+    GuiMode = TRUE;
+#endif
 
-    if (NewConsole || !ProcessData->bInheritHandles)
+#ifdef TUI_CONSOLE
+    if (!GuiMode)
     {
-        /* Insert the Objects */
-        Status = Win32CsrInsertObject(ProcessData,
-                                      &AllocConsoleRequest->InputHandle,
-                                      &Console->Header,
-                                      GENERIC_READ | GENERIC_WRITE,
-                                      TRUE,
-                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
-        if (! NT_SUCCESS(Status))
-        {
-            DPRINT1("Failed to insert object\n");
-            ConioDeleteConsole((Object_t *) Console);
-            ProcessData->Console = 0;
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
-        }
-
-        Status = Win32CsrInsertObject(ProcessData,
-                                      &AllocConsoleRequest->OutputHandle,
-                                      &Console->ActiveBuffer->Header,
-                                      GENERIC_READ | GENERIC_WRITE,
-                                      TRUE,
-                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
+        DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
+        Status = TuiInitConsole(Console,
+                                ConsoleStartInfo,
+                                &ConsoleInfo,
+                                ProcessId);
         if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Failed to insert object\n");
-            ConioDeleteConsole((Object_t *) Console);
-            Win32CsrReleaseObject(ProcessData,
-                                  AllocConsoleRequest->InputHandle);
-            ProcessData->Console = 0;
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
+            DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status);
+            GuiMode = TRUE;
         }
     }
-
-    /* Duplicate the Event */
-    if (!DuplicateHandle(GetCurrentProcess(),
-                         ProcessData->Console->ActiveEvent,
-                         ProcessData->ProcessHandle,
-                         &ProcessData->ConsoleEvent,
-                         EVENT_ALL_ACCESS,
-                         FALSE,
-                         0))
+#endif
+
+    /*
+     * 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).
+     */
+    if (GuiMode)
     {
-        DPRINT1("DuplicateHandle() failed: %lu\n", GetLastError());
-        ConioDeleteConsole((Object_t *) Console);
-        if (NewConsole || !ProcessData->bInheritHandles)
+        DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
+        Status = GuiInitConsole(Console,
+                                ConsoleStartInfo,
+                                &ConsoleInfo,
+                                ProcessId,
+                                IconPath,
+                                iIcon);
+        if (!NT_SUCCESS(Status))
         {
-            Win32CsrReleaseObject(ProcessData,
-                                  AllocConsoleRequest->OutputHandle);
-            Win32CsrReleaseObject(ProcessData,
-                                  AllocConsoleRequest->InputHandle);
+            DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
+            RtlFreeUnicodeString(&Console->Title);
+            RtlFreeUnicodeString(&Console->OriginalTitle);
+            ConioDeleteScreenBuffer(NewBuffer);
+            CloseHandle(Console->InputBuffer.ActiveEvent);
+            // LeaveCriticalSection(&Console->Lock);
+            DeleteCriticalSection(&Console->Lock);
+            RtlFreeHeap(ConSrvHeap, 0, Console);
+            return Status;
         }
-        ProcessData->Console = 0;
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return Status;
     }
 
-    /* Set the Ctrl Dispatcher */
-    ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
-    DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
+    DPRINT("Terminal initialized\n");
 
-    if (!NewConsole)
-    {
-        /* Insert into the list if it has not been added */
-        InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
-    }
+    /* All went right, so add the console to the list */
+    ConSrvLockConsoleListExclusive();
+    DPRINT("Insert in the list\n");
+    InsertTailList(&ConsoleList, &Console->Entry);
 
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-    return STATUS_SUCCESS;
-}
+    /* The initialization is finished */
+    DPRINT("Change state\n");
+    Console->State = CONSOLE_RUNNING;
 
-CSR_API(SrvFreeConsole)
-{
-    Win32CsrReleaseConsole(CsrGetClientThread()->Process);
+    /* Unlock the console */
+    // LeaveCriticalSection(&Console->Lock);
+
+    /* Unlock the console list */
+    ConSrvUnlockConsoleList();
+
+    /* Copy buffer contents to screen */
+    ConioDrawConsole(Console);
+    DPRINT("Console drawn\n");
+
+    /* Return the newly created console to the caller and a success code too */
+    *NewConsole = Console;
     return STATUS_SUCCESS;
 }
 
 VOID WINAPI
-ConioDeleteConsole(Object_t *Object)
+ConSrvDeleteConsole(PCONSOLE Console)
 {
-    PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
-    ConsoleInput *Event;
+    DPRINT("ConSrvDeleteConsole\n");
 
-    DPRINT("ConioDeleteConsole\n");
+    /*
+     * Forbid validation of any console by other threads
+     * during the deletion of this console.
+     */
+    ConSrvLockConsoleListExclusive();
 
-    /* Drain input event queue */
-    while (Console->InputEvents.Flink != &Console->InputEvents)
+    /* Check the existence of the console, and if it's ok, continue */
+    if (!ConSrvValidateConsolePointer(Console))
     {
-        Event = (ConsoleInput *) Console->InputEvents.Flink;
-        Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
-        Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
-        HeapFree(ConSrvHeap, 0, Event);
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
     }
 
+    /*
+     * If the console is already being destroyed
+     * (thus not running), just return.
+     */
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    {
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
+    }
+
+    /*
+     * We are about to be destroyed. Signal it to other people
+     * so that they can terminate what they are doing, and that
+     * they cannot longer validate the console.
+     */
+    Console->State = CONSOLE_TERMINATING;
+
+    /*
+     * Allow other threads to finish their job: basically, unlock
+     * all other calls to EnterCriticalSection(&Console->Lock); by
+     * ConSrvValidateConsole(Unsafe) functions so that they just see
+     * that we are not in CONSOLE_RUNNING state anymore, or unlock
+     * other concurrent calls to ConSrvDeleteConsole so that they
+     * can see that we are in fact already deleting the console.
+     */
+    LeaveCriticalSection(&Console->Lock);
+    ConSrvUnlockConsoleList();
+
+    /* FIXME: Send a terminate message to all the processes owning this console */
+
+    /* Cleanup the UI-oriented part */
     ConioCleanupConsole(Console);
-    if (Console->LineBuffer)
-        RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
-    while (!IsListEmpty(&Console->HistoryBuffers))
-        HistoryDeleteBuffer((struct tagHISTORY_BUFFER *)Console->HistoryBuffers.Flink);
+
+    /***
+     * Check that the console is in terminating state before continuing
+     * (the cleanup code must not change the state of the console...
+     * ...unless to cancel console deletion ?).
+     ***/
+
+    ConSrvLockConsoleListExclusive();
+
+    /* Re-check the existence of the console, and if it's ok, continue */
+    if (!ConSrvValidateConsolePointer(Console))
+    {
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
+    }
+
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
+    {
+        ConSrvUnlockConsoleList();
+        return;
+    }
+
+    /* We are in destruction */
+    Console->State = CONSOLE_IN_DESTRUCTION;
+
+    /* Remove the console from the list */
+    RemoveEntryList(&Console->Entry);
+
+    /* Reset the count to be sure */
+    Console->ReferenceCount = 0;
+
+    /* Discard all entries in the input event queue */
+    PurgeInputBuffer(Console);
+
+    if (Console->LineBuffer) RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
+
+    IntDeleteAllAliases(Console);
+    HistoryDeleteBuffers(Console);
 
     ConioDeleteScreenBuffer(Console->ActiveBuffer);
     if (!IsListEmpty(&Console->BufferList))
@@ -367,211 +817,423 @@ ConioDeleteConsole(Object_t *Object)
         DPRINT1("BUG: screen buffer list not empty\n");
     }
 
-    CloseHandle(Console->ActiveEvent);
+    // CloseHandle(Console->InputBuffer.ActiveEvent);
     if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
-    DeleteCriticalSection(&Console->Lock);
+
+    RtlFreeUnicodeString(&Console->OriginalTitle);
     RtlFreeUnicodeString(&Console->Title);
-    IntDeleteAllAliases(Console->Aliases);
-    HeapFree(ConSrvHeap, 0, Console);
-}
 
-VOID WINAPI
-CsrInitConsoleSupport(VOID)
-{
-    DPRINT("CSR: CsrInitConsoleSupport()\n");
+    DPRINT("ConSrvDeleteConsole - Unlocking\n");
+    LeaveCriticalSection(&Console->Lock);
+    DPRINT("ConSrvDeleteConsole - Destroying lock\n");
+    DeleteCriticalSection(&Console->Lock);
+    DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
 
-    /* Should call LoadKeyboardLayout */
-}
+    RtlFreeHeap(ConSrvHeap, 0, Console);
+    DPRINT("ConSrvDeleteConsole - Console freed\n");
 
-VOID FASTCALL
-ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
-{
-    Console->PauseFlags |= Flags;
-    if (!Console->UnpauseEvent)
-        Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
 }
 
-VOID FASTCALL
-ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(SrvAllocConsole)
 {
-    Console->PauseFlags &= ~Flags;
-    if (Console->PauseFlags == 0 && Console->UnpauseEvent)
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
+    PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
+
+    if (ProcessData->Console != NULL)
     {
-        SetEvent(Console->UnpauseEvent);
-        CloseHandle(Console->UnpauseEvent);
-        Console->UnpauseEvent = NULL;
+        DPRINT1("Process already has a console\n");
+        return STATUS_ACCESS_DENIED;
+    }
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
+                                  1,
+                                  sizeof(CONSOLE_START_INFO)))
+    {
+        return STATUS_INVALID_PARAMETER;
     }
+
+    /*
+     * We are about to create a new console. However when ConSrvNewProcess
+     * was called, we didn't know that we wanted to create a new console and
+     * therefore, we by default inherited the handles table from our parent
+     * process. It's only now that we notice that in fact we do not need
+     * them, because we've created a new console and thus we must use it.
+     *
+     * Therefore, free the console we can have and our handles table,
+     * and recreate a new one later on.
+     */
+    ConSrvRemoveConsole(ProcessData);
+
+    /* Initialize a new Console owned by the Console Leader Process */
+    Status = ConSrvAllocateConsole(ProcessData,
+                                   &AllocConsoleRequest->InputHandle,
+                                   &AllocConsoleRequest->OutputHandle,
+                                   &AllocConsoleRequest->ErrorHandle,
+                                   AllocConsoleRequest->ConsoleStartInfo);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Console allocation failed\n");
+        return Status;
+    }
+
+    /* Return it to the caller */
+    AllocConsoleRequest->Console = ProcessData->Console;
+
+    /* Input Wait Handle */
+    AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
+
+    /* Set the Property Dialog Handler */
+    ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
+
+    /* Set the Ctrl Dispatcher */
+    ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
+
+    return STATUS_SUCCESS;
 }
 
-CSR_API(SrvSetConsoleMode)
+CSR_API(SrvAttachConsole)
 {
-    NTSTATUS Status;
-    PCSRSS_SET_CONSOLE_MODE SetConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleModeRequest;
-    PCSRSS_CONSOLE Console;
-    PCSRSS_SCREEN_BUFFER Buff;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
+    PCSR_PROCESS SourceProcess = NULL;  // The parent process.
+    PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
+    HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
+    PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
 
-    DPRINT("SrvSetConsoleMode\n");
+    TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
 
-    Status = Win32CsrLockObject(CsrGetClientThread()->Process,
-                                SetConsoleModeRequest->ConsoleHandle,
-                                (Object_t **) &Console, GENERIC_WRITE, 0);
-    if (! NT_SUCCESS(Status))
+    if (TargetProcessData->Console != NULL)
     {
-        return Status;
+        DPRINT1("Process already has a console\n");
+        return STATUS_ACCESS_DENIED;
     }
 
-    Buff = (PCSRSS_SCREEN_BUFFER)Console;
-    if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
+    /* Check whether we try to attach to the parent's console */
+    if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
     {
-        Console->Mode = SetConsoleModeRequest->Mode & CONSOLE_INPUT_MODE_VALID;
+        PROCESS_BASIC_INFORMATION ProcessInfo;
+        ULONG Length = sizeof(ProcessInfo);
+
+        /* Get the real parent's ID */
+
+        Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
+                                           ProcessBasicInformation,
+                                           &ProcessInfo,
+                                           Length, &Length);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
+            return Status;
+        }
+
+        ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
     }
-    else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
+
+    /* Lock the source process via its PID */
+    Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
+
+    if (SourceProcessData->Console == NULL)
     {
-        Buff->Mode = SetConsoleModeRequest->Mode & CONSOLE_OUTPUT_MODE_VALID;
+        Status = STATUS_INVALID_HANDLE;
+        goto Quit;
     }
-    else
+
+    /*
+     * We are about to create a new console. However when ConSrvNewProcess
+     * was called, we didn't know that we wanted to create a new console and
+     * therefore, we by default inherited the handles table from our parent
+     * process. It's only now that we notice that in fact we do not need
+     * them, because we've created a new console and thus we must use it.
+     *
+     * Therefore, free the console we can have and our handles table,
+     * and recreate a new one later on.
+     */
+    ConSrvRemoveConsole(TargetProcessData);
+
+    /*
+     * Inherit the console from the parent,
+     * if any, otherwise return an error.
+     */
+    Status = ConSrvInheritConsole(TargetProcessData,
+                                  SourceProcessData->Console,
+                                  TRUE,
+                                  &AttachConsoleRequest->InputHandle,
+                                  &AttachConsoleRequest->OutputHandle,
+                                  &AttachConsoleRequest->ErrorHandle);
+    if (!NT_SUCCESS(Status))
     {
-        Status = STATUS_INVALID_HANDLE;
+        DPRINT1("Console inheritance failed\n");
+        goto Quit;
     }
 
-    Win32CsrUnlockObject((Object_t *)Console);
+    /* Return it to the caller */
+    AttachConsoleRequest->Console = TargetProcessData->Console;
+
+    /* Input Wait Handle */
+    AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
+
+    /* Set the Property Dialog Handler */
+    TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
+
+    /* Set the Ctrl Dispatcher */
+    TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
+
+    Status = STATUS_SUCCESS;
 
+Quit:
+    /* Unlock the "source" process and exit */
+    CsrUnlockProcess(SourceProcess);
     return Status;
 }
 
+CSR_API(SrvFreeConsole)
+{
+    ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
+    return STATUS_SUCCESS;
+}
+
 CSR_API(SrvGetConsoleMode)
 {
     NTSTATUS Status;
-    PCSRSS_GET_CONSOLE_MODE GetConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleModeRequest;
-    PCSRSS_CONSOLE Console;
-    PCSRSS_SCREEN_BUFFER Buff;
+    PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
+    PCONSOLE_IO_OBJECT Object = NULL;
 
-    DPRINT("SrvGetConsoleMode\n");
+    Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                             ConsoleModeRequest->ConsoleHandle,
+                             &Object, NULL, GENERIC_READ, TRUE, 0);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    Status = Win32CsrLockObject(CsrGetClientThread()->Process, GetConsoleModeRequest->ConsoleHandle,
-                                (Object_t **) &Console, GENERIC_READ, 0);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
     Status = STATUS_SUCCESS;
-    Buff = (PCSRSS_SCREEN_BUFFER) Console;
-    if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
+
+    if (INPUT_BUFFER == Object->Type)
     {
-        GetConsoleModeRequest->ConsoleMode = Console->Mode;
+        PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
+        PCONSOLE Console  = InputBuffer->Header.Console;
+        DWORD ConsoleMode = InputBuffer->Mode;
+
+        if (Console->QuickEdit || Console->InsertMode)
+        {
+            // Windows does this, even if it's not documented on MSDN
+            ConsoleMode |= ENABLE_EXTENDED_FLAGS;
+
+            if (Console->QuickEdit ) ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
+            if (Console->InsertMode) ConsoleMode |= ENABLE_INSERT_MODE;
+        }
+
+        ConsoleModeRequest->ConsoleMode = ConsoleMode;
     }
-    else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
+    else if (SCREEN_BUFFER == Object->Type)
     {
-        GetConsoleModeRequest->ConsoleMode = Buff->Mode;
+        PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
+        ConsoleModeRequest->ConsoleMode = Buffer->Mode;
     }
     else
     {
         Status = STATUS_INVALID_HANDLE;
     }
 
-    Win32CsrUnlockObject((Object_t *)Console);
+    ConSrvReleaseObject(Object, TRUE);
     return Status;
 }
 
-CSR_API(SrvSetConsoleTitle)
+CSR_API(SrvSetConsoleMode)
 {
+#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS   | ENABLE_INSERT_MODE  | ENABLE_QUICK_EDIT_MODE )
+#define CONSOLE_VALID_INPUT_MODES   ( ENABLE_PROCESSED_INPUT  | ENABLE_LINE_INPUT   | \
+                                      ENABLE_ECHO_INPUT       | ENABLE_WINDOW_INPUT | \
+                                      ENABLE_MOUSE_INPUT )
+#define CONSOLE_VALID_OUTPUT_MODES  ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
+
     NTSTATUS Status;
-    PCSRSS_SET_TITLE SetTitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTitleRequest;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    PWCHAR Buffer;
+    PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
+    DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode;
+    PCONSOLE_IO_OBJECT Object  = NULL;
 
-    DPRINT("SrvSetConsoleTitle\n");
+    Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                             ConsoleModeRequest->ConsoleHandle,
+                             &Object, NULL, GENERIC_WRITE, TRUE, 0);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    if (!Win32CsrValidateBuffer(ProcessData, SetTitleRequest->Title,
-                                SetTitleRequest->Length, 1))
+    Status = STATUS_SUCCESS;
+
+    if (INPUT_BUFFER == Object->Type)
     {
-        return STATUS_ACCESS_VIOLATION;
-    }
+        PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
+        PCONSOLE Console = InputBuffer->Header.Console;
+
+        DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode);
+
+        /*
+         * 1. Only the presence of valid mode flags is allowed.
+         */
+        if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES))
+        {
+            Status = STATUS_INVALID_PARAMETER;
+            goto Quit;
+        }
 
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if(NT_SUCCESS(Status))
+        /*
+         * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
+         *    then consider the flags invalid.
+         *
+        if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
+             (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
+        {
+            Status = STATUS_INVALID_PARAMETER;
+            goto Quit;
+        }
+        */
+
+        /*
+         * 3. Now we can continue.
+         */
+        if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
+        {
+            Console->QuickEdit  = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
+            Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
+        }
+        InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
+    }
+    else if (SCREEN_BUFFER == Object->Type)
     {
-        Buffer =  RtlAllocateHeap(RtlGetProcessHeap(), 0, SetTitleRequest->Length);
-        if (Buffer)
+        PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
+
+        DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode);
+
+        if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
         {
-            /* copy title to console */
-            RtlFreeUnicodeString(&Console->Title);
-            Console->Title.Buffer = Buffer;
-            Console->Title.Length = Console->Title.MaximumLength = SetTitleRequest->Length;
-            memcpy(Console->Title.Buffer, SetTitleRequest->Title, Console->Title.Length);
-            if (! ConioChangeTitle(Console))
-            {
-                Status = STATUS_UNSUCCESSFUL;
-            }
-            else
-            {
-                Status = STATUS_SUCCESS;
-            }
+            Status = STATUS_INVALID_PARAMETER;
         }
         else
         {
-            Status = STATUS_NO_MEMORY;
+            Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
         }
-        ConioUnlockConsole(Console);
+    }
+    else
+    {
+        Status = STATUS_INVALID_HANDLE;
     }
 
+Quit:
+    ConSrvReleaseObject(Object, TRUE);
     return Status;
 }
 
 CSR_API(SrvGetConsoleTitle)
 {
     NTSTATUS Status;
-    PCSRSS_GET_TITLE GetTitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetTitleRequest;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
+    PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
+    // PCSR_PROCESS Process = CsrGetClientThread()->Process;
+    PCONSOLE Console;
     DWORD Length;
 
-    DPRINT("SrvGetConsoleTitle\n");
-
-    if (!Win32CsrValidateBuffer(ProcessData, GetTitleRequest->Title,
-                                GetTitleRequest->Length, 1))
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID)&TitleRequest->Title,
+                                  TitleRequest->Length,
+                                  sizeof(BYTE)))
     {
-        return STATUS_ACCESS_VIOLATION;
+        return STATUS_INVALID_PARAMETER;
     }
 
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (! NT_SUCCESS(Status))
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status))
     {
         DPRINT1("Can't get console\n");
         return Status;
     }
 
     /* Copy title of the console to the user title buffer */
-    if (GetTitleRequest->Length >= sizeof(WCHAR))
+    if (TitleRequest->Length >= sizeof(WCHAR))
     {
-        Length = min(GetTitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
-        memcpy(GetTitleRequest->Title, Console->Title.Buffer, Length);
-        GetTitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
+        Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
+        memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
+        TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
     }
 
-    GetTitleRequest->Length = Console->Title.Length;
+    TitleRequest->Length = Console->Title.Length;
 
-    ConioUnlockConsole(Console);
+    ConSrvReleaseConsole(Console, TRUE);
     return STATUS_SUCCESS;
 }
 
+CSR_API(SrvSetConsoleTitle)
+{
+    NTSTATUS Status;
+    PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
+    // PCSR_PROCESS Process = CsrGetClientThread()->Process;
+    PCONSOLE Console;
+    PWCHAR Buffer;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID)&TitleRequest->Title,
+                                  TitleRequest->Length,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Can't get console\n");
+        return Status;
+    }
+
+    /* Allocate a new buffer to hold the new title (NULL-terminated) */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
+    if (Buffer)
+    {
+        /* Free the old title */
+        RtlFreeUnicodeString(&Console->Title);
+
+        /* Copy title to console */
+        Console->Title.Buffer = Buffer;
+        Console->Title.Length = TitleRequest->Length;
+        Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
+        RtlCopyMemory(Console->Title.Buffer,
+                      TitleRequest->Title,
+                      Console->Title.Length);
+        Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
+
+        ConioChangeTitle(Console);
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        Status = STATUS_NO_MEMORY;
+    }
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
 /**********************************************************************
- *     HardwareStateProperty
+ *  HardwareStateProperty
  *
- *     DESCRIPTION
- *             Set/Get the value of the HardwareState and switch
- *             between direct video buffer ouput and GDI windowed
- *             output.
- *     ARGUMENTS
- *             Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
- *             object. We use the same object to Request.
- *     NOTE
- *             ConsoleHwState has the correct size to be compatible
- *             with NT's, but values are not.
+ *  DESCRIPTION
+ *      Set/Get the value of the HardwareState and switch
+ *      between direct video buffer ouput and GDI windowed
+ *      output.
+ *  ARGUMENTS
+ *      Client hands us a CONSOLE_GETSETHWSTATE object.
+ *      We use the same object to Request.
+ *  NOTE
+ *      ConsoleHwState has the correct size to be compatible
+ *      with NT's, but values are not.
  */
 static NTSTATUS FASTCALL
-SetConsoleHardwareState(PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
+SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState)
 {
     DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
 
@@ -593,246 +1255,230 @@ SetConsoleHardwareState(PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
 
 CSR_API(SrvGetConsoleHardwareState)
 {
-    PCSRSS_SETGET_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
-
-    DPRINT("SrvGetConsoleHardwareState\n");
-
-    Status = ConioLockConsole(CsrGetClientThread()->Process,
-                              ConsoleHardwareStateRequest->ConsoleHandle,
-                              &Console,
-                              GENERIC_READ);
-    if (! NT_SUCCESS(Status))
+    PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
+    PCONSOLE_SCREEN_BUFFER Buff;
+    PCONSOLE Console;
+
+    Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                                  HardwareStateRequest->OutputHandle,
+                                  &Buff,
+                                  GENERIC_READ,
+                                  TRUE);
+    if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
+        DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
         return Status;
     }
 
-    switch (ConsoleHardwareStateRequest->SetGet)
-    {
-    case CONSOLE_HARDWARE_STATE_GET:
-        ConsoleHardwareStateRequest->State = Console->HardwareState;
-        break;
-
-    case CONSOLE_HARDWARE_STATE_SET:
-        DPRINT("Setting console hardware state.\n");
-        Status = SetConsoleHardwareState(Console, ConsoleHardwareStateRequest->State);
-        break;
-
-    default:
-        Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
-        break;
-    }
-
-    ConioUnlockConsole(Console);
+    Console = Buff->Header.Console;
+    HardwareStateRequest->State = Console->HardwareState;
 
+    ConSrvReleaseScreenBuffer(Buff, TRUE);
     return Status;
 }
 
 CSR_API(SrvSetConsoleHardwareState)
 {
-    PCSRSS_SETGET_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
-
-    DPRINT("SrvSetConsoleHardwareState\n");
-
-    Status = ConioLockConsole(CsrGetClientThread()->Process,
-                              ConsoleHardwareStateRequest->ConsoleHandle,
-                              &Console,
-                              GENERIC_READ);
-    if (! NT_SUCCESS(Status))
+    PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
+    PCONSOLE_SCREEN_BUFFER Buff;
+    PCONSOLE Console;
+
+    Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                                  HardwareStateRequest->OutputHandle,
+                                  &Buff,
+                                  GENERIC_WRITE,
+                                  TRUE);
+    if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
+        DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
         return Status;
     }
 
-    switch (ConsoleHardwareStateRequest->SetGet)
-    {
-    case CONSOLE_HARDWARE_STATE_GET:
-        ConsoleHardwareStateRequest->State = Console->HardwareState;
-        break;
-
-    case CONSOLE_HARDWARE_STATE_SET:
-        DPRINT("Setting console hardware state.\n");
-        Status = SetConsoleHardwareState(Console, ConsoleHardwareStateRequest->State);
-        break;
-
-    default:
-        Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
-        break;
-    }
-
-    ConioUnlockConsole(Console);
+    DPRINT("Setting console hardware state.\n");
+    Console = Buff->Header.Console;
+    Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
 
+    ConSrvReleaseScreenBuffer(Buff, TRUE);
     return Status;
 }
 
-CSR_API(SrvGetConsoleWindow)
+CSR_API(SrvGetConsoleDisplayMode)
 {
-    PCSRSS_GET_CONSOLE_WINDOW GetConsoleWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleWindowRequest;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
+    PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest;
+    PCONSOLE Console;
+    ULONG DisplayMode = 0;
 
-    DPRINT("SrvGetConsoleWindow\n");
-
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                              &Console, TRUE);
+    if (!NT_SUCCESS(Status))
     {
+        DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
         return Status;
     }
 
-    GetConsoleWindowRequest->WindowHandle = Console->hWindow;
-    ConioUnlockConsole(Console);
+    if (Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE)
+        DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
+    else if (Console->ActiveBuffer->DisplayMode & CONSOLE_WINDOWED_MODE)
+        DisplayMode |= CONSOLE_WINDOWED;
 
-    return STATUS_SUCCESS;
+    GetDisplayModeRequest->DisplayMode = DisplayMode;
+    Status = STATUS_SUCCESS;
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
 }
 
-CSR_API(SrvSetConsoleIcon)
+CSR_API(SrvSetConsoleDisplayMode)
 {
-    PCSRSS_SET_CONSOLE_ICON SetConsoleIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleIconRequest;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
-
-    DPRINT("SrvSetConsoleIcon\n");
-
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
+    PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest;
+    PCONSOLE_SCREEN_BUFFER Buff;
+
+    Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                                   SetDisplayModeRequest->OutputHandle,
+                                   &Buff,
+                                   GENERIC_WRITE,
+                                   TRUE);
+    if (!NT_SUCCESS(Status))
     {
+        DPRINT1("Failed to get console handle in SrvSetConsoleDisplayMode\n");
         return Status;
     }
 
-    Status = (ConioChangeIcon(Console, SetConsoleIconRequest->WindowIcon)
-              ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
-    ConioUnlockConsole(Console);
+    if (SetDisplayModeRequest->DisplayMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
+    {
+        Status = STATUS_INVALID_PARAMETER;
+    }
+    else
+    {
+        Buff->DisplayMode = SetDisplayModeRequest->DisplayMode;
+        // TODO: Change the display mode
+        SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize;
 
+        Status = STATUS_SUCCESS;
+    }
+
+    ConSrvReleaseScreenBuffer(Buff, TRUE);
     return Status;
 }
 
-CSR_API(SrvGetConsoleCP)
+CSR_API(SrvGetConsoleWindow)
 {
-    PCSRSS_GET_CONSOLE_CP GetConsoleCodePage = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCodePage;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
+    PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
+    PCONSOLE Console;
 
-    DPRINT("SrvGetConsoleCP\n");
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
+    GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console);
+    ConSrvReleaseConsole(Console, TRUE);
 
-    GetConsoleCodePage->CodePage = Console->CodePage;
-    ConioUnlockConsole(Console);
     return STATUS_SUCCESS;
 }
 
-CSR_API(CsrGetConsoleOutputCodePage) // TODO: Merge this function with the other one.
+CSR_API(SrvSetConsoleIcon)
 {
-    PCSRSS_GET_CONSOLE_OUTPUT_CP GetConsoleOutputCodePage = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleOutputCodePage;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
+    PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
+    PCONSOLE Console;
 
-    DPRINT("CsrGetConsoleOutputCodePage\n");
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
+    Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon)
+                ? STATUS_SUCCESS
+                : STATUS_UNSUCCESSFUL);
 
-    GetConsoleOutputCodePage->CodePage = Console->OutputCodePage;
-    ConioUnlockConsole(Console);
-    return STATUS_SUCCESS;
+    ConSrvReleaseConsole(Console, TRUE);
+
+    return Status;
 }
 
-CSR_API(SrvSetConsoleCP)
+CSR_API(SrvGetConsoleCP)
 {
-    PCSRSS_SET_CONSOLE_CP SetConsoleCodePage = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCodePage;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
+    PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
+    PCONSOLE Console;
 
-    DPRINT("SrvSetConsoleCP\n");
+    DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
+            ConsoleCPRequest->InputCP ? "Input" : "Output");
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    if (IsValidCodePage(SetConsoleCodePage->CodePage))
-    {
-        Console->CodePage = SetConsoleCodePage->CodePage;
-        ConioUnlockConsole(Console);
-        return STATUS_SUCCESS;
-    }
-
-    ConioUnlockConsole(Console);
-    return STATUS_INVALID_PARAMETER;
+    ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
+                                                            : Console->OutputCodePage);
+    ConSrvReleaseConsole(Console, TRUE);
+    return STATUS_SUCCESS;
 }
 
-CSR_API(CsrSetConsoleOutputCodePage) // TODO: Merge this function with the other one.
+CSR_API(SrvSetConsoleCP)
 {
-    PCSRSS_SET_CONSOLE_OUTPUT_CP SetConsoleOutputCodePage = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleOutputCodePage;
-    PCSRSS_CONSOLE Console;
     NTSTATUS Status;
+    PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
+    PCONSOLE Console;
 
-    DPRINT("CsrSetConsoleOutputCodePage\n");
+    DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
+            ConsoleCPRequest->InputCP ? "Input" : "Output");
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    if (IsValidCodePage(SetConsoleOutputCodePage->CodePage))
+    if (IsValidCodePage(ConsoleCPRequest->CodePage))
     {
-        Console->OutputCodePage = SetConsoleOutputCodePage->CodePage;
-        ConioUnlockConsole(Console);
+        if (ConsoleCPRequest->InputCP)
+            Console->CodePage = ConsoleCPRequest->CodePage;
+        else
+            Console->OutputCodePage = ConsoleCPRequest->CodePage;
+
+        ConSrvReleaseConsole(Console, TRUE);
         return STATUS_SUCCESS;
     }
 
-    ConioUnlockConsole(Console);
+    ConSrvReleaseConsole(Console, TRUE);
     return STATUS_INVALID_PARAMETER;
 }
 
 CSR_API(SrvGetConsoleProcessList)
 {
-    PCSRSS_GET_PROCESS_LIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
+    NTSTATUS Status;
+    PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
     PDWORD Buffer;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
-    PCSRSS_CONSOLE Console;
-    PCSR_PROCESS current;
+    // PCSR_PROCESS Process = CsrGetClientThread()->Process;
+    PCONSOLE Console;
+    PCONSOLE_PROCESS_DATA current;
     PLIST_ENTRY current_entry;
     ULONG nItems = 0;
-    NTSTATUS Status;
 
-    DPRINT("SrvGetConsoleProcessList\n");
-
-    Buffer = GetProcessListRequest->ProcessId;
-    if (!Win32CsrValidateBuffer(ProcessData, Buffer, GetProcessListRequest->nMaxIds, sizeof(DWORD)))
-        return STATUS_ACCESS_VIOLATION;
-
-    Status = ConioConsoleFromProcessData(ProcessData, &Console);
-    if (! NT_SUCCESS(Status))
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID)&GetProcessListRequest->pProcessIds,
+                                  GetProcessListRequest->nMaxIds,
+                                  sizeof(DWORD)))
     {
-        return Status;
+        return STATUS_INVALID_PARAMETER;
     }
 
+    Buffer = GetProcessListRequest->pProcessIds;
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
     for (current_entry = Console->ProcessList.Flink;
          current_entry != &Console->ProcessList;
          current_entry = current_entry->Flink)
     {
-        current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
+        current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
         if (++nItems <= GetProcessListRequest->nMaxIds)
         {
-            *Buffer++ = HandleToUlong(current->ClientId.UniqueProcess);
+            *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
         }
     }
 
-    ConioUnlockConsole(Console);
+    ConSrvReleaseConsole(Console, TRUE);
 
     GetProcessListRequest->nProcessIdsTotal = nItems;
     return STATUS_SUCCESS;
@@ -840,52 +1486,36 @@ CSR_API(SrvGetConsoleProcessList)
 
 CSR_API(SrvGenerateConsoleCtrlEvent)
 {
-    PCSRSS_GENERATE_CTRL_EVENT GenerateCtrlEvent = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEvent;
-    PCSRSS_CONSOLE Console;
-    PCSR_PROCESS current;
-    PLIST_ENTRY current_entry;
-    DWORD Group;
     NTSTATUS Status;
+    PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
+    PCONSOLE Console;
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    Group = GenerateCtrlEvent->ProcessGroup;
-    Status = STATUS_INVALID_PARAMETER;
-    for (current_entry = Console->ProcessList.Flink;
-            current_entry != &Console->ProcessList;
-            current_entry = current_entry->Flink)
-    {
-        current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
-        if (Group == 0 || current->ProcessGroupId == Group)
-        {
-            ConioConsoleCtrlEvent(GenerateCtrlEvent->Event, current);
-            Status = STATUS_SUCCESS;
-        }
-    }
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
 
-    ConioUnlockConsole(Console);
+    Status = ConSrvConsoleProcessCtrlEvent(Console,
+                                           GenerateCtrlEventRequest->ProcessGroup,
+                                           GenerateCtrlEventRequest->Event);
 
+    ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
 
 CSR_API(SrvGetConsoleSelectionInfo)
 {
     NTSTATUS Status;
-    PCSRSS_GET_CONSOLE_SELECTION_INFO GetConsoleSelectionInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleSelectionInfo;
-    PCSRSS_CONSOLE Console;
+    PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest;
+    PCONSOLE Console;
 
-    Status = ConioConsoleFromProcessData(CsrGetClientThread()->Process, &Console);
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (NT_SUCCESS(Status))
     {
-        memset(&GetConsoleSelectionInfo->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
+        memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
         if (Console->Selection.dwFlags != 0)
-            GetConsoleSelectionInfo->Info = Console->Selection;
-        ConioUnlockConsole(Console);
+            GetSelectionInfoRequest->Info = Console->Selection;
+        ConSrvReleaseConsole(Console, TRUE);
     }
+
     return Status;
 }