⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 conio.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -