reactos/win32ss/user/winsrv/consrv/coninput.c

603 lines
21 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/coninput.c
* PURPOSE: Console Input functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
#define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
(Access), (LockConsole), INPUT_BUFFER)
#define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
(Access), (LockConsole), INPUT_BUFFER)
#define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
typedef struct _GET_INPUT_INFO
{
PCSR_THREAD CallingThread; // The thread which called the input API.
PVOID HandleEntry; // The handle data associated with the wait thread.
PCONSOLE_INPUT_BUFFER InputBuffer; // The input buffer corresponding to the handle.
} GET_INPUT_INFO, *PGET_INPUT_INFO;
/* PRIVATE FUNCTIONS **********************************************************/
static NTSTATUS
WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL,
IN BOOLEAN CreateWaitBlock OPTIONAL)
{
if (CreateWaitBlock)
{
PGET_INPUT_INFO CapturedInputInfo;
CapturedInputInfo = ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO));
if (!CapturedInputInfo) return STATUS_NO_MEMORY;
RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
if (!CsrCreateWait(&InputInfo->InputBuffer->Header.Console->ReadWaitQueue,
WaitFunction,
InputInfo->CallingThread,
ApiMessage,
CapturedInputInfo))
{
ConsoleFreeHeap(CapturedInputInfo);
return STATUS_NO_MEMORY;
}
}
/* Wait for input */
return STATUS_PENDING;
}
static NTSTATUS
ReadChars(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOLEAN CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
NTAPI
ReadCharsThread(IN PLIST_ENTRY WaitList,
IN PCSR_THREAD WaitThread,
IN PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags)
{
NTSTATUS Status;
PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
PVOID InputHandle = WaitArgument2;
DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
/*
* If we are notified of the process termination via a call
* to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
* CsrDestroyThread, just return.
*/
if (WaitFlags & CsrProcessTerminating)
{
Status = STATUS_THREAD_IS_TERMINATING;
goto Quit;
}
/*
* Somebody is closing a handle to this input buffer,
* by calling ConSrvCloseHandleEntry.
* See whether we are linked to that handle (ie. we
* are a waiter for this handle), and if so, return.
* Otherwise, ignore the call and continue waiting.
*/
if (InputHandle != NULL)
{
Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
: STATUS_PENDING);
goto Quit;
}
/*
* If we go there, that means we are notified for some new input.
* The console is therefore already locked.
*/
Status = ReadChars(InputInfo, WaitApiMessage, FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
ConsoleFreeHeap(InputInfo);
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
NTSTATUS NTAPI
ConDrvReadConsole(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
/**/IN PUNICODE_STRING ExeName /**/OPTIONAL/**/,/**/
IN BOOLEAN Unicode,
OUT PVOID Buffer,
IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
IN ULONG NumCharsToRead,
OUT PULONG NumCharsRead OPTIONAL);
static NTSTATUS
ReadChars(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOLEAN CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
CONSOLE_READCONSOLE_CONTROL ReadControl;
UNICODE_STRING ExeName;
PVOID Buffer;
ULONG NrCharactersRead = 0;
ULONG CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
/* Compute the executable name, if needed */
if (ReadConsoleRequest->InitialNumBytes == 0 &&
ReadConsoleRequest->ExeLength <= sizeof(ReadConsoleRequest->StaticBuffer))
{
ExeName.Length = ExeName.MaximumLength = ReadConsoleRequest->ExeLength;
ExeName.Buffer = (PWCHAR)ReadConsoleRequest->StaticBuffer;
}
else
{
ExeName.Length = ExeName.MaximumLength = 0;
ExeName.Buffer = NULL;
}
/* Build the ReadControl structure */
ReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
ReadControl.nInitialChars = ReadConsoleRequest->InitialNumBytes / CharSize;
ReadControl.dwCtrlWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
ReadControl.dwControlKeyState = ReadConsoleRequest->ControlKeyState;
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
Buffer = ReadConsoleRequest->StaticBuffer;
}
else
{
Buffer = ReadConsoleRequest->Buffer;
}
DPRINT1("Calling ConDrvReadConsole(%wZ)\n", &ExeName);
Status = ConDrvReadConsole(InputBuffer->Header.Console,
InputBuffer,
&ExeName,
ReadConsoleRequest->Unicode,
Buffer,
&ReadControl,
ReadConsoleRequest->NumBytes / CharSize, // NrCharactersToRead
&NrCharactersRead);
DPRINT1("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
NrCharactersRead, Status);
// ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
if (Status == STATUS_PENDING)
{
/* We haven't completed a read, so start a wait */
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadCharsThread,
CreateWaitBlock);
}
else
{
/*
* We read all what we wanted. Set the number of bytes read and
* return the error code we were given.
*/
ReadConsoleRequest->NumBytes = NrCharactersRead * CharSize;
ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
return Status;
// return STATUS_SUCCESS;
}
}
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOLEAN CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
NTAPI
ReadInputBufferThread(IN PLIST_ENTRY WaitList,
IN PCSR_THREAD WaitThread,
IN PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags)
{
NTSTATUS Status;
PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
PVOID InputHandle = WaitArgument2;
DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
/*
* If we are notified of the process termination via a call
* to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
* CsrDestroyThread, just return.
*/
if (WaitFlags & CsrProcessTerminating)
{
Status = STATUS_THREAD_IS_TERMINATING;
goto Quit;
}
/*
* Somebody is closing a handle to this input buffer,
* by calling ConSrvCloseHandleEntry.
* See whether we are linked to that handle (ie. we
* are a waiter for this handle), and if so, return.
* Otherwise, ignore the call and continue waiting.
*/
if (InputHandle != NULL)
{
Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
: STATUS_PENDING);
goto Quit;
}
/*
* If we go there, that means we are notified for some new input.
* The console is therefore already locked.
*/
Status = ReadInputBuffer(InputInfo, WaitApiMessage, FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
ConsoleFreeHeap(InputInfo);
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
NTSTATUS NTAPI
ConDrvGetConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN KeepEvents,
IN BOOLEAN WaitForMoreEvents,
IN BOOLEAN Unicode,
OUT PINPUT_RECORD InputRecord,
IN ULONG NumEventsToRead,
OUT PULONG NumEventsRead OPTIONAL);
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOLEAN CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
ULONG NumEventsRead;
PINPUT_RECORD InputRecord;
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than five
* input records are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
InputRecord = GetInputRequest->RecordStaticBuffer;
}
else
{
InputRecord = GetInputRequest->RecordBufPtr;
}
NumEventsRead = 0;
Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
InputBuffer,
(GetInputRequest->Flags & CONSOLE_READ_KEEPEVENT) != 0,
(GetInputRequest->Flags & CONSOLE_READ_CONTINUE ) == 0,
GetInputRequest->Unicode,
InputRecord,
GetInputRequest->NumRecords,
&NumEventsRead);
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
if (Status == STATUS_PENDING)
{
/* We haven't completed a read, so start a wait */
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadInputBufferThread,
CreateWaitBlock);
}
else
{
/*
* We read all what we wanted. Set the number of events read and
* return the error code we were given.
*/
GetInputRequest->NumRecords = NumEventsRead;
return Status;
// return STATUS_SUCCESS;
}
}
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvReadConsole)
{
NTSTATUS Status;
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PVOID HandleEntry;
PCONSOLE_INPUT_BUFFER InputBuffer;
GET_INPUT_INFO InputInfo;
DPRINT("SrvReadConsole\n");
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than eighty
* bytes are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadConsoleRequest->Buffer,
ReadConsoleRequest->CaptureBufferSize,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
}
if (ReadConsoleRequest->InitialNumBytes > ReadConsoleRequest->NumBytes)
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
Status = ReadChars(&InputInfo, ApiMessage, TRUE);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
CSR_API(SrvGetConsoleInput)
{
NTSTATUS Status;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PVOID HandleEntry;
PCONSOLE_INPUT_BUFFER InputBuffer;
GET_INPUT_INFO InputInfo;
DPRINT("SrvGetConsoleInput\n");
if (GetInputRequest->Flags & ~(CONSOLE_READ_KEEPEVENT | CONSOLE_READ_CONTINUE))
return STATUS_INVALID_PARAMETER;
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than five
* input records are read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetInputRequest->RecordBufPtr,
GetInputRequest->NumRecords,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
}
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
Status = ReadInputBuffer(&InputInfo, ApiMessage, TRUE);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN Unicode,
IN BOOLEAN AppendToEnd,
IN PINPUT_RECORD InputRecord,
IN ULONG NumEventsToWrite,
OUT PULONG NumEventsWritten OPTIONAL);
CSR_API(SrvWriteConsoleInput)
{
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
NTSTATUS Status;
PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
ULONG NumEventsWritten;
PINPUT_RECORD InputRecord;
DPRINT("SrvWriteConsoleInput\n");
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than five
* input records are written. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
if (WriteInputRequest->NumRecords <= sizeof(WriteInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
{
/*
* Adjust the internal pointer, because its old value points to
* the static buffer in the original ApiMessage structure.
*/
// WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
InputRecord = WriteInputRequest->RecordStaticBuffer;
}
else
{
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteInputRequest->RecordBufPtr,
WriteInputRequest->NumRecords,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
InputRecord = WriteInputRequest->RecordBufPtr;
}
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteInputRequest->InputHandle,
&InputBuffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status))
{
WriteInputRequest->NumRecords = 0;
return Status;
}
NumEventsWritten = 0;
Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
InputBuffer,
WriteInputRequest->Unicode,
WriteInputRequest->AppendToEnd,
InputRecord,
WriteInputRequest->NumRecords,
&NumEventsWritten);
WriteInputRequest->NumRecords = NumEventsWritten;
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer);
CSR_API(SrvFlushConsoleInputBuffer)
{
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
NTSTATUS Status;
PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
DPRINT("SrvFlushConsoleInputBuffer\n");
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
FlushInputBufferRequest->InputHandle,
&InputBuffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvFlushConsoleInputBuffer(InputBuffer->Header.Console,
InputBuffer);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
OUT PULONG NumberOfEvents);
CSR_API(SrvGetConsoleNumberOfInputEvents)
{
NTSTATUS Status;
PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetNumInputEventsRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
DPRINT("SrvGetConsoleNumberOfInputEvents\n");
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
GetNumInputEventsRequest->InputHandle,
&InputBuffer, GENERIC_READ, TRUE);
[KERNEL32/CONSRV] - Move the waiting loop of IntReadConsole into SrvReadConsole instead. - Merge IntPeekConsoleInput and IntReadConsoleInput helpers into a single IntGetConsoleInput helper function and make PeekConsoleInputW/A and ReadConsoleInputW/A use it. Indeed, the "only" difference between these two functions, is that the first one keeps the data read inside the console input buffer, but on the contrary the second removes the data and does not return until at least one input record has been read. In server-side, CsrReadInputEvent and CsrPeekConsoleInput are merged into SrvGetConsoleInput. Merge the corresponding structures. - Use shorter variable names in IntReadConsoleOutput and use CONSOLE_PROCESS_DATA structure in SrvReadConsoleOutput. - Merge IntReadConsoleOutputCharacter and ReadConsoleOutputAttribute functions into a single IntReadConsoleOutputCode helper function, and make ReadConsoleOutputAttribute and ReadConsoleOutputCharacterW/A use it. In server-side, CsrReadConsoleOutputChar and CsrReadConsoleOutputAttrib are merged into SrvReadConsoleOutputString. (Remark: the SrvReadConsoleOutputString name comes from http://j00ru.vexillium.org/csrss_list/api_list.html and I checked that it was indeed the server function that was called by both ReadConsoleOutputAttribute and ReadConsoleOutputCharacter). The idea behind merging these two functions is, that an attribute or a character are instances of the same entity, namely a "code" (what would be called an (ANSI) escape sequence). Therefore I encode them inside the same CSRSS_READ_CONSOLE_OUTPUT_CODE structure and I use it with the previous functions. [CONSRV] - Make use of the CONSOLE_PROCESS_DATA structure (introduced in r57685). - Use CsrValidateMessageBuffer instead of Win32CsrValidateBuffer. - Reorganize conmsg.h a little bit. svn path=/branches/ros-csrss/; revision=57721
2012-11-17 21:39:41 +00:00
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleNumberOfInputEvents(InputBuffer->Header.Console,
InputBuffer,
&GetNumInputEventsRequest->NumberOfEvents);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return Status;
}
/* EOF */