📄 conio.c
字号:
/*
* reactos/subsys/csrss/win32csr/conio.c
*
* Console I/O functions
*
* ReactOS Operating System
*/
/* INCLUDES ******************************************************************/
#include "w32csr.h"
#define NDEBUG
#include <debug.h>
extern NTSTATUS FASTCALL
Win32CsrInsertObject2(PCSRSS_PROCESS_DATA, PHANDLE, Object_t *);
/* GLOBALS *******************************************************************/
#define ConioInitRect(Rect, Top, Left, Bottom, Right) \
((Rect)->top) = Top; \
((Rect)->left) = Left; \
((Rect)->bottom) = Bottom; \
((Rect)->right) = Right
#define ConioIsRectEmpty(Rect) \
(((Rect)->left > (Rect)->right) || ((Rect)->top > (Rect)->bottom))
#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleAnsiCharToUnicodeChar(Console, sWChar, dChar) \
MultiByteToWideChar((Console)->CodePage, 0, (dChar), 1, (sWChar), 1)
/* FUNCTIONS *****************************************************************/
static NTSTATUS FASTCALL
ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Console)
{
PCSRSS_CONSOLE ProcessConsole = ProcessData->Console;
if (!ProcessConsole)
{
*Console = NULL;
return STATUS_SUCCESS;
}
EnterCriticalSection(&(ProcessConsole->Header.Lock));
*Console = ProcessConsole;
return STATUS_SUCCESS;
}
VOID FASTCALL
ConioConsoleCtrlEventTimeout(DWORD Event, PCSRSS_PROCESS_DATA ProcessData, DWORD Timeout)
{
HANDLE Thread;
DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ProcessId);
if (ProcessData->CtrlDispatcher)
{
Thread = CreateRemoteThread(ProcessData->Process, NULL, 0,
(LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
(PVOID) Event, 0, NULL);
if (NULL == Thread)
{
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
return;
}
WaitForSingleObject(Thread, Timeout);
CloseHandle(Thread);
}
}
VOID FASTCALL
ConioConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
{
ConioConsoleCtrlEventTimeout(Event, ProcessData, INFINITE);
}
#define GET_CELL_BUFFER(b,o)\
(b)->Buffer[(o)++]
#define SET_CELL_BUFFER(b,o,c,a)\
(b)->Buffer[(o)++]=(c),\
(b)->Buffer[(o)++]=(a)
static VOID FASTCALL
ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
{
DWORD Offset = 2 * (Buff->CurrentY * Buff->MaxX);
UINT Pos;
for (Pos = 0; Pos < Buff->MaxX; Pos++)
{
/* Fill the cell: Offset is incremented by the macro */
SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
}
}
static NTSTATUS FASTCALL
CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
PCSRSS_SCREEN_BUFFER Buffer)
{
DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer->MaxX, Buffer->MaxY);
Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
Buffer->Header.ReferenceCount = 0;
Buffer->ShowX = 0;
Buffer->ShowY = 0;
Buffer->Buffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
if (NULL == Buffer->Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
InitializeCriticalSection(&Buffer->Header.Lock);
ConioInitScreenBuffer(Console, Buffer);
/* initialize buffer to be empty with default attributes */
for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
{
ClearLineBuffer(Buffer);
}
Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
Buffer->CurrentX = 0;
Buffer->CurrentY = 0;
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL
CsrInitConsole(PCSRSS_CONSOLE Console)
{
NTSTATUS Status;
SECURITY_ATTRIBUTES SecurityAttributes;
PCSRSS_SCREEN_BUFFER NewBuffer;
BOOL GuiMode;
Console->Title.MaximumLength = Console->Title.Length = 0;
Console->Title.Buffer = NULL;
//FIXME
RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
Console->Header.ReferenceCount = 0;
Console->WaitingChars = 0;
Console->WaitingLines = 0;
Console->EchoCount = 0;
Console->Header.Type = CONIO_CONSOLE_MAGIC;
Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
Console->EarlyReturn = FALSE;
Console->ActiveBuffer = NULL;
InitializeListHead(&Console->InputEvents);
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);
return STATUS_UNSUCCESSFUL;
}
Console->PrivateData = NULL;
InitializeCriticalSection(&Console->Header.Lock);
GuiMode = DtbgIsDesktopVisible();
/* allocate console screen buffer */
NewBuffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
/* init screen buffer with defaults */
NewBuffer->CursorInfo.bVisible = TRUE;
NewBuffer->CursorInfo.dwSize = 5;
/* make console active, and insert into console list */
Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
/* add a reference count because the buffer is tied to the console */
InterlockedIncrement(&Console->ActiveBuffer->Header.ReferenceCount);
if (NULL == NewBuffer)
{
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (! GuiMode)
{
Status = TuiInitConsole(Console);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
GuiMode = TRUE;
}
}
if (GuiMode)
{
Status = GuiInitConsole(Console);
if (! NT_SUCCESS(Status))
{
HeapFree(Win32CsrApiHeap,0, NewBuffer);
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
DPRINT1("GuiInitConsole: failed\n");
return Status;
}
}
Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
if (! NT_SUCCESS(Status))
{
ConioCleanupConsole(Console);
RtlFreeUnicodeString(&Console->Title);
DeleteCriticalSection(&Console->Header.Lock);
CloseHandle(Console->ActiveEvent);
HeapFree(Win32CsrApiHeap, 0, NewBuffer);
DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
return Status;
}
/* copy buffer contents to screen */
ConioDrawConsole(Console);
return STATUS_SUCCESS;
}
CSR_API(CsrAllocConsole)
{
PCSRSS_CONSOLE Console;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN NewConsole = FALSE;
DPRINT("CsrAllocConsole\n");
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (ProcessData == NULL)
{
DPRINT1("No process data\n");
return Request->Status = STATUS_INVALID_PARAMETER;
}
if (ProcessData->Console)
{
DPRINT1("Process already has a console\n");
Request->Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
/* Assume success */
Request->Status = STATUS_SUCCESS;
/* If we don't need a console, then get out of here */
if (!Request->Data.AllocConsoleRequest.ConsoleNeeded)
{
DPRINT("No console needed\n");
return STATUS_SUCCESS;
}
/* If we already have one, then don't create a new one... */
if (!Request->Data.AllocConsoleRequest.Console ||
Request->Data.AllocConsoleRequest.Console != ProcessData->ParentConsole)
{
/* Allocate a console structure */
NewConsole = TRUE;
Console = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
if (NULL == Console)
{
DPRINT1("Not enough memory for console\n");
Request->Status = STATUS_NO_MEMORY;
return STATUS_NO_MEMORY;
}
/* initialize list head */
InitializeListHead(&Console->ProcessList);
/* insert process data required for GUI initialization */
InsertHeadList(&Console->ProcessList, &ProcessData->ProcessEntry);
/* Initialize the Console */
Request->Status = CsrInitConsole(Console);
if (!NT_SUCCESS(Request->Status))
{
DPRINT1("Console init failed\n");
HeapFree(Win32CsrApiHeap, 0, Console);
return Request->Status;
}
}
else
{
/* Reuse our current console */
Console = Request->Data.AllocConsoleRequest.Console;
}
/* Set the Process Console */
ProcessData->Console = Console;
/* Return it to the caller */
Request->Data.AllocConsoleRequest.Console = Console;
/* Add a reference count because the process is tied to the console */
Console->Header.ReferenceCount++;
if (NewConsole || !ProcessData->bInheritHandles)
{
/* Insert the Objects */
Status = Win32CsrInsertObject2(ProcessData,
&Request->Data.AllocConsoleRequest.InputHandle,
&Console->Header);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
ProcessData->Console = 0;
return Request->Status = Status;
}
Status = Win32CsrInsertObject2(ProcessData,
&Request->Data.AllocConsoleRequest.OutputHandle,
&Console->ActiveBuffer->Header);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to insert object\n");
ConioDeleteConsole((Object_t *) Console);
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.InputHandle);
ProcessData->Console = 0;
return Request->Status = Status;
}
}
/* Duplicate the Event */
if (!DuplicateHandle(GetCurrentProcess(),
ProcessData->Console->ActiveEvent,
ProcessData->Process,
&ProcessData->ConsoleEvent,
EVENT_ALL_ACCESS,
FALSE,
0))
{
DPRINT1("DuplicateHandle() failed: %d\n", GetLastError);
ConioDeleteConsole((Object_t *) Console);
if (NewConsole || !ProcessData->bInheritHandles)
{
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.OutputHandle);
Win32CsrReleaseObject(ProcessData,
Request->Data.AllocConsoleRequest.InputHandle);
}
ProcessData->Console = 0;
return Request->Status = Status;
}
/* Set the Ctrl Dispatcher */
ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
if (!NewConsole)
{
/* Insert into the list if it has not been added */
InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ProcessEntry);
}
return STATUS_SUCCESS;
}
CSR_API(CsrFreeConsole)
{
PCSRSS_CONSOLE Console;
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (ProcessData == NULL || ProcessData->Console == NULL)
{
return Request->Status = STATUS_INVALID_PARAMETER;
}
Console = ProcessData->Console;
ProcessData->Console = NULL;
if (0 == InterlockedDecrement(&Console->Header.ReferenceCount))
{
ConioDeleteConsole((Object_t *) Console);
}
return STATUS_SUCCESS;
}
static VOID FASTCALL
ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, UINT *ScrolledLines)
{
/* slide the viewable screen */
if (((Buff->CurrentY - Buff->ShowY + Buff->MaxY) % Buff->MaxY) == (ULONG)Buff->MaxY - 1)
{
if (++Buff->ShowY == Buff->MaxY)
{
Buff->ShowY = 0;
}
(*ScrolledLines)++;
}
if (++Buff->CurrentY == Buff->MaxY)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -