[CONSOLE.DLL]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Mar 2013 18:44:56 +0000 (18:44 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Mar 2013 18:44:56 +0000 (18:44 +0000)
- Fix passing and retrieving gui terminal front-end information.
- Fix default (global) console parameters saving.

[CONSRV]
- PSEH2-protect calls to CreateRemoteThread when 1. calling console app. control handlers and 2. retrieving console settings from console.dll.
- Introduce a new way of locking consoles when being used, and store them in a list.

svn path=/branches/ros-csrss/; revision=58615

dll/cpl/console/console.c
win32ss/user/consrv/coninput.c
win32ss/user/consrv/conio.h
win32ss/user/consrv/conoutput.c
win32ss/user/consrv/console.c
win32ss/user/consrv/console.h [new file with mode: 0644]
win32ss/user/consrv/consrv.h
win32ss/user/consrv/guiconsole.c
win32ss/user/consrv/guisettings.c
win32ss/user/consrv/handle.c
win32ss/user/consrv/init.c

index cc9551d..d570085 100644 (file)
@@ -87,6 +87,8 @@ InitConsoleDefaults(PCONSOLE_PROPS pConInfo)
 {
     PGUI_CONSOLE_INFO GuiInfo = NULL;
 
+    /* FIXME: Get also the defaults from the registry */
+
     /* Initialize the default properties */
     pConInfo->ci.HistoryBufferSize = 50;
     pConInfo->ci.NumberOfHistoryBuffers = 4;
@@ -108,7 +110,8 @@ InitConsoleDefaults(PCONSOLE_PROPS pConInfo)
     /* Adapted for holding GUI terminal information */
     pConInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
     GuiInfo = pConInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pConInfo + 1);
-    GuiInfo->FaceName[0] = L'\0';
+    wcsncpy(GuiInfo->FaceName, L"Fixedsys", LF_FACESIZE); // HACK: !!
+    // GuiInfo->FaceName[0] = L'\0';
     GuiInfo->FontFamily = FF_DONTCARE;
     GuiInfo->FontSize = 0;
     GuiInfo->FontWeight = FW_DONTCARE;
@@ -166,16 +169,35 @@ BOOL
 ApplyConsoleInfo(HWND hwndDlg,
                  PCONSOLE_PROPS pConInfo)
 {
-    INT_PTR res = 0;
+    BOOL SetParams  = FALSE;
+    BOOL SaveParams = FALSE;
 
-    res = DialogBox(hApplet, MAKEINTRESOURCE(IDD_APPLYOPTIONS), hwndDlg, ApplyProc);
-    if (res == IDCANCEL)
+    /*
+     * If we are setting the default parameters, just save them,
+     * otherwise display the save-confirmation dialog.
+     */
+    if (pConInfo->ShowDefaultParams)
     {
-        /* Don't destroy when user presses cancel */
-        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
-        return TRUE;
+        SetParams  = TRUE;
+        SaveParams = TRUE;
     }
-    else if (res == IDC_RADIO_APPLY_ALL || res == IDC_RADIO_APPLY_CURRENT)
+    else
+    {
+        INT_PTR res = DialogBox(hApplet, MAKEINTRESOURCE(IDD_APPLYOPTIONS), hwndDlg, ApplyProc);
+
+        SetParams  = (res != IDCANCEL);
+        SaveParams = (res == IDC_RADIO_APPLY_ALL);
+
+        if (SetParams == FALSE)
+        {
+            /* Don't destroy when user presses cancel */
+            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
+            // return TRUE;
+        }
+    }
+
+    // if (res == IDC_RADIO_APPLY_ALL || res == IDC_RADIO_APPLY_CURRENT)
+    if (SetParams)
     {
         HANDLE hSection;
         PCONSOLE_PROPS pSharedInfo;
@@ -207,10 +229,15 @@ ApplyConsoleInfo(HWND hwndDlg,
         /* We are applying the chosen configuration */
         pConInfo->AppliedConfig = TRUE;
 
-        /* Copy the console info into the section */
+        /*
+         * Copy the console information into the section and
+         * offsetize the address of terminal-specific information.
+         * Do not perform the offsetization in pConInfo as it is
+         * likely to be reused later on. Instead, do it in pSharedInfo
+         * after having copied all the data.
+         */
         RtlCopyMemory(pSharedInfo, pConInfo, sizeof(CONSOLE_PROPS) + sizeof(GUI_CONSOLE_INFO));
-        /* Offsetize */
-        pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)pSharedInfo->TerminalInfo.TermInfo - (ULONG_PTR)pSharedInfo);
+        pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)pConInfo->TerminalInfo.TermInfo - (ULONG_PTR)pConInfo);
 
         /* Unmap it */
         UnmapViewOfFile(pSharedInfo);
@@ -220,11 +247,10 @@ ApplyConsoleInfo(HWND hwndDlg,
         SendMessage(pConInfo->hConsoleWindow,
                     PM_APPLY_CONSOLE_INFO,
                     (WPARAM)hSection,
-                    (LPARAM)(res == IDC_RADIO_APPLY_ALL));
+                    (LPARAM)SaveParams);
 
         /* Close the section and return */
         CloseHandle(hSection);
-        return TRUE;
     }
 
     return TRUE;
index bfe882a..a7c0ed5 100644 (file)
@@ -685,7 +685,6 @@ CSR_API(SrvReadConsole)
         return STATUS_INVALID_PARAMETER;
     }
 
-    // if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
     if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
     {
         return STATUS_INVALID_PARAMETER;
@@ -808,7 +807,7 @@ CSR_API(SrvFlushConsoleInputBuffer)
     PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
     PLIST_ENTRY CurrentEntry;
     PCONSOLE_INPUT_BUFFER InputBuffer;
-    ConsoleInput* Input;
+    ConsoleInput* Event;
 
     DPRINT("SrvFlushConsoleInputBuffer\n");
 
@@ -823,14 +822,12 @@ CSR_API(SrvFlushConsoleInputBuffer)
     while (!IsListEmpty(&InputBuffer->InputEvents))
     {
         CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
-        Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
-        /* Destroy the event */
-        RtlFreeHeap(ConSrvHeap, 0, Input);
+        Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+        RtlFreeHeap(ConSrvHeap, 0, Event);
     }
     ResetEvent(InputBuffer->ActiveEvent);
 
     ConSrvReleaseInputBuffer(InputBuffer, TRUE);
-
     return STATUS_SUCCESS;
 }
 
index 5825954..45d9b88 100644 (file)
@@ -147,12 +147,27 @@ typedef struct _FRONTEND_IFACE
     PVOID OldData;          /* Reserved      */
 } FRONTEND_IFACE, *PFRONTEND_IFACE;
 
+#if 0 // Temporarily put in consrv.h
+/*
+ * WARNING: Change the state of the console ONLY when the console is locked !
+ */
+typedef enum _CONSOLE_STATE
+{
+    CONSOLE_INITIALIZING,   /* Console is initializing */
+    CONSOLE_RUNNING     ,   /* Console running */
+    CONSOLE_TERMINATING ,   /* Console about to be destroyed (but still not) */
+    CONSOLE_IN_DESTRUCTION  /* Console in destruction */
+} CONSOLE_STATE, *PCONSOLE_STATE;
+#endif
+
 typedef struct _CONSOLE
 {
-    LONG ReferenceCount;                    /* Is incremented each time a handle to a screen-buffer or the input buffer of this console gets referenced, or the console gets locked */
+    LONG ReferenceCount;                    /* Is incremented each time a handle to something in the console (a screen-buffer or the input buffer of this console) gets referenced */
     CRITICAL_SECTION Lock;
+    CONSOLE_STATE State;                    /* State of the console */
 
-    struct _CONSOLE *Prev, *Next;           /* Next and Prev consoles in console wheel */
+    // struct _CONSOLE *Prev, *Next;           /* Next and Prev consoles in console wheel */
+    LIST_ENTRY Entry;                       /* Entry in the list of consoles */
     LIST_ENTRY ProcessList;                 /* List of processes owning the console. The first one is the so-called "Console Leader Process" */
 
     FRONTEND_IFACE TermIFace;               /* Frontend-specific interface */
@@ -218,11 +233,6 @@ typedef struct _CONSOLE
 #define PAUSED_FROM_SELECTION 0x4
 
 /* console.c */
-VOID WINAPI ConSrvDeleteConsole(PCONSOLE Console);
-VOID WINAPI ConSrvInitConsoleSupport(VOID);
-NTSTATUS WINAPI ConSrvInitConsole(OUT PCONSOLE* NewConsole,
-                                  IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
-                                  IN PCSR_PROCESS ConsoleLeaderProcess);
 VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags);
 VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags);
 ULONG FASTCALL ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
index 724cff8..679552b 100644 (file)
@@ -1278,15 +1278,18 @@ CSR_API(SrvCreateConsoleScreenBuffer)
 
     DPRINT("SrvCreateConsoleScreenBuffer\n");
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
         return Status;
     }
 
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
+    /*
     if (Console->ActiveBuffer)
     {
         ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
@@ -1299,6 +1302,23 @@ CSR_API(SrvCreateConsoleScreenBuffer)
         IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
         CursorSize      = Console->ActiveBuffer->CursorInfo.dwSize;
     }
+    */
+
+    // This is Windows' behaviour
+    {
+        ScreenBufferSize = Console->ConsoleSize; // Use the current console size
+        if (ScreenBufferSize.X == 0) ScreenBufferSize.X = 1;
+        if (ScreenBufferSize.Y == 0) ScreenBufferSize.Y = 1;
+
+        if (Console->ActiveBuffer)
+        {
+            ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
+            PopupAttrib  = Console->ActiveBuffer->PopupDefaultAttrib;
+
+            IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
+            CursorSize      = Console->ActiveBuffer->CursorInfo.dwSize;
+        }
+    }
 
     Status = ConSrvCreateScreenBuffer(Console,
                                       &Buff,
@@ -1309,6 +1329,7 @@ CSR_API(SrvCreateConsoleScreenBuffer)
                                       CursorSize);
     if (NT_SUCCESS(Status))
     {
+        /* Insert the new handle inside the process handles table */
         Status = ConSrvInsertObject(ProcessData,
                                     &CreateScreenBufferRequest->OutputHandle,
                                     &Buff->Header,
@@ -1317,10 +1338,11 @@ CSR_API(SrvCreateConsoleScreenBuffer)
                                     CreateScreenBufferRequest->ShareMode);
     }
 
-    ConSrvReleaseConsole(Console, TRUE);
+    // ConSrvReleaseConsole(Console, TRUE);
 
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
+    ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
 
index 92d8d2b..63c1ffc 100644 (file)
     #include "tuiconsole.h"
 #endif
 
+#include "console.h"
+
 #include <shlwapi.h>
 #include <shlobj.h>
 
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
+/* GLOBALS ********************************************************************/
+
+LIST_ENTRY ConsoleList;  /* The list of all the allocated consoles */
+/*static*/ RTL_RESOURCE ListLock;
+
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
@@ -44,26 +51,43 @@ ConSrvConsoleCtrlEventTimeout(DWORD Event,
                               DWORD Timeout)
 {
     ULONG Status = ERROR_SUCCESS;
-    HANDLE Thread;
 
-    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
         {
-            Status = GetLastError();
-            DPRINT1("Failed thread creation (Error: 0x%x)\n", Status);
+            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;
         }
-        else
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            DPRINT("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);
+            Status = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
+            DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status);
         }
+        _SEH2_END;
     }
 
     return Status;
@@ -85,6 +109,10 @@ ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
     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.
@@ -141,6 +169,18 @@ ConioUnpause(PCONSOLE Console, UINT Flags)
     }
 }
 
+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,
@@ -346,6 +386,7 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
     /*
      * Initialize the console
      */
+    Console->State = CONSOLE_INITIALIZING;
     InitializeCriticalSection(&Console->Lock);
     Console->ReferenceCount = 0;
     InitializeListHead(&Console->ProcessList);
@@ -428,6 +469,9 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
         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.
@@ -480,14 +524,33 @@ 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;
         }
     }
 
+    DPRINT1("Terminal initialized\n");
+
+    /* All went right, so add the console to the list */
+    ConSrvLockConsoleListExclusive();
+    DPRINT1("Insert in the list\n");
+    InsertTailList(&ConsoleList, &Console->Entry);
+
+    /* The initialization is finished */
+    DPRINT1("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);
+    DPRINT1("Console drawn\n");
 
     /* Return the newly created console to the caller and a success code too */
     *NewConsole = Console;
@@ -495,30 +558,100 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
 }
 
 VOID WINAPI
-ConSrvInitConsoleSupport(VOID)
+ConSrvDeleteConsole(PCONSOLE Console)
 {
-    DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
+    PLIST_ENTRY CurrentEntry;
+    ConsoleInput* Event;
 
-    /* Should call LoadKeyboardLayout */
-}
+    DPRINT1("ConSrvDeleteConsole\n");
 
-VOID WINAPI
-ConSrvDeleteConsole(PCONSOLE Console)
-{
-    ConsoleInput *Event;
+    /*
+     * Forbid validation of any console by other threads
+     * during the deletion of this console.
+     */
+    ConSrvLockConsoleListExclusive();
 
-    DPRINT("ConSrvDeleteConsole\n");
+    /* Check the existence of the console, and if it's ok, continue */
+    if (!ConSrvValidatePointer(Console))
+    {
+        /* Unlock the console list and return */
+        ConSrvUnlockConsoleList();
+        return;
+    }
 
-    /* Drain input event queue */
-    while (Console->InputBuffer.InputEvents.Flink != &Console->InputBuffer.InputEvents)
+    /*
+     * If the console is already being destroyed
+     * (thus not running), just return.
+     */
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
     {
-        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;
     }
 
+    /*
+     * 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);
+
+    /***
+     * 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 (!ConSrvValidatePointer(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 */
+    while (!IsListEmpty(&Console->InputBuffer.InputEvents))
+    {
+        CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents);
+        Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+        RtlFreeHeap(ConSrvHeap, 0, Event);
+    }
+
     if (Console->LineBuffer)
         RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
     while (!IsListEmpty(&Console->HistoryBuffers))
@@ -532,12 +665,22 @@ ConSrvDeleteConsole(PCONSOLE Console)
 
     CloseHandle(Console->InputBuffer.ActiveEvent);
     if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
-    DeleteCriticalSection(&Console->Lock);
 
     RtlFreeUnicodeString(&Console->OriginalTitle);
     RtlFreeUnicodeString(&Console->Title);
     IntDeleteAllAliases(Console->Aliases);
+
+    DPRINT1("ConSrvDeleteConsole - Unlocking\n");
+    LeaveCriticalSection(&Console->Lock);
+    DPRINT1("ConSrvDeleteConsole - Destroying lock\n");
+    DeleteCriticalSection(&Console->Lock);
+    DPRINT1("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
+
     RtlFreeHeap(ConSrvHeap, 0, Console);
+    DPRINT1("ConSrvDeleteConsole - Console freed\n");
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
 }
 
 
@@ -545,56 +688,59 @@ ConSrvDeleteConsole(PCONSOLE Console)
 
 CSR_API(SrvOpenConsole)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
     PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    PCONSOLE Console;
 
-    OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
+    DWORD DesiredAccess = OpenConsoleRequest->Access;
+    DWORD ShareMode = OpenConsoleRequest->ShareMode;
+    Object_t *Object;
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
 
-    if (ProcessData->Console)
+    Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
+    if (!NT_SUCCESS(Status))
     {
-        DWORD DesiredAccess = OpenConsoleRequest->Access;
-        DWORD ShareMode = OpenConsoleRequest->ShareMode;
-
-        PCONSOLE Console = ProcessData->Console;
-        Object_t *Object;
-
-        EnterCriticalSection(&Console->Lock);
+        DPRINT1("Can't get console\n");
+        return Status;
+    }
 
-        if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
-        {
-            Object = &Console->ActiveBuffer->Header;
-        }
-        else // HANDLE_INPUT
-        {
-            Object = &Console->InputBuffer.Header;
-        }
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
-        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);
-        }
+    /*
+     * Open a handle to either the active screen buffer or the input buffer.
+     */
+    if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
+    {
+        Object = &Console->ActiveBuffer->Header;
+    }
+    else // HANDLE_INPUT
+    {
+        Object = &Console->InputBuffer.Header;
+    }
 
-        LeaveCriticalSection(&Console->Lock);
+    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);
     }
 
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
+    ConSrvReleaseConsole(Console, TRUE);
     return Status;
 }
 
@@ -758,7 +904,6 @@ Quit:
 
 CSR_API(SrvFreeConsole)
 {
-    DPRINT1("SrvFreeConsole\n");
     ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
     return STATUS_SUCCESS;
 }
@@ -798,7 +943,6 @@ CSR_API(SrvSetConsoleMode)
     }
 
     ConSrvReleaseObject(Object, TRUE);
-
     return Status;
 }
 
@@ -831,7 +975,6 @@ CSR_API(SrvGetConsoleMode)
     }
 
     ConSrvReleaseObject(Object, TRUE);
-
     return Status;
 }
 
diff --git a/win32ss/user/consrv/console.h b/win32ss/user/consrv/console.h
new file mode 100644 (file)
index 0000000..a3f359a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Console Server DLL
+ * FILE:            win32ss/user/consrv/console.h
+ * PURPOSE:         Consoles Management
+ * PROGRAMMERS:     Hermes Belusca-Maito
+ */
+
+#pragma once
+
+#define ConSrvLockConsoleListExclusive()    \
+    RtlAcquireResourceExclusive(&ListLock, TRUE)
+
+#define ConSrvLockConsoleListShared()       \
+    RtlAcquireResourceShared(&ListLock, TRUE)
+
+#define ConSrvUnlockConsoleList()           \
+    RtlReleaseResource(&ListLock)
+
+extern LIST_ENTRY ConsoleList;
+extern RTL_RESOURCE ListLock;
+
+#if 0
+/*
+ * WARNING: Change the state of the console ONLY when the console is locked !
+ */
+typedef enum _CONSOLE_STATE
+{
+    CONSOLE_INITIALIZING,   /* Console is initializing */
+    CONSOLE_RUNNING     ,   /* Console running */
+    CONSOLE_TERMINATING ,   /* Console about to be destroyed (but still not) */
+    CONSOLE_IN_DESTRUCTION  /* Console in destruction */
+} CONSOLE_STATE, *PCONSOLE_STATE;
+#endif
+
+
+VOID WINAPI ConSrvInitConsoleSupport(VOID);
+NTSTATUS WINAPI ConSrvInitConsole(OUT PCONSOLE* NewConsole,
+                                  IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
+                                  IN PCSR_PROCESS ConsoleLeaderProcess);
+VOID WINAPI ConSrvDeleteConsole(PCONSOLE Console);
+BOOL FASTCALL ConSrvValidatePointer(PCONSOLE Console);
+BOOL FASTCALL ConSrvValidateConsoleState(PCONSOLE Console,
+                                         CONSOLE_STATE ExpectedState);
+BOOL FASTCALL ConSrvValidateConsoleUnsafe(PCONSOLE Console,
+                                          CONSOLE_STATE ExpectedState,
+                                          BOOL LockConsole);
+BOOL FASTCALL ConSrvValidateConsole(PCONSOLE Console,
+                                    CONSOLE_STATE ExpectedState,
+                                    BOOL LockConsole);
+
+/* EOF */
index c668456..11e5ac6 100644 (file)
@@ -34,6 +34,9 @@
 /* Public Win32K Headers */
 #include <ntuser.h>
 
+/* PSEH for SEH Support */
+#include <pseh/pseh2.h>
+
 /* CSRSS Header */
 #include <csr/csrsrv.h>
 
@@ -93,6 +96,20 @@ typedef struct _CONSOLE_PROCESS_DATA
 } CONSOLE_PROCESS_DATA, *PCONSOLE_PROCESS_DATA;
 
 
+#if 1 // Temporarily put there.
+/*
+ * WARNING: Change the state of the console ONLY when the console is locked !
+ */
+typedef enum _CONSOLE_STATE
+{
+    CONSOLE_INITIALIZING,   /* Console is initializing */
+    CONSOLE_RUNNING     ,   /* Console running */
+    CONSOLE_TERMINATING ,   /* Console about to be destroyed (but still not) */
+    CONSOLE_IN_DESTRUCTION  /* Console in destruction */
+} CONSOLE_STATE, *PCONSOLE_STATE;
+#endif
+
+
 /* alias.c */
 CSR_API(SrvAddConsoleAlias);
 CSR_API(SrvGetConsoleAlias);
@@ -177,12 +194,12 @@ NTSTATUS FASTCALL ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
                                        PHANDLE pInputHandle,
                                        PHANDLE pOutputHandle,
                                        PHANDLE pErrorHandle);
-VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData);
 NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
                                    struct _CONSOLE** Console,
                                    BOOL LockConsole);
 VOID FASTCALL ConSrvReleaseConsole(struct _CONSOLE* Console,
-                                   BOOL IsConsoleLocked);
+                                   BOOL WasConsoleLocked);
+VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData);
 
 NTSTATUS NTAPI ConSrvNewProcess(PCSR_PROCESS SourceProcess,
                                 PCSR_PROCESS TargetProcess);
index b66c32d..15ea916 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "consrv.h"
 #include "conio.h"
+#include "console.h"
 #include "settings.h"
 #include "guiconsole.h"
 #include "guisettings.h"
@@ -212,6 +213,13 @@ static LRESULT
 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
     LRESULT Ret = TRUE;
+    PCONSOLE Console = GuiData->Console;
+
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    {
+        Ret = FALSE;
+        goto Quit;
+    }
 
     switch (wParam)
     {
@@ -229,7 +237,6 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
 
         case ID_SYSTEM_EDIT_SELECTALL:
         {
-            PCONSOLE Console = GuiData->Console;
             COORD bottomRight = { 0, 0 };
 
             bottomRight.X = Console->ConsoleSize.X - 1;
@@ -255,15 +262,23 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
             break;
 
         default:
-            Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
+            Ret = FALSE;
             break;
     }
+
+    LeaveCriticalSection(&Console->Lock);
+
+Quit:
+    if (!Ret)
+        Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
+
     return Ret;
 }
 
 static PGUI_CONSOLE_DATA
 GuiGetGuiData(HWND hWnd)
 {
+    /* This function ensures that the console pointer is not NULL */
     PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
     return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
 }
@@ -342,6 +357,8 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     TEXTMETRICW Metrics;
     SIZE CharSize;
 
+    DPRINT1("GuiConsoleHandleNcCreate\n");
+
     if (NULL == GuiData)
     {
         DPRINT1("GuiConsoleNcCreate: No GUI data\n");
@@ -424,12 +441,7 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
     GuiConsoleCreateSysMenu(GuiData->hWindow);
 
-    /* Move and resize the window to the user's values */
-    GuiConsoleMoveWindow(GuiData);
-    GuiData->WindowSizeLock = TRUE;
-    GuiConsoleResizeWindow(GuiData);
-    GuiData->WindowSizeLock = FALSE;
-
+    DPRINT1("GuiConsoleHandleNcCreate - setting start event\n");
     SetEvent(GuiData->hGuiInitEvent);
 
     return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
@@ -526,8 +538,6 @@ GuiConsolePaint(PCONSOLE Console,
 
     Buff = Console->ActiveBuffer;
 
-    /// LOCK /// EnterCriticalSection(&Buff->Header.Console->Lock);
-
     TopLine = rc->top / GuiData->CharHeight + Buff->ShowY;
     BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY;
     LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX;
@@ -618,57 +628,71 @@ GuiConsolePaint(PCONSOLE Console,
         }
     }
 
-    /// LOCK /// LeaveCriticalSection(&Buff->Header.Console->Lock);
-
     SelectObject(hDC, OldFont);
 }
 
 static VOID
-GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData, HDC hDCPaint)
+GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
 {
+    BOOL Success = TRUE;
     PCONSOLE Console = GuiData->Console;
     HDC hDC;
     PAINTSTRUCT ps;
 
-    if (Console->ActiveBuffer == NULL) return;
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    {
+        Success = FALSE;
+        goto Quit;
+    }
+
+    if (Console->ActiveBuffer == NULL ||
+        Console->ActiveBuffer->Buffer == NULL)
+    {
+        goto Quit;
+    }
 
     hDC = BeginPaint(GuiData->hWindow, &ps);
     if (hDC != NULL &&
             ps.rcPaint.left < ps.rcPaint.right &&
             ps.rcPaint.top < ps.rcPaint.bottom)
     {
-        if (Console->ActiveBuffer->Buffer != NULL)
-        {
-            EnterCriticalSection(&GuiData->Lock);
+        EnterCriticalSection(&GuiData->Lock);
 
-            GuiConsolePaint(Console,
-                            GuiData,
-                            hDC,
-                            &ps.rcPaint);
+        GuiConsolePaint(Console,
+                        GuiData,
+                        hDC,
+                        &ps.rcPaint);
 
-            if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
-            {
-                RECT rc;
-                SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
+        if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+        {
+            RECT rc;
+            SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
 
-                /* invert the selection */
-                if (IntersectRect(&rc,
-                                  &ps.rcPaint,
-                                  &rc))
-                {
-                    PatBlt(hDC,
-                           rc.left,
-                           rc.top,
-                           rc.right - rc.left,
-                           rc.bottom - rc.top,
-                           DSTINVERT);
-                }
+            /* invert the selection */
+            if (IntersectRect(&rc,
+                              &ps.rcPaint,
+                              &rc))
+            {
+                PatBlt(hDC,
+                       rc.left,
+                       rc.top,
+                       rc.right - rc.left,
+                       rc.bottom - rc.top,
+                       DSTINVERT);
             }
-
-            LeaveCriticalSection(&GuiData->Lock);
         }
+
+        LeaveCriticalSection(&GuiData->Lock);
     }
     EndPaint(GuiData->hWindow, &ps);
+
+Quit:
+    if (Success)
+        LeaveCriticalSection(&Console->Lock);
+    else
+        DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
+
+    return;
 }
 
 static VOID
@@ -677,6 +701,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
     PCONSOLE Console = GuiData->Console;
     MSG Message;
 
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
     Message.hwnd = GuiData->hWindow;
     Message.message = msg;
     Message.wParam = wParam;
@@ -689,6 +715,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
     }
 
     ConioProcessKey(Console, &Message);
+
+    LeaveCriticalSection(&Console->Lock);
 }
 
 static VOID
@@ -706,6 +734,8 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
 
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
 
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
     Buff = Console->ActiveBuffer;
     GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
     Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
@@ -782,14 +812,15 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
             GuiData->OldCursor.y = Buff->CursorPosition.Y;
         }
     }
+
+    LeaveCriticalSection(&Console->Lock);
 }
 
 static VOID
 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSOLE Console = GuiData->Console;
-
-    /// LOCK /// EnterCriticalSection(&Console->Lock);
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
 
     /*
      * FIXME: Windows will wait up to 5 seconds for the thread to exit.
@@ -798,17 +829,23 @@ GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
      */
     ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
 
-    /// LOCK /// LeaveCriticalSection(&Console->Lock);
+    LeaveCriticalSection(&Console->Lock);
 }
 
-static VOID
-GuiConsoleHandleNcDestroy(PGUI_CONSOLE_DATA GuiData)
+static LRESULT
+GuiConsoleHandleNcDestroy(HWND hWnd)
 {
-    KillTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER);
-    GetSystemMenu(GuiData->hWindow, TRUE);
+    // PGUI_CONSOLE_DATA GuiData;
 
-    SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)NULL);
-    GuiData->hWindow = NULL;
+    KillTimer(hWnd, CONGUI_UPDATE_TIMER);
+    GetSystemMenu(hWnd, TRUE);
+
+    /* Free the GuiData registration */
+    SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
+    // GuiData->hWindow = NULL;
+
+    // return 0;
+    return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
 }
 
 static COORD
@@ -835,43 +872,85 @@ PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
     return Coord;
 }
 
-static VOID
-GuiConsoleLeftMouseDown(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
+static LRESULT
+GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 {
+    LRESULT Ret = TRUE;
     PCONSOLE Console = GuiData->Console;
 
-    Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
-    SetCapture(GuiData->hWindow);
-    Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-    GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
-}
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+    {
+        Ret = FALSE;
+        goto Quit;
+    }
 
-static VOID
-GuiConsoleLeftMouseUp(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
-{
-    PCONSOLE Console = GuiData->Console;
-    COORD c;
+    switch (msg)
+    {
+        case WM_LBUTTONDOWN:
+        {
+            Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
+            SetCapture(GuiData->hWindow);
+            Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+            GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
+            break;
+        }
 
-    if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
+        case WM_LBUTTONUP:
+        {
+            COORD c;
 
-    c = PointToCoord(GuiData, lParam);
-    Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
-    GuiConsoleUpdateSelection(Console, &c);
-    ReleaseCapture();
-}
+            if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-static VOID
-GuiConsoleMouseMove(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
-{
-    PCONSOLE Console = GuiData->Console;
-    COORD c;
+            c = PointToCoord(GuiData, lParam);
+            Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
+            GuiConsoleUpdateSelection(Console, &c);
+            ReleaseCapture();
+
+            break;
+        }
 
-    if (!(wParam & MK_LBUTTON)) return;
+        case WM_RBUTTONDOWN:
+        {
+            if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
+            {
+                GuiConsolePaste(GuiData);
+            }
+            else
+            {
+                GuiConsoleCopy(GuiData);
 
-    if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
+                /* Clear the selection */
+                GuiConsoleUpdateSelection(Console, NULL);
+            }
 
-    c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
-    GuiConsoleUpdateSelection(Console, &c);
+            break;
+        }
+
+        case WM_MOUSEMOVE:
+        {
+            COORD c;
+
+            if (!(wParam & MK_LBUTTON)) break;
+            if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
+
+            c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
+            GuiConsoleUpdateSelection(Console, &c);
+
+            break;
+        }
+
+        default:
+            Ret = FALSE;
+            break;
+    }
+
+    LeaveCriticalSection(&Console->Lock);
+
+Quit:
+    if (!Ret)
+        Ret = DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
+
+    return Ret;
 }
 
 static VOID
@@ -982,30 +1061,14 @@ GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
     }
 }
 
-static VOID
-GuiConsoleRightMouseDown(PGUI_CONSOLE_DATA GuiData)
-{
-    PCONSOLE Console = GuiData->Console;
-
-    if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
-    {
-        GuiConsolePaste(GuiData);
-    }
-    else
-    {
-        GuiConsoleCopy(GuiData);
-
-        /* Clear the selection */
-        GuiConsoleUpdateSelection(Console, NULL);
-    }
-}
-
 static VOID
 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 {
     PCONSOLE Console = GuiData->Console;
     DWORD windx, windy;
 
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
     windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
     windy = CONGUI_MIN_HEIGHT * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
 
@@ -1020,6 +1083,8 @@ GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
 
     minMaxInfo->ptMaxTrackSize.x = windx;
     minMaxInfo->ptMaxTrackSize.y = windy;
+
+    LeaveCriticalSection(&Console->Lock);
 }
 
 static VOID
@@ -1027,6 +1092,8 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 {
     PCONSOLE Console = GuiData->Console;
 
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
+
     if ((GuiData->WindowSizeLock == FALSE) &&
         (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
     {
@@ -1076,6 +1143,8 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
 
         GuiData->WindowSizeLock = FALSE;
     }
+
+    LeaveCriticalSection(&Console->Lock);
 }
 
 /*
@@ -1107,8 +1176,7 @@ GuiConsoleHandleScrollbarMenu(VOID)
 }
 */
 
-static
-LRESULT
+static LRESULT
 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
 {
     PCONSOLE Console = GuiData->Console;
@@ -1118,7 +1186,7 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
     int old_pos, Maximum;
     PUSHORT pShowXY;
 
-    if (GuiData == NULL) return FALSE;
+    if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
 
     Buff = Console->ActiveBuffer;
 
@@ -1139,10 +1207,7 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
     sInfo.cbSize = sizeof(SCROLLINFO);
     sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
 
-    if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo))
-    {
-        return FALSE;
-    }
+    if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
 
     old_pos = sInfo.nPos;
 
@@ -1209,6 +1274,8 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
         UpdateWindow(GuiData->hWindow);
     }
 
+Quit:
+    LeaveCriticalSection(&Console->Lock);
     return 0;
 }
 
@@ -1217,15 +1284,22 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     LRESULT Result = 0;
     PGUI_CONSOLE_DATA GuiData = NULL;
+    PCONSOLE Console = NULL;
 
     /*
-     * If it's the first time we create a window
-     * for the terminal, just initialize it.
+     * - If it's the first time we create a window for the terminal,
+     *   just initialize it and return.
+     *
+     * - If we are destroying the window, just do it and return.
      */
     if (msg == WM_NCCREATE)
     {
         return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
     }
+    else if (msg == WM_NCDESTROY)
+    {
+        return GuiConsoleHandleNcDestroy(hWnd);
+    }
 
     /*
      * Now the terminal window is initialized.
@@ -1235,24 +1309,20 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     GuiData = GuiGetGuiData(hWnd);
     if (GuiData == NULL) return 0;
 
-    // TODO: If the console is about to be destroyed, leave the loop.
-
-    /* Lock the console */
-    EnterCriticalSection(&GuiData->Console->Lock);
+    /*
+     * Each helper function which needs the console
+     * has to validate and lock it.
+     */
 
-    /* We have a console, start message dispatching. */
+    /* We have a console, start message dispatching */
     switch (msg)
     {
         case WM_CLOSE:
             GuiConsoleHandleClose(GuiData);
             break;
 
-        case WM_NCDESTROY:
-            GuiConsoleHandleNcDestroy(GuiData);
-            break;
-
         case WM_PAINT:
-            GuiConsoleHandlePaint(GuiData, (HDC)wParam);
+            GuiConsoleHandlePaint(GuiData);
             break;
 
         case WM_KEYDOWN:
@@ -1260,37 +1330,43 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         case WM_SYSKEYDOWN:
         case WM_SYSKEYUP:
         case WM_CHAR:
+        {
             GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
             break;
+        }
 
         case WM_TIMER:
             GuiConsoleHandleTimer(GuiData);
             break;
 
+        case WM_MOUSEMOVE:
         case WM_LBUTTONDOWN:
-            GuiConsoleLeftMouseDown(GuiData, lParam);
-            break;
-
         case WM_LBUTTONUP:
-            GuiConsoleLeftMouseUp(GuiData, lParam);
-            break;
-
+        case WM_LBUTTONDBLCLK:
         case WM_RBUTTONDOWN:
-            GuiConsoleRightMouseDown(GuiData);
-            break;
-
-        case WM_MOUSEMOVE:
-            GuiConsoleMouseMove(GuiData, wParam, lParam);
+        case WM_RBUTTONUP:
+        case WM_RBUTTONDBLCLK:
+        case WM_MBUTTONDOWN:
+        case WM_MBUTTONUP:
+        case WM_MBUTTONDBLCLK:
+        case WM_MOUSEWHEEL:
+        {
+            Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
             break;
+        }
 
         case WM_SYSCOMMAND:
+        {
             Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
             break;
+        }
 
         case WM_HSCROLL:
         case WM_VSCROLL:
+        {
             Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
             break;
+        }
 
         case WM_GETMINMAXINFO:
             GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
@@ -1301,26 +1377,30 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             break;
 
         case PM_APPLY_CONSOLE_INFO:
-            GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
+        {
+            Console = GuiData->Console; // Not NULL because checked in GuiGetGuiData.
+            if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
+            {
+                GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
+                LeaveCriticalSection(&Console->Lock);
+            }
             break;
+        }
 
         case PM_CONSOLE_BEEP:
             DPRINT1("Beep !!\n");
             Beep(800, 200);
             break;
 
-        case PM_CONSOLE_SET_TITLE:
-            SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
-            break;
+        // case PM_CONSOLE_SET_TITLE:
+            // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
+            // break;
 
         default:
-            Result = DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
+            Result = DefWindowProcW(hWnd, msg, wParam, lParam);
             break;
     }
 
-    /* Unlock the console */
-    LeaveCriticalSection(&GuiData->Console->Lock);
-
     return Result;
 }
 
@@ -1336,8 +1416,6 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     HWND NewWindow;
     LONG WindowCount;
     MSG Msg;
-    PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
-    PCONSOLE Console = GuiData->Console;
 
     switch (msg)
     {
@@ -1349,6 +1427,9 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
     
         case PM_CREATE_CONSOLE:
         {
+            PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
+            PCONSOLE Console = GuiData->Console;
+
             NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
                                         GUI_CONSOLE_WINDOW_CLASS,
                                         Console->Title.Buffer,
@@ -1381,7 +1462,16 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
                     SendMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
                 }
 
-                ShowWindow(NewWindow, (int)wParam);
+                /* Move and resize the window to the user's values */
+                /* CAN WE DEADLOCK ?? */
+                GuiConsoleMoveWindow(GuiData);
+                GuiData->WindowSizeLock = TRUE;
+                GuiConsoleResizeWindow(GuiData);
+                GuiData->WindowSizeLock = FALSE;
+
+                // ShowWindow(NewWindow, (int)wParam);
+                ShowWindowAsync(NewWindow, (int)wParam);
+                DPRINT1("Window showed\n");
             }
 
             return (LRESULT)NewWindow;
@@ -1389,16 +1479,20 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
         case PM_DESTROY_CONSOLE:
         {
+            PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
+
             /*
              * Window creation is done using a PostMessage(), so it's possible
              * that the window that we want to destroy doesn't exist yet.
              * So first empty the message queue.
              */
+            /*
             while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
             {
                 TranslateMessage(&Msg);
                 DispatchMessageW(&Msg);
-            }
+            }*/
+            while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
 
             if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
             {
@@ -1607,6 +1701,8 @@ GuiCleanupConsole(PCONSOLE Console)
     Console->TermIFace.Data = NULL;
     DeleteCriticalSection(&GuiData->Lock);
     RtlFreeHeap(ConSrvHeap, 0, GuiData);
+
+    DPRINT1("Quit GuiCleanupConsole\n");
 }
 
 static VOID WINAPI
@@ -1835,7 +1931,8 @@ static VOID WINAPI
 GuiChangeTitle(PCONSOLE Console)
 {
     PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
-    PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
+    // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
+    SetWindowText(GuiData->hWindow, Console->Title.Buffer);
 }
 
 static BOOL WINAPI
@@ -1916,6 +2013,7 @@ GuiInitConsole(PCONSOLE Console,
 {
     PGUI_CONSOLE_DATA GuiData;
     GUI_CONSOLE_INFO TermInfo;
+    SIZE_T Length = 0;
 
     if (Console == NULL || ConsoleInfo == NULL)
         return STATUS_INVALID_PARAMETER;
@@ -1984,7 +2082,9 @@ GuiInitConsole(PCONSOLE Console,
      * Set up the GUI data
      */
 
+    Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
     wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
+    GuiData->GuiInfo.FaceName[Length] = L'\0';
     GuiData->GuiInfo.FontFamily     = TermInfo.FontFamily;
     GuiData->GuiInfo.FontSize       = TermInfo.FontSize;
     GuiData->GuiInfo.FontWeight     = TermInfo.FontWeight;
@@ -2034,6 +2134,7 @@ GuiInitConsole(PCONSOLE Console,
 
     /* Wait until initialization has finished */
     WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
+    DPRINT1("OK we created the console window\n");
     CloseHandle(GuiData->hGuiInitEvent);
     GuiData->hGuiInitEvent = NULL;
 
index 2362ae6..2a4b71b 100644 (file)
@@ -86,7 +86,9 @@ GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
 
         if (!wcscmp(szValueName, L"FaceName"))
         {
+            SIZE_T Length = min(wcslen(szValue) + 1, LF_FACESIZE); // wcsnlen
             wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE);
+            TermInfo->FaceName[Length] = L'\0';
             RetVal = TRUE;
         }
         else if (!wcscmp(szValueName, L"FontFamily"))
@@ -150,7 +152,7 @@ do {
         return FALSE;
     }
 
-    SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(TermInfo->FaceName) + 1) * sizeof(WCHAR), TermInfo->FaceName, L'\0');
+    SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(TermInfo->FaceName) + 1) * sizeof(WCHAR), TermInfo->FaceName, L'\0'); // wcsnlen
     SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &TermInfo->FontFamily, FF_DONTCARE);
     SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0);
     SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE);
@@ -269,43 +271,59 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
     pSharedInfo->hConsoleWindow = GuiData->hWindow;
     pSharedInfo->ShowDefaultParams = Defaults;
 
-    /* Console information */
-    pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
-    pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
-    pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup;
-    pSharedInfo->ci.FullScreen = Console->FullScreen;
-    pSharedInfo->ci.QuickEdit = Console->QuickEdit;
-    pSharedInfo->ci.InsertMode = Console->InsertMode;
-    pSharedInfo->ci.InputBufferSize = 0;
-    pSharedInfo->ci.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
-    pSharedInfo->ci.ConsoleSize = Console->ConsoleSize;
-    pSharedInfo->ci.CursorBlinkOn;
-    pSharedInfo->ci.ForceCursorOff;
-    pSharedInfo->ci.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
-    pSharedInfo->ci.ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
-    pSharedInfo->ci.PopupAttrib  = Console->ActiveBuffer->PopupDefaultAttrib;
-    pSharedInfo->ci.CodePage;
-
-    /* GUI Information */
-    pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
-    GuiInfo = pSharedInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pSharedInfo + 1);
-    wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE);
-    GuiInfo->FontSize = (DWORD)GuiData->GuiInfo.FontSize;
-    GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
-    GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
-    /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
-    GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
-    GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin;
-    /* Offsetize */
-    pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)GuiInfo - (ULONG_PTR)pSharedInfo);
-
-    /* Palette */
-    memcpy(pSharedInfo->ci.Colors, Console->Colors, sizeof(Console->Colors));
-
-    /* Title of the console, original one corresponding to the one set by the console leader */
-    Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
-                 Console->OriginalTitle.Length / sizeof(WCHAR));
-    wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
+    /*
+     * We fill-in the fields only if we display
+     * our properties, not the default ones.
+     */
+    if (!Defaults)
+    {
+        /* Console information */
+        pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
+        pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
+        pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup;
+        pSharedInfo->ci.FullScreen = Console->FullScreen;
+        pSharedInfo->ci.QuickEdit = Console->QuickEdit;
+        pSharedInfo->ci.InsertMode = Console->InsertMode;
+        pSharedInfo->ci.InputBufferSize = 0;
+        pSharedInfo->ci.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
+        pSharedInfo->ci.ConsoleSize = Console->ConsoleSize;
+        pSharedInfo->ci.CursorBlinkOn;
+        pSharedInfo->ci.ForceCursorOff;
+        pSharedInfo->ci.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
+        pSharedInfo->ci.ScreenAttrib = Console->ActiveBuffer->ScreenDefaultAttrib;
+        pSharedInfo->ci.PopupAttrib  = Console->ActiveBuffer->PopupDefaultAttrib;
+        pSharedInfo->ci.CodePage;
+
+        /* GUI Information */
+        pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
+        GuiInfo = pSharedInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pSharedInfo + 1);
+        Length = min(wcslen(GuiData->GuiInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
+        wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE);
+        GuiInfo->FaceName[Length] = L'\0';
+        GuiInfo->FontFamily = GuiData->GuiInfo.FontFamily;
+        GuiInfo->FontSize = GuiData->GuiInfo.FontSize;
+        GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
+        GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
+        /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
+        GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
+        GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin;
+        /* Offsetize */
+        pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)GuiInfo - (ULONG_PTR)pSharedInfo);
+
+        /* Palette */
+        memcpy(pSharedInfo->ci.Colors, Console->Colors, sizeof(Console->Colors));
+
+        /* Title of the console, original one corresponding to the one set by the console leader */
+        Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
+                     Console->OriginalTitle.Length / sizeof(WCHAR));
+        wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
+    }
+    else
+    {
+        Length = 0;
+    }
+
+    /* Null-terminate the title */
     pSharedInfo->ci.ConsoleTitle[Length] = L'\0';
 
 
@@ -326,29 +344,46 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status);
-        NtClose(hSection);
-        return;
+        goto Quit;
     }
 
     /* Start the properties dialog */
     if (ProcessData->PropDispatcher)
     {
-        HANDLE Thread;
+        _SEH2_TRY
+        {
+            HANDLE Thread = NULL;
 
-        Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
-                                    ProcessData->PropDispatcher,
-                                    (PVOID)hClientSection, 0, NULL);
-        if (NULL == Thread)
+            _SEH2_TRY
+            {
+                Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
+                                            ProcessData->PropDispatcher,
+                                            (PVOID)hClientSection, 0, NULL);
+                if (NULL == Thread)
+                {
+                    DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
+                }
+                else
+                {
+                    DPRINT("ProcessData->PropDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
+                    /// WaitForSingleObject(Thread, INFINITE);
+                }
+            }
+            _SEH2_FINALLY
+            {
+                CloseHandle(Thread);
+            }
+            _SEH2_END;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
-            return;
+            Status = _SEH2_GetExceptionCode();
+            DPRINT1("GuiConsoleShowConsoleProperties - Caught an exception, Status = %08X\n", Status);
         }
-
-        DPRINT1("We succeeded at creating ProcessData->PropDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
-        /// WaitForSingleObject(Thread, INFINITE);
-        CloseHandle(Thread);
+        _SEH2_END;
     }
 
+Quit:
     /* We have finished, close the section handle */
     NtClose(hSection);
     return;
@@ -369,8 +404,6 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
     PTERMINAL_INFO TermInfo = NULL;
     PGUI_CONSOLE_INFO GuiInfo = NULL;
 
-    /// LOCK /// EnterCriticalSection(&Console->Lock);
-
     /* Get the console leader process, our client */
     ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
                                     CONSOLE_PROCESS_DATA,
@@ -406,51 +439,65 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
         return Status;
     }
 
-    /* Check that the section is well-sized */
-    if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
-         (pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
-         (ViewSize < sizeof(CONSOLE_PROPS) + pConInfo->TerminalInfo.Size) )
+    _SEH2_TRY
     {
-        DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
-        Status = STATUS_INVALID_VIEW_SIZE;
-        goto Quit;
-    }
+        /* Check that the section is well-sized */
+        if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
+             (pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
+             (ViewSize < sizeof(CONSOLE_PROPS) + pConInfo->TerminalInfo.Size) )
+        {
+            DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
+            Status = STATUS_INVALID_VIEW_SIZE;
+            _SEH2_YIELD(goto Quit);
+        }
 
-    // TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
+        // TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
 
-    /* Set the console informations */
-    ConInfo = &pConInfo->ci;
-    ConSrvApplyUserSettings(Console, ConInfo);
+        /* Retrieve terminal informations */
+        ConInfo  = &pConInfo->ci;
+        TermInfo = &pConInfo->TerminalInfo;
+        GuiInfo  = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo);
 
-    /* Set the terminal informations - De-offsetization of the pointer */
-    TermInfo = &pConInfo->TerminalInfo;
-    GuiInfo = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo);
+        /*
+         * If we don't set the default parameters,
+         * apply them, otherwise just save them.
+         */
+        if (pConInfo->ShowDefaultParams == FALSE)
+        {
+            /* Set the console informations */
+            ConSrvApplyUserSettings(Console, ConInfo);
 
-    // memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
+            /* Set the terminal informations */
 
-    /* Move the window to the user's values */
-    GuiData->GuiInfo.AutoPosition = GuiInfo->AutoPosition;
-    GuiData->GuiInfo.WindowOrigin = GuiInfo->WindowOrigin;
-    GuiConsoleMoveWindow(GuiData);
+            // memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
 
-    InvalidateRect(GuiData->hWindow, NULL, TRUE);
+            /* Move the window to the user's values */
+            GuiData->GuiInfo.AutoPosition = GuiInfo->AutoPosition;
+            GuiData->GuiInfo.WindowOrigin = GuiInfo->WindowOrigin;
+            GuiConsoleMoveWindow(GuiData);
 
+            InvalidateRect(GuiData->hWindow, NULL, TRUE);
+        }
 
-    /*
-     * Save settings if needed
-     */
+        /*
+         * Save settings if needed
+         */
+        // FIXME: Do it in the console properties applet ??
+        if (SaveSettings)
+        {
+            DWORD ProcessId = HandleToUlong(ProcessData->Process->ClientId.UniqueProcess);
+            ConSrvWriteUserSettings(ConInfo, ProcessId);
+            GuiConsoleWriteUserSettings(GuiInfo, ConInfo->ConsoleTitle, ProcessId);
+        }
 
-    // FIXME: Do it in the console properties applet ??
-    if (SaveSettings)
+        Status = STATUS_SUCCESS;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        DWORD ProcessId = HandleToUlong(ProcessData->Process->ClientId.UniqueProcess);
-        ConSrvWriteUserSettings(ConInfo, ProcessId);
-        GuiConsoleWriteUserSettings(GuiInfo, ConInfo->ConsoleTitle, ProcessId);
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("GuiApplyUserSettings - Caught an exception, Status = %08X\n", Status);
     }
-
-    Status = STATUS_SUCCESS;
-
-    /// LOCK /// LeaveCriticalSection(&Console->Lock);
+    _SEH2_END;
 
 Quit:
     /* Finally, close the section and return */
index 94549d6..bfb6490 100644 (file)
@@ -10,8 +10,9 @@
 
 #include "consrv.h"
 #include "conio.h"
+#include "console.h"
 
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
 
