[BASESRV-CONSRV-WINSRV]
[reactos.git] / win32ss / user / consrv / console.c
index 2964792..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 "settings.h"
-#include "guiconsole.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 "tuiconsole.h"
+    #include "frontends/tui/tuiterm.h"
 #endif
 
+#include "include/console.h"
+#include "console.h"
+#include "resource.h"
+
 #include <shlwapi.h>
 #include <shlobj.h>
 
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
+/* GLOBALS ********************************************************************/
 
-/* FUNCTIONS *****************************************************************/
+static LIST_ENTRY ConsoleList;  /* The list of all the allocated consoles */
+static RTL_RESOURCE ListLock;
 
-BOOL FASTCALL
+#define ConSrvLockConsoleListExclusive()    \
+    RtlAcquireResourceExclusive(&ListLock, TRUE)
+
+#define ConSrvLockConsoleListShared()       \
+    RtlAcquireResourceShared(&ListLock, TRUE)
+
+#define ConSrvUnlockConsoleList()           \
+    RtlReleaseResource(&ListLock)
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+#ifdef TUI_CONSOLE
+static BOOL
 DtbgIsDesktopVisible(VOID)
 {
     return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
 }
+#endif
 
-VOID FASTCALL
+static ULONG
 ConSrvConsoleCtrlEventTimeout(DWORD Event,
                               PCONSOLE_PROCESS_DATA ProcessData,
                               DWORD Timeout)
 {
-    HANDLE Thread;
+    ULONG Status = ERROR_SUCCESS;
 
-    DPRINT("ConSrvConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
+    DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
 
     if (ProcessData->CtrlDispatcher)
     {
-        Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
-                                    ProcessData->CtrlDispatcher,
-                                    UlongToPtr(Event), 0, NULL);
-        if (NULL == Thread)
+        _SEH2_TRY
         {
-            DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
-            return;
-        }
+            HANDLE Thread = NULL;
 
-        DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
-        WaitForSingleObject(Thread, Timeout);
-        CloseHandle(Thread);
+            _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 Status;
 }
 
-VOID FASTCALL
-ConSrvConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
+static ULONG
+ConSrvConsoleCtrlEvent(DWORD Event,
+                       PCONSOLE_PROCESS_DATA ProcessData)
+{
+    return ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
+}
+
+ULONG FASTCALL
+ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
+                              ULONG ProcessGroupId,
+                              DWORD Event)
 {
-    ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
+    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;
+
+    /*
+     * Loop through the process list, from the most recent process
+     * (the active one) to the oldest one (the first created, i.e.
+     * the console leader process), and for each, send an event
+     * (new processes are inserted at the head of the console process list).
+     */
+    current_entry = Console->ProcessList.Flink;
+    while (current_entry != &Console->ProcessList)
+    {
+        current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
+        current_entry = current_entry->Flink;
+
+        /*
+         * Only processes belonging to the same process group are signaled.
+         * If the process group ID is zero, then all the processes are signaled.
+         */
+        if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId)
+        {
+            Status = ConSrvConsoleCtrlEvent(Event, current);
+        }
+    }
+
+    return Status;
 }
 
 VOID FASTCALL
@@ -97,9 +187,164 @@ ConioUnpause(PCONSOLE Console, UINT Flags)
     }
 }
 
+BOOL FASTCALL
+ConSrvValidateConsolePointer(PCONSOLE Console)
+{
+    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;
+}
+
+BOOL FASTCALL
+ConSrvValidateConsoleState(PCONSOLE Console,
+                           CONSOLE_STATE ExpectedState)
+{
+    // if (!Console) return FALSE;
+
+    /* The console must be locked */
+    // ASSERT(Console_locked);
+
+    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))
+    {
+        if (LockConsole) LeaveCriticalSection(&Console->Lock);
+        return FALSE;
+    }
+
+    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))
+    {
+        RetVal = ConSrvValidateConsoleUnsafe(Console,
+                                             ExpectedState,
+                                             LockConsole);
+    }
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
+    return RetVal;
+}
+
+NTSTATUS
+FASTCALL
+ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
+                 PCONSOLE* Console,
+                 BOOL LockConsole)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSOLE ProcessConsole;
+
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    ProcessConsole = ProcessData->Console;
+
+    if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
+    {
+        InterlockedIncrement(&ProcessConsole->ReferenceCount);
+        *Console = ProcessConsole;
+    }
+    else
+    {
+        *Console = NULL;
+        Status = STATUS_INVALID_HANDLE;
+    }
+
+    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);
+
+    /* 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,
-                         OUT PCONSOLE_INFO ConsoleInfo,
+                         IN OUT PCONSOLE_INFO ConsoleInfo,
                          OUT LPWSTR IconPath,
                          IN SIZE_T IconPathLength,
                          OUT PINT piIcon)
@@ -165,14 +410,8 @@ LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
                     INT ShowCmd = 0;
                     // WORD HotKey = 0;
 
-                    /* Get the name of the shortcut */
-                    Length = min(Length - 4,
-                                 sizeof(ConsoleStartInfo->ConsoleTitle) / sizeof(ConsoleStartInfo->ConsoleTitle[0]) - 1);
-                    wcsncpy(ConsoleStartInfo->ConsoleTitle, LinkName, Length);
-                    ConsoleStartInfo->ConsoleTitle[Length] = L'\0';
-
-                    // HACK: Copy also the name of the shortcut
-                    Length = min(Length,
+                    /* 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';
@@ -208,7 +447,6 @@ LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
 
 NTSTATUS WINAPI
 ConSrvInitConsole(OUT PCONSOLE* NewConsole,
-                  IN LPCWSTR AppPath,
                   IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
                   IN PCSR_PROCESS ConsoleLeaderProcess)
 {
@@ -251,9 +489,9 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     ConsoleInfo.ConsoleTitle[Length] = L'\0';
 
     /*
-     * 3. Check whether the process creating the
-     *    console was launched via a shell-link
-     *    (ConsoleInfo.ConsoleTitle may be updated).
+     * 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)
     {
@@ -283,6 +521,7 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
          * 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)
         {
@@ -292,24 +531,16 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
         {
             ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
         }
-        if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
-        {
-            ConsoleInfo.u.GuiInfo.ShowWindow = ConsoleStartInfo->ShowWindow;
-        }
-        if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
-        {
-            ConsoleInfo.u.GuiInfo.AutoPosition = FALSE;
-            ConsoleInfo.u.GuiInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin;
-        }
         if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
         {
-            // ConsoleInfo.ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
+            // 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;
         }
         */
     }
@@ -317,16 +548,17 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     /*
      * 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->Size = ConsoleInfo.ConsoleSize;
+    Console->ConsoleSize = ConsoleInfo.ConsoleSize;
 
     /*
      * Initialize the input buffer
      */
-    Console->InputBuffer.Header.Type = CONIO_INPUT_BUFFER_MAGIC;
+    Console->InputBuffer.Header.Type = INPUT_BUFFER;
     Console->InputBuffer.Header.Console = Console;
 
     SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
@@ -340,9 +572,8 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
         return STATUS_UNSUCCESSFUL;
     }
 
-    // TODO: Use the values from ConsoleInfo.
-    Console->InputBuffer.Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
-                                ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
+    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);
@@ -358,6 +589,8 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
                                       ConsoleInfo.ScreenBufferSize,
                                       ConsoleInfo.ScreenAttrib,
                                       ConsoleInfo.PopupAttrib,
+                                      (ConsoleInfo.FullScreen ? CONSOLE_FULLSCREEN_MODE
+                                                              : CONSOLE_WINDOWED_MODE),
                                       TRUE,
                                       ConsoleInfo.CursorSize);
     if (!NT_SUCCESS(Status))
@@ -370,7 +603,6 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     }
     /* Make the new screen buffer active */
     Console->ActiveBuffer = NewBuffer;
-    Console->FullScreen = ConsoleInfo.FullScreen;
     InitializeListHead(&Console->WriteWaitQueue);
 
     /*
@@ -382,8 +614,8 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
 
     /* Initialize the console title */
-    RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleStartInfo->ConsoleTitle);
-    if (ConsoleStartInfo->ConsoleTitle[0] == L'\0')
+    RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
+    if (ConsoleInfo.ConsoleTitle[0] == L'\0')
     {
         if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, Title, sizeof(Title) / sizeof(Title[0])))
         {
@@ -396,9 +628,12 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     }
     else
     {
-        RtlCreateUnicodeString(&Console->Title, ConsoleStartInfo->ConsoleTitle);
+        RtlCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
     }
 
+    /* Lock the console until its initialization is finished */
+    // EnterCriticalSection(&Console->Lock);
+
     /*
      * If we are not in GUI-mode, start the text-mode terminal emulator.
      * If we fail, try to start the GUI-mode terminal emulator.
@@ -413,7 +648,10 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     if (!GuiMode)
     {
         DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
-        Status = TuiInitConsole(Console, &ConsoleInfo);
+        Status = TuiInitConsole(Console,
+                                ConsoleStartInfo,
+                                &ConsoleInfo,
+                                ProcessId);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status);
@@ -429,15 +667,16 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
      * - 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,
+     *   terminal emulator (Win32k will automatically switch to graphical mode,
      *   therefore no additional code is needed).
      */
     if (GuiMode)
     {
         DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
         Status = GuiInitConsole(Console,
-                                AppPath,
+                                ConsoleStartInfo,
                                 &ConsoleInfo,
+                                ProcessId,
                                 IconPath,
                                 iIcon);
         if (!NT_SUCCESS(Status))
@@ -447,127 +686,159 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
             RtlFreeUnicodeString(&Console->OriginalTitle);
             ConioDeleteScreenBuffer(NewBuffer);
             CloseHandle(Console->InputBuffer.ActiveEvent);
+            // LeaveCriticalSection(&Console->Lock);
             DeleteCriticalSection(&Console->Lock);
             RtlFreeHeap(ConSrvHeap, 0, Console);
             return Status;
         }
     }
 
+    DPRINT("Terminal initialized\n");
+
+    /* All went right, so add the console to the list */
+    ConSrvLockConsoleListExclusive();
+    DPRINT("Insert in the list\n");
+    InsertTailList(&ConsoleList, &Console->Entry);
+
+    /* The initialization is finished */
+    DPRINT("Change state\n");
+    Console->State = CONSOLE_RUNNING;
+
+    /* 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
-ConSrvInitConsoleSupport(VOID)
-{
-    DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
-
-    /* Should call LoadKeyboardLayout */
-}
-
 VOID WINAPI
 ConSrvDeleteConsole(PCONSOLE Console)
 {
-    ConsoleInput *Event;
-
     DPRINT("ConSrvDeleteConsole\n");
 
-    /* Drain input event queue */
-    while (Console->InputBuffer.InputEvents.Flink != &Console->InputBuffer.InputEvents)
+    /*
+     * Forbid validation of any console by other threads
+     * during the deletion of this console.
+     */
+    ConSrvLockConsoleListExclusive();
+
+    /* Check the existence of the console, and if it's ok, continue */
+    if (!ConSrvValidateConsolePointer(Console))
     {
-        Event = (ConsoleInput *) Console->InputBuffer.InputEvents.Flink;
-        Console->InputBuffer.InputEvents.Flink = Console->InputBuffer.InputEvents.Flink->Flink;
-        Console->InputBuffer.InputEvents.Flink->Flink->Blink = &Console->InputBuffer.InputEvents;
-        RtlFreeHeap(ConSrvHeap, 0, Event);
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
     }
 
-    ConioCleanupConsole(Console);
-    if (Console->LineBuffer)
-        RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
-    while (!IsListEmpty(&Console->HistoryBuffers))
-        HistoryDeleteBuffer((struct _HISTORY_BUFFER *)Console->HistoryBuffers.Flink);
-
-    ConioDeleteScreenBuffer(Console->ActiveBuffer);
-    if (!IsListEmpty(&Console->BufferList))
+    /*
+     * If the console is already being destroyed
+     * (thus not running), just return.
+     */
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
     {
-        DPRINT1("BUG: screen buffer list not empty\n");
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
     }
 
-    CloseHandle(Console->InputBuffer.ActiveEvent);
-    if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
-    DeleteCriticalSection(&Console->Lock);
+    /*
+     * 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;
 
-    RtlFreeUnicodeString(&Console->OriginalTitle);
-    RtlFreeUnicodeString(&Console->Title);
-    IntDeleteAllAliases(Console->Aliases);
-    RtlFreeHeap(ConSrvHeap, 0, Console);
-}
+    /*
+     * 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();
 
-CSR_API(SrvOpenConsole)
-{
-    NTSTATUS Status = STATUS_SUCCESS;
-    PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
-    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    /* FIXME: Send a terminate message to all the processes owning this console */
 
-    DPRINT("SrvOpenConsole\n");
+    /* Cleanup the UI-oriented part */
+    ConioCleanupConsole(Console);
 
-    OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
+    /***
+     * 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 ?).
+     ***/
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    ConSrvLockConsoleListExclusive();
 
-    DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
+    /* 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 (ProcessData->Console)
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
     {
-        DWORD DesiredAccess = OpenConsoleRequest->Access;
-        DWORD ShareMode = OpenConsoleRequest->ShareMode;
+        ConSrvUnlockConsoleList();
+        return;
+    }
 
-        PCONSOLE Console = ProcessData->Console;
-        Object_t *Object;
+    /* We are in destruction */
+    Console->State = CONSOLE_IN_DESTRUCTION;
 
-        DPRINT1("SrvOpenConsole - Checkpoint 1\n");
-        EnterCriticalSection(&Console->Lock);
-        DPRINT1("SrvOpenConsole - Checkpoint 2\n");
+    /* Remove the console from the list */
+    RemoveEntryList(&Console->Entry);
 
-        if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
-        {
-            Object = &Console->ActiveBuffer->Header;
-        }
-        else // HANDLE_INPUT
-        {
-            Object = &Console->InputBuffer.Header;
-        }
+    /* Reset the count to be sure */
+    Console->ReferenceCount = 0;
 
-        if (((DesiredAccess & GENERIC_READ)  && Object->ExclusiveRead  != 0) ||
-            ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
-            (!(ShareMode & FILE_SHARE_READ)  && Object->AccessRead     != 0) ||
-            (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite    != 0))
-        {
-            DPRINT1("Sharing violation\n");
-            Status = STATUS_SHARING_VIOLATION;
-        }
-        else
-        {
-            Status = ConSrvInsertObject(ProcessData,
-                                        &OpenConsoleRequest->ConsoleHandle,
-                                        Object,
-                                        DesiredAccess,
-                                        OpenConsoleRequest->Inheritable,
-                                        ShareMode);
-        }
+    /* Discard all entries in the input event queue */
+    PurgeInputBuffer(Console);
+
+    if (Console->LineBuffer) RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
+
+    IntDeleteAllAliases(Console);
+    HistoryDeleteBuffers(Console);
 
-        LeaveCriticalSection(&Console->Lock);
+    ConioDeleteScreenBuffer(Console->ActiveBuffer);
+    if (!IsListEmpty(&Console->BufferList))
+    {
+        DPRINT1("BUG: screen buffer list not empty\n");
     }
 
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+    // CloseHandle(Console->InputBuffer.ActiveEvent);
+    if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
 
-    return Status;
+    RtlFreeUnicodeString(&Console->OriginalTitle);
+    RtlFreeUnicodeString(&Console->Title);
+
+    DPRINT("ConSrvDeleteConsole - Unlocking\n");
+    LeaveCriticalSection(&Console->Lock);
+    DPRINT("ConSrvDeleteConsole - Destroying lock\n");
+    DeleteCriticalSection(&Console->Lock);
+    DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
+
+    RtlFreeHeap(ConSrvHeap, 0, Console);
+    DPRINT("ConSrvDeleteConsole - Console freed\n");
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
 }
 
