[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
This commit is contained in:
Hermès Bélusca-Maïto 2013-03-30 18:44:56 +00:00
parent 1e1a59fb22
commit 01729482ae
11 changed files with 921 additions and 377 deletions

View 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;

View 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;
}

View 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,

View 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;
}

View file

@ -21,12 +21,19 @@
#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,45 +524,134 @@ 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;
return STATUS_SUCCESS;
}
VOID WINAPI
ConSrvInitConsoleSupport(VOID)
{
DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
/* Should call LoadKeyboardLayout */
}
VOID WINAPI
ConSrvDeleteConsole(PCONSOLE Console)
{
ConsoleInput *Event;
PLIST_ENTRY CurrentEntry;
ConsoleInput* Event;
DPRINT("ConSrvDeleteConsole\n");
DPRINT1("ConSrvDeleteConsole\n");
/* Drain input event queue */
while (Console->InputBuffer.InputEvents.Flink != &Console->InputBuffer.InputEvents)
/*
* Forbid validation of any console by other threads
* during the deletion of this console.
*/
ConSrvLockConsoleListExclusive();
/* Check the existence of the console, and if it's ok, continue */
if (!ConSrvValidatePointer(Console))
{
Event = (ConsoleInput *) Console->InputBuffer.InputEvents.Flink;
Console->InputBuffer.InputEvents.Flink = Console->InputBuffer.InputEvents.Flink->Flink;
Console->InputBuffer.InputEvents.Flink->Flink->Blink = &Console->InputBuffer.InputEvents;
/* Unlock the console list and return */
ConSrvUnlockConsoleList();
return;
}
/*
* If the console is already being destroyed
* (thus not running), just return.
*/
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
{
/* Unlock the console list and return */
ConSrvUnlockConsoleList();
return;
}
/*
* We are about to be destroyed. Signal it to other people
* so that they can terminate what they are doing, and that
* they cannot longer validate the console.
*/
Console->State = CONSOLE_TERMINATING;
/*
* Allow other threads to finish their job: basically, unlock
* all other calls to EnterCriticalSection(&Console->Lock); by
* ConSrvValidateConsole(Unsafe) functions so that they just see
* that we are not in CONSOLE_RUNNING state anymore, or unlock
* other concurrent calls to ConSrvDeleteConsole so that they
* can see that we are in fact already deleting the console.
*/
LeaveCriticalSection(&Console->Lock);
ConSrvUnlockConsoleList();
/* FIXME: Send a terminate message to all the processes owning this console */
/* Cleanup the UI-oriented part */
ConioCleanupConsole(Console);
/***
* 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);
}
ConioCleanupConsole(Console);
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;
DWORD DesiredAccess = OpenConsoleRequest->Access;
DWORD ShareMode = OpenConsoleRequest->ShareMode;
Object_t *Object;
OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (ProcessData->Console)
/*
* Open a handle to either the active screen buffer or the input buffer.
*/
if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
{
DWORD DesiredAccess = OpenConsoleRequest->Access;
DWORD ShareMode = OpenConsoleRequest->ShareMode;
Object = &Console->ActiveBuffer->Header;
}
else // HANDLE_INPUT
{
Object = &Console->InputBuffer.Header;
}
PCONSOLE Console = ProcessData->Console;
Object_t *Object;
EnterCriticalSection(&Console->Lock);
if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
{
Object = &Console->ActiveBuffer->Header;
}
else // HANDLE_INPUT
{
Object = &Console->InputBuffer.Header;
}
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);
}
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;
}

View file

@ -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 */

View 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);

View 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);
GuiConsolePaint(Console,
GuiData,
hDC,
&ps.rcPaint);
if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
{
EnterCriticalSection(&GuiData->Lock);
RECT rc;
SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
GuiConsolePaint(Console,
GuiData,
hDC,
&ps.rcPaint);
if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
/* invert the selection */
if (IntersectRect(&rc,
&ps.rcPaint,
&rc))
{
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);
}
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();
if (!(wParam & MK_LBUTTON)) return;
break;
}
if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
case WM_RBUTTONDOWN:
{
if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
{
GuiConsolePaste(GuiData);
}
else
{
GuiConsoleCopy(GuiData);
c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
GuiConsoleUpdateSelection(Console, &c);
/* Clear the selection */
GuiConsoleUpdateSelection(Console, NULL);
}
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.
/*
* Each helper function which needs the console
* has to validate and lock it.
*/
/* Lock the console */
EnterCriticalSection(&GuiData->Console->Lock);
/* 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_LBUTTONDOWN:
GuiConsoleLeftMouseDown(GuiData, lParam);
break;
case WM_LBUTTONUP:
GuiConsoleLeftMouseUp(GuiData, lParam);
break;
case WM_RBUTTONDOWN:
GuiConsoleRightMouseDown(GuiData);
break;
case WM_MOUSEMOVE:
GuiConsoleMouseMove(GuiData, wParam, lParam);
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
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;

View 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;
/*
* 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);
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);
/* 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));
/* 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);
/* 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;
Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
ProcessData->PropDispatcher,
(PVOID)hClientSection, 0, NULL);
if (NULL == Thread)
_SEH2_TRY
{
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
return;
}
HANDLE Thread = NULL;
DPRINT1("We succeeded at creating ProcessData->PropDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
/// WaitForSingleObject(Thread, INFINITE);
CloseHandle(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)
{
Status = _SEH2_GetExceptionCode();
DPRINT1("GuiConsoleShowConsoleProperties - Caught an exception, Status = %08X\n", Status);
}
_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
/* Retrieve terminal informations */
ConInfo = &pConInfo->ci;
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);
/* Set the terminal informations */
// memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
/* 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
*/
// 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);
}
Status = STATUS_SUCCESS;
}
// TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
/* Set the console informations */
ConInfo = &pConInfo->ci;
ConSrvApplyUserSettings(Console, ConInfo);
/* Set the terminal informations - De-offsetization of the pointer */
TermInfo = &pConInfo->TerminalInfo;
GuiInfo = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo);
// memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
/* 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
*/
// FIXME: Do it in the console properties applet ??
if (SaveSettings)
_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 */

View 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;
/* Decrement reference count */
if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
ConSrvDeleteConsole(Console);
if (!Console) return;
// if (Console->ReferenceCount == 0) return; // This shouldn't happen
ASSERT(Console->ReferenceCount > 0);
/* The console must be locked */
// ASSERT(Console_locked);
/*
* Decrement the reference count. Save the new value too,
* because Console->ReferenceCount might be modified after
* the console gets unlocked but before we check whether we
* can destroy it.
*/
RefCount = _InterlockedDecrement(&Console->ReferenceCount);
/* Unlock the console if needed */
if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock);
/* Delete the console if needed */
if (RefCount <= 0) ConSrvDeleteConsole(Console);
}
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,

View file

@ -10,6 +10,7 @@
#include "consrv.h"
#include "conio.h"
#include "console.h"
#define NDEBUG
#include <debug.h>