@@ -22,7 +23,7 @@ AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
 {
     Object_t *Object = Entry->Object;
 
-    DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
+    DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
 
     if (Entry->Access & GENERIC_READ)           Object->AccessRead += Change;
     if (Entry->Access & GENERIC_WRITE)          Object->AccessWrite += Change;
@@ -236,8 +237,6 @@ Quit:
 static VOID
 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
 {
-    DPRINT1("ConSrvFreeHandlesTable\n");
-
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
     if (ProcessData->HandleTable != NULL)
@@ -267,12 +266,13 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
                    BOOL Inheritable,
                    DWORD ShareMode)
 {
-#define IO_HANDLES_INCREMENT    2*3
+#define IO_HANDLES_INCREMENT    2 * 3
 
     ULONG i;
     PCONSOLE_IO_HANDLE Block;
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    // NOTE: Commented out because calling code always lock HandleTableLock before.
+    // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
     for (i = 0; i < ProcessData->HandleTableSize; i++)
     {
@@ -289,7 +289,7 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
                                     IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
         if (Block == NULL)
         {
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+            // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
             return STATUS_UNSUCCESSFUL;
         }
         RtlCopyMemory(Block,
@@ -307,7 +307,7 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
     ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
     *Handle = ULongToHandle((i << 2) | 0x3);
 
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+    // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
     return STATUS_SUCCESS;
 }
@@ -329,11 +329,9 @@ ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
         return STATUS_INVALID_HANDLE;
     }
 
-    DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
     ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
 
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-
     return STATUS_SUCCESS;
 }
 
@@ -376,16 +374,24 @@ ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
         return STATUS_INVALID_HANDLE;
     }
 
-    _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-    if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock);
+    if (ConSrvValidateConsole(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole))
+    {
+        _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
 
-    /* Return the objects to the caller */
-    *Object = ObjectEntry;
-    if (Entry) *Entry = HandleEntry;
+        /* Return the objects to the caller */
+        *Object = ObjectEntry;
+        if (Entry) *Entry = HandleEntry;
 
-    return STATUS_SUCCESS;
+        // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return STATUS_INVALID_HANDLE;
+    }
 }
 
 VOID
@@ -465,6 +471,13 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
 {
     NTSTATUS Status = STATUS_SUCCESS;
 
+    /* Validate and lock the console */
+    if (!ConSrvValidateConsole(Console, CONSOLE_RUNNING, TRUE))
+    {
+        // FIXME: Find another status code
+        return STATUS_UNSUCCESSFUL;
+    }
+
     /* Inherit the console */
     ProcessData->Console = Console;
 
@@ -479,7 +492,7 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
         {
             DPRINT1("Failed to initialize the handles table\n");
             ProcessData->Console = NULL;
-            return Status;
+            goto Quit;
         }
     }
 
@@ -494,7 +507,7 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
         DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
         ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
         ProcessData->Console = NULL;
-        return Status;
+        goto Quit;
     }
 
     /* Insert the process into the processes list of the console */
@@ -506,30 +519,35 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
     /* Update the internal info of the terminal */
     ConioRefreshInternalInfo(ProcessData->Console);
 
-    return STATUS_SUCCESS;
+    Status = STATUS_SUCCESS;
+
+Quit:
+    /* Unlock the console and return */
+    LeaveCriticalSection(&Console->Lock);
+    return Status;
 }
 
 VOID
 FASTCALL
 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
 {
-    PCONSOLE Console;
+    PCONSOLE Console = ProcessData->Console;
 
     DPRINT1("ConSrvRemoveConsole\n");
 
-    /* Close all console handles and free the handle table memory */
-    ConSrvFreeHandlesTable(ProcessData);
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
-    /* Detach process from console */
-    Console = ProcessData->Console;
-    if (Console != NULL)
+    /* Validate and lock the console */
+    if (ConSrvValidateConsole(Console, CONSOLE_RUNNING, TRUE))
     {
-        DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
-        ProcessData->Console = NULL;
-
-        EnterCriticalSection(&Console->Lock);
         DPRINT1("ConSrvRemoveConsole - Locking OK\n");
 
+        /* Close all console handles and free the handles table */
+        ConSrvFreeHandlesTable(ProcessData);
+
+        /* Detach the process from the console */
+        ProcessData->Console = NULL;
+
         /* Remove ourselves from the console's list of processes */
         RemoveEntryList(&ProcessData->ConsoleLink);
 
@@ -537,10 +555,105 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
         ConioRefreshInternalInfo(Console);
 
         /* Release the console */
+        DPRINT1("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
         ConSrvReleaseConsole(Console, TRUE);
         //CloseHandle(ProcessData->ConsoleEvent);
         //ProcessData->ConsoleEvent = NULL;
     }
+
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+}
+
+BOOL
+FASTCALL
+ConSrvValidatePointer(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 (ConSrvValidatePointer(Console))
+    {
+        RetVal = ConSrvValidateConsoleUnsafe(Console,
+                                             ExpectedState,
+                                             LockConsole);
+    }
+
+    /* Unlock the console list and return */
+    ConSrvUnlockConsoleList();
+    return RetVal;
 }
 
 NTSTATUS
@@ -549,37 +662,53 @@ ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
                  PCONSOLE* Console,
                  BOOL LockConsole)
 {
+    NTSTATUS Status = STATUS_SUCCESS;
     PCONSOLE ProcessConsole;
 
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
     ProcessConsole = ProcessData->Console;
 
-    if (!ProcessConsole)
+    if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
+    {
+        InterlockedIncrement(&ProcessConsole->ReferenceCount);
+        *Console = ProcessConsole;
+    }
+    else
     {
         *Console = NULL;
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_INVALID_HANDLE;
+        Status = STATUS_INVALID_HANDLE;
     }
 
-    InterlockedIncrement(&ProcessConsole->ReferenceCount);
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-
-    if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
-
-    *Console = ProcessConsole;
-
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 VOID FASTCALL
 ConSrvReleaseConsole(PCONSOLE Console,
-                     BOOL IsConsoleLocked)
+                     BOOL WasConsoleLocked)
 {
-    if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
+    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 reference count */
-    if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
-        ConSrvDeleteConsole(Console);
+    /*
+     * Decrement the reference count. Save the new value too,
+     * because Console->ReferenceCount might be modified after
+     * the console gets unlocked but before we check whether we
+     * can destroy it.
+     */
+    RefCount = _InterlockedDecrement(&Console->ReferenceCount);
+
+    /* Unlock the console if needed */
+    if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock);
+
+    /* Delete the console if needed */
+    if (RefCount <= 0) ConSrvDeleteConsole(Console);
 }
 
 NTSTATUS
@@ -745,8 +874,6 @@ ConSrvDisconnect(PCSR_PROCESS Process)
      * This function is called whenever a new process (GUI or CUI) is destroyed.
      **************************************************************************/
 
-    DPRINT1("ConSrvDisconnect\n");
-
     if ( ProcessData->Console     != NULL ||
          ProcessData->HandleTable != NULL )
     {
@@ -828,6 +955,7 @@ CSR_API(SrvDuplicateHandle)
         }
     }
 
+    /* Insert the new handle inside the process handles table */
     ApiMessage->Status = ConSrvInsertObject(ProcessData,
                                             &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
                                             Entry->Object,
index e1b3063..3a73342 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "consrv.h"
 #include "conio.h"
+#include "console.h"
 
 #define NDEBUG
 #include <debug.h>