[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; PGUI_CONSOLE_INFO GuiInfo = NULL;
/* FIXME: Get also the defaults from the registry */
/* Initialize the default properties */ /* Initialize the default properties */
pConInfo->ci.HistoryBufferSize = 50; pConInfo->ci.HistoryBufferSize = 50;
pConInfo->ci.NumberOfHistoryBuffers = 4; pConInfo->ci.NumberOfHistoryBuffers = 4;
@ -108,7 +110,8 @@ InitConsoleDefaults(PCONSOLE_PROPS pConInfo)
/* Adapted for holding GUI terminal information */ /* Adapted for holding GUI terminal information */
pConInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO); pConInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
GuiInfo = pConInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pConInfo + 1); 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->FontFamily = FF_DONTCARE;
GuiInfo->FontSize = 0; GuiInfo->FontSize = 0;
GuiInfo->FontWeight = FW_DONTCARE; GuiInfo->FontWeight = FW_DONTCARE;
@ -166,16 +169,35 @@ BOOL
ApplyConsoleInfo(HWND hwndDlg, ApplyConsoleInfo(HWND hwndDlg,
PCONSOLE_PROPS pConInfo) 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)
{
SetParams = TRUE;
SaveParams = TRUE;
}
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 */ /* Don't destroy when user presses cancel */
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
return TRUE; // return TRUE;
} }
else if (res == IDC_RADIO_APPLY_ALL || res == IDC_RADIO_APPLY_CURRENT) }
// if (res == IDC_RADIO_APPLY_ALL || res == IDC_RADIO_APPLY_CURRENT)
if (SetParams)
{ {
HANDLE hSection; HANDLE hSection;
PCONSOLE_PROPS pSharedInfo; PCONSOLE_PROPS pSharedInfo;
@ -207,10 +229,15 @@ ApplyConsoleInfo(HWND hwndDlg,
/* We are applying the chosen configuration */ /* We are applying the chosen configuration */
pConInfo->AppliedConfig = TRUE; 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)); RtlCopyMemory(pSharedInfo, pConInfo, sizeof(CONSOLE_PROPS) + sizeof(GUI_CONSOLE_INFO));
/* Offsetize */ pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)pConInfo->TerminalInfo.TermInfo - (ULONG_PTR)pConInfo);
pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)pSharedInfo->TerminalInfo.TermInfo - (ULONG_PTR)pSharedInfo);
/* Unmap it */ /* Unmap it */
UnmapViewOfFile(pSharedInfo); UnmapViewOfFile(pSharedInfo);
@ -220,11 +247,10 @@ ApplyConsoleInfo(HWND hwndDlg,
SendMessage(pConInfo->hConsoleWindow, SendMessage(pConInfo->hConsoleWindow,
PM_APPLY_CONSOLE_INFO, PM_APPLY_CONSOLE_INFO,
(WPARAM)hSection, (WPARAM)hSection,
(LPARAM)(res == IDC_RADIO_APPLY_ALL)); (LPARAM)SaveParams);
/* Close the section and return */ /* Close the section and return */
CloseHandle(hSection); CloseHandle(hSection);
return TRUE;
} }
return TRUE; return TRUE;

View file

@ -685,7 +685,6 @@ CSR_API(SrvReadConsole)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
// if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead) if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
{ {
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -808,7 +807,7 @@ CSR_API(SrvFlushConsoleInputBuffer)
PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest; PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
PLIST_ENTRY CurrentEntry; PLIST_ENTRY CurrentEntry;
PCONSOLE_INPUT_BUFFER InputBuffer; PCONSOLE_INPUT_BUFFER InputBuffer;
ConsoleInput* Input; ConsoleInput* Event;
DPRINT("SrvFlushConsoleInputBuffer\n"); DPRINT("SrvFlushConsoleInputBuffer\n");
@ -823,14 +822,12 @@ CSR_API(SrvFlushConsoleInputBuffer)
while (!IsListEmpty(&InputBuffer->InputEvents)) while (!IsListEmpty(&InputBuffer->InputEvents))
{ {
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* Destroy the event */ RtlFreeHeap(ConSrvHeap, 0, Event);
RtlFreeHeap(ConSrvHeap, 0, Input);
} }
ResetEvent(InputBuffer->ActiveEvent); ResetEvent(InputBuffer->ActiveEvent);
ConSrvReleaseInputBuffer(InputBuffer, TRUE); ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -147,12 +147,27 @@ typedef struct _FRONTEND_IFACE
PVOID OldData; /* Reserved */ PVOID OldData; /* Reserved */
} FRONTEND_IFACE, *PFRONTEND_IFACE; } 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 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; 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" */ 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 */ FRONTEND_IFACE TermIFace; /* Frontend-specific interface */
@ -218,11 +233,6 @@ typedef struct _CONSOLE
#define PAUSED_FROM_SELECTION 0x4 #define PAUSED_FROM_SELECTION 0x4
/* console.c */ /* 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 ConioPause(PCONSOLE Console, UINT Flags);
VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags); VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags);
ULONG FASTCALL ConSrvConsoleProcessCtrlEvent(PCONSOLE Console, ULONG FASTCALL ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,

View file

@ -1278,15 +1278,18 @@ CSR_API(SrvCreateConsoleScreenBuffer)
DPRINT("SrvCreateConsoleScreenBuffer\n"); DPRINT("SrvCreateConsoleScreenBuffer\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock); // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConSrvGetConsole(ProcessData, &Console, TRUE); Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status; return Status;
} }
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/*
if (Console->ActiveBuffer) if (Console->ActiveBuffer)
{ {
ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize; ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
@ -1299,6 +1302,23 @@ CSR_API(SrvCreateConsoleScreenBuffer)
IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible; IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
CursorSize = Console->ActiveBuffer->CursorInfo.dwSize; 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, Status = ConSrvCreateScreenBuffer(Console,
&Buff, &Buff,
@ -1309,6 +1329,7 @@ CSR_API(SrvCreateConsoleScreenBuffer)
CursorSize); CursorSize);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Insert the new handle inside the process handles table */
Status = ConSrvInsertObject(ProcessData, Status = ConSrvInsertObject(ProcessData,
&CreateScreenBufferRequest->OutputHandle, &CreateScreenBufferRequest->OutputHandle,
&Buff->Header, &Buff->Header,
@ -1317,10 +1338,11 @@ CSR_API(SrvCreateConsoleScreenBuffer)
CreateScreenBufferRequest->ShareMode); CreateScreenBufferRequest->ShareMode);
} }
ConSrvReleaseConsole(Console, TRUE); // ConSrvReleaseConsole(Console, TRUE);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvReleaseConsole(Console, TRUE);
return Status; return Status;
} }