+
+/* PUBLIC SERVER APIS *********************************************************/
+
 CSR_API(SrvAllocConsole)
 {
     NTSTATUS Status = STATUS_SUCCESS;
@@ -575,22 +846,16 @@ CSR_API(SrvAllocConsole)
     PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
 
-    DPRINT("SrvAllocConsole\n");
-
     if (ProcessData->Console != NULL)
     {
         DPRINT1("Process already has a console\n");
         return STATUS_ACCESS_DENIED;
     }
 
-    if ( !CsrValidateMessageBuffer(ApiMessage,
-                                   (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
-                                   1,
-                                   sizeof(CONSOLE_START_INFO))      ||
-         !CsrValidateMessageBuffer(ApiMessage,
-                                   (PVOID*)&AllocConsoleRequest->AppPath,
-                                   MAX_PATH + 1,
-                                   sizeof(WCHAR)) )
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
+                                  1,
+                                  sizeof(CONSOLE_START_INFO)))
     {
         return STATUS_INVALID_PARAMETER;
     }
@@ -606,11 +871,9 @@ CSR_API(SrvAllocConsole)
      * and recreate a new one later on.
      */
     ConSrvRemoveConsole(ProcessData);
-    // ConSrvFreeHandlesTable(ProcessData);
 
     /* Initialize a new Console owned by the Console Leader Process */
     Status = ConSrvAllocateConsole(ProcessData,
-                                   AllocConsoleRequest->AppPath,
                                    &AllocConsoleRequest->InputHandle,
                                    &AllocConsoleRequest->OutputHandle,
                                    &AllocConsoleRequest->ErrorHandle,
@@ -632,7 +895,6 @@ CSR_API(SrvAllocConsole)
 
     /* Set the Ctrl Dispatcher */
     ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
-    DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
 
     return STATUS_SUCCESS;
 }
@@ -646,8 +908,6 @@ CSR_API(SrvAttachConsole)
     HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
     PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
 
-    DPRINT("SrvAttachConsole\n");
-
     TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
 
     if (TargetProcessData->Console != NULL)
@@ -674,19 +934,15 @@ CSR_API(SrvAttachConsole)
             return Status;
         }
 
-        DPRINT("We, process (ID) %lu;%lu\n", TargetProcess->ClientId.UniqueProcess, TargetProcess->ClientId.UniqueThread);
         ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
-        DPRINT("Parent process ID = %lu\n", ProcessId);
     }
 
     /* Lock the source process via its PID */
     Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
-    DPRINT1("Lock process Id %lu - Status %lu\n", ProcessId, Status);
     if (!NT_SUCCESS(Status)) return Status;
 
     SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
 
-    DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData->Console);
     if (SourceProcessData->Console == NULL)
     {
         Status = STATUS_INVALID_HANDLE;
@@ -704,7 +960,6 @@ CSR_API(SrvAttachConsole)
      * and recreate a new one later on.
      */
     ConSrvRemoveConsole(TargetProcessData);
-    // ConSrvFreeHandlesTable(TargetProcessData);
 
     /*
      * Inherit the console from the parent,
@@ -733,7 +988,6 @@ CSR_API(SrvAttachConsole)
 
     /* Set the Ctrl Dispatcher */
     TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
-    DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData->CtrlDispatcher);
 
     Status = STATUS_SUCCESS;
 
@@ -745,41 +999,44 @@ Quit:
 
 CSR_API(SrvFreeConsole)
 {
-    DPRINT1("SrvFreeConsole\n");
     ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
     return STATUS_SUCCESS;
 }
 
-CSR_API(SrvSetConsoleMode)
+CSR_API(SrvGetConsoleMode)
 {
-#define CONSOLE_INPUT_MODE_VALID  ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT   | \
-                                    ENABLE_ECHO_INPUT      | ENABLE_WINDOW_INPUT | \
-                                    ENABLE_MOUSE_INPUT | \
-                                    ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS )
-#define CONSOLE_OUTPUT_MODE_VALID ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
-
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
-    Object_t* Object = NULL;
-
-    DPRINT("SrvSetConsoleMode\n");
+    PCONSOLE_IO_OBJECT Object = NULL;
 
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
-                                ConsoleModeRequest->ConsoleHandle,
-                                &Object, NULL, GENERIC_WRITE, TRUE, 0);
+                             ConsoleModeRequest->ConsoleHandle,
+                             &Object, NULL, GENERIC_READ, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
     Status = STATUS_SUCCESS;
 
