From 01729482ae55d06885ec64848b65e020bd122497 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sat, 30 Mar 2013 18:44:56 +0000 Subject: [PATCH] [CONSOLE.DLL] - 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 | 52 +++-- win32ss/user/consrv/coninput.c | 9 +- win32ss/user/consrv/conio.h | 24 +- win32ss/user/consrv/conoutput.c | 28 ++- win32ss/user/consrv/console.c | 281 ++++++++++++++++------ win32ss/user/consrv/console.h | 52 +++++ win32ss/user/consrv/consrv.h | 21 +- win32ss/user/consrv/guiconsole.c | 373 +++++++++++++++++++----------- win32ss/user/consrv/guisettings.c | 219 +++++++++++------- win32ss/user/consrv/handle.c | 220 ++++++++++++++---- win32ss/user/consrv/init.c | 1 + 11 files changed, 912 insertions(+), 368 deletions(-) create mode 100644 win32ss/user/consrv/console.h diff --git a/dll/cpl/console/console.c b/dll/cpl/console/console.c index cc9551dead0..d570085e7ab 100644 --- a/dll/cpl/console/console.c +++ b/dll/cpl/console/console.c @@ -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; diff --git a/win32ss/user/consrv/coninput.c b/win32ss/user/consrv/coninput.c index bfe882a37f9..a7c0ed502d0 100644 --- a/win32ss/user/consrv/coninput.c +++ b/win32ss/user/consrv/coninput.c @@ -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; } diff --git a/win32ss/user/consrv/conio.h b/win32ss/user/consrv/conio.h index 58259547a5a..45d9b882015 100644 --- a/win32ss/user/consrv/conio.h +++ b/win32ss/user/consrv/conio.h @@ -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, diff --git a/win32ss/user/consrv/conoutput.c b/win32ss/user/consrv/conoutput.c index 724cff869c0..679552bfd77 100644 --- a/win32ss/user/consrv/conoutput.c +++ b/win32ss/user/consrv/conoutput.c @@ -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; } diff --git a/win32ss/user/consrv/console.c b/win32ss/user/consrv/console.c index 92d8d2be0df..63c1ffc6227 100644 --- a/win32ss/user/consrv/console.c +++ b/win32ss/user/consrv/console.c @@ -21,12 +21,19 @@ #include "tuiconsole.h" #endif +#include "console.h" + #include #include -//#define NDEBUG +#define NDEBUG #include +/* 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 index 00000000000..a3f359a53f7 --- /dev/null +++ b/win32ss/user/consrv/console.h @@ -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 */ diff --git a/win32ss/user/consrv/consrv.h b/win32ss/user/consrv/consrv.h index c668456dac2..11e5ac66ef4 100644 --- a/win32ss/user/consrv/consrv.h +++ b/win32ss/user/consrv/consrv.h @@ -34,6 +34,9 @@ /* Public Win32K Headers */ #include +/* PSEH for SEH Support */ +#include + /* CSRSS Header */ #include @@ -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); diff --git a/win32ss/user/consrv/guiconsole.c b/win32ss/user/consrv/guiconsole.c index b66c32dbdce..15ea9164ccc 100644 --- a/win32ss/user/consrv/guiconsole.c +++ b/win32ss/user/consrv/guiconsole.c @@ -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; diff --git a/win32ss/user/consrv/guisettings.c b/win32ss/user/consrv/guisettings.c index 2362ae6a84c..2a4b71ba58c 100644 --- a/win32ss/user/consrv/guisettings.c +++ b/win32ss/user/consrv/guisettings.c @@ -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 */ diff --git a/win32ss/user/consrv/handle.c b/win32ss/user/consrv/handle.c index 94549d60675..bfb6490ffc7 100644 --- a/win32ss/user/consrv/handle.c +++ b/win32ss/user/consrv/handle.c @@ -10,8 +10,9 @@ #include "consrv.h" #include "conio.h" +#include "console.h" -//#define NDEBUG +#define NDEBUG #include @@ -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, diff --git a/win32ss/user/consrv/init.c b/win32ss/user/consrv/init.c index e1b30634021..3a73342add5 100644 --- a/win32ss/user/consrv/init.c +++ b/win32ss/user/consrv/init.c @@ -10,6 +10,7 @@ #include "consrv.h" #include "conio.h" +#include "console.h" #define NDEBUG #include -- 2.17.1