View file

@ -21,12 +21,19 @@
#include "tuiconsole.h" #include "tuiconsole.h"
#endif #endif
#include "console.h"
#include <shlwapi.h> #include <shlwapi.h>
#include <shlobj.h> #include <shlobj.h>
//#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* GLOBALS ********************************************************************/
LIST_ENTRY ConsoleList; /* The list of all the allocated consoles */
/*static*/ RTL_RESOURCE ListLock;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
@ -44,11 +51,16 @@ ConSrvConsoleCtrlEventTimeout(DWORD Event,
DWORD Timeout) DWORD Timeout)
{ {
ULONG Status = ERROR_SUCCESS; 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) if (ProcessData->CtrlDispatcher)
{
_SEH2_TRY
{
HANDLE Thread = NULL;
_SEH2_TRY
{ {
Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
ProcessData->CtrlDispatcher, ProcessData->CtrlDispatcher,
@ -60,10 +72,22 @@ ConSrvConsoleCtrlEventTimeout(DWORD Event,
} }
else else
{ {
DPRINT("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
WaitForSingleObject(Thread, Timeout); WaitForSingleObject(Thread, Timeout);
}
}
_SEH2_FINALLY
{
CloseHandle(Thread); CloseHandle(Thread);
} }
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status);
}
_SEH2_END;
} }
return Status; return Status;
@ -85,6 +109,10 @@ ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
PLIST_ENTRY current_entry; PLIST_ENTRY current_entry;
PCONSOLE_PROCESS_DATA current; 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 * Loop through the process list, from the most recent process
* (the active one) to the oldest one (the first created, i.e. * (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 static BOOL
LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
IN OUT PCONSOLE_INFO ConsoleInfo, IN OUT PCONSOLE_INFO ConsoleInfo,
@ -346,6 +386,7 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
/* /*
* Initialize the console * Initialize the console
*/ */
Console->State = CONSOLE_INITIALIZING;
InitializeCriticalSection(&Console->Lock); InitializeCriticalSection(&Console->Lock);
Console->ReferenceCount = 0; Console->ReferenceCount = 0;
InitializeListHead(&Console->ProcessList); InitializeListHead(&Console->ProcessList);
@ -428,6 +469,9 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole,
RtlCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle); RtlCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
} }
/* Lock the console until its initialization is finished */
// EnterCriticalSection(&Console->Lock);
/* /*
* If we are not in GUI-mode, start the text-mode terminal emulator. * If we are not in GUI-mode, start the text-mode terminal emulator.
* If we fail, try to start the GUI-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); RtlFreeUnicodeString(&Console->OriginalTitle);
ConioDeleteScreenBuffer(NewBuffer); ConioDeleteScreenBuffer(NewBuffer);
CloseHandle(Console->InputBuffer.ActiveEvent); CloseHandle(Console->InputBuffer.ActiveEvent);
// LeaveCriticalSection(&Console->Lock);
DeleteCriticalSection(&Console->Lock); DeleteCriticalSection(&Console->Lock);
RtlFreeHeap(ConSrvHeap, 0, Console); RtlFreeHeap(ConSrvHeap, 0, Console);
return Status; 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 */ /* Copy buffer contents to screen */
ConioDrawConsole(Console); ConioDrawConsole(Console);
DPRINT1("Console drawn\n");
/* Return the newly created console to the caller and a success code too */ /* Return the newly created console to the caller and a success code too */
*NewConsole = Console; *NewConsole = Console;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
VOID WINAPI
ConSrvInitConsoleSupport(VOID)
{
DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
/* Should call LoadKeyboardLayout */
}
VOID WINAPI VOID WINAPI
ConSrvDeleteConsole(PCONSOLE Console) 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; /* Unlock the console list and return */
Console->InputBuffer.InputEvents.Flink = Console->InputBuffer.InputEvents.Flink->Flink; ConSrvUnlockConsoleList();
Console->InputBuffer.InputEvents.Flink->Flink->Blink = &Console->InputBuffer.InputEvents; 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); RtlFreeHeap(ConSrvHeap, 0, Event);
} }
ConioCleanupConsole(Console);
if (Console->LineBuffer) if (Console->LineBuffer)
RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer); RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
while (!IsListEmpty(&Console->HistoryBuffers)) while (!IsListEmpty(&Console->HistoryBuffers))
@ -532,12 +665,22 @@ ConSrvDeleteConsole(PCONSOLE Console)
CloseHandle(Console->InputBuffer.ActiveEvent); CloseHandle(Console->InputBuffer.ActiveEvent);
if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent); if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
DeleteCriticalSection(&Console->Lock);
RtlFreeUnicodeString(&Console->OriginalTitle); RtlFreeUnicodeString(&Console->OriginalTitle);
RtlFreeUnicodeString(&Console->Title); RtlFreeUnicodeString(&Console->Title);
IntDeleteAllAliases(Console->Aliases); 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); RtlFreeHeap(ConSrvHeap, 0, Console);
DPRINT1("ConSrvDeleteConsole - Console freed\n");
/* Unlock the console list and return */
ConSrvUnlockConsoleList();
} }
@ -545,24 +688,29 @@ ConSrvDeleteConsole(PCONSOLE Console)
CSR_API(SrvOpenConsole) CSR_API(SrvOpenConsole)
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status;
PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest; PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 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; 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); RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (ProcessData->Console) /*
{ * Open a handle to either the active screen buffer or the input buffer.
DWORD DesiredAccess = OpenConsoleRequest->Access; */
DWORD ShareMode = OpenConsoleRequest->ShareMode;
PCONSOLE Console = ProcessData->Console;
Object_t *Object;
EnterCriticalSection(&Console->Lock);
if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT) if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
{ {
Object = &Console->ActiveBuffer->Header; Object = &Console->ActiveBuffer->Header;
@ -590,11 +738,9 @@ CSR_API(SrvOpenConsole)
ShareMode); ShareMode);
} }
LeaveCriticalSection(&Console->Lock);
}
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvReleaseConsole(Console, TRUE);
return Status; return Status;
} }
@ -758,7 +904,6 @@ Quit:
CSR_API(SrvFreeConsole) CSR_API(SrvFreeConsole)
{ {
DPRINT1("SrvFreeConsole\n");
ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process)); ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -798,7 +943,6 @@ CSR_API(SrvSetConsoleMode)
} }
ConSrvReleaseObject(Object, TRUE); ConSrvReleaseObject(Object, TRUE);
return Status; return Status;
} }
@ -831,7 +975,6 @@ CSR_API(SrvGetConsoleMode)
} }
ConSrvReleaseObject(Object, TRUE); ConSrvReleaseObject(Object, TRUE);
return Status; 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 */ /* Public Win32K Headers */
#include <ntuser.h> #include <ntuser.h>
/* PSEH for SEH Support */
#include <pseh/pseh2.h>
/* CSRSS Header */ /* CSRSS Header */
#include <csr/csrsrv.h> #include <csr/csrsrv.h>
@ -93,6 +96,20 @@ typedef struct _CONSOLE_PROCESS_DATA
} CONSOLE_PROCESS_DATA, *PCONSOLE_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 */ /* alias.c */
CSR_API(SrvAddConsoleAlias); CSR_API(SrvAddConsoleAlias);
CSR_API(SrvGetConsoleAlias); CSR_API(SrvGetConsoleAlias);
@ -177,12 +194,12 @@ NTSTATUS FASTCALL ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE pInputHandle, PHANDLE pInputHandle,
PHANDLE pOutputHandle, PHANDLE pOutputHandle,
PHANDLE pErrorHandle); PHANDLE pErrorHandle);
VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData);
NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
struct _CONSOLE** Console, struct _CONSOLE** Console,
BOOL LockConsole); BOOL LockConsole);
VOID FASTCALL ConSrvReleaseConsole(struct _CONSOLE* Console, VOID FASTCALL ConSrvReleaseConsole(struct _CONSOLE* Console,
BOOL IsConsoleLocked); BOOL WasConsoleLocked);
VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData);
NTSTATUS NTAPI ConSrvNewProcess(PCSR_PROCESS SourceProcess, NTSTATUS NTAPI ConSrvNewProcess(PCSR_PROCESS SourceProcess,
PCSR_PROCESS TargetProcess); PCSR_PROCESS TargetProcess);

View file

@ -10,6 +10,7 @@
#include "consrv.h" #include "consrv.h"
#include "conio.h" #include "conio.h"
#include "console.h"
#include "settings.h" #include "settings.h"
#include "guiconsole.h" #include "guiconsole.h"
#include "guisettings.h" #include "guisettings.h"
@ -212,6 +213,13 @@ static LRESULT
GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
{ {
LRESULT Ret = TRUE; LRESULT Ret = TRUE;
PCONSOLE Console = GuiData->Console;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
{
Ret = FALSE;
goto Quit;
}
switch (wParam) switch (wParam)
{ {
@ -229,7 +237,6 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
case ID_SYSTEM_EDIT_SELECTALL: case ID_SYSTEM_EDIT_SELECTALL:
{ {
PCONSOLE Console = GuiData->Console;
COORD bottomRight = { 0, 0 }; COORD bottomRight = { 0, 0 };
bottomRight.X = Console->ConsoleSize.X - 1; bottomRight.X = Console->ConsoleSize.X - 1;
@ -255,15 +262,23 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM
break; break;
default: default:
Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam); Ret = FALSE;
break; break;
} }
LeaveCriticalSection(&Console->Lock);
Quit:
if (!Ret)
Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
return Ret; return Ret;
} }
static PGUI_CONSOLE_DATA static PGUI_CONSOLE_DATA
GuiGetGuiData(HWND hWnd) GuiGetGuiData(HWND hWnd)
{ {
/* This function ensures that the console pointer is not NULL */
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA); PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL ); return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
} }
@ -342,6 +357,8 @@ GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
TEXTMETRICW Metrics; TEXTMETRICW Metrics;
SIZE CharSize; SIZE CharSize;
DPRINT1("GuiConsoleHandleNcCreate\n");
if (NULL == GuiData) if (NULL == GuiData)
{ {
DPRINT1("GuiConsoleNcCreate: No GUI data\n"); 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); SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
GuiConsoleCreateSysMenu(GuiData->hWindow); GuiConsoleCreateSysMenu(GuiData->hWindow);
/* Move and resize the window to the user's values */ DPRINT1("GuiConsoleHandleNcCreate - setting start event\n");
GuiConsoleMoveWindow(GuiData);
GuiData->WindowSizeLock = TRUE;
GuiConsoleResizeWindow(GuiData);
GuiData->WindowSizeLock = FALSE;
SetEvent(GuiData->hGuiInitEvent); SetEvent(GuiData->hGuiInitEvent);
return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create); return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
@ -526,8 +538,6 @@ GuiConsolePaint(PCONSOLE Console,
Buff = Console->ActiveBuffer; Buff = Console->ActiveBuffer;
/// LOCK /// EnterCriticalSection(&Buff->Header.Console->Lock);
TopLine = rc->top / GuiData->CharHeight + Buff->ShowY; TopLine = rc->top / GuiData->CharHeight + Buff->ShowY;
BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY; BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY;
LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX; LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX;
@ -618,26 +628,33 @@ GuiConsolePaint(PCONSOLE Console,
} }
} }
/// LOCK /// LeaveCriticalSection(&Buff->Header.Console->Lock);
SelectObject(hDC, OldFont); SelectObject(hDC, OldFont);
} }
static VOID static VOID
GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData, HDC hDCPaint) GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
{ {
BOOL Success = TRUE;
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
HDC hDC; HDC hDC;
PAINTSTRUCT ps; 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); hDC = BeginPaint(GuiData->hWindow, &ps);
if (hDC != NULL && if (hDC != NULL &&
ps.rcPaint.left < ps.rcPaint.right && ps.rcPaint.left < ps.rcPaint.right &&
ps.rcPaint.top < ps.rcPaint.bottom) ps.rcPaint.top < ps.rcPaint.bottom)
{
if (Console->ActiveBuffer->Buffer != NULL)
{ {
EnterCriticalSection(&GuiData->Lock); EnterCriticalSection(&GuiData->Lock);
@ -667,8 +684,15 @@ GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData, HDC hDCPaint)
LeaveCriticalSection(&GuiData->Lock); LeaveCriticalSection(&GuiData->Lock);
} }
}
EndPaint(GuiData->hWindow, &ps); EndPaint(GuiData->hWindow, &ps);
Quit:
if (Success)
LeaveCriticalSection(&Console->Lock);
else
DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
return;
} }
static VOID static VOID
@ -677,6 +701,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
MSG Message; MSG Message;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
Message.hwnd = GuiData->hWindow; Message.hwnd = GuiData->hWindow;
Message.message = msg; Message.message = msg;
Message.wParam = wParam; Message.wParam = wParam;
@ -689,6 +715,8 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l
} }
ConioProcessKey(Console, &Message); ConioProcessKey(Console, &Message);
LeaveCriticalSection(&Console->Lock);
} }
static VOID static VOID
@ -706,6 +734,8 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL); SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
Buff = Console->ActiveBuffer; Buff = Console->ActiveBuffer;
GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
Buff->CursorBlinkOn = !Buff->CursorBlinkOn; Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
@ -782,14 +812,15 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
GuiData->OldCursor.y = Buff->CursorPosition.Y; GuiData->OldCursor.y = Buff->CursorPosition.Y;
} }
} }
LeaveCriticalSection(&Console->Lock);
} }
static VOID static VOID
GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData) GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
{ {
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
/// LOCK /// EnterCriticalSection(&Console->Lock);
/* /*
* FIXME: Windows will wait up to 5 seconds for the thread to exit. * 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); ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
/// LOCK /// LeaveCriticalSection(&Console->Lock); LeaveCriticalSection(&Console->Lock);
} }
static VOID static LRESULT
GuiConsoleHandleNcDestroy(PGUI_CONSOLE_DATA GuiData) GuiConsoleHandleNcDestroy(HWND hWnd)
{ {
KillTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER); // PGUI_CONSOLE_DATA GuiData;
GetSystemMenu(GuiData->hWindow, TRUE);
SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)NULL); KillTimer(hWnd, CONGUI_UPDATE_TIMER);
GuiData->hWindow = NULL; 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 static COORD
@ -835,43 +872,85 @@ PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
return Coord; return Coord;
} }
static VOID static LRESULT
GuiConsoleLeftMouseDown(PGUI_CONSOLE_DATA GuiData, LPARAM lParam) GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
LRESULT Ret = TRUE;
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
{
Ret = FALSE;
goto Quit;
}
switch (msg)
{
case WM_LBUTTONDOWN:
{
Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam); Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
SetCapture(GuiData->hWindow); SetCapture(GuiData->hWindow);
Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN; Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor); GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
} break;
}
static VOID case WM_LBUTTONUP:
GuiConsoleLeftMouseUp(PGUI_CONSOLE_DATA GuiData, LPARAM lParam) {
{
PCONSOLE Console = GuiData->Console;
COORD c; COORD c;
if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return; if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
c = PointToCoord(GuiData, lParam); c = PointToCoord(GuiData, lParam);
Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN; Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
GuiConsoleUpdateSelection(Console, &c); GuiConsoleUpdateSelection(Console, &c);
ReleaseCapture(); ReleaseCapture();
}
static VOID break;
GuiConsoleMouseMove(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) }
{
PCONSOLE Console = GuiData->Console; case WM_RBUTTONDOWN:
{
if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
{
GuiConsolePaste(GuiData);
}
else
{
GuiConsoleCopy(GuiData);
/* Clear the selection */
GuiConsoleUpdateSelection(Console, NULL);
}
break;
}
case WM_MOUSEMOVE:
{
COORD c; COORD c;
if (!(wParam & MK_LBUTTON)) return; if (!(wParam & MK_LBUTTON)) break;
if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */ c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
GuiConsoleUpdateSelection(Console, &c); 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 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 static VOID
GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo) GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
{ {
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
DWORD windx, windy; DWORD windx, windy;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); 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); 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.x = windx;
minMaxInfo->ptMaxTrackSize.y = windy; minMaxInfo->ptMaxTrackSize.y = windy;
LeaveCriticalSection(&Console->Lock);
} }
static VOID static VOID
@ -1027,6 +1092,8 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
{ {
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
if ((GuiData->WindowSizeLock == FALSE) && if ((GuiData->WindowSizeLock == FALSE) &&
(wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED)) (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; GuiData->WindowSizeLock = FALSE;
} }
LeaveCriticalSection(&Console->Lock);
} }
/* /*
@ -1107,8 +1176,7 @@ GuiConsoleHandleScrollbarMenu(VOID)
} }
*/ */
static static LRESULT
LRESULT
GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam) GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
{ {
PCONSOLE Console = GuiData->Console; PCONSOLE Console = GuiData->Console;
@ -1118,7 +1186,7 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
int old_pos, Maximum; int old_pos, Maximum;
PUSHORT pShowXY; PUSHORT pShowXY;
if (GuiData == NULL) return FALSE; if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
Buff = Console->ActiveBuffer; Buff = Console->ActiveBuffer;
@ -1139,10 +1207,7 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
sInfo.cbSize = sizeof(SCROLLINFO); sInfo.cbSize = sizeof(SCROLLINFO);
sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS; sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
{
return FALSE;
}
old_pos = sInfo.nPos; old_pos = sInfo.nPos;
@ -1209,6 +1274,8 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
UpdateWindow(GuiData->hWindow); UpdateWindow(GuiData->hWindow);
} }
Quit:
LeaveCriticalSection(&Console->Lock);
return 0; return 0;
} }
@ -1217,15 +1284,22 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
LRESULT Result = 0; LRESULT Result = 0;
PGUI_CONSOLE_DATA GuiData = NULL; PGUI_CONSOLE_DATA GuiData = NULL;
PCONSOLE Console = NULL;
/* /*
* If it's the first time we create a window * - If it's the first time we create a window for the terminal,
* for the terminal, just initialize it. * just initialize it and return.
*
* - If we are destroying the window, just do it and return.
*/ */
if (msg == WM_NCCREATE) if (msg == WM_NCCREATE)
{ {
return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam); return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
} }
else if (msg == WM_NCDESTROY)
{
return GuiConsoleHandleNcDestroy(hWnd);
}
/* /*
* Now the terminal window is initialized. * Now the terminal window is initialized.
@ -1235,24 +1309,20 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
GuiData = GuiGetGuiData(hWnd); GuiData = GuiGetGuiData(hWnd);
if (GuiData == NULL) return 0; 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 */ /* We have a console, start message dispatching */
EnterCriticalSection(&GuiData->Console->Lock);
/* We have a console, start message dispatching. */
switch (msg) switch (msg)
{ {
case WM_CLOSE: case WM_CLOSE:
GuiConsoleHandleClose(GuiData); GuiConsoleHandleClose(GuiData);
break; break;
case WM_NCDESTROY:
GuiConsoleHandleNcDestroy(GuiData);
break;
case WM_PAINT: case WM_PAINT:
GuiConsoleHandlePaint(GuiData, (HDC)wParam); GuiConsoleHandlePaint(GuiData);
break; break;
case WM_KEYDOWN: case WM_KEYDOWN:
@ -1260,37 +1330,43 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
case WM_SYSKEYUP: case WM_SYSKEYUP:
case WM_CHAR: case WM_CHAR:
{
GuiConsoleHandleKey(GuiData, msg, wParam, lParam); GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
break; break;
}
case WM_TIMER: case WM_TIMER:
GuiConsoleHandleTimer(GuiData); GuiConsoleHandleTimer(GuiData);
break; break;
case WM_LBUTTONDOWN:
GuiConsoleLeftMouseDown(GuiData, lParam);
break;
case WM_LBUTTONUP:
GuiConsoleLeftMouseUp(GuiData, lParam);
break;
case WM_RBUTTONDOWN:
GuiConsoleRightMouseDown(GuiData);
break;
case WM_MOUSEMOVE: 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; break;
}
case WM_SYSCOMMAND: case WM_SYSCOMMAND:
{
Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam); Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
break; break;
}
case WM_HSCROLL: case WM_HSCROLL:
case WM_VSCROLL: case WM_VSCROLL:
{
Result = GuiConsoleHandleScroll(GuiData, msg, wParam); Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
break; break;
}
case WM_GETMINMAXINFO: case WM_GETMINMAXINFO:
GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam); GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
@ -1301,26 +1377,30 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
break; break;
case PM_APPLY_CONSOLE_INFO: case PM_APPLY_CONSOLE_INFO:
{
Console = GuiData->Console; // Not NULL because checked in GuiGetGuiData.
if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
{
GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam); GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
LeaveCriticalSection(&Console->Lock);
}
break; break;
}
case PM_CONSOLE_BEEP: case PM_CONSOLE_BEEP:
DPRINT1("Beep !!\n"); DPRINT1("Beep !!\n");
Beep(800, 200); Beep(800, 200);
break; break;
case PM_CONSOLE_SET_TITLE: // case PM_CONSOLE_SET_TITLE:
SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer); // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
break; // break;
default: default:
Result = DefWindowProcW(GuiData->hWindow, msg, wParam, lParam); Result = DefWindowProcW(hWnd, msg, wParam, lParam);
break; break;
} }
/* Unlock the console */
LeaveCriticalSection(&GuiData->Console->Lock);
return Result; return Result;
} }
@ -1336,8 +1416,6 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
HWND NewWindow; HWND NewWindow;
LONG WindowCount; LONG WindowCount;
MSG Msg; MSG Msg;
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
PCONSOLE Console = GuiData->Console;
switch (msg) switch (msg)
{ {
@ -1349,6 +1427,9 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case PM_CREATE_CONSOLE: case PM_CREATE_CONSOLE:
{ {
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
PCONSOLE Console = GuiData->Console;
NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE, NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
GUI_CONSOLE_WINDOW_CLASS, GUI_CONSOLE_WINDOW_CLASS,
Console->Title.Buffer, 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); 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; return (LRESULT)NewWindow;
@ -1389,16 +1479,20 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case PM_DESTROY_CONSOLE: case PM_DESTROY_CONSOLE:
{ {
PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
/* /*
* Window creation is done using a PostMessage(), so it's possible * Window creation is done using a PostMessage(), so it's possible
* that the window that we want to destroy doesn't exist yet. * that the window that we want to destroy doesn't exist yet.
* So first empty the message queue. * So first empty the message queue.
*/ */
/*
while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
{ {
TranslateMessage(&Msg); TranslateMessage(&Msg);
DispatchMessageW(&Msg); DispatchMessageW(&Msg);
} }*/
while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */ if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
{ {
@ -1607,6 +1701,8 @@ GuiCleanupConsole(PCONSOLE Console)
Console->TermIFace.Data = NULL; Console->TermIFace.Data = NULL;
DeleteCriticalSection(&GuiData->Lock); DeleteCriticalSection(&GuiData->Lock);
RtlFreeHeap(ConSrvHeap, 0, GuiData); RtlFreeHeap(ConSrvHeap, 0, GuiData);
DPRINT1("Quit GuiCleanupConsole\n");
} }
static VOID WINAPI static VOID WINAPI
@ -1835,7 +1931,8 @@ static VOID WINAPI
GuiChangeTitle(PCONSOLE Console) GuiChangeTitle(PCONSOLE Console)
{ {
PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; 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 static BOOL WINAPI
@ -1916,6 +2013,7 @@ GuiInitConsole(PCONSOLE Console,
{ {
PGUI_CONSOLE_DATA GuiData; PGUI_CONSOLE_DATA GuiData;
GUI_CONSOLE_INFO TermInfo; GUI_CONSOLE_INFO TermInfo;
SIZE_T Length = 0;
if (Console == NULL || ConsoleInfo == NULL) if (Console == NULL || ConsoleInfo == NULL)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -1984,7 +2082,9 @@ GuiInitConsole(PCONSOLE Console,
* Set up the GUI data * Set up the GUI data
*/ */
Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE); wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
GuiData->GuiInfo.FaceName[Length] = L'\0';
GuiData->GuiInfo.FontFamily = TermInfo.FontFamily; GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
GuiData->GuiInfo.FontSize = TermInfo.FontSize; GuiData->GuiInfo.FontSize = TermInfo.FontSize;
GuiData->GuiInfo.FontWeight = TermInfo.FontWeight; GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
@ -2034,6 +2134,7 @@ GuiInitConsole(PCONSOLE Console,
/* Wait until initialization has finished */ /* Wait until initialization has finished */
WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE); WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
DPRINT1("OK we created the console window\n");
CloseHandle(GuiData->hGuiInitEvent); CloseHandle(GuiData->hGuiInitEvent);
GuiData->hGuiInitEvent = NULL; GuiData->hGuiInitEvent = NULL;

View file

@ -86,7 +86,9 @@ GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
if (!wcscmp(szValueName, L"FaceName")) if (!wcscmp(szValueName, L"FaceName"))
{ {
SIZE_T Length = min(wcslen(szValue) + 1, LF_FACESIZE); // wcsnlen
wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE); wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE);
TermInfo->FaceName[Length] = L'\0';
RetVal = TRUE; RetVal = TRUE;
} }
else if (!wcscmp(szValueName, L"FontFamily")) else if (!wcscmp(szValueName, L"FontFamily"))
@ -150,7 +152,7 @@ do {
return FALSE; 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"FontFamily", REG_DWORD, sizeof(DWORD), &TermInfo->FontFamily, FF_DONTCARE);
SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0); SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0);
SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE); SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE);
@ -269,6 +271,12 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
pSharedInfo->hConsoleWindow = GuiData->hWindow; pSharedInfo->hConsoleWindow = GuiData->hWindow;
pSharedInfo->ShowDefaultParams = Defaults; pSharedInfo->ShowDefaultParams = Defaults;
/*
* We fill-in the fields only if we display
* our properties, not the default ones.
*/
if (!Defaults)
{
/* Console information */ /* Console information */
pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize; pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers; pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
@ -289,8 +297,11 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
/* GUI Information */ /* GUI Information */
pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO); pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
GuiInfo = pSharedInfo->TerminalInfo.TermInfo = (PGUI_CONSOLE_INFO)(pSharedInfo + 1); 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); wcsncpy(GuiInfo->FaceName, GuiData->GuiInfo.FaceName, LF_FACESIZE);
GuiInfo->FontSize = (DWORD)GuiData->GuiInfo.FontSize; GuiInfo->FaceName[Length] = L'\0';
GuiInfo->FontFamily = GuiData->GuiInfo.FontFamily;
GuiInfo->FontSize = GuiData->GuiInfo.FontSize;
GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight; GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts; GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
/// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition; /// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
@ -306,6 +317,13 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1, Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
Console->OriginalTitle.Length / sizeof(WCHAR)); Console->OriginalTitle.Length / sizeof(WCHAR));
wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length); wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
}
else
{
Length = 0;
}
/* Null-terminate the title */
pSharedInfo->ci.ConsoleTitle[Length] = L'\0'; pSharedInfo->ci.ConsoleTitle[Length] = L'\0';
@ -326,29 +344,46 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status); DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status);
NtClose(hSection); goto Quit;
return;
} }
/* Start the properties dialog */ /* Start the properties dialog */
if (ProcessData->PropDispatcher) if (ProcessData->PropDispatcher)
{ {
HANDLE Thread; _SEH2_TRY
{
HANDLE Thread = NULL;
_SEH2_TRY
{
Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
ProcessData->PropDispatcher, ProcessData->PropDispatcher,
(PVOID)hClientSection, 0, NULL); (PVOID)hClientSection, 0, NULL);
if (NULL == Thread) if (NULL == Thread)
{ {
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError()); DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
return;
} }
else
DPRINT1("We succeeded at creating ProcessData->PropDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); {
DPRINT("ProcessData->PropDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
/// WaitForSingleObject(Thread, INFINITE); /// WaitForSingleObject(Thread, INFINITE);
}
}
_SEH2_FINALLY
{
CloseHandle(Thread); 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 */ /* We have finished, close the section handle */
NtClose(hSection); NtClose(hSection);
return; return;
@ -369,8 +404,6 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
PTERMINAL_INFO TermInfo = NULL; PTERMINAL_INFO TermInfo = NULL;
PGUI_CONSOLE_INFO GuiInfo = NULL; PGUI_CONSOLE_INFO GuiInfo = NULL;
/// LOCK /// EnterCriticalSection(&Console->Lock);
/* Get the console leader process, our client */ /* Get the console leader process, our client */
ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink, ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA, CONSOLE_PROCESS_DATA,
@ -406,6 +439,8 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
return Status; return Status;
} }
_SEH2_TRY
{
/* Check that the section is well-sized */ /* Check that the section is well-sized */
if ( (ViewSize < sizeof(CONSOLE_PROPS)) || if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
(pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) || (pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
@ -413,19 +448,27 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
{ {
DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n"); DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
Status = STATUS_INVALID_VIEW_SIZE; Status = STATUS_INVALID_VIEW_SIZE;
goto Quit; _SEH2_YIELD(goto Quit);
} }
// TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow // TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
/* Set the console informations */ /* Retrieve terminal informations */
ConInfo = &pConInfo->ci; ConInfo = &pConInfo->ci;
ConSrvApplyUserSettings(Console, ConInfo);
/* Set the terminal informations - De-offsetization of the pointer */
TermInfo = &pConInfo->TerminalInfo; TermInfo = &pConInfo->TerminalInfo;
GuiInfo = TermInfo->TermInfo = (PVOID)((ULONG_PTR)pConInfo + (ULONG_PTR)TermInfo->TermInfo); 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)); // memcpy(&GuiData->GuiInfo, GuiInfo, sizeof(GUI_CONSOLE_INFO));
/* Move the window to the user's values */ /* Move the window to the user's values */
@ -434,12 +477,11 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
GuiConsoleMoveWindow(GuiData); GuiConsoleMoveWindow(GuiData);
InvalidateRect(GuiData->hWindow, NULL, TRUE); InvalidateRect(GuiData->hWindow, NULL, TRUE);
}
/* /*
* Save settings if needed * Save settings if needed
*/ */
// FIXME: Do it in the console properties applet ?? // FIXME: Do it in the console properties applet ??
if (SaveSettings) if (SaveSettings)
{ {
@ -449,8 +491,13 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
} }
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
}
/// LOCK /// LeaveCriticalSection(&Console->Lock); _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
DPRINT1("GuiApplyUserSettings - Caught an exception, Status = %08X\n", Status);
}
_SEH2_END;
Quit: Quit:
/* Finally, close the section and return */ /* Finally, close the section and return */