-    if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+    if (INPUT_BUFFER == Object->Type)
     {
         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
-        InputBuffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
+        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 == Object->Type)
+    else if (SCREEN_BUFFER == Object->Type)
     {
         PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
-        Buffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
+        ConsoleModeRequest->ConsoleMode = Buffer->Mode;
     }
     else
     {
@@ -787,54 +1044,99 @@ CSR_API(SrvSetConsoleMode)
     }
 
     ConSrvReleaseObject(Object, TRUE);
-
     return Status;
 }
 
-CSR_API(SrvGetConsoleMode)
+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;
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
-    Object_t* Object = NULL;
-
-    DPRINT("SrvGetConsoleMode\n");
+    DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode;
+    PCONSOLE_IO_OBJECT Object  = NULL;
 
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
-                                ConsoleModeRequest->ConsoleHandle,
-                                &Object, NULL, GENERIC_READ, TRUE, 0);
+                             ConsoleModeRequest->ConsoleHandle,
+                             &Object, NULL, GENERIC_WRITE, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
     Status = STATUS_SUCCESS;
 
-    if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+    if (INPUT_BUFFER == Object->Type)
     {
         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
-        ConsoleModeRequest->ConsoleMode = InputBuffer->Mode;
+        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;
+        }
+
+        /*
+         * 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 (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
+    else if (SCREEN_BUFFER == Object->Type)
     {
         PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
-        ConsoleModeRequest->ConsoleMode = Buffer->Mode;
+
+        DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode);
+
+        if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
+        {
+            Status = STATUS_INVALID_PARAMETER;
+        }
+        else
+        {
+            Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
+        }
     }
     else
     {
         Status = STATUS_INVALID_HANDLE;
     }
 
+Quit:
     ConSrvReleaseObject(Object, TRUE);
-
     return Status;
 }
 
-CSR_API(SrvSetConsoleTitle)
+CSR_API(SrvGetConsoleTitle)
 {
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
     // PCSR_PROCESS Process = CsrGetClientThread()->Process;
     PCONSOLE Console;
-    PWCHAR Buffer;
-
-    DPRINT("SrvSetConsoleTitle\n");
+    DWORD Length;
 
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&TitleRequest->Title,
@@ -851,43 +1153,27 @@ CSR_API(SrvSetConsoleTitle)
         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
+    /* Copy title of the console to the user title buffer */
+    if (TitleRequest->Length >= sizeof(WCHAR))
     {
-        Status = STATUS_NO_MEMORY;
+        Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
+        memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
+        TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
     }
 
+    TitleRequest->Length = Console->Title.Length;
+
     ConSrvReleaseConsole(Console, TRUE);
-    return Status;
+    return STATUS_SUCCESS;
 }
 
-CSR_API(SrvGetConsoleTitle)
+CSR_API(SrvSetConsoleTitle)
 {
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
     // PCSR_PROCESS Process = CsrGetClientThread()->Process;
     PCONSOLE Console;
-    DWORD Length;
-
-    DPRINT("SrvGetConsoleTitle\n");
+    PWCHAR Buffer;
 
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&TitleRequest->Title,
@@ -904,18 +1190,32 @@ CSR_API(SrvGetConsoleTitle)
         return Status;
     }
 
-    /* Copy title of the console to the user title buffer */
-    if (TitleRequest->Length >= sizeof(WCHAR))
+    /* Allocate a new buffer to hold the new title (NULL-terminated) */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
+    if (Buffer)
     {
-        Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
-        memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
-        TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
-    }
+        /* Free the old title */
+        RtlFreeUnicodeString(&Console->Title);
 
-    TitleRequest->Length = Console->Title.Length;
+        /* 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_SUCCESS;
+    return Status;
 }
 
 /**********************************************************************
@@ -933,7 +1233,7 @@ CSR_API(SrvGetConsoleTitle)
  *      with NT's, but values are not.
  */
 static NTSTATUS FASTCALL
-SetConsoleHardwareState(PCONSOLE Console, DWORD ConsoleHwState)
+SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState)
 {
     DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
 
@@ -960,8 +1260,6 @@ CSR_API(SrvGetConsoleHardwareState)
     PCONSOLE_SCREEN_BUFFER Buff;
     PCONSOLE Console;
 
-    DPRINT("SrvGetConsoleHardwareState\n");
-
     Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                                   HardwareStateRequest->OutputHandle,
                                   &Buff,
@@ -977,7 +1275,6 @@ CSR_API(SrvGetConsoleHardwareState)
     HardwareStateRequest->State = Console->HardwareState;
 
     ConSrvReleaseScreenBuffer(Buff, TRUE);
-
     return Status;
 }
 
@@ -988,12 +1285,10 @@ CSR_API(SrvSetConsoleHardwareState)
     PCONSOLE_SCREEN_BUFFER Buff;
     PCONSOLE Console;
 
-    DPRINT("SrvSetConsoleHardwareState\n");
-
     Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                                   HardwareStateRequest->OutputHandle,
                                   &Buff,
-                                  GENERIC_READ,
+                                  GENERIC_WRITE,
                                   TRUE);
     if (!NT_SUCCESS(Status))
     {
@@ -1006,7 +1301,67 @@ CSR_API(SrvSetConsoleHardwareState)
     Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
 
     ConSrvReleaseScreenBuffer(Buff, TRUE);
+    return Status;
+}
 
+CSR_API(SrvGetConsoleDisplayMode)
+{
+    NTSTATUS Status;
+    PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest;
+    PCONSOLE Console;
+    ULONG DisplayMode = 0;
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                              &Console, TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
+        return Status;
+    }
+
+    if (Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE)
+        DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
+    else if (Console->ActiveBuffer->DisplayMode & CONSOLE_WINDOWED_MODE)
+        DisplayMode |= CONSOLE_WINDOWED;
+
+    GetDisplayModeRequest->DisplayMode = DisplayMode;
+    Status = STATUS_SUCCESS;
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+CSR_API(SrvSetConsoleDisplayMode)
+{
+    NTSTATUS 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;
+    }
+
+    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;
 }
 
@@ -1016,12 +1371,10 @@ CSR_API(SrvGetConsoleWindow)
     PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
     PCONSOLE Console;
 
-    DPRINT("SrvGetConsoleWindow\n");
-
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
-    GetWindowRequest->WindowHandle = Console->TermIFace.Vtbl->GetConsoleWindowHandle(Console);
+    GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console);
     ConSrvReleaseConsole(Console, TRUE);
 
     return STATUS_SUCCESS;
@@ -1033,8 +1386,6 @@ CSR_API(SrvSetConsoleIcon)
     PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
     PCONSOLE Console;
 
-    DPRINT("SrvSetConsoleIcon\n");
-
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
@@ -1103,8 +1454,6 @@ CSR_API(SrvGetConsoleProcessList)
     PLIST_ENTRY current_entry;
     ULONG nItems = 0;
 
-    DPRINT("SrvGetConsoleProcessList\n");
-
     if (!CsrValidateMessageBuffer(ApiMessage,
                                   (PVOID)&GetProcessListRequest->pProcessIds,
                                   GetProcessListRequest->nMaxIds,
@@ -1140,29 +1489,15 @@ CSR_API(SrvGenerateConsoleCtrlEvent)
     NTSTATUS Status;
     PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
     PCONSOLE Console;
-    PCONSOLE_PROCESS_DATA current;
-    PLIST_ENTRY current_entry;
-    DWORD Group;
 
     Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
     if (!NT_SUCCESS(Status)) return Status;
 
-    Group = GenerateCtrlEventRequest->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, CONSOLE_PROCESS_DATA, ConsoleLink);
-        if (Group == 0 || current->Process->ProcessGroupId == Group)
-        {
-            ConSrvConsoleCtrlEvent(GenerateCtrlEventRequest->Event, current);
-            Status = STATUS_SUCCESS;
-        }
-    }
+    Status = ConSrvConsoleProcessCtrlEvent(Console,
+                                           GenerateCtrlEventRequest->ProcessGroup,
+                                           GenerateCtrlEventRequest->Event);
 
     ConSrvReleaseConsole(Console, TRUE);
-
     return Status;
 }