mirror of
https://github.com/reactos/reactos.git
synced 2024-10-18 23:18:56 +00:00
7851c1a1c2
- Start to implement NtUserConsoleControl to allow the console server define Console Window Class atom. - In UserInitialize, initialize the current thread by a call to UserCreateThreadInfo. - In UserCreateThreadInfo, set the TIF_CSRSSTHREAD flag for threads created by CSRSS. - In NtUserQueryWindow, when querying the process/thread ID associated to a given window, check whether the window was created by CSRSS and if so, if this is a Console window, get the process/thread ID of the associated console process (console leader process), instead of the CID of CSRSS. [CONSRV] - Introduce the concept of console leader process (to be used as the process owning the console window). - Introduce extra console window information to store the PID and TID of the console leader process via new internal flags to be used by GetWindowLong. - Effectively set the console window console leader CID at its creation. - Improve CsrInitConsole to set a console leader process to the console being created. This fixes http://jira.reactos.org/browse/CORE-122 in this branch. [CONSRV-WIN32K] Fix various code misspellings. svn path=/branches/ros-csrss/; revision=58107
940 lines
30 KiB
C
940 lines
30 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Console Server DLL
|
|
* FILE: win32ss/user/consrv/console.c
|
|
* PURPOSE: Console I/O functions
|
|
* PROGRAMMERS:
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "consrv.h"
|
|
#include "guiconsole.h"
|
|
#include "tuiconsole.h"
|
|
|
|
//#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
BOOL FASTCALL
|
|
DtbgIsDesktopVisible(VOID)
|
|
{
|
|
HWND VisibleDesktopWindow = GetDesktopWindow(); // DESKTOPWNDPROC
|
|
|
|
if (VisibleDesktopWindow != NULL &&
|
|
!IsWindowVisible(VisibleDesktopWindow))
|
|
{
|
|
VisibleDesktopWindow = NULL;
|
|
}
|
|
|
|
return VisibleDesktopWindow != NULL;
|
|
}
|
|
|
|
NTSTATUS FASTCALL
|
|
ConioConsoleFromProcessData(PCONSOLE_PROCESS_DATA ProcessData,
|
|
PCSRSS_CONSOLE *Console)
|
|
{
|
|
PCSRSS_CONSOLE ProcessConsole;
|
|
|
|
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
|
|
ProcessConsole = ProcessData->Console;
|
|
|
|
if (!ProcessConsole)
|
|
{
|
|
*Console = NULL;
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
InterlockedIncrement(&ProcessConsole->ReferenceCount);
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
EnterCriticalSection(&(ProcessConsole->Lock));
|
|
*Console = ProcessConsole;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
ConioConsoleCtrlEventTimeout(DWORD Event,
|
|
PCONSOLE_PROCESS_DATA ProcessData,
|
|
DWORD Timeout)
|
|
{
|
|
HANDLE Thread;
|
|
|
|
DPRINT("ConioConsoleCtrlEvent 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)
|
|
{
|
|
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
|
|
return;
|
|
}
|
|
|
|
DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
|
|
WaitForSingleObject(Thread, Timeout);
|
|
CloseHandle(Thread);
|
|
}
|
|
}
|
|
|
|
VOID FASTCALL
|
|
ConioConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
|
|
{
|
|
ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
|
|
}
|
|
|
|
NTSTATUS WINAPI
|
|
CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd, PCSR_PROCESS ConsoleLeaderProcess)
|
|
{
|
|
NTSTATUS Status;
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
PCSRSS_CONSOLE Console;
|
|
PCSRSS_SCREEN_BUFFER NewBuffer;
|
|
BOOL GuiMode;
|
|
WCHAR Title[255];
|
|
|
|
if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
*NewConsole = NULL;
|
|
|
|
/* Allocate a console structure */
|
|
Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
|
|
if (NULL == Console)
|
|
{
|
|
DPRINT1("Not enough memory for console creation.\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Initialize the console */
|
|
Console->Title.MaximumLength = Console->Title.Length = 0;
|
|
Console->Title.Buffer = NULL;
|
|
|
|
if (LoadStringW(ConSrvDllInstance, IDS_COMMAND_PROMPT, Title, sizeof(Title) / sizeof(Title[0])))
|
|
{
|
|
RtlCreateUnicodeString(&Console->Title, Title);
|
|
}
|
|
else
|
|
{
|
|
RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
|
|
}
|
|
|
|
Console->ReferenceCount = 0;
|
|
Console->LineBuffer = NULL;
|
|
Console->Header.Type = CONIO_CONSOLE_MAGIC;
|
|
Console->Header.Console = Console;
|
|
Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
|
|
Console->ConsoleLeaderCID = ConsoleLeaderProcess->ClientId;
|
|
InitializeListHead(&Console->ProcessList);
|
|
InitializeListHead(&Console->BufferList);
|
|
Console->ActiveBuffer = NULL;
|
|
InitializeListHead(&Console->ReadWaitQueue);
|
|
InitializeListHead(&Console->WriteWaitQueue);
|
|
InitializeListHead(&Console->InputEvents);
|
|
InitializeListHead(&Console->HistoryBuffers);
|
|
Console->CodePage = GetOEMCP();
|
|
Console->OutputCodePage = GetOEMCP();
|
|
|
|
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
SecurityAttributes.lpSecurityDescriptor = NULL;
|
|
SecurityAttributes.bInheritHandle = TRUE;
|
|
|
|
Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
|
|
if (NULL == Console->ActiveEvent)
|
|
{
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
HeapFree(ConSrvHeap, 0, Console);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
Console->PrivateData = NULL;
|
|
InitializeCriticalSection(&Console->Lock);
|
|
|
|
GuiMode = DtbgIsDesktopVisible();
|
|
|
|
/* allocate console screen buffer */
|
|
NewBuffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
|
|
if (NULL == NewBuffer)
|
|
{
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
DeleteCriticalSection(&Console->Lock);
|
|
CloseHandle(Console->ActiveEvent);
|
|
HeapFree(ConSrvHeap, 0, Console);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
/* init screen buffer with defaults */
|
|
NewBuffer->CursorInfo.bVisible = TRUE;
|
|
NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
|
|
/* make console active, and insert into console list */
|
|
Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
|
|
|
|
/*
|
|
* If we are not in GUI-mode, start the text-mode console. If we fail,
|
|
* try to start the GUI-mode console (win32k will automatically switch
|
|
* to graphical mode, therefore no additional code is needed).
|
|
*/
|
|
if (!GuiMode)
|
|
{
|
|
DPRINT1("CONSRV: Opening text-mode console\n");
|
|
Status = TuiInitConsole(Console);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to open text-mode console, switching to gui-mode, Status = 0x%08lx\n", Status);
|
|
GuiMode = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to open the GUI-mode console. Two cases are possible:
|
|
* - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
|
|
* failed and we start GUI-mode console.
|
|
* - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
|
|
* succeeded BUT we failed at starting text-mode console. Then GuiMode
|
|
* was switched to TRUE in order to try to open the console in GUI-mode.
|
|
*/
|
|
if (GuiMode)
|
|
{
|
|
DPRINT1("CONSRV: Opening GUI-mode console\n");
|
|
Status = GuiInitConsole(Console, ShowCmd);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
HeapFree(ConSrvHeap,0, NewBuffer);
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
DeleteCriticalSection(&Console->Lock);
|
|
CloseHandle(Console->ActiveEvent);
|
|
DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
|
|
HeapFree(ConSrvHeap, 0, Console);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ConioCleanupConsole(Console);
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
DeleteCriticalSection(&Console->Lock);
|
|
CloseHandle(Console->ActiveEvent);
|
|
HeapFree(ConSrvHeap, 0, NewBuffer);
|
|
DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
|
|
HeapFree(ConSrvHeap, 0, Console);
|
|
return Status;
|
|
}
|
|
|
|
/* Copy buffer contents to screen */
|
|
ConioDrawConsole(Console);
|
|
|
|
*NewConsole = Console;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CSR_API(SrvOpenConsole)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PCSRSS_OPEN_CONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
|
|
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
|
|
|
DPRINT("SrvOpenConsole\n");
|
|
|
|
OpenConsoleRequest->Handle = INVALID_HANDLE_VALUE;
|
|
|
|
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
DPRINT1("SrvOpenConsole - Checkpoint 1\n");
|
|
DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
|
|
|
|
if (ProcessData->Console)
|
|
{
|
|
DWORD DesiredAccess = OpenConsoleRequest->Access;
|
|
DWORD ShareMode = OpenConsoleRequest->ShareMode;
|
|
|
|
PCSRSS_CONSOLE Console = ProcessData->Console;
|
|
Object_t *Object;
|
|
|
|
DPRINT1("SrvOpenConsole - Checkpoint 2\n");
|
|
EnterCriticalSection(&Console->Lock);
|
|
DPRINT1("SrvOpenConsole - Checkpoint 3\n");
|
|
|
|
if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
|
|
Object = &Console->ActiveBuffer->Header;
|
|
else // HANDLE_INPUT
|
|
Object = &Console->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 = Win32CsrInsertObject(ProcessData,
|
|
&OpenConsoleRequest->Handle,
|
|
Object,
|
|
DesiredAccess,
|
|
OpenConsoleRequest->Inheritable,
|
|
ShareMode);
|
|
}
|
|
|
|
LeaveCriticalSection(&Console->Lock);
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvAllocConsole)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PCSRSS_ALLOC_CONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
|
|
PCSR_PROCESS ConsoleLeader = CsrGetClientThread()->Process;
|
|
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(ConsoleLeader);
|
|
|
|
DPRINT("SrvAllocConsole\n");
|
|
|
|
if (ProcessData->Console != NULL)
|
|
{
|
|
DPRINT1("Process already has a console\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
DPRINT1("SrvAllocConsole - Checkpoint 1\n");
|
|
|
|
/* Initialize a new Console owned by the Console Leader Process */
|
|
Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd, ConsoleLeader);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Console initialization failed\n");
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return Status;
|
|
}
|
|
|
|
/* Insert the process into the processes list of the console */
|
|
InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
|
|
|
|
/* Return it to the caller */
|
|
AllocConsoleRequest->Console = ProcessData->Console;
|
|
|
|
/* Add a reference count because the process is tied to the console */
|
|
_InterlockedIncrement(&ProcessData->Console->ReferenceCount);
|
|
|
|
#if 0000
|
|
/*
|
|
* We've just created a new console. However when ConsoleNewProcess was
|
|
* called, we didn't know that we wanted to create a new console and
|
|
* therefore, we by default inherited the handles table from our parent
|
|
* process. It's only now that we notice that in fact we do not need
|
|
* them, because we've created a new console and thus we must use it.
|
|
*
|
|
* Therefore, free our handles table and recreate a new one.
|
|
*/
|
|
|
|
ULONG i;
|
|
|
|
/* Close all console handles and free the handle table memory */
|
|
for (i = 0; i < ProcessData->HandleTableSize; i++)
|
|
{
|
|
Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
|
|
}
|
|
ProcessData->HandleTableSize = 0;
|
|
RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
|
|
ProcessData->HandleTable = NULL;
|
|
#endif
|
|
|
|
/*
|
|
* Create a new handle table - Insert the IO handles
|
|
*/
|
|
|
|
/* Insert the Input handle */
|
|
Status = Win32CsrInsertObject(ProcessData,
|
|
&AllocConsoleRequest->InputHandle,
|
|
&ProcessData->Console->Header,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
TRUE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to insert the input handle\n");
|
|
ConioDeleteConsole(ProcessData->Console);
|
|
ProcessData->Console = NULL;
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return Status;
|
|
}
|
|
|
|
/* Insert the Output handle */
|
|
Status = Win32CsrInsertObject(ProcessData,
|
|
&AllocConsoleRequest->OutputHandle,
|
|
&ProcessData->Console->ActiveBuffer->Header,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
TRUE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to insert the output handle\n");
|
|
ConioDeleteConsole(ProcessData->Console);
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->InputHandle);
|
|
ProcessData->Console = NULL;
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return Status;
|
|
}
|
|
|
|
/* Insert the Error handle */
|
|
Status = Win32CsrInsertObject(ProcessData,
|
|
&AllocConsoleRequest->ErrorHandle,
|
|
&ProcessData->Console->ActiveBuffer->Header,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
TRUE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to insert the error handle\n");
|
|
ConioDeleteConsole(ProcessData->Console);
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->OutputHandle);
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->InputHandle);
|
|
ProcessData->Console = NULL;
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return Status;
|
|
}
|
|
|
|
/* Duplicate the Event */
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
ProcessData->Console->ActiveEvent,
|
|
ProcessData->Process->ProcessHandle,
|
|
&ProcessData->ConsoleEvent,
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
|
|
ConioDeleteConsole(ProcessData->Console);
|
|
// if (NewConsole /* || !ProcessData->bInheritHandles */)
|
|
{
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->ErrorHandle);
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->OutputHandle);
|
|
Win32CsrReleaseObject(ProcessData,
|
|
AllocConsoleRequest->InputHandle);
|
|
}
|
|
ProcessData->Console = NULL;
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return Status;
|
|
}
|
|
/* Input Wait Handle */
|
|
AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
|
|
|
|
/* Set the Ctrl Dispatcher */
|
|
ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
|
|
DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CSR_API(SrvFreeConsole)
|
|
{
|
|
DPRINT1("SrvFreeConsole\n");
|
|
Win32CsrReleaseConsole(CsrGetClientThread()->Process);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID WINAPI
|
|
ConioDeleteConsole(PCSRSS_CONSOLE Console)
|
|
{
|
|
ConsoleInput *Event;
|
|
|
|
DPRINT("ConioDeleteConsole\n");
|
|
|
|
/* Drain input event queue */
|
|
while (Console->InputEvents.Flink != &Console->InputEvents)
|
|
{
|
|
Event = (ConsoleInput *) Console->InputEvents.Flink;
|
|
Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
|
|
Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
|
|
HeapFree(ConSrvHeap, 0, Event);
|
|
}
|
|
|
|
ConioCleanupConsole(Console);
|
|
if (Console->LineBuffer)
|
|
RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
|
|
while (!IsListEmpty(&Console->HistoryBuffers))
|
|
HistoryDeleteBuffer((struct tagHISTORY_BUFFER *)Console->HistoryBuffers.Flink);
|
|
|
|
ConioDeleteScreenBuffer(Console->ActiveBuffer);
|
|
if (!IsListEmpty(&Console->BufferList))
|
|
{
|
|
DPRINT1("BUG: screen buffer list not empty\n");
|
|
}
|
|
|
|
CloseHandle(Console->ActiveEvent);
|
|
if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
|
|
DeleteCriticalSection(&Console->Lock);
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
IntDeleteAllAliases(Console->Aliases);
|
|
HeapFree(ConSrvHeap, 0, Console);
|
|
}
|
|
|
|
VOID WINAPI
|
|
CsrInitConsoleSupport(VOID)
|
|
{
|
|
DPRINT("CSR: CsrInitConsoleSupport()\n");
|
|
|
|
/* Should call LoadKeyboardLayout */
|
|
}
|
|
|
|
VOID FASTCALL
|
|
ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
|
|
{
|
|
Console->PauseFlags |= Flags;
|
|
if (!Console->UnpauseEvent)
|
|
Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
}
|
|
|
|
VOID FASTCALL
|
|
ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
|
|
{
|
|
Console->PauseFlags &= ~Flags;
|
|
|
|
// if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
|
|
if (Console->PauseFlags == 0 && Console->UnpauseEvent)
|
|
{
|
|
SetEvent(Console->UnpauseEvent);
|
|
CloseHandle(Console->UnpauseEvent);
|
|
Console->UnpauseEvent = NULL;
|
|
|
|
CsrNotifyWait(&Console->WriteWaitQueue,
|
|
WaitAll,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
CSR_API(SrvSetConsoleMode)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
PCSRSS_SCREEN_BUFFER Buff;
|
|
|
|
DPRINT("SrvSetConsoleMode\n");
|
|
|
|
Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
|
|
ConsoleModeRequest->ConsoleHandle,
|
|
(Object_t **) &Console, GENERIC_WRITE, 0);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
Buff = (PCSRSS_SCREEN_BUFFER)Console;
|
|
|
|
if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
|
|
{
|
|
Console->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
|
|
}
|
|
else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
|
|
{
|
|
Buff->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
Win32CsrUnlockObject((Object_t *)Console);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleMode)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
PCSRSS_SCREEN_BUFFER Buff;
|
|
|
|
DPRINT("SrvGetConsoleMode\n");
|
|
|
|
Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
|
|
ConsoleModeRequest->ConsoleHandle,
|
|
(Object_t **) &Console, GENERIC_READ, 0);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Buff = (PCSRSS_SCREEN_BUFFER) Console;
|
|
|
|
if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
|
|
{
|
|
ConsoleModeRequest->ConsoleMode = Console->Mode;
|
|
}
|
|
else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
|
|
{
|
|
ConsoleModeRequest->ConsoleMode = Buff->Mode;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
Win32CsrUnlockObject((Object_t *)Console);
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvSetConsoleTitle)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
|
|
// PCSR_PROCESS Process = CsrGetClientThread()->Process;
|
|
PCSRSS_CONSOLE Console;
|
|
PWCHAR Buffer;
|
|
|
|
DPRINT("SrvSetConsoleTitle\n");
|
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
(PVOID)&TitleRequest->Title,
|
|
TitleRequest->Length,
|
|
sizeof(BYTE)))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length);
|
|
if (Buffer)
|
|
{
|
|
/* Copy title to console */
|
|
RtlFreeUnicodeString(&Console->Title);
|
|
Console->Title.Buffer = Buffer;
|
|
Console->Title.Length = Console->Title.MaximumLength = TitleRequest->Length;
|
|
memcpy(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length);
|
|
|
|
if (!ConioChangeTitle(Console))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
ConioUnlockConsole(Console);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleTitle)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
|
|
// PCSR_PROCESS Process = CsrGetClientThread()->Process;
|
|
PCSRSS_CONSOLE Console;
|
|
DWORD Length;
|
|
|
|
DPRINT("SrvGetConsoleTitle\n");
|
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
(PVOID)&TitleRequest->Title,
|
|
TitleRequest->Length,
|
|
sizeof(BYTE)))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Can't get console\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Copy title of the console to the user title buffer */
|
|
if (TitleRequest->Length >= sizeof(WCHAR))
|
|
{
|
|
Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
|
|
memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
|
|
TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
|
|
}
|
|
|
|
TitleRequest->Length = Console->Title.Length;
|
|
|
|
ConioUnlockConsole(Console);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* HardwareStateProperty
|
|
*
|
|
* DESCRIPTION
|
|
* Set/Get the value of the HardwareState and switch
|
|
* between direct video buffer ouput and GDI windowed
|
|
* output.
|
|
* ARGUMENTS
|
|
* Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
|
|
* object. We use the same object to Request.
|
|
* NOTE
|
|
* ConsoleHwState has the correct size to be compatible
|
|
* with NT's, but values are not.
|
|
*/
|
|
static NTSTATUS FASTCALL
|
|
SetConsoleHardwareState(PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
|
|
{
|
|
DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
|
|
|
|
if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
|
|
||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
|
|
{
|
|
if (Console->HardwareState != ConsoleHwState)
|
|
{
|
|
/* TODO: implement switching from full screen to windowed mode */
|
|
/* TODO: or back; now simply store the hardware state */
|
|
Console->HardwareState = ConsoleHwState;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleHardwareState)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvGetConsoleHardwareState\n");
|
|
|
|
Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
|
|
ConsoleHardwareStateRequest->ConsoleHandle,
|
|
&Console,
|
|
GENERIC_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
|
|
return Status;
|
|
}
|
|
|
|
ConsoleHardwareStateRequest->State = Console->HardwareState;
|
|
|
|
ConioUnlockConsole(Console);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvSetConsoleHardwareState)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvSetConsoleHardwareState\n");
|
|
|
|
Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
|
|
ConsoleHardwareStateRequest->ConsoleHandle,
|
|
&Console,
|
|
GENERIC_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
|
|
return Status;
|
|
}
|
|
|
|
DPRINT("Setting console hardware state.\n");
|
|
Status = SetConsoleHardwareState(Console, ConsoleHardwareStateRequest->State);
|
|
|
|
ConioUnlockConsole(Console);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleWindow)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_GET_CONSOLE_WINDOW GetConsoleWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleWindowRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvGetConsoleWindow\n");
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
GetConsoleWindowRequest->WindowHandle = Console->hWindow;
|
|
ConioUnlockConsole(Console);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CSR_API(SrvSetConsoleIcon)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_SET_CONSOLE_ICON SetConsoleIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleIconRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvSetConsoleIcon\n");
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
Status = (ConioChangeIcon(Console, SetConsoleIconRequest->WindowIcon)
|
|
? STATUS_SUCCESS
|
|
: STATUS_UNSUCCESSFUL);
|
|
|
|
ConioUnlockConsole(Console);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleCP)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
|
|
ConsoleCPRequest->InputCP ? "Input" : "Output");
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
|
|
: Console->OutputCodePage);
|
|
ConioUnlockConsole(Console);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CSR_API(SrvSetConsoleCP)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
|
|
ConsoleCPRequest->InputCP ? "Input" : "Output");
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
if (IsValidCodePage(ConsoleCPRequest->CodePage))
|
|
{
|
|
if (ConsoleCPRequest->InputCP)
|
|
Console->CodePage = ConsoleCPRequest->CodePage;
|
|
else
|
|
Console->OutputCodePage = ConsoleCPRequest->CodePage;
|
|
|
|
ConioUnlockConsole(Console);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ConioUnlockConsole(Console);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleProcessList)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_GET_PROCESS_LIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
|
|
PDWORD Buffer;
|
|
// PCSR_PROCESS Process = CsrGetClientThread()->Process;
|
|
PCSRSS_CONSOLE Console;
|
|
PCONSOLE_PROCESS_DATA current;
|
|
PLIST_ENTRY current_entry;
|
|
ULONG nItems = 0;
|
|
|
|
DPRINT("SrvGetConsoleProcessList\n");
|
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
(PVOID)&GetProcessListRequest->pProcessIds,
|
|
GetProcessListRequest->nMaxIds,
|
|
sizeof(DWORD)))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Buffer = GetProcessListRequest->pProcessIds;
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
for (current_entry = Console->ProcessList.Flink;
|
|
current_entry != &Console->ProcessList;
|
|
current_entry = current_entry->Flink)
|
|
{
|
|
current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
|
|
if (++nItems <= GetProcessListRequest->nMaxIds)
|
|
{
|
|
*Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
|
|
}
|
|
}
|
|
|
|
ConioUnlockConsole(Console);
|
|
|
|
GetProcessListRequest->nProcessIdsTotal = nItems;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CSR_API(SrvGenerateConsoleCtrlEvent)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_GENERATE_CTRL_EVENT GenerateCtrlEvent = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEvent;
|
|
PCSRSS_CONSOLE Console;
|
|
PCONSOLE_PROCESS_DATA current;
|
|
PLIST_ENTRY current_entry;
|
|
DWORD Group;
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
Group = GenerateCtrlEvent->ProcessGroup;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
for (current_entry = Console->ProcessList.Flink;
|
|
current_entry != &Console->ProcessList;
|
|
current_entry = current_entry->Flink)
|
|
{
|
|
current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
|
|
if (Group == 0 || current->Process->ProcessGroupId == Group)
|
|
{
|
|
ConioConsoleCtrlEvent(GenerateCtrlEvent->Event, current);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
ConioUnlockConsole(Console);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(SrvGetConsoleSelectionInfo)
|
|
{
|
|
NTSTATUS Status;
|
|
PCSRSS_GET_CONSOLE_SELECTION_INFO GetConsoleSelectionInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleSelectionInfo;
|
|
PCSRSS_CONSOLE Console;
|
|
|
|
Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
memset(&GetConsoleSelectionInfo->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
|
|
if (Console->Selection.dwFlags != 0)
|
|
GetConsoleSelectionInfo->Info = Console->Selection;
|
|
ConioUnlockConsole(Console);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|