View file

@ -10,8 +10,9 @@
#include "consrv.h" #include "consrv.h"
#include "conio.h" #include "conio.h"
#include "console.h"
//#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
@ -22,7 +23,7 @@ AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
{ {
Object_t *Object = Entry->Object; 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_READ) Object->AccessRead += Change;
if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change; if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
@ -236,8 +237,6 @@ Quit:
static VOID static VOID
ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData) ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
{ {
DPRINT1("ConSrvFreeHandlesTable\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock); RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (ProcessData->HandleTable != NULL) if (ProcessData->HandleTable != NULL)
@ -267,12 +266,13 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
BOOL Inheritable, BOOL Inheritable,
DWORD ShareMode) DWORD ShareMode)
{ {
#define IO_HANDLES_INCREMENT 2*3 #define IO_HANDLES_INCREMENT 2 * 3
ULONG i; ULONG i;
PCONSOLE_IO_HANDLE Block; 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++) for (i = 0; i < ProcessData->HandleTableSize; i++)
{ {
@ -289,7 +289,7 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE)); IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
if (Block == NULL) if (Block == NULL)
{ {
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
RtlCopyMemory(Block, RtlCopyMemory(Block,
@ -307,7 +307,7 @@ ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]); ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
*Handle = ULongToHandle((i << 2) | 0x3); *Handle = ULongToHandle((i << 2) | 0x3);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -329,11 +329,9 @@ ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]); ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -376,16 +374,24 @@ ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
_InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 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 */ /* Return the objects to the caller */
*Object = ObjectEntry; *Object = ObjectEntry;
if (Entry) *Entry = HandleEntry; if (Entry) *Entry = HandleEntry;
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
}
else
{
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_INVALID_HANDLE;
}
} }
VOID VOID
@ -465,6 +471,13 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
{ {
NTSTATUS Status = STATUS_SUCCESS; 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 */ /* Inherit the console */
ProcessData->Console = Console; ProcessData->Console = Console;
@ -479,7 +492,7 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
{ {
DPRINT1("Failed to initialize the handles table\n"); DPRINT1("Failed to initialize the handles table\n");
ProcessData->Console = NULL; ProcessData->Console = NULL;
return Status; goto Quit;
} }
} }
@ -494,7 +507,7 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
DPRINT1("NtDuplicateObject() failed: %lu\n", Status); DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table. ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
ProcessData->Console = NULL; ProcessData->Console = NULL;
return Status; goto Quit;
} }
/* Insert the process into the processes list of the console */ /* 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 */ /* Update the internal info of the terminal */
ConioRefreshInternalInfo(ProcessData->Console); ConioRefreshInternalInfo(ProcessData->Console);
return STATUS_SUCCESS; Status = STATUS_SUCCESS;
Quit:
/* Unlock the console and return */
LeaveCriticalSection(&Console->Lock);
return Status;
} }
VOID VOID
FASTCALL FASTCALL
ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
{ {
PCONSOLE Console; PCONSOLE Console = ProcessData->Console;
DPRINT1("ConSrvRemoveConsole\n"); DPRINT1("ConSrvRemoveConsole\n");
/* Close all console handles and free the handle table memory */ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Validate and lock the console */
if (ConSrvValidateConsole(Console, CONSOLE_RUNNING, TRUE))
{
DPRINT1("ConSrvRemoveConsole - Locking OK\n");
/* Close all console handles and free the handles table */
ConSrvFreeHandlesTable(ProcessData); ConSrvFreeHandlesTable(ProcessData);
/* Detach process from console */ /* Detach the process from the console */
Console = ProcessData->Console;
if (Console != NULL)
{
DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
ProcessData->Console = NULL; ProcessData->Console = NULL;
EnterCriticalSection(&Console->Lock);
DPRINT1("ConSrvRemoveConsole - Locking OK\n");
/* Remove ourselves from the console's list of processes */ /* Remove ourselves from the console's list of processes */
RemoveEntryList(&ProcessData->ConsoleLink); RemoveEntryList(&ProcessData->ConsoleLink);
@ -537,10 +555,105 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
ConioRefreshInternalInfo(Console); ConioRefreshInternalInfo(Console);
/* Release the console */ /* Release the console */
DPRINT1("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
ConSrvReleaseConsole(Console, TRUE); ConSrvReleaseConsole(Console, TRUE);
//CloseHandle(ProcessData->ConsoleEvent); //CloseHandle(ProcessData->ConsoleEvent);
//ProcessData->ConsoleEvent = NULL; //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 NTSTATUS
@ -549,37 +662,53 @@ ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
PCONSOLE* Console, PCONSOLE* Console,
BOOL LockConsole) BOOL LockConsole)
{ {
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE ProcessConsole; PCONSOLE ProcessConsole;
RtlEnterCriticalSection(&ProcessData->HandleTableLock); RtlEnterCriticalSection(&ProcessData->HandleTableLock);
ProcessConsole = ProcessData->Console; ProcessConsole = ProcessData->Console;
if (!ProcessConsole) if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
{
InterlockedIncrement(&ProcessConsole->ReferenceCount);
*Console = ProcessConsole;
}
else
{ {
*Console = NULL; *Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); Status = STATUS_INVALID_HANDLE;
return STATUS_INVALID_HANDLE;
} }
InterlockedIncrement(&ProcessConsole->ReferenceCount);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
*Console = ProcessConsole;
return STATUS_SUCCESS;
} }
VOID FASTCALL VOID FASTCALL
ConSrvReleaseConsole(PCONSOLE Console, ConSrvReleaseConsole(PCONSOLE Console,
BOOL IsConsoleLocked) BOOL WasConsoleLocked)
{ {
if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock); LONG RefCount = 0;
/* Decrement reference count */ if (!Console) return;
if (_InterlockedDecrement(&Console->ReferenceCount) == 0) // if (Console->ReferenceCount == 0) return; // This shouldn't happen
ConSrvDeleteConsole(Console); 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 NTSTATUS
@ -745,8 +874,6 @@ ConSrvDisconnect(PCSR_PROCESS Process)
* This function is called whenever a new process (GUI or CUI) is destroyed. * This function is called whenever a new process (GUI or CUI) is destroyed.
**************************************************************************/ **************************************************************************/
DPRINT1("ConSrvDisconnect\n");
if ( ProcessData->Console != NULL || if ( ProcessData->Console != NULL ||
ProcessData->HandleTable != NULL ) ProcessData->HandleTable != NULL )
{ {
@ -828,6 +955,7 @@ CSR_API(SrvDuplicateHandle)
} }
} }
/* Insert the new handle inside the process handles table */
ApiMessage->Status = ConSrvInsertObject(ProcessData, ApiMessage->Status = ConSrvInsertObject(ProcessData,
&DuplicateHandleRequest->ConsoleHandle, // Use the new handle value! &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
Entry->Object, Entry->Object,

View file

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