Create a new consrv_new to study its interfacing with the console driver (condrv).

svn path=/trunk/; revision=59470
This commit is contained in:
Hermès Bélusca-Maïto
2013-07-13 15:18:34 +00:00
parent ecf9d0b046
commit a60aae50e9
91 changed files with 16161 additions and 0 deletions
@@ -0,0 +1,587 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/alias.c
* PURPOSE: Alias support functions
* PROGRAMMERS: Christoph Wittich
* Johannes Anderwald
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "console.h"
#include "include/conio.h"
#define NDEBUG
#include <debug.h>
/* TYPES **********************************************************************/
typedef struct _ALIAS_ENTRY
{
LPCWSTR lpSource;
LPCWSTR lpTarget;
struct _ALIAS_ENTRY* Next;
} ALIAS_ENTRY, *PALIAS_ENTRY;
typedef struct _ALIAS_HEADER
{
LPCWSTR lpExeName;
PALIAS_ENTRY Data;
struct _ALIAS_HEADER* Next;
} ALIAS_HEADER, *PALIAS_HEADER;
/* PRIVATE FUNCTIONS **********************************************************/
static
PALIAS_HEADER
IntFindAliasHeader(PALIAS_HEADER RootHeader, LPCWSTR lpExeName)
{
while (RootHeader)
{
INT diff = _wcsicmp(RootHeader->lpExeName, lpExeName);
if (!diff) return RootHeader;
if (diff > 0) break;
RootHeader = RootHeader->Next;
}
return NULL;
}
PALIAS_HEADER
IntCreateAliasHeader(LPCWSTR lpExeName)
{
PALIAS_HEADER Entry;
UINT dwLength = wcslen(lpExeName) + 1;
Entry = ConsoleAllocHeap(0, sizeof(ALIAS_HEADER) + sizeof(WCHAR) * dwLength);
if (!Entry) return Entry;
Entry->lpExeName = (LPCWSTR)(Entry + 1);
wcscpy((PWCHAR)Entry->lpExeName, lpExeName);
Entry->Data = NULL;
Entry->Next = NULL;
return Entry;
}
VOID
IntInsertAliasHeader(PALIAS_HEADER * RootHeader, PALIAS_HEADER NewHeader)
{
PALIAS_HEADER CurrentHeader;
PALIAS_HEADER *LastLink = RootHeader;
while ((CurrentHeader = *LastLink) != NULL)
{
INT Diff = _wcsicmp(NewHeader->lpExeName, CurrentHeader->lpExeName);
if (Diff < 0) break;
LastLink = &CurrentHeader->Next;
}
*LastLink = NewHeader;
NewHeader->Next = CurrentHeader;
}
PALIAS_ENTRY
IntGetAliasEntry(PALIAS_HEADER Header, LPCWSTR lpSrcName)
{
PALIAS_ENTRY RootHeader;
if (Header == NULL) return NULL;
RootHeader = Header->Data;
while (RootHeader)
{
INT diff;
DPRINT("IntGetAliasEntry->lpSource %S\n", RootHeader->lpSource);
diff = _wcsicmp(RootHeader->lpSource, lpSrcName);
if (!diff) return RootHeader;
if (diff > 0) break;
RootHeader = RootHeader->Next;
}
return NULL;
}
VOID
IntInsertAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY NewEntry)
{
PALIAS_ENTRY CurrentEntry;
PALIAS_ENTRY *LastLink = &Header->Data;
while ((CurrentEntry = *LastLink) != NULL)
{
INT Diff = _wcsicmp(NewEntry->lpSource, CurrentEntry->lpSource);
if (Diff < 0) break;
LastLink = &CurrentEntry->Next;
}
*LastLink = NewEntry;
NewEntry->Next = CurrentEntry;
}
PALIAS_ENTRY
IntCreateAliasEntry(LPCWSTR lpSource, LPCWSTR lpTarget)
{
UINT dwSource;
UINT dwTarget;
PALIAS_ENTRY Entry;
dwSource = wcslen(lpSource) + 1;
dwTarget = wcslen(lpTarget) + 1;
Entry = ConsoleAllocHeap(0, sizeof(ALIAS_ENTRY) + sizeof(WCHAR) * (dwSource + dwTarget));
if (!Entry) return Entry;
Entry->lpSource = (LPCWSTR)(Entry + 1);
wcscpy((LPWSTR)Entry->lpSource, lpSource);
Entry->lpTarget = Entry->lpSource + dwSource;
wcscpy((LPWSTR)Entry->lpTarget, lpTarget);
Entry->Next = NULL;
return Entry;
}
UINT
IntGetConsoleAliasesExesLength(PALIAS_HEADER RootHeader)
{
UINT length = 0;
while (RootHeader)
{
length += (wcslen(RootHeader->lpExeName) + 1) * sizeof(WCHAR);
RootHeader = RootHeader->Next;
}
if (length)
length += sizeof(WCHAR); // last entry entry is terminated with 2 zero bytes
return length;
}
UINT
IntGetConsoleAliasesExes(PALIAS_HEADER RootHeader, LPWSTR TargetBuffer, UINT TargetBufferSize)
{
UINT Offset = 0;
UINT Length;
TargetBufferSize /= sizeof(WCHAR);
while (RootHeader)
{
Length = wcslen(RootHeader->lpExeName) + 1;
if (TargetBufferSize > Offset + Length)
{
wcscpy(&TargetBuffer[Offset], RootHeader->lpExeName);
Offset += Length;
}
else
{
break;
}
RootHeader = RootHeader->Next;
}
Length = min(Offset+1, TargetBufferSize);
TargetBuffer[Length] = L'\0';
return Length * sizeof(WCHAR);
}
UINT
IntGetAllConsoleAliasesLength(PALIAS_HEADER Header)
{
UINT Length = 0;
PALIAS_ENTRY CurEntry = Header->Data;
while (CurEntry)
{
Length += wcslen(CurEntry->lpSource);
Length += wcslen(CurEntry->lpTarget);
Length += 2; // zero byte and '='
CurEntry = CurEntry->Next;
}
if (Length)
{
return (Length+1) * sizeof(WCHAR);
}
return 0;
}
UINT
IntGetAllConsoleAliases(PALIAS_HEADER Header, LPWSTR TargetBuffer, UINT TargetBufferLength)
{
PALIAS_ENTRY CurEntry = Header->Data;
UINT Offset = 0;
UINT SrcLength, TargetLength;
TargetBufferLength /= sizeof(WCHAR);
while (CurEntry)
{
SrcLength = wcslen(CurEntry->lpSource) + 1;
TargetLength = wcslen(CurEntry->lpTarget) + 1;
if (Offset + TargetLength + SrcLength >= TargetBufferLength)
break;
wcscpy(&TargetBuffer[Offset], CurEntry->lpSource);
Offset += SrcLength;
TargetBuffer[Offset] = L'=';
wcscpy(&TargetBuffer[Offset], CurEntry->lpTarget);
Offset += TargetLength;
CurEntry = CurEntry->Next;
}
TargetBuffer[Offset] = L'\0';
return Offset * sizeof(WCHAR);
}
VOID
IntDeleteAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY Entry)
{
PALIAS_ENTRY *LastLink = &Header->Data;
PALIAS_ENTRY CurEntry;
while ((CurEntry = *LastLink) != NULL)
{
if (CurEntry == Entry)
{
*LastLink = Entry->Next;
ConsoleFreeHeap(Entry);
return;
}
LastLink = &CurEntry->Next;
}
}
VOID
IntDeleteAllAliases(PCONSOLE Console)
{
PALIAS_HEADER Header, NextHeader;
PALIAS_ENTRY Entry, NextEntry;
for (Header = Console->Aliases; Header; Header = NextHeader)
{
NextHeader = Header->Next;
for (Entry = Header->Data; Entry; Entry = NextEntry)
{
NextEntry = Entry->Next;
ConsoleFreeHeap(Entry);
}
ConsoleFreeHeap(Header);
}
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvAddConsoleAlias)
{
PCONSOLE_ADDGETALIAS ConsoleAliasRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleAliasRequest;
PCONSOLE Console;
PALIAS_HEADER Header;
PALIAS_ENTRY Entry;
LPWSTR lpSource, lpTarget, lpExeName;
DPRINT("SrvAddConsoleAlias entered ApiMessage %p\n", ApiMessage);
if ( !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Source,
ConsoleAliasRequest->SourceLength,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Target,
ConsoleAliasRequest->TargetLength,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Exe,
ConsoleAliasRequest->ExeLength,
sizeof(BYTE)) )
{
return STATUS_INVALID_PARAMETER;
}
lpSource = ConsoleAliasRequest->Source;
lpTarget = (ConsoleAliasRequest->TargetLength != 0 ? ConsoleAliasRequest->Target : NULL);
lpExeName = ConsoleAliasRequest->Exe;
DPRINT("SrvAddConsoleAlias lpSource %p lpExeName %p lpTarget %p\n", lpSource, lpExeName, lpTarget);
if (lpExeName == NULL || lpSource == NULL)
{
return STATUS_INVALID_PARAMETER;
}
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(ApiMessage->Status))
{
return ApiMessage->Status;
}
Header = IntFindAliasHeader(Console->Aliases, lpExeName);
if (!Header && lpTarget != NULL)
{
Header = IntCreateAliasHeader(lpExeName);
if (!Header)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INSUFFICIENT_RESOURCES;
}
IntInsertAliasHeader(&Console->Aliases, Header);
}
if (lpTarget == NULL) // Delete the entry
{
Entry = IntGetAliasEntry(Header, lpSource);
if (Entry)
{
IntDeleteAliasEntry(Header, Entry);
ApiMessage->Status = STATUS_SUCCESS;
}
else
{
ApiMessage->Status = STATUS_INVALID_PARAMETER;
}
ConSrvReleaseConsole(Console, TRUE);
return ApiMessage->Status;
}
Entry = IntCreateAliasEntry(lpSource, lpTarget);
if (!Entry)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INSUFFICIENT_RESOURCES;
}
IntInsertAliasEntry(Header, Entry);
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleAlias)
{
PCONSOLE_ADDGETALIAS ConsoleAliasRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleAliasRequest;
PCONSOLE Console;
PALIAS_HEADER Header;
PALIAS_ENTRY Entry;
UINT Length;
LPWSTR lpSource, lpTarget, lpExeName;
DPRINT("SrvGetConsoleAlias entered ApiMessage %p\n", ApiMessage);
if ( !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Source,
ConsoleAliasRequest->SourceLength,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Target,
ConsoleAliasRequest->TargetLength,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ConsoleAliasRequest->Exe,
ConsoleAliasRequest->ExeLength,
sizeof(BYTE)) )
{
return STATUS_INVALID_PARAMETER;
}
lpSource = ConsoleAliasRequest->Source;
lpTarget = ConsoleAliasRequest->Target;
lpExeName = ConsoleAliasRequest->Exe;
DPRINT("SrvGetConsoleAlias lpExeName %p lpSource %p TargetBuffer %p TargetLength %u\n",
lpExeName, lpSource, lpTarget, ConsoleAliasRequest->TargetLength);
if (ConsoleAliasRequest->ExeLength == 0 || lpTarget == NULL ||
ConsoleAliasRequest->TargetLength == 0 || ConsoleAliasRequest->SourceLength == 0)
{
return STATUS_INVALID_PARAMETER;
}
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(ApiMessage->Status))
{
return ApiMessage->Status;
}
Header = IntFindAliasHeader(Console->Aliases, lpExeName);
if (!Header)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INVALID_PARAMETER;
}
Entry = IntGetAliasEntry(Header, lpSource);
if (!Entry)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INVALID_PARAMETER;
}
Length = (wcslen(Entry->lpTarget) + 1) * sizeof(WCHAR);
if (Length > ConsoleAliasRequest->TargetLength)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_BUFFER_TOO_SMALL;
}
wcscpy(lpTarget, Entry->lpTarget);
ConsoleAliasRequest->TargetLength = Length;
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleAliases)
{
PCONSOLE_GETALLALIASES GetAllAliasesRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetAllAliasesRequest;
PCONSOLE Console;
ULONG BytesWritten;
PALIAS_HEADER Header;
if ( !CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetAllAliasesRequest->ExeName,
GetAllAliasesRequest->ExeLength,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetAllAliasesRequest->AliasesBuffer,
GetAllAliasesRequest->AliasesBufferLength,
sizeof(BYTE)) )
{
return STATUS_INVALID_PARAMETER;
}
if (GetAllAliasesRequest->ExeName == NULL)
{
return STATUS_INVALID_PARAMETER;
}
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(ApiMessage->Status))
{
return ApiMessage->Status;
}
Header = IntFindAliasHeader(Console->Aliases, GetAllAliasesRequest->ExeName);
if (!Header)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INVALID_PARAMETER;
}
if (IntGetAllConsoleAliasesLength(Header) > GetAllAliasesRequest->AliasesBufferLength)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_BUFFER_OVERFLOW;
}
BytesWritten = IntGetAllConsoleAliases(Header,
GetAllAliasesRequest->AliasesBuffer,
GetAllAliasesRequest->AliasesBufferLength);
GetAllAliasesRequest->AliasesBufferLength = BytesWritten;
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleAliasesLength)
{
PCONSOLE_GETALLALIASESLENGTH GetAllAliasesLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetAllAliasesLengthRequest;
PCONSOLE Console;
PALIAS_HEADER Header;
UINT Length;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetAllAliasesLengthRequest->ExeName,
GetAllAliasesLengthRequest->ExeLength,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
if (GetAllAliasesLengthRequest->ExeName == NULL)
{
return STATUS_INVALID_PARAMETER;
}
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(ApiMessage->Status))
{
return ApiMessage->Status;
}
Header = IntFindAliasHeader(Console->Aliases, GetAllAliasesLengthRequest->ExeName);
if (!Header)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INVALID_PARAMETER;
}
Length = IntGetAllConsoleAliasesLength(Header);
GetAllAliasesLengthRequest->Length = Length;
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleAliasExes)
{
PCONSOLE_GETALIASESEXES GetAliasesExesRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetAliasesExesRequest;
PCONSOLE Console;
UINT BytesWritten;
UINT ExesLength;
DPRINT("SrvGetConsoleAliasExes entered\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetAliasesExesRequest->ExeNames,
GetAliasesExesRequest->Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(ApiMessage->Status))
{
return ApiMessage->Status;
}
ExesLength = IntGetConsoleAliasesExesLength(Console->Aliases);
if (ExesLength > GetAliasesExesRequest->Length)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_BUFFER_OVERFLOW;
}
if (GetAliasesExesRequest->ExeNames == NULL)
{
ConSrvReleaseConsole(Console, TRUE);
return STATUS_INVALID_PARAMETER;
}
BytesWritten = IntGetConsoleAliasesExes(Console->Aliases,
GetAliasesExesRequest->ExeNames,
GetAliasesExesRequest->Length);
GetAliasesExesRequest->Length = BytesWritten;
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleAliasExesLength)
{
PCONSOLE_GETALIASESEXESLENGTH GetAliasesExesLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetAliasesExesLengthRequest;
PCONSOLE Console;
DPRINT("SrvGetConsoleAliasExesLength entered\n");
ApiMessage->Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (NT_SUCCESS(ApiMessage->Status))
{
GetAliasesExesLengthRequest->Length = IntGetConsoleAliasesExesLength(Console->Aliases);
ConSrvReleaseConsole(Console, TRUE);
}
return ApiMessage->Status;
}
/* EOF */
@@ -0,0 +1,14 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/alias.h
* PURPOSE: Alias support functions
* PROGRAMMERS: Christoph Wittich
* Johannes Anderwald
*/
#pragma once
VOID IntDeleteAllAliases(PCONSOLE Console);
/* EOF */
@@ -0,0 +1,84 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/api.h
* PURPOSE: Public server APIs definitions
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
/* alias.c */
CSR_API(SrvAddConsoleAlias);
CSR_API(SrvGetConsoleAlias);
CSR_API(SrvGetConsoleAliases);
CSR_API(SrvGetConsoleAliasesLength);
CSR_API(SrvGetConsoleAliasExes);
CSR_API(SrvGetConsoleAliasExesLength);
/* coninput.c */
CSR_API(SrvReadConsole);
CSR_API(SrvGetConsoleInput);
CSR_API(SrvWriteConsoleInput);
CSR_API(SrvFlushConsoleInputBuffer);
CSR_API(SrvGetConsoleNumberOfInputEvents);
/* conoutput.c */
CSR_API(SrvInvalidateBitMapRect);
CSR_API(SrvReadConsoleOutput);
CSR_API(SrvWriteConsole);
CSR_API(SrvWriteConsoleOutput);
CSR_API(SrvReadConsoleOutputString);
CSR_API(SrvWriteConsoleOutputString);
CSR_API(SrvFillConsoleOutput);
CSR_API(SrvGetConsoleCursorInfo);
CSR_API(SrvSetConsoleCursorInfo);
CSR_API(SrvSetConsoleCursorPosition);
CSR_API(SrvSetConsoleTextAttribute);
CSR_API(SrvCreateConsoleScreenBuffer);
CSR_API(SrvGetConsoleScreenBufferInfo);
CSR_API(SrvSetConsoleActiveScreenBuffer);
CSR_API(SrvScrollConsoleScreenBuffer);
CSR_API(SrvSetConsoleScreenBufferSize);
/* console.c */
CSR_API(SrvAllocConsole);
CSR_API(SrvAttachConsole);
CSR_API(SrvFreeConsole);
CSR_API(SrvGetConsoleMode);
CSR_API(SrvSetConsoleMode);
CSR_API(SrvGetConsoleTitle);
CSR_API(SrvSetConsoleTitle);
CSR_API(SrvGetConsoleHardwareState);
CSR_API(SrvSetConsoleHardwareState);
CSR_API(SrvGetConsoleDisplayMode);
CSR_API(SrvSetConsoleDisplayMode);
CSR_API(SrvGetLargestConsoleWindowSize);
CSR_API(SrvShowConsoleCursor);
CSR_API(SrvSetConsoleCursor);
CSR_API(SrvConsoleMenuControl);
CSR_API(SrvSetConsoleMenuClose);
CSR_API(SrvSetConsoleWindowInfo);
CSR_API(SrvGetConsoleWindow);
CSR_API(SrvSetConsoleIcon);
CSR_API(SrvGetConsoleCP);
CSR_API(SrvSetConsoleCP);
CSR_API(SrvGetConsoleProcessList);
CSR_API(SrvGenerateConsoleCtrlEvent);
CSR_API(SrvGetConsoleSelectionInfo);
/* handle.c */
CSR_API(SrvOpenConsole);
CSR_API(SrvCloseHandle);
CSR_API(SrvVerifyConsoleIoHandle);
CSR_API(SrvDuplicateHandle);
/* lineinput.c */
CSR_API(SrvGetConsoleCommandHistory);
CSR_API(SrvGetConsoleCommandHistoryLength);
CSR_API(SrvExpungeConsoleCommandHistory);
CSR_API(SrvSetConsoleNumberOfCommands);
CSR_API(SrvGetConsoleHistory);
CSR_API(SrvSetConsoleHistory);
/* EOF */
@@ -0,0 +1,514 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Driver DLL
* FILE: win32ss/user/winsrv/consrv/condrv/coninput.c
* PURPOSE: Console Input functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "handle.h"
#include "lineinput.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))
#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
typedef struct ConsoleInput_t
{
LIST_ENTRY ListEntry;
INPUT_RECORD InputEvent;
} ConsoleInput;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID FASTCALL
ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
{
if (InputEvent->EventType == KEY_EVENT)
{
WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
ConsoleInputUnicodeCharToAnsiChar(Console,
&InputEvent->Event.KeyEvent.uChar.AsciiChar,
&UnicodeChar);
}
}
NTSTATUS FASTCALL
ConioProcessInputEvent(PCONSOLE Console,
PINPUT_RECORD InputEvent)
{
ConsoleInput *ConInRec;
/* Check for pause or unpause */
if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
{
WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
{
DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT &&
(vk == VK_PAUSE || (vk == 'S' &&
(cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
!(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
{
ConioPause(Console, PAUSED_FROM_KEYBOARD);
return STATUS_SUCCESS;
}
}
else
{
if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
{
ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
return STATUS_SUCCESS;
}
}
}
/* Add event to the queue */
ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput));
if (ConInRec == NULL) return STATUS_INSUFFICIENT_RESOURCES;
ConInRec->InputEvent = *InputEvent;
InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
SetEvent(Console->InputBuffer.ActiveEvent);
CsrNotifyWait(&Console->InputBuffer.ReadWaitQueue,
WaitAny,
NULL,
NULL);
if (!IsListEmpty(&Console->InputBuffer.ReadWaitQueue))
{
CsrDereferenceWait(&Console->InputBuffer.ReadWaitQueue);
}
return STATUS_SUCCESS;
}
VOID FASTCALL
PurgeInputBuffer(PCONSOLE Console)
{
PLIST_ENTRY CurrentEntry;
ConsoleInput* Event;
while (!IsListEmpty(&Console->InputBuffer.InputEvents))
{
CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents);
Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
ConsoleFreeHeap(Event);
}
CloseHandle(Console->InputBuffer.ActiveEvent);
}
VOID NTAPI
ConDrvProcessKey(IN PCONSOLE Console,
IN BOOLEAN Down,
IN UINT VirtualKeyCode,
IN UINT VirtualScanCode,
IN WCHAR UnicodeChar,
IN ULONG ShiftState,
IN BYTE KeyStateCtrl)
{
INPUT_RECORD er;
/* process Ctrl-C and Ctrl-Break */
if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') &&
(ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyStateCtrl & 0x80) )
{
DPRINT1("Console_Api Ctrl-C\n");
ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT);
if (Console->LineBuffer && !Console->LineComplete)
{
/* Line input is in progress; end it */
Console->LinePos = Console->LineSize = 0;
Console->LineComplete = TRUE;
}
return;
}
if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 &&
(VK_UP == VirtualKeyCode || VK_DOWN == VirtualKeyCode) )
{
if (!Down) return;
/* scroll up or down */
if (VK_UP == VirtualKeyCode)
{
/* only scroll up if there is room to scroll up into */
if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1)
{
Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
Console->ActiveBuffer->ScreenBufferSize.Y - 1) %
Console->ActiveBuffer->ScreenBufferSize.Y;
Console->ActiveBuffer->CursorPosition.Y++;
}
}
else
{
/* only scroll down if there is room to scroll down into */
if (Console->ActiveBuffer->CursorPosition.Y != 0)
{
Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
Console->ActiveBuffer->ScreenBufferSize.Y;
Console->ActiveBuffer->CursorPosition.Y--;
}
}
ConioDrawConsole(Console);
return;
}
er.EventType = KEY_EVENT;
er.Event.KeyEvent.bKeyDown = Down;
er.Event.KeyEvent.wRepeatCount = 1;
er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
er.Event.KeyEvent.dwControlKeyState = ShiftState;
ConioProcessInputEvent(Console, &er);
}
/* PUBLIC DRIVER APIS *********************************************************/
NTSTATUS NTAPI
ConDrvReadConsole(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN Unicode,
OUT PVOID Buffer,
IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
IN ULONG NumCharsToRead,
OUT PULONG NumCharsRead OPTIONAL)
{
// STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
NTSTATUS Status = STATUS_PENDING;
PLIST_ENTRY CurrentEntry;
ConsoleInput *Input;
ULONG i = ReadControl->nInitialChars;
if (Console == NULL || InputBuffer == NULL || /* Buffer == NULL || */
ReadControl == NULL || ReadControl->nLength != sizeof(CONSOLE_READCONSOLE_CONTROL))
{
return STATUS_INVALID_PARAMETER;
}
/* Validity checks */
ASSERT(Console == InputBuffer->Header.Console);
ASSERT( (Buffer != NULL && NumCharsToRead >= 0) ||
(Buffer == NULL && NumCharsToRead == 0) );
/* We haven't read anything (yet) */
if (InputBuffer->Mode & ENABLE_LINE_INPUT)
{
if (Console->LineBuffer == NULL)
{
/* Starting a new line */
Console->LineMaxSize = (WORD)max(256, NumCharsToRead);
Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR));
if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY;
Console->LineComplete = FALSE;
Console->LineUpPressed = FALSE;
Console->LineInsertToggle = 0;
Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask;
Console->LineSize = ReadControl->nInitialChars;
Console->LinePos = Console->LineSize;
/*
* Pre-filling the buffer is only allowed in the Unicode API,
* so we don't need to worry about ANSI <-> Unicode conversion.
*/
memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
if (Console->LineSize == Console->LineMaxSize)
{
Console->LineComplete = TRUE;
Console->LinePos = 0;
}
}
/* If we don't have a complete line yet, process the pending input */
while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents))
{
/* Remove input event from queue */
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
if (IsListEmpty(&InputBuffer->InputEvents))
{
ResetEvent(InputBuffer->ActiveEvent);
}
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* Only pay attention to key down */
if (Input->InputEvent.EventType == KEY_EVENT &&
Input->InputEvent.Event.KeyEvent.bKeyDown)
{
LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
}
ConsoleFreeHeap(Input);
}
/* Check if we have a complete line to read from */
if (Console->LineComplete)
{
while (i < NumCharsToRead && Console->LinePos != Console->LineSize)
{
WCHAR Char = Console->LineBuffer[Console->LinePos++];
if (Unicode)
{
((PWCHAR)Buffer)[i] = Char;
}
else
{
ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
}
++i;
}
if (Console->LinePos == Console->LineSize)
{
/* Entire line has been read */
ConsoleFreeHeap(Console->LineBuffer);
Console->LineBuffer = NULL;
}
Status = STATUS_SUCCESS;
}
}
else
{
/* Character input */
while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents))
{
/* Remove input event from queue */
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
if (IsListEmpty(&InputBuffer->InputEvents))
{
ResetEvent(InputBuffer->ActiveEvent);
}
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
/* Only pay attention to valid ASCII chars, on key down */
if (Input->InputEvent.EventType == KEY_EVENT &&
Input->InputEvent.Event.KeyEvent.bKeyDown &&
Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
{
WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
if (Unicode)
{
((PWCHAR)Buffer)[i] = Char;
}
else
{
ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
}
++i;
/* Did read something */
Status = STATUS_SUCCESS;
}
ConsoleFreeHeap(Input);
}
}
if (NumCharsRead) *NumCharsRead = i;
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN WaitForMoreEvents,
IN BOOLEAN Unicode,
OUT PINPUT_RECORD InputRecord,
IN ULONG NumEventsToRead,
OUT PULONG NumEventsRead OPTIONAL)
{
PLIST_ENTRY CurrentInput;
ConsoleInput* Input;
ULONG i = 0;
if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
return STATUS_INVALID_PARAMETER;
/* Validity checks */
ASSERT(Console == InputBuffer->Header.Console);
ASSERT( (InputRecord != NULL && NumEventsToRead >= 0) ||
(InputRecord == NULL && NumEventsToRead == 0) );
// Do NOT do that !! Use the existing number of events already read, if any...
// if (NumEventsRead) *NumEventsRead = 0;
if (IsListEmpty(&InputBuffer->InputEvents))
{
/*
* No input is available. Wait for more input if requested,
* otherwise, we don't wait, so we return success.
*/
return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
}
/* Only get input if there is any */
CurrentInput = InputBuffer->InputEvents.Flink;
if (NumEventsRead) i = *NumEventsRead; // We will read the remaining events...
while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
{
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
*InputRecord = Input->InputEvent;
if (!Unicode)
{
ConioInputEventToAnsi(InputBuffer->Header.Console, InputRecord);
}
++InputRecord;
++i;
CurrentInput = CurrentInput->Flink;
if (WaitForMoreEvents) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
{
RemoveEntryList(&Input->ListEntry);
ConsoleFreeHeap(Input);
}
}
if (NumEventsRead) *NumEventsRead = i;
if (IsListEmpty(&InputBuffer->InputEvents))
{
ResetEvent(InputBuffer->ActiveEvent);
}
/* We read all the inputs available, we return success */
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvWriteConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN Unicode,
IN PINPUT_RECORD InputRecord,
IN ULONG NumEventsToWrite,
OUT PULONG NumEventsWritten OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
return STATUS_INVALID_PARAMETER;
/* Validity checks */
ASSERT(Console == InputBuffer->Header.Console);
ASSERT( (InputRecord != NULL && NumEventsToWrite >= 0) ||
(InputRecord == NULL && NumEventsToWrite == 0) );
// Do NOT do that !! Use the existing number of events already written, if any...
// if (NumEventsWritten) *NumEventsWritten = 0;
for (i = (NumEventsWritten ? *NumEventsWritten : 0); i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
{
if (InputRecord->EventType == KEY_EVENT && !Unicode)
{
CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar;
ConsoleInputAnsiCharToUnicodeChar(Console,
&InputRecord->Event.KeyEvent.uChar.UnicodeChar,
&AsciiChar);
}
Status = ConioProcessInputEvent(Console, InputRecord++);
}
if (NumEventsWritten) *NumEventsWritten = i;
return Status;
}
NTSTATUS NTAPI
ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer)
{
PLIST_ENTRY CurrentEntry;
ConsoleInput* Event;
if (Console == NULL || InputBuffer == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == InputBuffer->Header.Console);
/* Discard all entries in the input event queue */
while (!IsListEmpty(&InputBuffer->InputEvents))
{
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
ConsoleFreeHeap(Event);
}
ResetEvent(InputBuffer->ActiveEvent);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
OUT PULONG NumEvents)
{
PLIST_ENTRY CurrentInput;
if (Console == NULL || InputBuffer == NULL || NumEvents == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == InputBuffer->Header.Console);
*NumEvents = 0;
/* If there are any events ... */
CurrentInput = InputBuffer->InputEvents.Flink;
while (CurrentInput != &InputBuffer->InputEvents)
{
CurrentInput = CurrentInput->Flink;
(*NumEvents)++;
}
return STATUS_SUCCESS;
}
/* EOF */
@@ -0,0 +1,287 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Driver DLL
* FILE: win32ss/user/winsrv/consrv/condrv/conoutput.c
* PURPOSE: General Console Output Functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "console.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "conoutput.h"
#include "handle.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS
TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN PTEXTMODE_BUFFER_INFO TextModeInfo);
NTSTATUS
GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN PGRAPHICS_BUFFER_INFO GraphicsInfo);
VOID
TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
VOID
GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
NTSTATUS
CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN SIZE_T Size)
{
if (Buffer == NULL || Console == NULL)
return STATUS_INVALID_PARAMETER;
*Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, max(sizeof(CONSOLE_SCREEN_BUFFER), Size));
if (*Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES;
/* Initialize the header with the default type */
ConSrvInitObject(&(*Buffer)->Header, SCREEN_BUFFER, Console);
(*Buffer)->Vtbl = NULL;
return STATUS_SUCCESS;
}
VOID
CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
{
if (Buffer->Header.Type == TEXTMODE_BUFFER)
TEXTMODE_BUFFER_Destroy(Buffer);
else if (Buffer->Header.Type == GRAPHICS_BUFFER)
GRAPHICS_BUFFER_Destroy(Buffer);
else if (Buffer->Header.Type == SCREEN_BUFFER)
ConsoleFreeHeap(Buffer);
// else
// do_nothing;
}
// ConDrvCreateConsoleScreenBuffer
NTSTATUS FASTCALL
ConDrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN ULONG BufferType,
IN PVOID ScreenBufferInfo)
{
NTSTATUS Status = STATUS_SUCCESS;
if ( Console == NULL || Buffer == NULL ||
(BufferType != CONSOLE_TEXTMODE_BUFFER && BufferType != CONSOLE_GRAPHICS_BUFFER) )
{
return STATUS_INVALID_PARAMETER;
}
if (BufferType == CONSOLE_TEXTMODE_BUFFER)
{
Status = TEXTMODE_BUFFER_Initialize(Buffer,
Console,
(PTEXTMODE_BUFFER_INFO)ScreenBufferInfo);
}
else if (BufferType == CONSOLE_GRAPHICS_BUFFER)
{
Status = GRAPHICS_BUFFER_Initialize(Buffer,
Console,
(PGRAPHICS_BUFFER_INFO)ScreenBufferInfo);
}
else
{
/* Never ever go there!! */
ASSERT(FALSE);
}
/* Insert the newly created screen buffer into the list, if succeeded */
if (NT_SUCCESS(Status)) InsertHeadList(&Console->BufferList, &(*Buffer)->ListEntry);
return Status;
}
static VOID
ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
VOID WINAPI
ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
{
PCONSOLE Console = Buffer->Header.Console;
PCONSOLE_SCREEN_BUFFER NewBuffer;
RemoveEntryList(&Buffer->ListEntry);
if (Buffer == Console->ActiveBuffer)
{
/* Delete active buffer; switch to most recently created */
Console->ActiveBuffer = NULL;
if (!IsListEmpty(&Console->BufferList))
{
NewBuffer = CONTAINING_RECORD(Console->BufferList.Flink,
CONSOLE_SCREEN_BUFFER,
ListEntry);
ConioSetActiveScreenBuffer(NewBuffer);
}
}
CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
}
VOID FASTCALL
ConioDrawConsole(PCONSOLE Console)
{
SMALL_RECT Region;
PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
if (ActiveBuffer)
{
ConioInitRect(&Region, 0, 0, ActiveBuffer->ViewSize.Y - 1, ActiveBuffer->ViewSize.X - 1);
ConioDrawRegion(Console, &Region);
}
}
static VOID
ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer)
{
PCONSOLE Console = Buffer->Header.Console;
Console->ActiveBuffer = Buffer;
ConioResizeTerminal(Console);
// ConioDrawConsole(Console);
}
NTSTATUS NTAPI
ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer)
{
if (Console == NULL || Buffer == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
if (Buffer == Console->ActiveBuffer) return STATUS_SUCCESS;
/* If old buffer has no handles, it's now unreferenced */
if (Console->ActiveBuffer->Header.HandleCount == 0)
{
ConioDeleteScreenBuffer(Console->ActiveBuffer);
}
/* Tie console to new buffer */
ConioSetActiveScreenBuffer(Buffer);
return STATUS_SUCCESS;
}
PCONSOLE_SCREEN_BUFFER
ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
{
return (Console ? Console->ActiveBuffer : NULL);
}
/* PUBLIC DRIVER APIS *********************************************************/
NTSTATUS NTAPI
ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer,
IN PSMALL_RECT Region)
{
if (Console == NULL || Buffer == NULL || Region == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
/* If the output buffer is the current one, redraw the correct portion of the screen */
if (Buffer == Console->ActiveBuffer) ConioDrawRegion(Console, Region);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
OUT PCONSOLE_CURSOR_INFO CursorInfo)
{
if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
*CursorInfo = Buffer->CursorInfo;
// CursorInfo->bVisible = Buffer->CursorInfo.bVisible;
// CursorInfo->dwSize = Buffer->CursorInfo.dwSize;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCONSOLE_CURSOR_INFO CursorInfo)
{
ULONG Size;
BOOLEAN Visible, Success = TRUE;
if (Console == NULL || Buffer == NULL || CursorInfo == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
Size = min(max(CursorInfo->dwSize, 1), 100);
Visible = CursorInfo->bVisible;
if ( (Size != Buffer->CursorInfo.dwSize) ||
(Visible && !Buffer->CursorInfo.bVisible) ||
(!Visible && Buffer->CursorInfo.bVisible) )
{
Buffer->CursorInfo.dwSize = Size;
Buffer->CursorInfo.bVisible = Visible;
Success = ConioSetCursorInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer);
}
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCOORD Position)
{
SHORT OldCursorX, OldCursorY;
if (Console == NULL || Buffer == NULL || Position == NULL)
return STATUS_INVALID_PARAMETER;
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
if ( Position->X < 0 || Position->X >= Buffer->ScreenBufferSize.X ||
Position->Y < 0 || Position->Y >= Buffer->ScreenBufferSize.Y )
{
return STATUS_INVALID_PARAMETER;
}
OldCursorX = Buffer->CursorPosition.X;
OldCursorY = Buffer->CursorPosition.Y;
Buffer->CursorPosition = *Position;
// Buffer->CursorPosition.X = Position->X;
// Buffer->CursorPosition.Y = Position->Y;
if ( ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer) &&
(!ConioSetScreenInfo(Console, (PCONSOLE_SCREEN_BUFFER)Buffer, OldCursorX, OldCursorY)) )
{
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
/* EOF */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,185 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/condrv/dummyfrontend.c
* PURPOSE: Dummy Terminal Front-End used when no frontend
* is attached to the specified console.
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
/* DUMMY FRONTEND INTERFACE ***************************************************/
static NTSTATUS NTAPI
DummyInitFrontEnd(IN OUT PFRONTEND This,
IN PCONSOLE Console)
{
/* Load some settings ?? */
return STATUS_SUCCESS;
}
static VOID NTAPI
DummyDeinitFrontEnd(IN OUT PFRONTEND This)
{
/* Free some settings ?? */
}
static VOID NTAPI
DummyDrawRegion(IN OUT PFRONTEND This,
SMALL_RECT* Region)
{
}
static VOID NTAPI
DummyWriteStream(IN OUT PFRONTEND This,
SMALL_RECT* Region,
SHORT CursorStartX,
SHORT CursorStartY,
UINT ScrolledLines,
PWCHAR Buffer,
UINT Length)
{
}
static BOOL NTAPI
DummySetCursorInfo(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER Buff)
{
return TRUE;
}
static BOOL NTAPI
DummySetScreenInfo(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER Buff,
SHORT OldCursorX,
SHORT OldCursorY)
{
return TRUE;
}
static VOID NTAPI
DummyResizeTerminal(IN OUT PFRONTEND This)
{
}
static BOOL NTAPI
DummyProcessKeyCallback(IN OUT PFRONTEND This,
MSG* msg,
BYTE KeyStateMenu,
DWORD ShiftState,
UINT VirtualKeyCode,
BOOL Down)
{
return FALSE;
}
static VOID NTAPI
DummyRefreshInternalInfo(IN OUT PFRONTEND This)
{
}
static VOID NTAPI
DummyChangeTitle(IN OUT PFRONTEND This)
{
}
static BOOL NTAPI
DummyChangeIcon(IN OUT PFRONTEND This,
HICON hWindowIcon)
{
return TRUE;
}
static HWND NTAPI
DummyGetConsoleWindowHandle(IN OUT PFRONTEND This)
{
return NULL;
}
static VOID NTAPI
DummyGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
PCOORD pSize)
{
}
static ULONG NTAPI
DummyGetDisplayMode(IN OUT PFRONTEND This)
{
return 0;
}
static BOOL NTAPI
DummySetDisplayMode(IN OUT PFRONTEND This,
ULONG NewMode)
{
return TRUE;
}
static INT NTAPI
DummyShowMouseCursor(IN OUT PFRONTEND This,
BOOL Show)
{
return 0;
}
static BOOL NTAPI
DummySetMouseCursor(IN OUT PFRONTEND This,
HCURSOR hCursor)
{
return TRUE;
}
static HMENU NTAPI
DummyMenuControl(IN OUT PFRONTEND This,
UINT cmdIdLow,
UINT cmdIdHigh)
{
return NULL;
}
static BOOL NTAPI
DummySetMenuClose(IN OUT PFRONTEND This,
BOOL Enable)
{
return TRUE;
}
static FRONTEND_VTBL DummyVtbl =
{
DummyInitFrontEnd,
DummyDeinitFrontEnd,
DummyDrawRegion,
DummyWriteStream,
DummySetCursorInfo,
DummySetScreenInfo,
DummyResizeTerminal,
DummyProcessKeyCallback,
DummyRefreshInternalInfo,
DummyChangeTitle,
DummyChangeIcon,
DummyGetConsoleWindowHandle,
DummyGetLargestConsoleWindowSize,
DummyGetDisplayMode,
DummySetDisplayMode,
DummyShowMouseCursor,
DummySetMouseCursor,
DummyMenuControl,
DummySetMenuClose,
};
VOID
ResetFrontEnd(IN PCONSOLE Console)
{
if (!Console) return;
/* Reinitialize the frontend interface */
RtlZeroMemory(&Console->TermIFace, sizeof(Console->TermIFace));
Console->TermIFace.Vtbl = &DummyVtbl;
}
/* EOF */
@@ -0,0 +1,274 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Driver DLL
* FILE: win32ss/user/winsrv/consrv/condrv/graphics.c
* PURPOSE: Console Output Functions for graphics-mode screen-buffers
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*
* NOTE: See http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/
* for more information.
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "conoutput.h"
#include "handle.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
CONSOLE_IO_OBJECT_TYPE
GRAPHICS_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
{
// return This->Header.Type;
return GRAPHICS_BUFFER;
}
static CONSOLE_SCREEN_BUFFER_VTBL GraphicsVtbl =
{
GRAPHICS_BUFFER_GetType,
};
NTSTATUS
CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN SIZE_T Size);
VOID
CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
NTSTATUS
GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN PGRAPHICS_BUFFER_INFO GraphicsInfo)
{
NTSTATUS Status = STATUS_SUCCESS;
PGRAPHICS_SCREEN_BUFFER NewBuffer = NULL;
LARGE_INTEGER SectionSize;
ULONG ViewSize = 0;
HANDLE ProcessHandle;
if (Buffer == NULL || Console == NULL || GraphicsInfo == NULL)
return STATUS_INVALID_PARAMETER;
*Buffer = NULL;
Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
Console,
sizeof(GRAPHICS_SCREEN_BUFFER));
if (!NT_SUCCESS(Status)) return Status;
NewBuffer->Header.Type = GRAPHICS_BUFFER;
NewBuffer->Vtbl = &GraphicsVtbl;
/*
* Remember the handle to the process so that we can close or unmap
* correctly the allocated resources when the client releases the
* screen buffer.
*/
ProcessHandle = CsrGetClientThread()->Process->ProcessHandle;
NewBuffer->ClientProcess = ProcessHandle;
/* Get infos from the graphics buffer information structure */
NewBuffer->BitMapInfoLength = GraphicsInfo->Info.dwBitMapInfoLength;
NewBuffer->BitMapInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, NewBuffer->BitMapInfoLength);
if (NewBuffer->BitMapInfo == NULL)
{
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */
if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight > 0)
GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight = -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight;
/* We do not use anything else than uncompressed bitmaps */
if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression != BI_RGB)
{
DPRINT1("biCompression == %d != BI_RGB, correct that!\n", GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression);
GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression = BI_RGB;
}
RtlCopyMemory(NewBuffer->BitMapInfo,
GraphicsInfo->Info.lpBitMapInfo,
GraphicsInfo->Info.dwBitMapInfoLength);
NewBuffer->BitMapUsage = GraphicsInfo->Info.dwUsage;
/* Set the screen buffer size. Fight against overflows. */
if ( GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth <= 0xFFFF &&
-GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight <= 0xFFFF )
{
/* Be careful about the sign of biHeight */
NewBuffer->ScreenBufferSize.X = (SHORT)GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth ;
NewBuffer->ScreenBufferSize.Y = (SHORT)-GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight;
NewBuffer->OldViewSize = NewBuffer->ViewSize =
NewBuffer->OldScreenBufferSize = NewBuffer->ScreenBufferSize;
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
/*
* Create a mutex to synchronize bitmap memory access
* between ourselves and the client.
*/
Status = NtCreateMutant(&NewBuffer->Mutex, MUTANT_ALL_ACCESS, NULL, FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateMutant() failed: %lu\n", Status);
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
/*
* Duplicate the Mutex for the client. We must keep a trace of it
* so that we can close it when the client releases the screen buffer.
*/
Status = NtDuplicateObject(NtCurrentProcess(),
NewBuffer->Mutex,
ProcessHandle,
&NewBuffer->ClientMutex,
0, 0, DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
NtClose(NewBuffer->Mutex);
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
/*
* Create a memory section for the bitmap area, to share with the client.
*/
SectionSize.QuadPart = NewBuffer->BitMapInfo->bmiHeader.biSizeImage;
Status = NtCreateSection(&NewBuffer->hSection,
SECTION_ALL_ACCESS,
NULL,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status);
NtClose(NewBuffer->ClientMutex);
NtClose(NewBuffer->Mutex);
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
/*
* Create a view for our needs.
*/
ViewSize = 0;
NewBuffer->BitMap = NULL;
Status = NtMapViewOfSection(NewBuffer->hSection,
NtCurrentProcess(),
(PVOID*)&NewBuffer->BitMap,
0,
0,
NULL,
&ViewSize,
ViewUnmap,
0,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status);
NtClose(NewBuffer->hSection);
NtClose(NewBuffer->ClientMutex);
NtClose(NewBuffer->Mutex);
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
/*
* Create a view for the client. We must keep a trace of it so that
* we can unmap it when the client releases the screen buffer.
*/
ViewSize = 0;
NewBuffer->ClientBitMap = NULL;
Status = NtMapViewOfSection(NewBuffer->hSection,
ProcessHandle,
(PVOID*)&NewBuffer->ClientBitMap,
0,
0,
NULL,
&ViewSize,
ViewUnmap,
0,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status);
NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer->BitMap);
NtClose(NewBuffer->hSection);
NtClose(NewBuffer->ClientMutex);
NtClose(NewBuffer->Mutex);
ConsoleFreeHeap(NewBuffer->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
goto Quit;
}
NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
NewBuffer->VirtualY = 0;
NewBuffer->CursorBlinkOn = FALSE;
NewBuffer->ForceCursorOff = TRUE;
NewBuffer->CursorInfo.bVisible = FALSE;
NewBuffer->CursorInfo.dwSize = 0;
NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
NewBuffer->Mode = 0;
*Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
Status = STATUS_SUCCESS;
Quit:
return Status;
}
VOID
GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
{
PGRAPHICS_SCREEN_BUFFER Buff = (PGRAPHICS_SCREEN_BUFFER)Buffer;
/*
* IMPORTANT !! Reinitialize the type so that we don't enter a recursive
* infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
*/
Buffer->Header.Type = SCREEN_BUFFER;
/*
* Uninitialize the graphics screen buffer
* in the reverse way we initialized it.
*/
NtUnmapViewOfSection(Buff->ClientProcess, Buff->ClientBitMap);
NtUnmapViewOfSection(NtCurrentProcess(), Buff->BitMap);
NtClose(Buff->hSection);
NtClose(Buff->ClientMutex);
NtClose(Buff->Mutex);
ConsoleFreeHeap(Buff->BitMapInfo);
CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
}
/* EOF */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,479 @@
/*
* 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 ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "handle.h"
#include "lineinput.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 BOOL 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));
if (!CsrCreateWait(&InputInfo->InputBuffer->ReadWaitQueue,
WaitFunction,
InputInfo->CallingThread,
ApiMessage,
CapturedInputInfo,
NULL))
{
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 BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
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;
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 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 BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
CONSOLE_READCONSOLE_CONTROL ReadControl;
ReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
ReadControl.nInitialChars = ReadConsoleRequest->NrCharactersRead;
ReadControl.dwCtrlWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
ReadControl.dwControlKeyState = ReadConsoleRequest->ControlKeyState;
Status = ConDrvReadConsole(InputBuffer->Header.Console,
InputBuffer,
ReadConsoleRequest->Unicode,
ReadConsoleRequest->Buffer,
&ReadControl,
ReadConsoleRequest->NrCharactersToRead,
&ReadConsoleRequest->NrCharactersRead);
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, we return the error code we were given */
return Status;
// return STATUS_SUCCESS;
}
}
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN BOOL Wait,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
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;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)WaitApiMessage)->Data.GetInputRequest;
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,
GetInputRequest->bRead,
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 WaitForMoreEvents,
IN BOOLEAN Unicode,
OUT PINPUT_RECORD InputRecord,
IN ULONG NumEventsToRead,
OUT PULONG NumEventsRead);
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN BOOL Wait, // TRUE --> Read ; FALSE --> Peek
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
// GetInputRequest->InputsRead = 0;
Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
InputBuffer,
Wait,
GetInputRequest->Unicode,
GetInputRequest->InputRecord,
GetInputRequest->Length,
&GetInputRequest->InputsRead);
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, we return the error code we were given */
return Status;
// return STATUS_SUCCESS;
}
}
/* 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");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadConsoleRequest->Buffer,
ReadConsoleRequest->BufferSize,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
// This member is set by the caller (IntReadConsole in kernel32)
// ReadConsoleRequest->NrCharactersRead = 0;
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 (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetInputRequest->InputRecord,
GetInputRequest->Length,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
GetInputRequest->InputsRead = 0;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
Status = ReadInputBuffer(&InputInfo,
GetInputRequest->bRead,
ApiMessage,
TRUE);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN Unicode,
IN PINPUT_RECORD InputRecord,
IN ULONG NumEventsToWrite,
OUT PULONG NumEventsWritten OPTIONAL);
CSR_API(SrvWriteConsoleInput)
{
NTSTATUS Status;
PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
ULONG NumEventsWritten;
DPRINT("SrvWriteConsoleInput\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteInputRequest->InputRecord,
WriteInputRequest->Length,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteInputRequest->InputHandle,
&InputBuffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
NumEventsWritten = 0;
Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
InputBuffer,
WriteInputRequest->Unicode,
WriteInputRequest->InputRecord,
WriteInputRequest->Length,
&NumEventsWritten);
WriteInputRequest->Length = NumEventsWritten;
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer);
CSR_API(SrvFlushConsoleInputBuffer)
{
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 NumEvents);
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);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleNumberOfInputEvents(InputBuffer->Header.Console,
InputBuffer,
&GetNumInputEventsRequest->NumInputEvents);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return Status;
}
/* EOF */
@@ -0,0 +1,23 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/coninput.h
* PURPOSE: Console Input functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
VOID FASTCALL PurgeInputBuffer(PCONSOLE Console);
VOID NTAPI
ConDrvProcessKey(IN PCONSOLE Console,
IN BOOLEAN Down,
IN UINT VirtualKeyCode,
IN UINT VirtualScanCode,
IN WCHAR UnicodeChar,
IN ULONG ShiftState,
IN BYTE KeyStateCtrl);
/* EOF */
@@ -0,0 +1,793 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/conoutput.c
* PURPOSE: General Console Output Functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "console.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "conoutput.h"
#include "handle.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
/* PUBLIC SERVER APIS *********************************************************/
NTSTATUS NTAPI
ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer,
IN PSMALL_RECT Region);
CSR_API(SrvInvalidateBitMapRect)
{
NTSTATUS Status;
PCONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.InvalidateDIBitsRequest;
PCONSOLE_SCREEN_BUFFER Buffer;
DPRINT("SrvInvalidateBitMapRect\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
InvalidateDIBitsRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvInvalidateBitMapRect(Buffer->Header.Console,
Buffer,
&InvalidateDIBitsRequest->Region);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
OUT PCONSOLE_CURSOR_INFO CursorInfo);
CSR_API(SrvGetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvGetConsoleCursorInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
CursorInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleCursorInfo(Buffer->Header.Console,
Buffer,
&CursorInfoRequest->Info);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCONSOLE_CURSOR_INFO CursorInfo);
CSR_API(SrvSetConsoleCursorInfo)
{
NTSTATUS Status;
PCONSOLE_GETSETCURSORINFO CursorInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CursorInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleCursorInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
CursorInfoRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCursorInfo(Buffer->Header.Console,
Buffer,
&CursorInfoRequest->Info);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCOORD Position);
CSR_API(SrvSetConsoleCursorPosition)
{
NTSTATUS Status;
PCONSOLE_SETCURSORPOSITION SetCursorPositionRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorPositionRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleCursorPosition\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetCursorPositionRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCursorPosition(Buffer->Header.Console,
Buffer,
&SetCursorPositionRequest->Position);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
CSR_API(SrvCreateConsoleScreenBuffer)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PCONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CreateScreenBufferRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
PVOID ScreenBufferInfo = NULL;
TEXTMODE_BUFFER_INFO TextModeInfo = {{80, 25},
DEFAULT_SCREEN_ATTRIB,
DEFAULT_POPUP_ATTRIB ,
TRUE,
CSR_DEFAULT_CURSOR_SIZE};
GRAPHICS_BUFFER_INFO GraphicsInfo;
GraphicsInfo.Info = CreateScreenBufferRequest->GraphicsBufferInfo; // HACK for MSVC
DPRINT("SrvCreateConsoleScreenBuffer\n");
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_TEXTMODE_BUFFER)
{
ScreenBufferInfo = &TextModeInfo;
/*
if (Console->ActiveBuffer)
{
TextModeInfo.ScreenBufferSize = Console->ActiveBuffer->ScreenBufferSize;
if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 80;
if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 25;
TextModeInfo.ScreenAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.ScreenDefaultAttrib;
TextModeInfo.PopupAttrib = Console->ActiveBuffer->ScreenBuffer.TextBuffer.PopupDefaultAttrib;
TextModeInfo.IsCursorVisible = Console->ActiveBuffer->CursorInfo.bVisible;
TextModeInfo.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
}
*/
/*
* This is Windows' behaviour
*/
/* Use the current console size. Regularize it if needed. */
TextModeInfo.ScreenBufferSize = Console->ConsoleSize;
if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 1;
if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 1;
/* If we have an active screen buffer, use its attributes as the new ones */
if (Console->ActiveBuffer && GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib;
TextModeInfo.PopupAttrib = Buffer->PopupDefaultAttrib;
TextModeInfo.IsCursorVisible = Buffer->CursorInfo.bVisible;
TextModeInfo.CursorSize = Buffer->CursorInfo.dwSize;
}
}
else if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
{
/* Get infos from the graphics buffer information structure */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo,
1,
CreateScreenBufferRequest->GraphicsBufferInfo.dwBitMapInfoLength))
{
Status = STATUS_INVALID_PARAMETER;
goto Quit;
}
ScreenBufferInfo = &GraphicsInfo;
/* Initialize shared variables */
CreateScreenBufferRequest->GraphicsBufferInfo.hMutex = GraphicsInfo.Info.hMutex = INVALID_HANDLE_VALUE;
CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap = GraphicsInfo.Info.lpBitMap = NULL;
/* A graphics screen buffer is never inheritable */
CreateScreenBufferRequest->Inheritable = FALSE;
}
Status = ConDrvCreateScreenBuffer(&Buff,
Console,
CreateScreenBufferRequest->ScreenBufferType,
ScreenBufferInfo);
if (!NT_SUCCESS(Status)) goto Quit;
/* Insert the new handle inside the process handles table */
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConSrvInsertObject(ProcessData,
&CreateScreenBufferRequest->OutputHandle,
&Buff->Header,
CreateScreenBufferRequest->Access,
CreateScreenBufferRequest->Inheritable,
CreateScreenBufferRequest->ShareMode);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
if (!NT_SUCCESS(Status)) goto Quit;
if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
{
PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)Buff;
/*
* Initialize the graphics buffer information structure
* and give it back to the client.
*/
CreateScreenBufferRequest->GraphicsBufferInfo.hMutex = Buffer->ClientMutex;
CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap = Buffer->ClientBitMap;
}
Quit:
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer);
CSR_API(SrvSetConsoleActiveScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferRequest;
PCONSOLE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleActiveScreenBuffer\n");
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetScreenBufferRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleActiveScreenBuffer(Buffer->Header.Console,
Buffer);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
/* CSR THREADS FOR WriteConsole ***********************************************/
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
WriteConsoleThread(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;
DPRINT("WriteConsoleThread - 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;
}
Status = DoWriteConsole(WaitApiMessage,
WaitThread,
FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
IN BOOLEAN Unicode,
IN PVOID StringBuffer,
IN ULONG NumCharsToWrite,
OUT PULONG NumCharsWritten OPTIONAL);
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
PTEXTMODE_SCREEN_BUFFER ScreenBuffer;
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process),
WriteConsoleRequest->OutputHandle,
&ScreenBuffer, GENERIC_WRITE, FALSE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvWriteConsole(ScreenBuffer->Header.Console,
ScreenBuffer,
WriteConsoleRequest->Unicode,
WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
&WriteConsoleRequest->NrCharactersWritten);
if (Status == STATUS_PENDING)
{
if (CreateWaitBlock)
{
if (!CsrCreateWait(&ScreenBuffer->Header.Console->WriteWaitQueue,
WriteConsoleThread,
ClientThread,
ApiMessage,
NULL,
NULL))
{
/* Fail */
Status = STATUS_NO_MEMORY;
goto Quit;
}
}
/* Wait until we un-pause the console */
// Status = STATUS_PENDING;
}
Quit:
ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
return Status;
}
/* TEXT OUTPUT APIS ***********************************************************/
NTSTATUS NTAPI
ConDrvReadConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
OUT PCHAR_INFO CharInfo/*Buffer*/,
IN PCOORD BufferSize,
IN PCOORD BufferCoord,
IN OUT PSMALL_RECT ReadRegion);
CSR_API(SrvReadConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvReadConsoleOutput\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputRequest->CharInfo,
ReadOutputRequest->BufferSize.X * ReadOutputRequest->BufferSize.Y,
sizeof(CHAR_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ReadOutputRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvReadConsoleOutput(Buffer->Header.Console,
Buffer,
ReadOutputRequest->Unicode,
ReadOutputRequest->CharInfo,
&ReadOutputRequest->BufferSize,
&ReadOutputRequest->BufferCoord,
&ReadOutputRequest->ReadRegion);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
IN PCHAR_INFO CharInfo/*Buffer*/,
IN PCOORD BufferSize,
IN PCOORD BufferCoord,
IN OUT PSMALL_RECT WriteRegion);
CSR_API(SrvWriteConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvWriteConsoleOutput\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputRequest->CharInfo,
WriteOutputRequest->BufferSize.X * WriteOutputRequest->BufferSize.Y,
sizeof(CHAR_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvWriteConsoleOutput(Buffer->Header.Console,
Buffer,
WriteOutputRequest->Unicode,
WriteOutputRequest->CharInfo,
&WriteOutputRequest->BufferSize,
&WriteOutputRequest->BufferCoord,
&WriteOutputRequest->WriteRegion);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
CSR_API(SrvWriteConsole)
{
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
DPRINT("SrvWriteConsole\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&WriteConsoleRequest->Buffer,
WriteConsoleRequest->BufferSize,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = DoWriteConsole(ApiMessage,
CsrGetClientThread(),
TRUE);
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
NTSTATUS NTAPI
ConDrvReadConsoleOutputString(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
OUT PVOID StringBuffer,
IN ULONG NumCodesToRead,
IN PCOORD ReadCoord,
OUT PCOORD EndCoord,
OUT PULONG CodesRead);
CSR_API(SrvReadConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
DPRINT("SrvReadConsoleOutputString\n");
switch (ReadOutputCodeRequest->CodeType)
{
case CODE_ASCII:
CodeSize = sizeof(CHAR);
break;
case CODE_UNICODE:
CodeSize = sizeof(WCHAR);
break;
case CODE_ATTRIBUTE:
CodeSize = sizeof(WORD);
break;
default:
return STATUS_INVALID_PARAMETER;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadOutputCodeRequest->pCode.pCode,
ReadOutputCodeRequest->NumCodesToRead,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ReadOutputCodeRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvReadConsoleOutputString(Buffer->Header.Console,
Buffer,
ReadOutputCodeRequest->CodeType,
ReadOutputCodeRequest->pCode.pCode,
ReadOutputCodeRequest->NumCodesToRead,
&ReadOutputCodeRequest->ReadCoord,
&ReadOutputCodeRequest->EndCoord,
&ReadOutputCodeRequest->CodesRead);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
IN PVOID StringBuffer,
IN ULONG NumCodesToWrite,
IN PCOORD WriteCoord /*,
OUT PCOORD EndCoord,
OUT PULONG CodesWritten */);
CSR_API(SrvWriteConsoleOutputString)
{
NTSTATUS Status;
PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
ULONG CodeSize;
DPRINT("SrvWriteConsoleOutputString\n");
switch (WriteOutputCodeRequest->CodeType)
{
case CODE_ASCII:
CodeSize = sizeof(CHAR);
break;
case CODE_UNICODE:
CodeSize = sizeof(WCHAR);
break;
case CODE_ATTRIBUTE:
CodeSize = sizeof(WORD);
break;
default:
return STATUS_INVALID_PARAMETER;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteOutputCodeRequest->pCode.pCode,
WriteOutputCodeRequest->Length,
CodeSize))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
WriteOutputCodeRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console,
Buffer,
WriteOutputCodeRequest->CodeType,
WriteOutputCodeRequest->pCode.pCode,
WriteOutputCodeRequest->Length, // NumCodesToWrite,
&WriteOutputCodeRequest->Coord /*, // WriteCoord,
&WriteOutputCodeRequest->EndCoord,
&WriteOutputCodeRequest->NrCharactersWritten */);
// WriteOutputCodeRequest->NrCharactersWritten = Written;
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvFillConsoleOutput(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN CODE_TYPE CodeType,
IN PVOID Code,
IN ULONG NumCodesToWrite,
IN PCOORD WriteCoord /*,
OUT PULONG CodesWritten */);
CSR_API(SrvFillConsoleOutput)
{
NTSTATUS Status;
PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
USHORT CodeType = FillOutputRequest->CodeType;
DPRINT("SrvFillConsoleOutput\n");
if ( (CodeType != CODE_ASCII ) &&
(CodeType != CODE_UNICODE ) &&
(CodeType != CODE_ATTRIBUTE) )
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
FillOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvFillConsoleOutput(Buffer->Header.Console,
Buffer,
CodeType,
&FillOutputRequest->Code,
FillOutputRequest->Length, // NumCodesToWrite,
&FillOutputRequest->Coord /*, // WriteCoord,
&FillOutputRequest->NrCharactersWritten */);
// FillOutputRequest->NrCharactersWritten = Written;
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
OUT PCONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo);
CSR_API(SrvGetConsoleScreenBufferInfo)
{
NTSTATUS Status;
PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvGetConsoleScreenBufferInfo\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ScreenBufferInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleScreenBufferInfo(Buffer->Header.Console,
Buffer,
&ScreenBufferInfoRequest->Info);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN WORD Attribute);
CSR_API(SrvSetConsoleTextAttribute)
{
NTSTATUS Status;
PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleTextAttribute\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetTextAttribRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleTextAttribute(Buffer->Header.Console,
Buffer,
SetTextAttribRequest->Attrib);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCOORD Size);
CSR_API(SrvSetConsoleScreenBufferSize)
{
NTSTATUS Status;
PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvSetConsoleScreenBufferSize\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetScreenBufferSizeRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleScreenBufferSize(Buffer->Header.Console,
Buffer,
&SetScreenBufferSizeRequest->Size);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Unicode,
IN PSMALL_RECT ScrollRectangle,
IN BOOLEAN UseClipRectangle,
IN PSMALL_RECT ClipRectangle OPTIONAL,
IN PCOORD DestinationOrigin,
IN CHAR_INFO FillChar);
CSR_API(SrvScrollConsoleScreenBuffer)
{
NTSTATUS Status;
PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT("SrvScrollConsoleScreenBuffer\n");
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ScrollScreenBufferRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvScrollConsoleScreenBuffer(Buffer->Header.Console,
Buffer,
ScrollScreenBufferRequest->Unicode,
&ScrollScreenBufferRequest->ScrollRectangle,
ScrollScreenBufferRequest->UseClipRectangle,
&ScrollScreenBufferRequest->ClipRectangle,
&ScrollScreenBufferRequest->DestinationOrigin,
ScrollScreenBufferRequest->Fill);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN BOOLEAN Absolute,
IN PSMALL_RECT WindowRect);
CSR_API(SrvSetConsoleWindowInfo)
{
NTSTATUS Status;
PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest;
// PCONSOLE_SCREEN_BUFFER Buffer;
PTEXTMODE_SCREEN_BUFFER Buffer;
DPRINT1("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute,
SetWindowInfoRequest->WindowRect.Left ,
SetWindowInfoRequest->WindowRect.Top ,
SetWindowInfoRequest->WindowRect.Right,
SetWindowInfoRequest->WindowRect.Bottom);
// ConSrvGetScreenBuffer
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetWindowInfoRequest->OutputHandle,
&Buffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleWindowInfo(Buffer->Header.Console,
Buffer,
SetWindowInfoRequest->Absolute,
&SetWindowInfoRequest->WindowRect);
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
/* EOF */
@@ -0,0 +1,46 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/conoutput.h
* PURPOSE: Console Output functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
#define ConSrvGetTextModeBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
(Access), (LockConsole), TEXTMODE_BUFFER)
#define ConSrvGetTextModeBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
(Access), (LockConsole), TEXTMODE_BUFFER)
#define ConSrvGetGraphicsBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
(Access), (LockConsole), GRAPHICS_BUFFER)
#define ConSrvGetGraphicsBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
(Access), (LockConsole), GRAPHICS_BUFFER)
#define ConSrvGetScreenBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
(Access), (LockConsole), SCREEN_BUFFER)
#define ConSrvGetScreenBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
(Access), (LockConsole), SCREEN_BUFFER)
#define ConSrvReleaseScreenBuffer(Buff, IsConsoleLocked) \
ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
NTSTATUS FASTCALL ConDrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
IN OUT PCONSOLE Console,
IN ULONG BufferType,
IN PVOID ScreenBufferInfo);
VOID WINAPI ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
// VOID FASTCALL ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer);
PCONSOLE_SCREEN_BUFFER
ConDrvGetActiveScreenBuffer(IN PCONSOLE Console);
/* EOF */
@@ -0,0 +1,652 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/console.c
* PURPOSE: Console Management Functions
* PROGRAMMERS: Gé van Geldorp
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "handle.h"
#include "procinit.h"
#include "alias.h"
#include "coninput.h"
#include "conoutput.h"
#include "lineinput.h"
#include "include/settings.h"
#include "frontends/gui/guiterm.h"
#ifdef TUITERM_COMPILE
#include "frontends/tui/tuiterm.h"
#endif
#include "include/console.h"
#include "console.h"
#include "resource.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
/***************/
#ifdef TUITERM_COMPILE
NTSTATUS NTAPI
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
NTSTATUS NTAPI
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
#endif
NTSTATUS NTAPI
GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
NTSTATUS NTAPI
GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
/***************/
typedef
NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
typedef
NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
/*
* If we are not in GUI-mode, start the text-mode terminal emulator.
* If we fail, try to start the GUI-mode terminal emulator.
*
* Try to open the GUI-mode terminal emulator. Two cases are possible:
* - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
* failed and we start GUI-mode terminal emulator.
* - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
* succeeded BUT we failed at starting text-mode terminal emulator.
* Then GuiMode was switched to TRUE in order to try to open the GUI-mode
* terminal emulator (Win32k will automatically switch to graphical mode,
* therefore no additional code is needed).
*/
/*
* NOTE: Each entry of the table should be retrieved when loading a front-end
* (examples of the CSR servers which register some data for CSRSS).
*/
struct
{
CHAR FrontEndName[80];
FRONTEND_LOAD FrontEndLoad;
FRONTEND_UNLOAD FrontEndUnload;
} FrontEndLoadingMethods[] =
{
#ifdef TUITERM_COMPILE
{"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd},
#endif
{"GUI", GuiLoadFrontEnd, GuiUnloadFrontEnd},
// {"Not found", 0, NULL}
};
/* PRIVATE FUNCTIONS **********************************************************/
#if 0000
VOID FASTCALL
ConioPause(PCONSOLE Console, UINT Flags)
{
Console->PauseFlags |= Flags;
if (!Console->UnpauseEvent)
Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
VOID FASTCALL
ConioUnpause(PCONSOLE 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);
if (!IsListEmpty(&Console->WriteWaitQueue))
{
CsrDereferenceWait(&Console->WriteWaitQueue);
}
}
}
#endif
NTSTATUS FASTCALL
ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
PCONSOLE* Console,
BOOL LockConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE ProcessConsole;
ASSERT(Console);
*Console = NULL;
// RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConDrvGetConsole(&ProcessConsole, ProcessData->ConsoleHandle, LockConsole);
if (NT_SUCCESS(Status)) *Console = ProcessConsole;
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
}
VOID FASTCALL
ConSrvReleaseConsole(PCONSOLE Console,
BOOL WasConsoleLocked)
{
/* Just call the driver*/
ConDrvReleaseConsole(Console, WasConsoleLocked);
}
NTSTATUS WINAPI
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
OUT PCONSOLE* NewConsole,
IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
IN ULONG ConsoleLeaderProcessId)
{
NTSTATUS Status;
HANDLE ConsoleHandle;
PCONSOLE Console;
CONSOLE_INFO ConsoleInfo;
SIZE_T Length = 0;
ULONG i = 0;
FRONTEND FrontEnd;
if (NewConsole == NULL || ConsoleStartInfo == NULL)
return STATUS_INVALID_PARAMETER;
*NewConsole = NULL;
/*
* Load the console settings
*/
/* 1. Load the default settings */
ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId);
/* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
ConsoleInfo.ConsoleTitle[Length] = L'\0';
/*
* Choose an adequate terminal front-end to load, and load it
*/
Status = STATUS_SUCCESS;
for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i)
{
DPRINT("CONSRV: Trying to load %s terminal emulator...\n", FrontEndLoadingMethods[i].FrontEndName);
Status = FrontEndLoadingMethods[i].FrontEndLoad(&FrontEnd,
&ConsoleInfo,
ConsoleStartInfo,
ConsoleLeaderProcessId);
if (NT_SUCCESS(Status))
{
DPRINT("CONSRV: %s terminal emulator loaded successfully\n", FrontEndLoadingMethods[i].FrontEndName);
break;
}
else
{
DPRINT1("CONSRV: Loading %s terminal emulator failed, Status = 0x%08lx , continuing...\n", FrontEndLoadingMethods[i].FrontEndName, Status);
}
}
if (!NT_SUCCESS(Status))
{
DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
return Status;
}
DPRINT("CONSRV: Frontend initialized\n");
/******************************************************************************/
/*
* 4. Load the remaining console settings via the registry.
*/
if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
{
/*
* Either we weren't created by an app launched via a shell-link,
* or we failed to load shell-link console properties.
* Therefore, load the console infos for the application from the registry.
*/
ConSrvReadUserSettings(&ConsoleInfo, ConsoleLeaderProcessId);
/*
* Now, update them with the properties the user might gave to us
* via the STARTUPINFO structure before calling CreateProcess
* (and which was transmitted via the ConsoleStartInfo structure).
* We therefore overwrite the values read in the registry.
*/
if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
{
ConsoleInfo.ScreenAttrib = (USHORT)ConsoleStartInfo->FillAttribute;
}
if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
{
ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
}
if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
{
// ConsoleInfo.ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx;
ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy;
}
}
/* Set-up the code page */
ConsoleInfo.CodePage = GetOEMCP();
/******************************************************************************/
Status = ConDrvInitConsole(&ConsoleHandle,
&Console,
&ConsoleInfo,
ConsoleLeaderProcessId);
if (!NT_SUCCESS(Status))
{
DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status);
FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
return Status;
}
ASSERT(Console);
DPRINT("Console initialized\n");
Status = ConDrvRegisterFrontEnd(Console, &FrontEnd);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to register frontend to the given console, Status = 0x%08lx\n", Status);
ConDrvDeleteConsole(Console);
FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
return Status;
}
DPRINT("FrontEnd registered\n");
/* Return the newly created console to the caller and a success code too */
*NewConsoleHandle = ConsoleHandle;
*NewConsole = Console;
return STATUS_SUCCESS;
}
VOID WINAPI
ConSrvDeleteConsole(PCONSOLE Console)
{
DPRINT("ConSrvDeleteConsole\n");
/* Just call the driver. ConSrvDeregisterFrontEnd is called on-demand. */
ConDrvDeleteConsole(Console);
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvAllocConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
if (ProcessData->ConsoleHandle != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
1,
sizeof(CONSOLE_START_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
/* Initialize a new Console owned by the Console Leader Process */
Status = ConSrvAllocateConsole(ProcessData,
&AllocConsoleRequest->InputHandle,
&AllocConsoleRequest->OutputHandle,
&AllocConsoleRequest->ErrorHandle,
AllocConsoleRequest->ConsoleStartInfo);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console allocation failed\n");
return Status;
}
/* Return the console handle and the input wait handle to the caller */
AllocConsoleRequest->ConsoleHandle = ProcessData->ConsoleHandle;
AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
/* Set the Property-Dialog and Control-Dispatcher handlers */
ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
return STATUS_SUCCESS;
}
CSR_API(SrvAttachConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
PCSR_PROCESS SourceProcess = NULL; // The parent process.
PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
if (TargetProcessData->ConsoleHandle != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
/* Check whether we try to attach to the parent's console */
if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
{
PROCESS_BASIC_INFORMATION ProcessInfo;
ULONG Length = sizeof(ProcessInfo);
/* Get the real parent's ID */
Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
ProcessBasicInformation,
&ProcessInfo,
Length, &Length);
if (!NT_SUCCESS(Status))
{
DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
return Status;
}
ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
}
/* Lock the source process via its PID */
Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
if (!NT_SUCCESS(Status)) return Status;
SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
if (SourceProcessData->ConsoleHandle == NULL)
{
Status = STATUS_INVALID_HANDLE;
goto Quit;
}
/*
* Inherit the console from the parent,
* if any, otherwise return an error.
*/
Status = ConSrvInheritConsole(TargetProcessData,
SourceProcessData->ConsoleHandle,
TRUE,
&AttachConsoleRequest->InputHandle,
&AttachConsoleRequest->OutputHandle,
&AttachConsoleRequest->ErrorHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console inheritance failed\n");
goto Quit;
}
/* Return the console handle and the input wait handle to the caller */
AttachConsoleRequest->ConsoleHandle = TargetProcessData->ConsoleHandle;
AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
/* Set the Property-Dialog and Control-Dispatcher handlers */
TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
Status = STATUS_SUCCESS;
Quit:
/* Unlock the "source" process and exit */
CsrUnlockProcess(SourceProcess);
return Status;
}
CSR_API(SrvFreeConsole)
{
ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvGetConsoleMode(IN PCONSOLE Console,
IN PCONSOLE_IO_OBJECT Object,
OUT PULONG ConsoleMode);
CSR_API(SrvGetConsoleMode)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
PCONSOLE_IO_OBJECT Object;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ConsoleModeRequest->ConsoleHandle,
&Object, NULL, GENERIC_READ, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleMode(Object->Console, Object,
&ConsoleModeRequest->ConsoleMode);
ConSrvReleaseObject(Object, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleMode(IN PCONSOLE Console,
IN PCONSOLE_IO_OBJECT Object,
IN ULONG ConsoleMode);
CSR_API(SrvSetConsoleMode)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
PCONSOLE_IO_OBJECT Object;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ConsoleModeRequest->ConsoleHandle,
&Object, NULL, GENERIC_WRITE, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleMode(Object->Console, Object,
ConsoleModeRequest->ConsoleMode);
ConSrvReleaseObject(Object, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleTitle(IN PCONSOLE Console,
IN OUT PWCHAR Title,
IN OUT PULONG BufLength);
CSR_API(SrvGetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
TitleRequest->Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
Status = ConDrvGetConsoleTitle(Console,
TitleRequest->Title,
&TitleRequest->Length);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleTitle(IN PCONSOLE Console,
IN PWCHAR Title,
IN ULONG BufLength);
CSR_API(SrvSetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
TitleRequest->Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
Status = ConDrvSetConsoleTitle(Console,
TitleRequest->Title,
TitleRequest->Length);
if (NT_SUCCESS(Status)) ConioChangeTitle(Console);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleCP(IN PCONSOLE Console,
OUT PUINT CodePage,
IN BOOLEAN InputCP);
CSR_API(SrvGetConsoleCP)
{
NTSTATUS Status;
PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
PCONSOLE Console;
DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
ConsoleCPRequest->InputCP ? "Input" : "Output");
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleCP(Console,
&ConsoleCPRequest->CodePage,
ConsoleCPRequest->InputCP);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCP(IN PCONSOLE Console,
IN UINT CodePage,
IN BOOLEAN InputCP);
CSR_API(SrvSetConsoleCP)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
PCONSOLE Console;
DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
ConsoleCPRequest->InputCP ? "Input" : "Output");
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCP(Console,
ConsoleCPRequest->CodePage,
ConsoleCPRequest->InputCP);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleProcessList(IN PCONSOLE Console,
IN OUT PULONG ProcessIdsList,
IN ULONG MaxIdListItems,
OUT PULONG ProcessIdsTotal);
CSR_API(SrvGetConsoleProcessList)
{
NTSTATUS Status;
PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetProcessListRequest->pProcessIds,
GetProcessListRequest->nMaxIds,
sizeof(DWORD)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleProcessList(Console,
GetProcessListRequest->pProcessIds,
GetProcessListRequest->nMaxIds,
&GetProcessListRequest->nProcessIdsTotal);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvGenerateConsoleCtrlEvent)
{
NTSTATUS Status;
PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvConsoleProcessCtrlEvent(Console,
GenerateCtrlEventRequest->ProcessGroup,
GenerateCtrlEventRequest->Event);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
/* EOF */
@@ -0,0 +1,27 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/console.h
* PURPOSE: Console Initialization Functions
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
// FIXME: Fix compilation
struct _CONSOLE;
NTSTATUS WINAPI
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
OUT struct _CONSOLE** /* PCONSOLE* */ NewConsole,
IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
IN ULONG ConsoleLeaderProcessId);
VOID WINAPI ConSrvDeleteConsole(struct _CONSOLE* /* PCONSOLE */ Console);
NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
struct _CONSOLE** /* PCONSOLE* */ Console,
BOOL LockConsole);
VOID FASTCALL ConSrvReleaseConsole(struct _CONSOLE* /* PCONSOLE */ Console,
BOOL WasConsoleLocked);
/* EOF */
@@ -0,0 +1,79 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/consrv.h
* PURPOSE: Main header - Definitions
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#ifndef __CONSRV_H__
#define __CONSRV_H__
#pragma once
/* PSDK/NDK Headers */
#include <stdarg.h>
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winnls.h>
#include <winreg.h>
#include <wincon.h>
#include <winuser.h>
#define NTOS_MODE_USER
#include <ndk/exfuncs.h>
#include <ndk/iofuncs.h>
#include <ndk/mmfuncs.h>
#include <ndk/obfuncs.h>
#include <ndk/psfuncs.h>
#include <ndk/setypes.h>
#include <ndk/rtlfuncs.h>
/* Public Win32K Headers */
#include <ntuser.h>
/* PSEH for SEH Support */
#include <pseh/pseh2.h>
/* CSRSS Header */
#include <csr/csrsrv.h>
/* CONSOLE Headers */
#include <win/console.h>
#include <win/conmsg.h>
/* Heap Helpers */
#include "heap.h"
/* Globals */
extern HINSTANCE ConSrvDllInstance;
#define ConsoleGetPerProcessData(Process) \
((PCONSOLE_PROCESS_DATA)((Process)->ServerData[CONSRV_SERVERDLL_INDEX]))
typedef struct _CONSOLE_PROCESS_DATA
{
LIST_ENTRY ConsoleLink;
PCSR_PROCESS Process; // Process owning this structure.
HANDLE ConsoleEvent;
HANDLE ConsoleHandle;
HANDLE ParentConsoleHandle;
BOOL ConsoleApp; // TRUE if it is a CUI app, FALSE otherwise.
RTL_CRITICAL_SECTION HandleTableLock;
ULONG HandleTableSize;
struct _CONSOLE_IO_HANDLE* /* PCONSOLE_IO_HANDLE */ HandleTable; // Length-varying table
LPTHREAD_START_ROUTINE CtrlDispatcher;
LPTHREAD_START_ROUTINE PropDispatcher; // We hold the property dialog handler there, till all the GUI thingie moves out from CSRSS.
} CONSOLE_PROCESS_DATA, *PCONSOLE_PROCESS_DATA;
#endif // __CONSRV_H__
/* EOF */
@@ -0,0 +1,6 @@
#include <windef.h>
#include <winuser.h>
#include "resource.h"
#include "rsrc.rc"
#include "frontends/frontends.rc"
@@ -0,0 +1,331 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontendctl.c
* PURPOSE: Terminal Front-Ends Control
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "conoutput.h"
#include "console.h"
#include "handle.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
/* PUBLIC SERVER APIS *********************************************************/
/**********************************************************************
* 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 CONSOLE_GETSETHWSTATE object.
* We use the same object to Request.
* NOTE
* ConsoleHwState has the correct size to be compatible
* with NT's, but values are not.
*/
#if 0
static NTSTATUS FASTCALL
SetConsoleHardwareState(PCONSOLE Console, ULONG 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]) */
}
#endif
CSR_API(SrvGetConsoleHardwareState)
{
#if 0
NTSTATUS Status;
PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE Console;
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
HardwareStateRequest->OutputHandle,
&Buff,
GENERIC_READ,
TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
return Status;
}
Console = Buff->Header.Console;
HardwareStateRequest->State = Console->HardwareState;
ConSrvReleaseScreenBuffer(Buff, TRUE);
return Status;
#else
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
#endif
}
CSR_API(SrvSetConsoleHardwareState)
{
#if 0
NTSTATUS Status;
PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE Console;
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
HardwareStateRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
return Status;
}
DPRINT("Setting console hardware state.\n");
Console = Buff->Header.Console;
Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return Status;
#else
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
#endif
}
CSR_API(SrvGetConsoleDisplayMode)
{
NTSTATUS Status;
PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
&Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
GetDisplayModeRequest->DisplayMode = ConioGetDisplayMode(Console);
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleDisplayMode)
{
NTSTATUS Status;
PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetDisplayModeRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
if (ConioSetDisplayMode(Console, SetDisplayModeRequest->DisplayMode))
{
SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize;
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
ConSrvReleaseScreenBuffer(Buff, TRUE);
return Status;
}
CSR_API(SrvGetLargestConsoleWindowSize)
{
NTSTATUS Status;
PCONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetLargestWindowSizeRequest;
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE Console;
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
GetLargestWindowSizeRequest->OutputHandle,
&Buff,
GENERIC_READ,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
ConioGetLargestConsoleWindowSize(Console, &GetLargestWindowSizeRequest->Size);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvShowConsoleCursor)
{
NTSTATUS Status;
PCONSOLE_SHOWCURSOR ShowCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ShowCursorRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ShowCursorRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
ShowCursorRequest->RefCount = ConioShowMouseCursor(Console, ShowCursorRequest->Show);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleCursor)
{
NTSTATUS Status;
BOOL Success;
PCONSOLE_SETCURSOR SetCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
// FIXME: Tests show that this function is used only for graphics screen buffers
// and otherwise it returns false + set last error to invalid handle.
// NOTE: I find that behaviour is ridiculous but ok, let's accept that at the moment...
Status = ConSrvGetGraphicsBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
SetCursorRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
Success = ConioSetMouseCursor(Console, SetCursorRequest->hCursor);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
CSR_API(SrvConsoleMenuControl)
{
NTSTATUS Status;
PCONSOLE_MENUCONTROL MenuControlRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.MenuControlRequest;
PCONSOLE Console;
PCONSOLE_SCREEN_BUFFER Buff;
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
MenuControlRequest->OutputHandle,
&Buff,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
MenuControlRequest->hMenu = ConioMenuControl(Console,
MenuControlRequest->dwCmdIdLow,
MenuControlRequest->dwCmdIdHigh);
ConSrvReleaseScreenBuffer(Buff, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleMenuClose)
{
NTSTATUS Status;
BOOL Success;
PCONSOLE_SETMENUCLOSE SetMenuCloseRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetMenuCloseRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
&Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Success = ConioSetMenuClose(Console, SetMenuCloseRequest->Enable);
ConSrvReleaseConsole(Console, TRUE);
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
CSR_API(SrvGetConsoleWindow)
{
NTSTATUS Status;
PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console);
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleIcon)
{
NTSTATUS Status;
PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon)
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvGetConsoleSelectionInfo)
{
NTSTATUS Status;
PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (NT_SUCCESS(Status))
{
memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
if (Console->Selection.dwFlags != 0)
GetSelectionInfoRequest->Info = Console->Selection;
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
/* EOF */
@@ -0,0 +1,2 @@
#include "gui/guiterm.rc"
@@ -0,0 +1,14 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/consolecpl.h
* PURPOSE: GUI front-end settings management - Header for console.dll
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
#include "include/settings.h"
#include "guisettings.h"
/* EOF */
@@ -0,0 +1,81 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/gui/graphics.c
* PURPOSE: GUI Terminal Front-End - Support for graphics-mode screen-buffers
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/settings.h"
#include "guisettings.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer)
{
/*
* This function supposes that the system clipboard was opened.
*/
// PCONSOLE Console = Buffer->Header.Console;
UNIMPLEMENTED;
}
VOID
GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer)
{
/*
* This function supposes that the system clipboard was opened.
*/
// PCONSOLE Console = Buffer->Header.Console;
UNIMPLEMENTED;
}
VOID
GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
PGUI_CONSOLE_DATA GuiData,
HDC hDC,
PRECT rc)
{
if (Buffer->BitMap == NULL) return;
/* Grab the mutex */
NtWaitForSingleObject(Buffer->Mutex, FALSE, NULL);
/*
* The seventh parameter (YSrc) of SetDIBitsToDevice always designates
* the Y-coordinate of the "lower-left corner" of the image, be the DIB
* in bottom-up or top-down mode.
*/
SetDIBitsToDevice(hDC,
/* Coordinates / size of the repainted rectangle, in the view's frame */
rc->left,
rc->top,
rc->right - rc->left,
rc->bottom - rc->top,
/* Coordinates / size of the corresponding image portion, in the graphics screen-buffer's frame */
Buffer->ViewOrigin.X + rc->left,
Buffer->ViewOrigin.Y + rc->top,
0,
Buffer->ScreenBufferSize.Y, // == Buffer->BitMapInfo->bmiHeader.biHeight
Buffer->BitMap,
Buffer->BitMapInfo,
Buffer->BitMapUsage);
/* Release the mutex */
NtReleaseMutant(Buffer->Mutex, NULL);
}
/* EOF */
@@ -0,0 +1,541 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/gui/guisettings.c
* PURPOSE: GUI Terminal Front-End Settings Management
* PROGRAMMERS: Johannes Anderwald
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/settings.h"
#include "guisettings.h"
#define NDEBUG
#include <debug.h>
VOID GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData);
/* FUNCTIONS ******************************************************************/
BOOL
GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN LPCWSTR ConsoleTitle,
IN DWORD ProcessId)
{
/*****************************************************
* Adapted from ConSrvReadUserSettings in settings.c *
*****************************************************/
BOOL RetVal = FALSE;
HKEY hKey;
DWORD dwNumSubKeys = 0;
DWORD dwIndex;
DWORD dwType;
WCHAR szValueName[MAX_PATH];
DWORD dwValueName;
WCHAR szValue[LF_FACESIZE] = L"\0";
DWORD Value;
DWORD dwValue;
if (!ConSrvOpenUserSettings(ProcessId,
ConsoleTitle,
&hKey, KEY_READ,
FALSE))
{
DPRINT("ConSrvOpenUserSettings failed\n");
return FALSE;
}
if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{
DPRINT("GuiConsoleReadUserSettings: RegQueryInfoKey failed\n");
RegCloseKey(hKey);
return FALSE;
}
DPRINT("GuiConsoleReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
{
dwValue = sizeof(Value);
dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
{
if (dwType == REG_SZ)
{
/*
* Retry in case of string value
*/
dwValue = sizeof(szValue);
dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
break;
}
else
{
break;
}
}
if (!wcscmp(szValueName, L"FaceName"))
{
SIZE_T Length = min(wcslen(szValue) + 1, LF_FACESIZE); // wcsnlen
wcsncpy(TermInfo->FaceName, szValue, LF_FACESIZE);
TermInfo->FaceName[Length] = L'\0';
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"FontFamily"))
{
TermInfo->FontFamily = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"FontSize"))
{
TermInfo->FontSize = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"FontWeight"))
{
TermInfo->FontWeight = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"FullScreen"))
{
TermInfo->FullScreen = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"WindowPosition"))
{
TermInfo->AutoPosition = FALSE;
TermInfo->WindowOrigin.x = LOWORD(Value);
TermInfo->WindowOrigin.y = HIWORD(Value);
RetVal = TRUE;
}
}
RegCloseKey(hKey);
return RetVal;
}
BOOL
GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN LPCWSTR ConsoleTitle,
IN DWORD ProcessId)
{
/******************************************************
* Adapted from ConSrvWriteUserSettings in settings.c *
******************************************************/
BOOL GlobalSettings = (ConsoleTitle[0] == L'\0');
HKEY hKey;
DWORD Storage = 0;
#define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
do { \
if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
{ \
RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
} \
else \
{ \
RegDeleteValue(hKey, (SettingName)); \
} \
} while (0)
if (!ConSrvOpenUserSettings(ProcessId,
ConsoleTitle,
&hKey, KEY_WRITE,
TRUE))
{
return FALSE;
}
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"FontSize", REG_DWORD, sizeof(DWORD), &TermInfo->FontSize, 0);
SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &TermInfo->FontWeight, FW_DONTCARE);
Storage = TermInfo->FullScreen;
SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
if (TermInfo->AutoPosition == FALSE)
{
Storage = MAKELONG(TermInfo->WindowOrigin.x, TermInfo->WindowOrigin.y);
RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
}
else
{
RegDeleteValue(hKey, L"WindowPosition");
}
RegCloseKey(hKey);
return TRUE;
}
VOID
GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN DWORD ProcessId)
{
/*******************************************************
* Adapted from ConSrvGetDefaultSettings in settings.c *
*******************************************************/
if (TermInfo == NULL) return;
/*
* 1. Load the default values
*/
// wcsncpy(TermInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
// TermInfo->FontSize = MAKELONG(12, 8); // 0x0008000C; // font is 8x12
// TermInfo->FontSize = MAKELONG(16, 16); // font is 16x16
// TermInfo->FontWeight = FW_NORMAL;
wcsncpy(TermInfo->FaceName, L"Fixedsys", LF_FACESIZE); // HACK: !!
// TermInfo->FaceName[0] = L'\0';
TermInfo->FontFamily = FF_DONTCARE;
TermInfo->FontSize = 0;
TermInfo->FontWeight = FW_DONTCARE;
TermInfo->UseRasterFonts = TRUE;
TermInfo->FullScreen = FALSE;
TermInfo->ShowWindow = SW_SHOWNORMAL;
TermInfo->AutoPosition = TRUE;
TermInfo->WindowOrigin.x = 0;
TermInfo->WindowOrigin.y = 0;
/*
* 2. Overwrite them with the ones stored in HKCU\Console.
* If the HKCU\Console key doesn't exist, create it
* and store the default values inside.
*/
if (!GuiConsoleReadUserSettings(TermInfo, L"", ProcessId))
{
GuiConsoleWriteUserSettings(TermInfo, L"", ProcessId);
}
}
VOID
GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
BOOL Defaults)
{
NTSTATUS Status;
PCONSOLE Console = GuiData->Console;
PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
PCONSOLE_PROCESS_DATA ProcessData;
HANDLE hSection = NULL, hClientSection = NULL;
LARGE_INTEGER SectionSize;
ULONG ViewSize = 0;
SIZE_T Length = 0;
PCONSOLE_PROPS pSharedInfo = NULL;
PGUI_CONSOLE_INFO GuiInfo = NULL;
DPRINT("GuiConsoleShowConsoleProperties entered\n");
/*
* Create a memory section to share with the applet, and map it.
*/
/* Holds data for console.dll + console info + terminal-specific info */
SectionSize.QuadPart = sizeof(CONSOLE_PROPS) + sizeof(GUI_CONSOLE_INFO);
Status = NtCreateSection(&hSection,
SECTION_ALL_ACCESS,
NULL,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status);
return;
}
Status = NtMapViewOfSection(hSection,
NtCurrentProcess(),
(PVOID*)&pSharedInfo,
0,
0,
NULL,
&ViewSize,
ViewUnmap,
0,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status);
NtClose(hSection);
return;
}
/*
* Setup the shared console properties structure.
*/
/* Header */
pSharedInfo->hConsoleWindow = GuiData->hWindow;
pSharedInfo->ShowDefaultParams = Defaults;
/*
* We fill-in the fields only if we display
* our properties, not the default ones.
*/
if (!Defaults)
{
/* Console information */
pSharedInfo->ci.HistoryBufferSize = Console->HistoryBufferSize;
pSharedInfo->ci.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
pSharedInfo->ci.HistoryNoDup = Console->HistoryNoDup;
pSharedInfo->ci.QuickEdit = Console->QuickEdit;
pSharedInfo->ci.InsertMode = Console->InsertMode;
pSharedInfo->ci.InputBufferSize = 0;
pSharedInfo->ci.ScreenBufferSize = ActiveBuffer->ScreenBufferSize;
pSharedInfo->ci.ConsoleSize = ActiveBuffer->ViewSize;
pSharedInfo->ci.CursorBlinkOn;
pSharedInfo->ci.ForceCursorOff;
pSharedInfo->ci.CursorSize = ActiveBuffer->CursorInfo.dwSize;
if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer;
pSharedInfo->ci.ScreenAttrib = Buffer->ScreenDefaultAttrib;
pSharedInfo->ci.PopupAttrib = Buffer->PopupDefaultAttrib;
}
else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
{
// PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer;
DPRINT1("GuiConsoleShowConsoleProperties - Graphics buffer\n");
// FIXME: Gather defaults from the registry ?
pSharedInfo->ci.ScreenAttrib = DEFAULT_SCREEN_ATTRIB;
pSharedInfo->ci.PopupAttrib = DEFAULT_POPUP_ATTRIB ;
}
pSharedInfo->ci.CodePage;
/* GUI Information */
pSharedInfo->TerminalInfo.Size = sizeof(GUI_CONSOLE_INFO);
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);
GuiInfo->FaceName[Length] = L'\0';
GuiInfo->FontFamily = GuiData->GuiInfo.FontFamily;
GuiInfo->FontSize = GuiData->GuiInfo.FontSize;
GuiInfo->FontWeight = GuiData->GuiInfo.FontWeight;
GuiInfo->UseRasterFonts = GuiData->GuiInfo.UseRasterFonts;
GuiInfo->FullScreen = GuiData->GuiInfo.FullScreen;
/// GuiInfo->WindowPosition = GuiData->GuiInfo.WindowPosition;
GuiInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
GuiInfo->WindowOrigin = GuiData->GuiInfo.WindowOrigin;
/* Offsetize */
pSharedInfo->TerminalInfo.TermInfo = (PVOID)((ULONG_PTR)GuiInfo - (ULONG_PTR)pSharedInfo);
/* Palette */
memcpy(pSharedInfo->ci.Colors, Console->Colors, sizeof(Console->Colors));
/* Title of the console, original one corresponding to the one set by the console leader */
Length = min(sizeof(pSharedInfo->ci.ConsoleTitle) / sizeof(pSharedInfo->ci.ConsoleTitle[0]) - 1,
Console->OriginalTitle.Length / sizeof(WCHAR));
wcsncpy(pSharedInfo->ci.ConsoleTitle, Console->OriginalTitle.Buffer, Length);
}
else
{
Length = 0;
// FIXME: Load the default parameters from the registry.
}
/* Null-terminate the title */
pSharedInfo->ci.ConsoleTitle[Length] = L'\0';
/* Unmap the view */
NtUnmapViewOfSection(NtCurrentProcess(), pSharedInfo);
/* Get the console leader process, our client */
ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
/* Duplicate the section handle for the client */
Status = NtDuplicateObject(NtCurrentProcess(),
hSection,
ProcessData->Process->ProcessHandle,
&hClientSection,
0, 0, DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Impossible to duplicate section handle for client ; Status = %lu\n", Status);
goto Quit;
}
/* Start the properties dialog */
if (ProcessData->PropDispatcher)
{
_SEH2_TRY
{
HANDLE Thread = NULL;
_SEH2_TRY
{
Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
ProcessData->PropDispatcher,
(PVOID)hClientSection, 0, NULL);
if (NULL == Thread)
{
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
}
else
{
DPRINT("ProcessData->PropDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
/// WaitForSingleObject(Thread, INFINITE);
}
}
_SEH2_FINALLY
{
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 */
NtClose(hSection);
return;
}
NTSTATUS
GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
HANDLE hClientSection,
BOOL SaveSettings)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE Console = GuiData->Console;
PCONSOLE_PROCESS_DATA ProcessData;
HANDLE hSection = NULL;
ULONG ViewSize = 0;
PCONSOLE_PROPS pConInfo = NULL;
PCONSOLE_INFO ConInfo = NULL;
PTERMINAL_INFO TermInfo = NULL;
PGUI_CONSOLE_INFO GuiInfo = NULL;
/* Get the console leader process, our client */
ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
/* Duplicate the section handle for ourselves */
Status = NtDuplicateObject(ProcessData->Process->ProcessHandle,
hClientSection,
NtCurrentProcess(),
&hSection,
0, 0, DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error when mapping client handle, Status = %lu\n", Status);
return Status;
}
/* Get a view of the shared section */
Status = NtMapViewOfSection(hSection,
NtCurrentProcess(),
(PVOID*)&pConInfo,
0,
0,
NULL,
&ViewSize,
ViewUnmap,
0,
PAGE_READONLY);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error when mapping view of file, Status = %lu\n", Status);
NtClose(hSection);
return Status;
}
_SEH2_TRY
{
/* Check that the section is well-sized */
if ( (ViewSize < sizeof(CONSOLE_PROPS)) ||
(pConInfo->TerminalInfo.Size != sizeof(GUI_CONSOLE_INFO)) ||
(ViewSize < sizeof(CONSOLE_PROPS) + pConInfo->TerminalInfo.Size) )
{
DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_PROPS) + sizeof(Terminal_specific_info)\n");
Status = STATUS_INVALID_VIEW_SIZE;
_SEH2_YIELD(goto Quit);
}
// TODO: Check that GuiData->hWindow == pConInfo->hConsoleWindow
/* Retrieve terminal informations */
ConInfo = &pConInfo->ci;
TermInfo = &pConInfo->TerminalInfo;
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));
/* Move the window to the user's values */
GuiData->GuiInfo.AutoPosition = GuiInfo->AutoPosition;
GuiData->GuiInfo.WindowOrigin = GuiInfo->WindowOrigin;
GuiConsoleMoveWindow(GuiData);
InvalidateRect(GuiData->hWindow, NULL, TRUE);
/*
* Apply full-screen mode.
*/
GuiData->GuiInfo.FullScreen = GuiInfo->FullScreen;
// TODO: Apply it really
}
/*
* Save settings if needed
*/
// FIXME: Do it in the console properties applet ??
if (SaveSettings)
{
DWORD ProcessId = HandleToUlong(ProcessData->Process->ClientId.UniqueProcess);
ConSrvWriteUserSettings(ConInfo, ProcessId);
GuiConsoleWriteUserSettings(GuiInfo, ConInfo->ConsoleTitle, ProcessId);
}
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
DPRINT1("GuiApplyUserSettings - Caught an exception, Status = %08X\n", Status);
}
_SEH2_END;
Quit:
/* Finally, close the section and return */
NtUnmapViewOfSection(NtCurrentProcess(), pConInfo);
NtClose(hSection);
return Status;
}
/* EOF */
@@ -0,0 +1,94 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/guisettings.h
* PURPOSE: GUI front-end settings management
* PROGRAMMERS: Johannes Anderwald
* Hermes Belusca-Maito ([email protected])
*
* NOTE: Also used by console.dll
*/
#pragma once
#ifndef WM_APP
#define WM_APP 0x8000
#endif
#define PM_APPLY_CONSOLE_INFO (WM_APP + 100)
/* STRUCTURES *****************************************************************/
typedef struct _GUI_CONSOLE_INFO
{
// FONTSIGNATURE FontSignature;
WCHAR FaceName[LF_FACESIZE];
UINT FontFamily;
DWORD FontSize;
DWORD FontWeight;
BOOL UseRasterFonts;
BOOL FullScreen; /* Whether the console is displayed in full-screen or windowed mode */
// ULONG HardwareState; /* _GDI_MANAGED, _DIRECT */
WORD ShowWindow;
BOOL AutoPosition;
POINT WindowOrigin;
} GUI_CONSOLE_INFO, *PGUI_CONSOLE_INFO;
#ifndef CONSOLE_H__ // If we aren't included by console.dll
typedef struct _GUI_CONSOLE_DATA
{
CRITICAL_SECTION Lock;
HANDLE hGuiInitEvent;
BOOL WindowSizeLock;
POINT OldCursor;
HWND hWindow; /* Handle to the console's window */
HICON hIcon; /* Handle to the console's icon (big) */
HICON hIconSm; /* Handle to the console's icon (small) */
HCURSOR hCursor; /* Handle to the mouse cursor */
INT MouseCursorRefCount; /* The reference counter associated with the mouse cursor. >= 0 and the cursor is shown; < 0 and the cursor is hidden. */
BOOL IgnoreNextMouseSignal; /* Used in cases where we don't want to treat a mouse signal */
BOOL IsCloseButtonEnabled; /* TRUE if the Close button and the corresponding system menu item are enabled (default), FALSE otherwise */
UINT cmdIdLow ; /* Lowest menu id of the user-reserved menu id range */
UINT cmdIdHigh; /* Highest menu id of the user-reserved menu id range */
// COLORREF Colors[16];
// PVOID ScreenBuffer; /* Hardware screen buffer */
HFONT Font;
UINT CharWidth;
UINT CharHeight;
PCONSOLE Console; /* Pointer to the owned console */
GUI_CONSOLE_INFO GuiInfo; /* GUI terminal settings */
} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
/* FUNCTIONS ******************************************************************/
BOOL
GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN LPCWSTR ConsoleTitle,
IN DWORD ProcessId);
BOOL
GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN LPCWSTR ConsoleTitle,
IN DWORD ProcessId);
VOID
GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo,
IN DWORD ProcessId);
VOID
GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
BOOL Defaults);
NTSTATUS
GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
HANDLE hClientSection,
BOOL SaveSettings);
#endif
/* EOF */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.h
* PURPOSE: GUI Terminal Front-End
* PROGRAMMERS: Gé van Geldorp
* Johannes Anderwald
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
#define CONGUI_MIN_WIDTH 10
#define CONGUI_MIN_HEIGHT 10
#define CONGUI_UPDATE_TIME 0
#define CONGUI_UPDATE_TIMER 1
#define CURSOR_BLINK_TIME 500
NTSTATUS FASTCALL GuiInitConsole(PCONSOLE Console,
/*IN*/ PCONSOLE_START_INFO ConsoleStartInfo,
PCONSOLE_INFO ConsoleInfo,
DWORD ProcessId,
LPCWSTR IconPath,
INT IconIndex);
/* EOF */
@@ -0,0 +1,16 @@
#include <windef.h>
#include <winuser.h>
#include "resource.h"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// #define REACTOS_VERSION_DLL
// #define REACTOS_STR_FILE_DESCRIPTION "ReactOS Console Server & Terminal Emulator DLL"
// #define REACTOS_STR_INTERNAL_NAME "consrv"
// #define REACTOS_STR_ORIGINAL_FILENAME "consrv.dll"
// #include <reactos/version.rc>
// IDI_TERMINAL ICON DISCARDABLE "res/terminal.ico"
IDI_TERMINAL ICON DISCARDABLE "frontends/gui/res/terminal.ico"
#include "rsrc.rc"
@@ -0,0 +1,32 @@
/*
* PROJECT: ReactOS CSRSS subsystem
* FILE: win32ss/user/winsrv/consrv/lang/bg-BG.rc
* PURPOSE: Bulgarian resource file
*/
LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Обработка"
IDS_MARK "Отбелязване"
IDS_COPY "Запомняне\tEnter"
IDS_PASTE "Поставяне"
IDS_SELECTALL "Избор на всичко"
IDS_SCROLL "Прелистване"
IDS_FIND "Търсене..."
IDS_DEFAULTS "Подразбирани"
IDS_PROPERTIES "Свойства"
/*
IDS_SCROLLHERE "Прелистване тук"
IDS_SCROLLTOP "Прелистване до горе"
IDS_SCROLLBOTTOM "Прелистване до долу"
IDS_SCROLLPAGE_UP "Горна страница"
IDS_SCROLLPAGE_DOWN "Долна страница"
IDS_SCROLLUP "Прелистване нагоре"
IDS_SCROLLDOWN "Прелистване надолу"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,32 @@
/*
* FILE: win32ss/user/winsrv/consrv/lang/cs-CZ.rc
* TRANSLATOR: Radek Liska aka Black_Fox (radekliska at gmail dot com)
* UPDATED: 2011-04-09
*/
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Upravit"
IDS_MARK "Označit"
IDS_COPY "Kopírovat\tEnter"
IDS_PASTE "Vložit"
IDS_SELECTALL "Označit vše"
IDS_SCROLL "Posunout"
IDS_FIND "Najít..."
IDS_DEFAULTS "Výchozí"
IDS_PROPERTIES "Vlastnosti"
/*
IDS_SCROLLHERE "Posunout sem"
IDS_SCROLLTOP "Posunout na začátek"
IDS_SCROLLBOTTOM "Posunout na konec"
IDS_SCROLLPAGE_UP "O stránku výše"
IDS_SCROLLPAGE_DOWN "O stránku níže"
IDS_SCROLLUP "Posunout nahoru"
IDS_SCROLLDOWN "Posunout dolů"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Bearbeiten"
IDS_MARK "Markieren"
IDS_COPY "Kopieren\tEnter"
IDS_PASTE "Einfügen"
IDS_SELECTALL "Alles auswählen"
IDS_SCROLL "Scrollen"
IDS_FIND "Suchen..."
IDS_DEFAULTS "Standardwerte"
IDS_PROPERTIES "Eigenschaften"
/*
IDS_SCROLLHERE "Hier scrollen"
IDS_SCROLLTOP "Ganz nach oben scrollen"
IDS_SCROLLBOTTOM "Ganz nach unten scrollen"
IDS_SCROLLPAGE_UP "Seite nach oben"
IDS_SCROLLPAGE_DOWN "Seite nach unten"
IDS_SCROLLUP "Nach oben scrollen"
IDS_SCROLLDOWN "Nach unten scrollen"
*/
IDS_TERMINAL_TITLE "ReactOS Eingabeaufforderung"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Επεξεργασία"
IDS_MARK "Μαρκάρισμα"
IDS_COPY "Αντιγραφή\tEnter"
IDS_PASTE "Επικόλληση"
IDS_SELECTALL "Επιλογή όλων"
IDS_SCROLL "Κύλιση"
IDS_FIND "Εύρεση..."
IDS_DEFAULTS "Προεπιλογή"
IDS_PROPERTIES "Ιδιότητες"
/*
IDS_SCROLLHERE "Κύλιση εδώ"
IDS_SCROLLTOP "Αρχή"
IDS_SCROLLBOTTOM "Τέλος"
IDS_SCROLLPAGE_UP "Προηγούμενη σελίδα"
IDS_SCROLLPAGE_DOWN "Επόμενη σελίδα"
IDS_SCROLLUP "Κύλιση πάνω"
IDS_SCROLLDOWN "Κύλιση κάτω"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
BEGIN
IDS_EDIT "Edit"
IDS_MARK "Mark"
IDS_COPY "Copy\tEnter"
IDS_PASTE "Paste"
IDS_SELECTALL "Select All"
IDS_SCROLL "Scroll"
IDS_FIND "Find..."
IDS_DEFAULTS "Defaults"
IDS_PROPERTIES "Properties"
/*
IDS_SCROLLHERE "Scroll here"
IDS_SCROLLTOP "Scroll top"
IDS_SCROLLBOTTOM "Scroll bottom"
IDS_SCROLLPAGE_UP "Page up"
IDS_SCROLLPAGE_DOWN "Page down"
IDS_SCROLLUP "Scroll up"
IDS_SCROLLDOWN "Scroll down"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,31 @@
/*
* Spanish Language resource file
* Traducido por: Javier Remacha 2008-26-01
*/
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Editar"
IDS_MARK "Marcar"
IDS_COPY "Copiar\tIntroducir"
IDS_PASTE "Pegar"
IDS_SELECTALL "Seleccionar Todo"
IDS_SCROLL "Desplazar"
IDS_FIND "Buscar..."
IDS_DEFAULTS "Por defecto"
IDS_PROPERTIES "Propiedades"
/*
IDS_SCROLLHERE "Desplazar aquí"
IDS_SCROLLTOP "Desplazar hasta arriba"
IDS_SCROLLBOTTOM "Desplazar hasta abajo"
IDS_SCROLLPAGE_UP "Subir página"
IDS_SCROLLPAGE_DOWN "Bajar página"
IDS_SCROLLUP "Desplazar arriba"
IDS_SCROLLDOWN "Desplazar abajo"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,28 @@
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
/* Fixme : Translation could be really improved, with context
La traduction pourrait réellement être améliorée grâce au contexte */
STRINGTABLE
BEGIN
IDS_EDIT "Éditer"
IDS_MARK "Marquer"
IDS_COPY "Copier\tEntrée"
IDS_PASTE "Coller"
IDS_SELECTALL "Tout sélectionner"
IDS_SCROLL "Défiler"
IDS_FIND "Trouver..."
IDS_DEFAULTS "Défauts"
IDS_PROPERTIES "Propriétés"
/*
IDS_SCROLLHERE "Défiler ici"
IDS_SCROLLTOP "Défiler tout en haut"
IDS_SCROLLBOTTOM "Défiler tout en bas"
IDS_SCROLLPAGE_UP "Page précédente"
IDS_SCROLLPAGE_DOWN "Page suivante"
IDS_SCROLLUP "Défiler en haut"
IDS_SCROLLDOWN "Défiler en bas"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_HEBREW, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "ערוך"
IDS_MARK "סמן"
IDS_COPY "העתק\tEnter"
IDS_PASTE "הדבק"
IDS_SELECTALL "בחר הכל"
IDS_SCROLL "גלול"
IDS_FIND "מצא..."
IDS_DEFAULTS "ברירת מחדל"
IDS_PROPERTIES "מאפיינים"
/*
IDS_SCROLLHERE "גלול לכאן"
IDS_SCROLLTOP "גלול למעלה"
IDS_SCROLLBOTTOM "גלול למטה"
IDS_SCROLLPAGE_UP "עמוד מעלה"
IDS_SCROLLPAGE_DOWN "עמוד מטה"
IDS_SCROLLUP "גלול מעלה"
IDS_SCROLLDOWN "גלול מטה"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_INDONESIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Edit"
IDS_MARK "Tandai"
IDS_COPY "Copy\tEnter"
IDS_PASTE "Paste"
IDS_SELECTALL "Pilih Semua"
IDS_SCROLL "Gulung"
IDS_FIND "Cari..."
IDS_DEFAULTS "Standar"
IDS_PROPERTIES "Properti"
/*
IDS_SCROLLHERE "Gulung ke Sini"
IDS_SCROLLTOP "Gulung ke Atas"
IDS_SCROLLBOTTOM "Gulung ke Bawah"
IDS_SCROLLPAGE_UP "Halaman Naik"
IDS_SCROLLPAGE_DOWN "Halaman Turun"
IDS_SCROLLUP "Gulung Naik"
IDS_SCROLLDOWN "Gulung Turun"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,35 @@
/*
* PROJECT: ReactOS Client/Server Runtime subsystem
* LICENSE: GPL - See COPYING in the top level directory
* FILE: win32ss/user/winsrv/consrv/lang/it-IT.rc
* PURPOSE: Italian Translation
* PROGRAMMERS:
* Copyright (C) 2007 Daniele Forsi (dforsi at gmail.com) Italian Translation
*/
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Modifica"
IDS_MARK "Seleziona"
IDS_COPY "Copia\tInvio"
IDS_PASTE "Incolla"
IDS_SELECTALL "Seleziona tutto"
IDS_SCROLL "Scorri"
IDS_FIND "Trova..."
IDS_DEFAULTS "Impostazioni predefinite"
IDS_PROPERTIES "Proprietà"
/*
IDS_SCROLLHERE "Scorri qui"
IDS_SCROLLTOP "Scorri in cima"
IDS_SCROLLBOTTOM "Scorri in fondo"
IDS_SCROLLPAGE_UP "Pagina sù"
IDS_SCROLLPAGE_DOWN "Pagina giù"
IDS_SCROLLUP "Scorri sù"
IDS_SCROLLDOWN "Scorri giù"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "編集"
IDS_MARK "範囲指定"
IDS_COPY "コピー\tEnter"
IDS_PASTE "貼り付け"
IDS_SELECTALL "すべて選択"
IDS_SCROLL "スクロール"
IDS_FIND "検索..."
IDS_DEFAULTS "規定値"
IDS_PROPERTIES "プロパティ"
/*
IDS_SCROLLHERE "ここにスクロール"
IDS_SCROLLTOP "一番上にスクロール"
IDS_SCROLLBOTTOM "一番下にスクロール"
IDS_SCROLLPAGE_UP "Page up"
IDS_SCROLLPAGE_DOWN "Page down"
IDS_SCROLLUP "上にスクロール"
IDS_SCROLLDOWN "下にスクロール"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Rediger"
IDS_MARK "Merk"
IDS_COPY "Kopier\tEnter"
IDS_PASTE "Lim inn"
IDS_SELECTALL "Velg alt"
IDS_SCROLL "Rull"
IDS_FIND "Finn..."
IDS_DEFAULTS "Standard"
IDS_PROPERTIES "Egenskaper"
/*
IDS_SCROLLHERE "Rull her"
IDS_SCROLLTOP "Rull til toppen"
IDS_SCROLLBOTTOM "Rull knapp"
IDS_SCROLLPAGE_UP "Side opp"
IDS_SCROLLPAGE_DOWN "Side ned"
IDS_SCROLLUP "Rull opp"
IDS_SCROLLDOWN "Rull ned"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,34 @@
/*
* translated by xrogers
* [email protected]
* https://sourceforge.net/projects/reactospl
* translation update by Olaf Siejka (Caemyr), Apr 2011
* UTF-8 conversion by Caemyr (May, 2011)
*/
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Edytuj"
IDS_MARK "Zaznacz"
IDS_COPY "Kopiuj\tWejdź"
IDS_PASTE "Wklej"
IDS_SELECTALL "Zaznacz wszystko"
IDS_SCROLL "Przewiń"
IDS_FIND "Znajdź..."
IDS_DEFAULTS "Ustawienia domyślne"
IDS_PROPERTIES "Właściwości"
/*
IDS_SCROLLHERE "Przewiń tutaj"
IDS_SCROLLTOP "Przewiń na początek"
IDS_SCROLLBOTTOM "Przewiń na koniec"
IDS_SCROLLPAGE_UP "Poprzednia strona"
IDS_SCROLLPAGE_DOWN "Następna strona"
IDS_SCROLLUP "Przewiń do góry"
IDS_SCROLLDOWN "Przewiń na dół"
*/
IDS_TERMINAL_TITLE "Konsola ReactOS"
END
@@ -0,0 +1,28 @@
/* Translation and UTF-8 Conversion by mkbu95 <[email protected]> (May, 2012) */
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Editar"
IDS_MARK "Marcar"
IDS_COPY "Copiar\tEnter"
IDS_PASTE "Colar"
IDS_SELECTALL "Selecionar Tudo"
IDS_SCROLL "Rolar"
IDS_FIND "Procurar..."
IDS_DEFAULTS "Padrões"
IDS_PROPERTIES "Propriedades"
/*
IDS_SCROLLHERE "Rolar aqui"
IDS_SCROLLTOP "Rolar até o topo"
IDS_SCROLLBOTTOM "Rolar até o fim"
IDS_SCROLLPAGE_UP "Page up"
IDS_SCROLLPAGE_DOWN "Page down"
IDS_SCROLLUP "Scroll up"
IDS_SCROLLDOWN "Scroll down"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,33 @@
/*
* FILE: win32ss/user/winsrv/consrv/lang/ro-RO.rc
* ReactOS Project (http://www.reactos.org)
* TRANSLATOR: Fulea Ștefan (PM on ReactOS Forum at fulea.stefan)
* CHANGE LOG: 2011-10-16 initial translation
*/
LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Editare"
IDS_MARK "Marchează"
IDS_COPY "Copiază\tEnter"
IDS_PASTE "Lipește"
IDS_SELECTALL "Selectează tot"
IDS_SCROLL "Derulează"
IDS_FIND "Găsire…"
IDS_DEFAULTS "Implicite"
IDS_PROPERTIES "Proprietăți"
/*
IDS_SCROLLHERE "Derulează aici"
IDS_SCROLLTOP "Derulează la început"
IDS_SCROLLBOTTOM "Derulează la sfârșit"
IDS_SCROLLPAGE_UP "Pagina anterioară"
IDS_SCROLLPAGE_DOWN "Pagina următoare"
IDS_SCROLLUP "Derulează în sus"
IDS_SCROLLDOWN "Derulează în jos"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Изменить"
IDS_MARK "Пометить"
IDS_COPY "Копировать\tEnter"
IDS_PASTE "Вставить"
IDS_SELECTALL "Выделить все"
IDS_SCROLL "Прокрутить"
IDS_FIND "Искать..."
IDS_DEFAULTS "Умолчания"
IDS_PROPERTIES "Свойства"
/*
IDS_SCROLLHERE "Scroll Here"
IDS_SCROLLTOP "Scroll Top"
IDS_SCROLLBOTTOM "Прокрутить вниз"
IDS_SCROLLPAGE_UP "Вверх страницы"
IDS_SCROLLPAGE_DOWN "Вниз страницы"
IDS_SCROLLUP "Прокрутить вверх"
IDS_SCROLLDOWN "Scroll Down"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,31 @@
/* TRANSLATOR: Mário Kačmár /Mario Kacmar/ aka Kario ([email protected])
* DATE OF TR: 29-05-2008
* LastChange: 12-04-2011
*/
LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Upraviť"
IDS_MARK "Označiť"
IDS_COPY "Kopírovať\tEnter"
IDS_PASTE "Vložiť"
IDS_SELECTALL "Vybrať všetko"
IDS_SCROLL "Rolovať"
IDS_FIND "Nájsť..." // Find
IDS_DEFAULTS "Predvolené" // Defaults
IDS_PROPERTIES "Vlastnosti"
/*
IDS_SCROLLHERE "Rolovať sem"
IDS_SCROLLTOP "K hornému okraju"
IDS_SCROLLBOTTOM "K dolnému okraju"
IDS_SCROLLPAGE_UP "O stránku vyššie"
IDS_SCROLLPAGE_DOWN "O stránku nižšie"
IDS_SCROLLUP "Rolovať nahor"
IDS_SCROLLDOWN "Rolovať nadol"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,33 @@
/*
* PROJECT: ReactOS CSRSS subsystem
* FILE: win32ss/user/winsrv/consrv/lang/sv-SE.rc
* PURPOSE: Swedish resource file
* Translation: Jaix Bly
*/
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_EDIT "Redigera"
IDS_MARK "Markera"
IDS_COPY "Kopiera\tEnter"
IDS_PASTE "Klistra in"
IDS_SELECTALL "Markera Allt"
IDS_SCROLL "Skrolla"
IDS_FIND "Sök..."
IDS_DEFAULTS "Ursprunglig"
IDS_PROPERTIES "Egenskaper"
/*
IDS_SCROLLHERE "Skrolla hit"
IDS_SCROLLTOP "Skrolla till topp"
IDS_SCROLLBOTTOM "Skrolla till botten"
IDS_SCROLLPAGE_UP "Sida upp"
IDS_SCROLLPAGE_DOWN "Sida ner"
IDS_SCROLLUP "Skrolla upp"
IDS_SCROLLDOWN "Skrolla ner"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,46 @@
/*
* Turkish resources
*
* Copyright 2012 Arda Tanrikulu <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Düzenle"
IDS_MARK "İşaretle"
IDS_COPY "Kopyala\tEnter"
IDS_PASTE "Yapıştır"
IDS_SELECTALL "Tümünü Seç"
IDS_SCROLL "Yuvarla"
IDS_FIND "Bul..."
IDS_DEFAULTS "Varsayılanlar"
IDS_PROPERTIES "Özellikler"
/*
IDS_SCROLLHERE "Buraya yuvarla"
IDS_SCROLLTOP "Üste yuvarla"
IDS_SCROLLBOTTOM "Alta yuvarla"
IDS_SCROLLPAGE_UP "Sayfa yukarı"
IDS_SCROLLPAGE_DOWN "Sayfa aşağı"
IDS_SCROLLUP "Yukarı yuvarla"
IDS_SCROLLDOWN "Aşağı yuvarla"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,34 @@
/*
* PROJECT: ReactOS CSRSS subsystem
* LICENSE: GPL - See COPYING in the top level directory
* FILE: win32ss/user/winsrv/consrv/lang/uk-UA.rc
* PURPOSE: Ukraianian resource file
* TRANSLATOR: Artem Reznikov
*/
LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_EDIT "Редагувати"
IDS_MARK "Виділити"
IDS_COPY "Копіювати\tEnter"
IDS_PASTE "Вставити"
IDS_SELECTALL "Виділити все"
IDS_SCROLL "Прокрутити"
IDS_FIND "Знайти..."
IDS_DEFAULTS "Замовчування"
IDS_PROPERTIES "Властивості"
/*
IDS_SCROLLHERE "Прокрутити сюди"
IDS_SCROLLTOP "Прокрутити на початок"
IDS_SCROLLBOTTOM "Прокрутити на кінець"
IDS_SCROLLPAGE_UP "Попередня сотрінка"
IDS_SCROLLPAGE_DOWN "Наступна сторінка"
IDS_SCROLLUP "Прокрутити догори"
IDS_SCROLLDOWN "Прокрутити донизу"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
STRINGTABLE
BEGIN
IDS_EDIT "编辑"
IDS_MARK "标记"
IDS_COPY "复制\tEnter"
IDS_PASTE "黏贴"
IDS_SELECTALL "全部选择"
IDS_SCROLL "滚动"
IDS_FIND "查找..."
IDS_DEFAULTS "默认"
IDS_PROPERTIES "属性"
/*
IDS_SCROLLHERE "滚动到此"
IDS_SCROLLTOP "滚动至顶端"
IDS_SCROLLBOTTOM "滚动至末端"
IDS_SCROLLPAGE_UP "上一页"
IDS_SCROLLPAGE_DOWN "下一页"
IDS_SCROLLUP "向上滚动"
IDS_SCROLLDOWN "向下滚动"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
@@ -0,0 +1,26 @@
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
STRINGTABLE
BEGIN
IDS_EDIT "編輯"
IDS_MARK "標記"
IDS_COPY "複製\tEnter"
IDS_PASTE "黏貼"
IDS_SELECTALL "全部選擇"
IDS_SCROLL "滾動"
IDS_FIND "尋找..."
IDS_DEFAULTS "預設"
IDS_PROPERTIES "屬性"
/*
IDS_SCROLLHERE "滾動到此 "
IDS_SCROLLTOP "滾動到頂置"
IDS_SCROLLBOTTOM "滾動到末端"
IDS_SCROLLPAGE_UP "上一頁"
IDS_SCROLLPAGE_DOWN "下一頁"
IDS_SCROLLUP "向上滾動"
IDS_SCROLLDOWN "向下滾動"
*/
IDS_TERMINAL_TITLE "ReactOS Console"
END
Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

@@ -0,0 +1,45 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/resource.h
* PURPOSE: Resource #defines
*/
#pragma once
#define ID_SYSTEM_EDIT_MARK 1001
#define ID_SYSTEM_EDIT_COPY 1002
#define ID_SYSTEM_EDIT_PASTE 1003
#define ID_SYSTEM_EDIT_SELECTALL 1004
#define ID_SYSTEM_EDIT_SCROLL 1005
#define ID_SYSTEM_EDIT_FIND 1006
#define ID_SYSTEM_DEFAULTS 1007
#define ID_SYSTEM_PROPERTIES 1008
#define NCPOPUP_MENU 103
#define IDS_EDIT 204
#define IDS_MARK 205
#define IDS_COPY 206
#define IDS_PASTE 207
#define IDS_SELECTALL 208
#define IDS_SCROLL 209
#define IDS_FIND 210
#define IDS_DEFAULTS 211
#define IDS_PROPERTIES 212
// Scrollbar resource ids. Unused.
/*
#define IDS_SCROLLHERE 304
#define IDS_SCROLLTOP 305
#define IDS_SCROLLBOTTOM 306
#define IDS_SCROLLPAGE_UP 307
#define IDS_SCROLLPAGE_DOWN 308
#define IDS_SCROLLUP 309
#define IDS_SCROLLDOWN 310
*/
#define IDI_TERMINAL 1
#define IDS_TERMINAL_TITLE 400
/* EOF */
@@ -0,0 +1,70 @@
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// UTF-8
#pragma code_page(65001)
#ifdef LANGUAGE_BG_BG
#include "lang/bg-BG.rc"
#endif
#ifdef LANGUAGE_CS_CZ
#include "lang/cs-CZ.rc"
#endif
#ifdef LANGUAGE_DE_DE
#include "lang/de-DE.rc"
#endif
#ifdef LANGUAGE_EL_GR
#include "lang/el-GR.rc"
#endif
#ifdef LANGUAGE_EN_US
#include "lang/en-US.rc"
#endif
#ifdef LANGUAGE_ES_ES
#include "lang/es-ES.rc"
#endif
#ifdef LANGUAGE_FR_FR
#include "lang/fr-FR.rc"
#endif
#ifdef LANGUAGE_HE_IL
#include "lang/he-IL.rc"
#endif
#ifdef LANGUAGE_ID_ID
#include "lang/id-ID.rc"
#endif
#ifdef LANGUAGE_IT_IT
#include "lang/it-IT.rc"
#endif
#ifdef LANGUAGE_JA_JP
#include "lang/ja-JP.rc"
#endif
#ifdef LANGUAGE_NB_NO
#include "lang/no-NO.rc"
#endif
#ifdef LANGUAGE_PL_PL
#include "lang/pl-PL.rc"
#endif
#ifdef LANGUAGE_PT_BR
#include "lang/pt-BR.rc"
#endif
#ifdef LANGUAGE_RO_RO
#include "lang/ro-RO.rc"
#endif
#ifdef LANGUAGE_RU_RU
#include "lang/ru-RU.rc"
#endif
#ifdef LANGUAGE_SK_SK
#include "lang/sk-SK.rc"
#endif
#ifdef LANGUAGE_SV_SE
#include "lang/sv-SE.rc"
#endif
#ifdef LANGUAGE_TR_TR
#include "lang/tr-TR.rc"
#endif
#ifdef LANGUAGE_UK_UA
#include "lang/uk-UA.rc"
#endif
#ifdef LANGUAGE_ZH_CN
#include "lang/zh-CN.rc"
#endif
#ifdef LANGUAGE_ZH_TW
#include "lang/zh-TW.rc"
#endif
@@ -0,0 +1,300 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/gui/text.c
* PURPOSE: GUI Terminal Front-End - Support for text-mode screen-buffers
* PROGRAMMERS: Gé van Geldorp
* Johannes Anderwald
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/settings.h"
#include "guisettings.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer)
{
/*
* This function supposes that the system clipboard was opened.
*/
PCONSOLE Console = Buffer->Header.Console;
/*
* Pressing the Shift key while copying text, allows us to copy
* text without newline characters (inline-text copy mode).
*/
BOOL InlineCopyMode = (GetKeyState(VK_SHIFT) & 0x8000);
HANDLE hData;
PCHAR_INFO ptr;
LPWSTR data, dstPos;
ULONG selWidth, selHeight;
ULONG xPos, yPos, size;
selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1;
selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1;
DPRINT("Selection is (%d|%d) to (%d|%d)\n",
Console->Selection.srSelection.Left,
Console->Selection.srSelection.Top,
Console->Selection.srSelection.Right,
Console->Selection.srSelection.Bottom);
/* Basic size for one line... */
size = selWidth;
/* ... and for the other lines, add newline characters if needed. */
if (selHeight > 0)
{
/*
* If we are not in inline-text copy mode, each selected line must
* finish with \r\n . Otherwise, the lines will be just concatenated.
*/
size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1);
}
size += 1; /* Null-termination */
size *= sizeof(WCHAR);
/* Allocate memory, it will be passed to the system and may not be freed here */
hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
if (hData == NULL) return;
data = GlobalLock(hData);
if (data == NULL) return;
DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
dstPos = data;
for (yPos = 0; yPos < selHeight; yPos++)
{
ptr = ConioCoordToPointer(Buffer,
Console->Selection.srSelection.Left,
yPos + Console->Selection.srSelection.Top);
/* Copy only the characters, leave attributes alone */
for (xPos = 0; xPos < selWidth; xPos++)
{
/*
* Sometimes, applications can put NULL chars into the screen-buffer
* (this behaviour is allowed). Detect this and replace by a space.
* FIXME - HACK: Improve the way we're doing that (i.e., put spaces
* instead of NULLs (or even, nothing) only if it exists a non-null
* char *after* those NULLs, before the end-of-line of the selection.
* Do the same concerning spaces -- i.e. trailing spaces --).
*/
dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
}
dstPos += selWidth;
/* Add newline characters if we are not in inline-text copy mode */
if (!InlineCopyMode)
{
if (yPos != (selHeight - 1))
{
wcscat(data, L"\r\n");
dstPos += 2;
}
}
}
DPRINT("Setting data <%S> to clipboard\n", data);
GlobalUnlock(hData);
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT, hData);
}
VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer)
{
/*
* This function supposes that the system clipboard was opened.
*/
PCONSOLE Console = Buffer->Header.Console;
HANDLE hData;
LPWSTR str;
WCHAR CurChar = 0;
SHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state);
INPUT_RECORD er;
hData = GetClipboardData(CF_UNICODETEXT);
if (hData == NULL) return;
str = GlobalLock(hData);
if (str == NULL) return;
DPRINT("Got data <%S> from clipboard\n", str);
er.EventType = KEY_EVENT;
er.Event.KeyEvent.wRepeatCount = 1;
while (*str)
{
/* \r or \n characters. Go to the line only if we get "\r\n" sequence. */
if (CurChar == L'\r' && *str == L'\n')
{
str++;
continue;
}
CurChar = *str++;
/* Get the key code (+ shift state) corresponding to the character */
VkKey = VkKeyScanW(CurChar);
if (VkKey == 0xFFFF)
{
DPRINT1("VkKeyScanW failed - Should simulate the key...\n");
continue;
}
/* Pressing some control keys */
/* Pressing the character key, with the control keys maintained pressed */
er.Event.KeyEvent.bKeyDown = TRUE;
er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey);
er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR);
er.Event.KeyEvent.uChar.UnicodeChar = CurChar;
er.Event.KeyEvent.dwControlKeyState = 0;
if (HIBYTE(VkKey) & 1)
er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
if (HIBYTE(VkKey) & 2)
er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED;
if (HIBYTE(VkKey) & 4)
er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED;
ConioProcessInputEvent(Console, &er);
/* Up all the character and control keys */
er.Event.KeyEvent.bKeyDown = FALSE;
ConioProcessInputEvent(Console, &er);
}
GlobalUnlock(hData);
}
VOID
GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
PGUI_CONSOLE_DATA GuiData,
HDC hDC,
PRECT rc)
{
PCONSOLE Console = Buffer->Header.Console;
// ASSERT(Console == GuiData->Console);
ULONG TopLine, BottomLine, LeftChar, RightChar;
ULONG Line, Char, Start;
PCHAR_INFO From;
PWCHAR To;
WORD LastAttribute, Attribute;
ULONG CursorX, CursorY, CursorHeight;
HBRUSH CursorBrush, OldBrush;
HFONT OldFont;
if (Buffer->Buffer == NULL) return;
TopLine = rc->top / GuiData->CharHeight + Buffer->ViewOrigin.Y;
BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buffer->ViewOrigin.Y;
LeftChar = rc->left / GuiData->CharWidth + Buffer->ViewOrigin.X;
RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buffer->ViewOrigin.X;
LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)->Attributes;
SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute)));
SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute)));
if (BottomLine >= Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1;
if (RightChar >= Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1;
OldFont = SelectObject(hDC, GuiData->Font);
for (Line = TopLine; Line <= BottomLine; Line++)
{
WCHAR LineBuffer[80]; // Buffer containing a part or all the line to be displayed
From = ConioCoordToPointer(Buffer, LeftChar, Line); // Get the first code of the line
Start = LeftChar;
To = LineBuffer;
for (Char = LeftChar; Char <= RightChar; Char++)
{
/*
* We flush the buffer if the new attribute is different
* from the current one, or if the buffer is full.
*/
if (From->Attributes != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR)))
{
TextOutW(hDC,
(Start - Buffer->ViewOrigin.X) * GuiData->CharWidth ,
(Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight,
LineBuffer,
Char - Start);
Start = Char;
To = LineBuffer;
Attribute = From->Attributes;
if (Attribute != LastAttribute)
{
SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(Attribute)));
SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute)));
LastAttribute = Attribute;
}
}
*(To++) = (From++)->Char.UnicodeChar;
}
TextOutW(hDC,
(Start - Buffer->ViewOrigin.X) * GuiData->CharWidth ,
(Line - Buffer->ViewOrigin.Y) * GuiData->CharHeight,
LineBuffer,
RightChar - Start + 1);
}
/*
* Draw the caret
*/
if (Buffer->CursorInfo.bVisible &&
Buffer->CursorBlinkOn &&
!Buffer->ForceCursorOff)
{
CursorX = Buffer->CursorPosition.X;
CursorY = Buffer->CursorPosition.Y;
if (LeftChar <= CursorX && CursorX <= RightChar &&
TopLine <= CursorY && CursorY <= BottomLine)
{
CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
Attribute = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y)->Attributes;
if (Attribute != DEFAULT_SCREEN_ATTRIB)
{
CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Attribute));
}
else
{
CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Buffer->ScreenDefaultAttrib));
}
OldBrush = SelectObject(hDC, CursorBrush);
PatBlt(hDC,
(CursorX - Buffer->ViewOrigin.X) * GuiData->CharWidth,
(CursorY - Buffer->ViewOrigin.Y) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
GuiData->CharWidth,
CursorHeight,
PATCOPY);
SelectObject(hDC, OldBrush);
DeleteObject(CursorBrush);
}
}
SelectObject(hDC, OldFont);
}
/* EOF */
@@ -0,0 +1,146 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/input.c
* PURPOSE: Common Front-Ends Input functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "coninput.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
static DWORD FASTCALL
ConioGetShiftState(PBYTE KeyState, LPARAM lParam)
{
DWORD ssOut = 0;
if (KeyState[VK_CAPITAL] & 0x01)
ssOut |= CAPSLOCK_ON;
if (KeyState[VK_NUMLOCK] & 0x01)
ssOut |= NUMLOCK_ON;
if (KeyState[VK_SCROLL] & 0x01)
ssOut |= SCROLLLOCK_ON;
if (KeyState[VK_SHIFT] & 0x80)
ssOut |= SHIFT_PRESSED;
if (KeyState[VK_LCONTROL] & 0x80)
ssOut |= LEFT_CTRL_PRESSED;
if (KeyState[VK_RCONTROL] & 0x80)
ssOut |= RIGHT_CTRL_PRESSED;
if (KeyState[VK_LMENU] & 0x80)
ssOut |= LEFT_ALT_PRESSED;
if (KeyState[VK_RMENU] & 0x80)
ssOut |= RIGHT_ALT_PRESSED;
/* See WM_CHAR MSDN documentation for instance */
if (lParam & 0x01000000)
ssOut |= ENHANCED_KEY;
return ssOut;
}
VOID WINAPI
ConioProcessKey(PCONSOLE Console, MSG* msg)
{
static BYTE KeyState[256] = { 0 };
/* MSDN mentions that you should use the last virtual key code received
* when putting a virtual key identity to a WM_CHAR message since multiple
* or translated keys may be involved. */
static UINT LastVirtualKey = 0;
DWORD ShiftState;
WCHAR UnicodeChar;
UINT VirtualKeyCode;
UINT VirtualScanCode;
BOOL Down = FALSE;
BOOLEAN Fake; // synthesized, not a real event
BOOLEAN NotChar; // message should not be used to return a character
if (NULL == Console)
{
DPRINT1("No Active Console!\n");
return;
}
VirtualScanCode = HIWORD(msg->lParam) & 0xFF;
Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
GetKeyboardState(KeyState);
ShiftState = ConioGetShiftState(KeyState, msg->lParam);
if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
{
VirtualKeyCode = LastVirtualKey;
UnicodeChar = msg->wParam;
}
else
{
WCHAR Chars[2];
INT RetChars = 0;
VirtualKeyCode = msg->wParam;
RetChars = ToUnicodeEx(VirtualKeyCode,
VirtualScanCode,
KeyState,
Chars,
2,
0,
NULL);
UnicodeChar = (1 == RetChars ? Chars[0] : 0);
}
if (ConioProcessKeyCallback(Console,
msg,
KeyState[VK_MENU],
ShiftState,
VirtualKeyCode,
Down))
{
return;
}
Fake = UnicodeChar &&
(msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
if (NotChar) LastVirtualKey = msg->wParam;
DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
Down ? "down" : "up ",
(msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
"char" : "key ",
Fake ? "fake" : "real",
NotChar ? "notc" : "char",
VirtualScanCode,
VirtualKeyCode,
(UnicodeChar >= L' ') ? UnicodeChar : L'.',
ShiftState);
if (Fake) return;
/* Send the key press to the console driver */
ConDrvProcessKey(Console,
Down,
VirtualKeyCode,
VirtualScanCode,
UnicodeChar,
ShiftState,
KeyState[VK_CONTROL]);
}
/* EOF */
@@ -0,0 +1,861 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c
* PURPOSE: TUI Terminal Front-End - Virtual Consoles...
* PROGRAMMERS: David Welch
* Gé van Geldorp
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#ifdef TUITERM_COMPILE
#include "consrv.h"
#include "include/conio.h"
#include "include/console.h"
#include "include/settings.h"
#include "tuiterm.h"
#include <drivers/blue/ntddblue.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
#define GetNextConsole(Console) \
CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry)
#define GetPrevConsole(Console) \
CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry)
/* TUI Console Window Class name */
#define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
typedef struct _TUI_CONSOLE_DATA
{
CRITICAL_SECTION Lock;
LIST_ENTRY Entry; /* Entry in the list of virtual consoles */
// HANDLE hTuiInitEvent;
HWND hWindow; /* Handle to the console's window (used for the window's procedure */
PCONSOLE Console; /* Pointer to the owned console */
// TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */
} TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA;
/* List of the maintained virtual consoles and its lock */
static LIST_ENTRY VirtConsList;
static PTUI_CONSOLE_DATA ActiveConsole; /* The active console on screen */
static CRITICAL_SECTION ActiveVirtConsLock;
static COORD PhysicalConsoleSize;
static HANDLE ConsoleDeviceHandle;
static BOOL ConsInitialized = FALSE;
/******************************************************************************\
|** BlueScreen Driver management **|
\**/
/* Code taken and adapted from base/system/services/driver.c */
static DWORD
ScmLoadDriver(LPCWSTR lpServiceName)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN WasPrivilegeEnabled = FALSE;
PWSTR pszDriverPath;
UNICODE_STRING DriverPath;
/* Build the driver path */
/* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
(52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
if (pszDriverPath == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
wcscpy(pszDriverPath,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
wcscat(pszDriverPath,
lpServiceName);
RtlInitUnicodeString(&DriverPath,
pszDriverPath);
DPRINT(" Path: %wZ\n", &DriverPath);
/* Acquire driver-loading privilege */
Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
TRUE,
FALSE,
&WasPrivilegeEnabled);
if (!NT_SUCCESS(Status))
{
/* We encountered a failure, exit properly */
DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status);
goto done;
}
Status = NtLoadDriver(&DriverPath);
/* Release driver-loading privilege */
RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
WasPrivilegeEnabled,
FALSE,
&WasPrivilegeEnabled);
done:
ConsoleFreeHeap(pszDriverPath);
return RtlNtStatusToDosError(Status);
}
#ifdef BLUESCREEN_DRIVER_UNLOADING
static DWORD
ScmUnloadDriver(LPCWSTR lpServiceName)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN WasPrivilegeEnabled = FALSE;
PWSTR pszDriverPath;
UNICODE_STRING DriverPath;
/* Build the driver path */
/* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
(52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
if (pszDriverPath == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
wcscpy(pszDriverPath,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
wcscat(pszDriverPath,
lpServiceName);
RtlInitUnicodeString(&DriverPath,
pszDriverPath);
DPRINT(" Path: %wZ\n", &DriverPath);
/* Acquire driver-unloading privilege */
Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
TRUE,
FALSE,
&WasPrivilegeEnabled);
if (!NT_SUCCESS(Status))
{
/* We encountered a failure, exit properly */
DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status);
goto done;
}
Status = NtUnloadDriver(&DriverPath);
/* Release driver-unloading privilege */
RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
WasPrivilegeEnabled,
FALSE,
&WasPrivilegeEnabled);
done:
ConsoleFreeHeap(pszDriverPath);
return RtlNtStatusToDosError(Status);
}
#endif
/**\
\******************************************************************************/
static BOOL FASTCALL
TuiSwapConsole(INT Next)
{
static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */
DWORD BytesReturned;
ANSI_STRING Title;
PVOID Buffer;
PCOORD pos;
if (0 != Next)
{
/*
* Alt-Tab, swap consoles.
* move SwapConsole to next console, and print its title.
*/
EnterCriticalSection(&ActiveVirtConsLock);
if (!SwapConsole) SwapConsole = ActiveConsole;
SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole));
Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title);
Title.Length = 0;
Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength);
pos = (PCOORD)Buffer;
Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD));
RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE);
pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
pos->Y = PhysicalConsoleSize.Y / 2;
/* Redraw the console to clear off old title */
ConioDrawConsole(ActiveConsole->Console);
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
NULL, 0, Buffer, sizeof(COORD) + Title.Length,
&BytesReturned, NULL))
{
DPRINT1( "Error writing to console\n" );
}
ConsoleFreeHeap(Buffer);
LeaveCriticalSection(&ActiveVirtConsLock);
return TRUE;
}
else if (NULL != SwapConsole)
{
EnterCriticalSection(&ActiveVirtConsLock);
if (SwapConsole != ActiveConsole)
{
/* First remove swapconsole from the list */
SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink;
SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink;
/* Now insert before activeconsole */
SwapConsole->Entry.Flink = &ActiveConsole->Entry;
SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink;
ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry;
ActiveConsole->Entry.Blink = &SwapConsole->Entry;
}
ActiveConsole = SwapConsole;
SwapConsole = NULL;
ConioDrawConsole(ActiveConsole->Console);
LeaveCriticalSection(&ActiveVirtConsLock);
return TRUE;
}
else
{
return FALSE;
}
}
static VOID FASTCALL
TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region)
{
UINT SrcDelta, DestDelta;
LONG i;
PCHAR_INFO Src, SrcEnd;
Src = ConioCoordToPointer(Buff, Region->Left, Region->Top);
SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */;
for (i = Region->Top; i <= Region->Bottom; i++)
{
ConsoleUnicodeCharToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar);
*(PBYTE)(Dest + 1) = (BYTE)Src->Attributes;
Src += SrcDelta;
if (SrcEnd <= Src)
{
Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
}
Dest += DestDelta;
}
}
static LRESULT CALLBACK
TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
/*
PTUI_CONSOLE_DATA TuiData = NULL;
PCONSOLE Console = NULL;
TuiData = TuiGetGuiData(hWnd);
if (TuiData == NULL) return 0;
*/
switch (msg)
{
case WM_CHAR:
case WM_SYSCHAR:
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
{
if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
{
MSG Message;
Message.hwnd = hWnd;
Message.message = msg;
Message.wParam = wParam;
Message.lParam = lParam;
ConioProcessKey(ActiveConsole->Console, &Message);
LeaveCriticalSection(&ActiveConsole->Console->Lock);
}
break;
}
case WM_ACTIVATE:
{
if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
{
if (LOWORD(wParam) != WA_INACTIVE)
{
SetFocus(hWnd);
ConioDrawConsole(ActiveConsole->Console);
}
LeaveCriticalSection(&ActiveConsole->Console->Lock);
}
break;
}
default:
break;
}
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
static DWORD WINAPI
TuiConsoleThread(PVOID Data)
{
PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Data;
PCONSOLE Console = TuiData->Console;
HWND NewWindow;
MSG msg;
NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS,
Console->Title.Buffer,
0,
-32000, -32000, 0, 0,
NULL, NULL,
ConSrvDllInstance,
(PVOID)Console);
if (NULL == NewWindow)
{
DPRINT1("CONSRV: Unable to create console window\n");
return 1;
}
TuiData->hWindow = NewWindow;
SetForegroundWindow(TuiData->hWindow);
NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
static BOOL
TuiInit(DWORD OemCP)
{
BOOL Ret = FALSE;
CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
DWORD BytesReturned;
WNDCLASSEXW wc;
ATOM ConsoleClassAtom;
USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
/* Exit if we were already initialized */
if (ConsInitialized) return TRUE;
/*
* Initialize the TUI front-end:
* - load the console driver,
* - set default screen attributes,
* - grab the console size.
*/
ScmLoadDriver(L"Blue");
ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen",
FILE_ALL_ACCESS,
0, NULL,
OPEN_EXISTING,
0, NULL);
if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
{
DPRINT1("Failed to open BlueScreen.\n");
return FALSE;
}
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT,
&OemCP, sizeof(OemCP), NULL, 0,
&BytesReturned, NULL))
{
DPRINT1("Failed to load the font for codepage %d\n", OemCP);
/* Let's suppose the font is good enough to continue */
}
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
&TextAttribute, sizeof(TextAttribute), NULL, 0,
&BytesReturned, NULL))
{
DPRINT1("Failed to set text attribute\n");
}
ActiveConsole = NULL;
InitializeListHead(&VirtConsList);
InitializeCriticalSection(&ActiveVirtConsLock);
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
{
DPRINT1("Failed to get console info\n");
Ret = FALSE;
goto Quit;
}
PhysicalConsoleSize = ScrInfo.dwSize;
/* Register the TUI notification window class */
RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS;
wc.lpfnWndProc = TuiConsoleWndProc;
wc.cbWndExtra = 0;
wc.hInstance = ConSrvDllInstance;
ConsoleClassAtom = RegisterClassExW(&wc);
if (ConsoleClassAtom == 0)
{
DPRINT1("Failed to register TUI console wndproc\n");
Ret = FALSE;
}
else
{
Ret = TRUE;
}
Quit:
if (Ret == FALSE)
{
DeleteCriticalSection(&ActiveVirtConsLock);
CloseHandle(ConsoleDeviceHandle);
}
ConsInitialized = Ret;
return Ret;
}
/******************************************************************************
* TUI Console Driver *
******************************************************************************/
static VOID WINAPI
TuiDeinitFrontEnd(IN OUT PFRONTEND This /*,
IN PCONSOLE Console */);
NTSTATUS NTAPI
TuiInitFrontEnd(IN OUT PFRONTEND This,
IN PCONSOLE Console)
{
PTUI_CONSOLE_DATA TuiData;
HANDLE ThreadHandle;
if (This == NULL || Console == NULL)
return STATUS_INVALID_PARAMETER;
// if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER)
// return STATUS_INVALID_PARAMETER;
// /* Initialize the console */
// Console->TermIFace.Vtbl = &TuiVtbl;
TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA));
if (!TuiData)
{
DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n");
return STATUS_UNSUCCESSFUL;
}
// Console->TermIFace.Data = (PVOID)TuiData;
TuiData->Console = Console;
TuiData->hWindow = NULL;
InitializeCriticalSection(&TuiData->Lock);
/*
* HACK: Resize the console since we don't support for now changing
* the console size when we display it with the hardware.
*/
// Console->ConsoleSize = PhysicalConsoleSize;
// ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize);
// /* The console cannot be resized anymore */
// Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !!
// // ConioResizeTerminal(Console);
/*
* Contrary to what we do in the GUI front-end, here we create
* an input thread for each console. It will dispatch all the
* input messages to the proper console (on the GUI it is done
* via the default GUI dispatch thread).
*/
ThreadHandle = CreateThread(NULL,
0,
TuiConsoleThread,
(PVOID)TuiData,
0,
NULL);
if (NULL == ThreadHandle)
{
DPRINT1("CONSRV: Unable to create console thread\n");
// TuiDeinitFrontEnd(Console);
TuiDeinitFrontEnd(This);
return STATUS_UNSUCCESSFUL;
}
CloseHandle(ThreadHandle);
/*
* Insert the newly created console in the list of virtual consoles
* and activate it (give it the focus).
*/
EnterCriticalSection(&ActiveVirtConsLock);
InsertTailList(&VirtConsList, &TuiData->Entry);
ActiveConsole = TuiData;
LeaveCriticalSection(&ActiveVirtConsLock);
/* Finally, initialize the frontend structure */
This->Data = TuiData;
This->OldData = NULL;
return STATUS_SUCCESS;
}
static VOID WINAPI
TuiDeinitFrontEnd(IN OUT PFRONTEND This)
{
// PCONSOLE Console = This->Console;
PTUI_CONSOLE_DATA TuiData = This->Data; // Console->TermIFace.Data;
/* Close the notification window */
DestroyWindow(TuiData->hWindow);
/*
* Set the active console to the next one
* and remove the console from the list.
*/
EnterCriticalSection(&ActiveVirtConsLock);
ActiveConsole = GetNextConsole(TuiData);
RemoveEntryList(&TuiData->Entry);
// /* Switch to next console */
// if (ActiveConsole == TuiData)
// if (ActiveConsole->Console == Console)
// {
// ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL);
// }
// if (GetNextConsole(TuiData) != TuiData)
// {
// TuiData->Entry.Blink->Flink = TuiData->Entry.Flink;
// TuiData->Entry.Flink->Blink = TuiData->Entry.Blink;
// }
LeaveCriticalSection(&ActiveVirtConsLock);
/* Switch to the next console */
if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console);
// Console->TermIFace.Data = NULL;
This->Data = NULL;
DeleteCriticalSection(&TuiData->Lock);
ConsoleFreeHeap(TuiData);
}
static VOID WINAPI
TuiDrawRegion(IN OUT PFRONTEND This,
SMALL_RECT* Region)
{
DWORD BytesReturned;
PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
PCONSOLE_DRAW ConsoleDraw;
UINT ConsoleDrawSize;
if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return;
ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
(ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize);
if (NULL == ConsoleDraw)
{
DPRINT1("ConsoleAllocHeap failed\n");
return;
}
ConsoleDraw->X = Region->Left;
ConsoleDraw->Y = Region->Top;
ConsoleDraw->SizeX = ConioRectWidth(Region);
ConsoleDraw->SizeY = ConioRectHeight(Region);
ConsoleDraw->CursorX = Buff->CursorPosition.X;
ConsoleDraw->CursorY = Buff->CursorPosition.Y;
TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region);
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
{
DPRINT1("Failed to draw console\n");
ConsoleFreeHeap(ConsoleDraw);
return;
}
ConsoleFreeHeap(ConsoleDraw);
}
static VOID WINAPI
TuiWriteStream(IN OUT PFRONTEND This,
SMALL_RECT* Region,
SHORT CursorStartX,
SHORT CursorStartY,
UINT ScrolledLines,
PWCHAR Buffer,
UINT Length)
{
PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
PCHAR NewBuffer;
ULONG NewLength;
DWORD BytesWritten;
if (ActiveConsole->Console->ActiveBuffer != Buff) return;
NewLength = WideCharToMultiByte(Console->OutputCodePage, 0,
Buffer, Length,
NULL, 0, NULL, NULL);
NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR));
if (!NewBuffer) return;
WideCharToMultiByte(Console->OutputCodePage, 0,
Buffer, Length,
NewBuffer, NewLength, NULL, NULL);
if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL))
{
DPRINT1("Error writing to BlueScreen\n");
}
RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
}
static BOOL WINAPI
TuiSetCursorInfo(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER Buff)
{
CONSOLE_CURSOR_INFO Info;
DWORD BytesReturned;
if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
Info.dwSize = ConioEffectiveCursorSize(Console, 100);
Info.bVisible = Buff->CursorInfo.bVisible;
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
&Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
{
DPRINT1( "Failed to set cursor info\n" );
return FALSE;
}
return TRUE;
}
static BOOL WINAPI
TuiSetScreenInfo(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER Buff,
SHORT OldCursorX,
SHORT OldCursorY)
{
CONSOLE_SCREEN_BUFFER_INFO Info;
DWORD BytesReturned;
if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE;
Info.dwCursorPosition = Buff->CursorPosition;
Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib;
if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
&Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
&BytesReturned, NULL))
{
DPRINT1( "Failed to set cursor position\n" );
return FALSE;
}
return TRUE;
}
static VOID WINAPI
TuiResizeTerminal(IN OUT PFRONTEND This)
{
}
static BOOL WINAPI
TuiProcessKeyCallback(IN OUT PFRONTEND This,
MSG* msg,
BYTE KeyStateMenu,
DWORD ShiftState,
UINT VirtualKeyCode,
BOOL Down)
{
if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) &&
VK_TAB == VirtualKeyCode)
{
if (Down)
{
TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
}
return TRUE;
}
else if (VK_MENU == VirtualKeyCode && !Down)
{
return TuiSwapConsole(0);
}
return FALSE;
}
static VOID WINAPI
TuiRefreshInternalInfo(IN OUT PFRONTEND This)
{
}
static VOID WINAPI
TuiChangeTitle(IN OUT PFRONTEND This)
{
}
static BOOL WINAPI
TuiChangeIcon(IN OUT PFRONTEND This,
HICON hWindowIcon)
{
return TRUE;
}
static HWND WINAPI
TuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
{
PTUI_CONSOLE_DATA TuiData = This->Data;
return TuiData->hWindow;
}
static VOID WINAPI
TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
PCOORD pSize)
{
if (!pSize) return;
*pSize = PhysicalConsoleSize;
}
static ULONG WINAPI
TuiGetDisplayMode(IN OUT PFRONTEND This)
{
return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN;
}
static BOOL WINAPI
TuiSetDisplayMode(IN OUT PFRONTEND This,
ULONG NewMode)
{
// if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
// return FALSE;
return TRUE;
}
static INT WINAPI
TuiShowMouseCursor(IN OUT PFRONTEND This,
BOOL Show)
{
return 0;
}
static BOOL WINAPI
TuiSetMouseCursor(IN OUT PFRONTEND This,
HCURSOR hCursor)
{
return TRUE;
}
static HMENU WINAPI
TuiMenuControl(IN OUT PFRONTEND This,
UINT cmdIdLow,
UINT cmdIdHigh)
{
return NULL;
}
static BOOL WINAPI
TuiSetMenuClose(IN OUT PFRONTEND This,
BOOL Enable)
{
return TRUE;
}
static FRONTEND_VTBL TuiVtbl =
{
TuiInitFrontEnd,
TuiDeinitFrontEnd,
TuiDrawRegion,
TuiWriteStream,
TuiSetCursorInfo,
TuiSetScreenInfo,
TuiResizeTerminal,
TuiProcessKeyCallback,
TuiRefreshInternalInfo,
TuiChangeTitle,
TuiChangeIcon,
TuiGetConsoleWindowHandle,
TuiGetLargestConsoleWindowSize,
TuiGetDisplayMode,
TuiSetDisplayMode,
TuiShowMouseCursor,
TuiSetMouseCursor,
TuiMenuControl,
TuiSetMenuClose,
};
// static BOOL
// DtbgIsDesktopVisible(VOID)
// {
// return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
// }
static BOOLEAN
IsConsoleMode(VOID)
{
return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE);
}
NTSTATUS NTAPI
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId)
{
if (FrontEnd == NULL || ConsoleInfo == NULL)
return STATUS_INVALID_PARAMETER;
/* We must be in console mode already */
if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL;
/* Initialize the TUI terminal emulator */
if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL;
/* Finally, initialize the frontend structure */
FrontEnd->Vtbl = &TuiVtbl;
FrontEnd->Data = NULL;
FrontEnd->OldData = NULL;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
{
if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
if (FrontEnd->Data) TuiDeinitFrontEnd(FrontEnd);
return STATUS_SUCCESS;
}
#endif
/* EOF */
@@ -0,0 +1,19 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/frontends/tui/tuiterm.h
* PURPOSE: TUI Terminal Front-End
* PROGRAMMERS: David Welch
* Gé van Geldorp
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
NTSTATUS FASTCALL TuiInitConsole(PCONSOLE Console,
/*IN*/ PCONSOLE_START_INFO ConsoleStartInfo,
PCONSOLE_INFO ConsoleInfo,
DWORD ProcessId);
/* EOF */
@@ -0,0 +1,866 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/handle.c
* PURPOSE: Console I/O Handles functions
* PROGRAMMERS: David Welch
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "handle.h"
#include "include/console.h"
#include "console.h"
#include "conoutput.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
typedef struct _CONSOLE_IO_HANDLE
{
PCONSOLE_IO_OBJECT Object; /* The object on which the handle points to */
DWORD Access;
BOOL Inheritable;
DWORD ShareMode;
} CONSOLE_IO_HANDLE, *PCONSOLE_IO_HANDLE;
/* PRIVATE FUNCTIONS **********************************************************/
static INT
AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
{
PCONSOLE_IO_OBJECT Object = Entry->Object;
DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n", Entry, Change, Object);
DPRINT("\tAdjustHandleCounts(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_WRITE) Object->AccessWrite += Change;
if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
Object->HandleCount += Change;
return Object->HandleCount;
}
static VOID
ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
{
/// LOCK /// PCONSOLE_IO_OBJECT Object = Entry->Object;
/// LOCK /// EnterCriticalSection(&Object->Console->Lock);
AdjustHandleCounts(Entry, +1);
/// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
}
static VOID
ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
{
PCONSOLE_IO_OBJECT Object = Entry->Object;
if (Object != NULL)
{
/// LOCK /// PCONSOLE Console = Object->Console;
/// LOCK /// EnterCriticalSection(&Console->Lock);
/*
* If this is a input handle, notify and dereference
* all the waits related to this handle.
*/
if (Object->Type == INPUT_BUFFER)
{
PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
/*
* Wake up all the writing waiters related to this handle for this
* input buffer, if any, then dereference them and purge them all
* from the list.
* To select them amongst all the waiters for this input buffer,
* pass the handle pointer to the waiters, then they will check
* whether or not they are related to this handle and if so, they
* return.
*/
CsrNotifyWait(&InputBuffer->ReadWaitQueue,
WaitAll,
NULL,
(PVOID)Entry);
if (!IsListEmpty(&InputBuffer->ReadWaitQueue))
{
CsrDereferenceWait(&InputBuffer->ReadWaitQueue);
}
}
/* If the last handle to a screen buffer is closed, delete it... */
if (AdjustHandleCounts(Entry, -1) == 0)
{
if (Object->Type == TEXTMODE_BUFFER || Object->Type == GRAPHICS_BUFFER)
{
PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
/* ...unless it's the only buffer left. Windows allows deletion
* even of the last buffer, but having to deal with a lack of
* any active buffer might be error-prone. */
if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
ConioDeleteScreenBuffer(Buffer);
}
else if (Object->Type == INPUT_BUFFER)
{
DPRINT("Closing the input buffer\n");
}
else
{
DPRINT1("Invalid object type %d\n", Object->Type);
}
}
/// LOCK /// LeaveCriticalSection(&Console->Lock);
/* Invalidate (zero-out) this handle entry */
// Entry->Object = NULL;
// RtlZeroMemory(Entry, sizeof(*Entry));
}
RtlZeroMemory(Entry, sizeof(*Entry)); // Be sure the whole entry is invalidated.
}
/* Forward declaration, used in ConSrvInitHandlesTable */
static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData);
static NTSTATUS
ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
IN PCONSOLE Console,
OUT PHANDLE pInputHandle,
OUT PHANDLE pOutputHandle,
OUT PHANDLE pErrorHandle)
{
NTSTATUS Status;
HANDLE InputHandle = INVALID_HANDLE_VALUE,
OutputHandle = INVALID_HANDLE_VALUE,
ErrorHandle = INVALID_HANDLE_VALUE;
/*
* Initialize the handles table. Use temporary variables to store
* the handles values in such a way that, if we fail, we don't
* return to the caller invalid handle values.
*
* Insert the IO handles.
*/
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Insert the Input handle */
Status = ConSrvInsertObject(ProcessData,
&InputHandle,
&Console->InputBuffer.Header,
GENERIC_READ | GENERIC_WRITE,
TRUE,
FILE_SHARE_READ | FILE_SHARE_WRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to insert the input handle\n");
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvFreeHandlesTable(ProcessData);
return Status;
}
/* Insert the Output handle */
Status = ConSrvInsertObject(ProcessData,
&OutputHandle,
&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");
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvFreeHandlesTable(ProcessData);
return Status;
}
/* Insert the Error handle */
Status = ConSrvInsertObject(ProcessData,
&ErrorHandle,
&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");
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvFreeHandlesTable(ProcessData);
return Status;
}
/* Return the newly created handles */
*pInputHandle = InputHandle;
*pOutputHandle = OutputHandle;
*pErrorHandle = ErrorHandle;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS;
}
NTSTATUS
ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
IN PCONSOLE_PROCESS_DATA TargetProcessData)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i, j;
RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
/* Inherit a handles table only if there is no already */
if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
{
Status = STATUS_UNSUCCESSFUL;
goto Quit;
}
/* Allocate a new handle table for the child process */
TargetProcessData->HandleTable = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
SourceProcessData->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE));
if (TargetProcessData->HandleTable == NULL)
{
Status = STATUS_NO_MEMORY;
goto Quit;
}
TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
/*
* Parse the parent process' handles table and, for each handle,
* do a copy of it and reference it, if the handle is inheritable.
*/
for (i = 0, j = 0; i < SourceProcessData->HandleTableSize; i++)
{
if (SourceProcessData->HandleTable[i].Object != NULL &&
SourceProcessData->HandleTable[i].Inheritable)
{
/*
* Copy the handle data and increment the reference count of the
* pointed object (via the call to ConSrvCreateHandleEntry).
*/
TargetProcessData->HandleTable[j] = SourceProcessData->HandleTable[i];
ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[j]);
++j;
}
}
Quit:
RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
return Status;
}
static VOID
ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
{
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (ProcessData->HandleTable != NULL)
{
ULONG i;
/*
* ProcessData->ConsoleHandle is NULL (and the assertion fails) when
* ConSrvFreeHandlesTable is called in ConSrvConnect during the
* allocation of a new console.
*/
// ASSERT(ProcessData->ConsoleHandle);
if (ProcessData->ConsoleHandle != NULL)
{
/* Close all the console handles */
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
}
}
/* Free the handles table memory */
ConsoleFreeHeap(ProcessData->HandleTable);
ProcessData->HandleTable = NULL;
}
ProcessData->HandleTableSize = 0;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
}
VOID
FASTCALL
ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object,
IN CONSOLE_IO_OBJECT_TYPE Type,
IN PCONSOLE Console)
{
ASSERT(Object);
// if (!Object) return;
Object->Type = Type;
Object->Console = Console;
Object->AccessRead = Object->AccessWrite = 0;
Object->ExclusiveRead = Object->ExclusiveWrite = 0;
Object->HandleCount = 0;
}
NTSTATUS
FASTCALL
ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE Handle,
PCONSOLE_IO_OBJECT Object,
DWORD Access,
BOOL Inheritable,
DWORD ShareMode)
{
#define IO_HANDLES_INCREMENT 2 * 3
ULONG i = 0;
PCONSOLE_IO_HANDLE Block;
// NOTE: Commented out because calling code always lock HandleTableLock before.
// RtlEnterCriticalSection(&ProcessData->HandleTableLock);
ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
(ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
if (ProcessData->HandleTable)
{
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
if (ProcessData->HandleTable[i].Object == NULL)
break;
}
}
if (i >= ProcessData->HandleTableSize)
{
/* Allocate a new handles table */
Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
(ProcessData->HandleTableSize +
IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
if (Block == NULL)
{
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_UNSUCCESSFUL;
}
/* If we previously had a handles table, free it and use the new one */
if (ProcessData->HandleTable)
{
/* Copy the handles from the old table to the new one */
RtlCopyMemory(Block,
ProcessData->HandleTable,
ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
ConsoleFreeHeap(ProcessData->HandleTable);
}
ProcessData->HandleTable = Block;
ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
}
ProcessData->HandleTable[i].Object = Object;
ProcessData->HandleTable[i].Access = Access;
ProcessData->HandleTable[i].Inheritable = Inheritable;
ProcessData->HandleTable[i].ShareMode = ShareMode;
ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
*Handle = ULongToHandle((i << 2) | 0x3);
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE Handle)
{
ULONG Index = HandleToULong(Handle) >> 2;
PCONSOLE_IO_OBJECT Object;
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
ASSERT(ProcessData->HandleTable);
if (Index >= ProcessData->HandleTableSize ||
(Object = ProcessData->HandleTable[Index].Object) == NULL)
{
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_INVALID_HANDLE;
}
ASSERT(ProcessData->ConsoleHandle);
ConSrvCloseHandleEntry(&ProcessData->HandleTable[Index]);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE Handle,
PCONSOLE_IO_OBJECT* Object,
PVOID* Entry OPTIONAL,
DWORD Access,
BOOL LockConsole,
CONSOLE_IO_OBJECT_TYPE Type)
{
// NTSTATUS Status;
ULONG Index = HandleToULong(Handle) >> 2;
PCONSOLE_IO_HANDLE HandleEntry = NULL;
PCONSOLE_IO_OBJECT ObjectEntry = NULL;
// PCONSOLE ObjectConsole;
ASSERT(Object);
if (Entry) *Entry = NULL;
DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object, Handle);
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if ( IsConsoleHandle(Handle) &&
Index < ProcessData->HandleTableSize )
{
HandleEntry = &ProcessData->HandleTable[Index];
ObjectEntry = HandleEntry->Object;
}
if ( HandleEntry == NULL ||
ObjectEntry == NULL ||
(HandleEntry->Access & Access) == 0 ||
/*(Type != 0 && ObjectEntry->Type != Type)*/
(Type != 0 && (ObjectEntry->Type & Type) == 0) )
{
DPRINT1("ConSrvGetObject -- Invalid handle 0x%x of type %lu with access %lu ; retrieved object 0x%x (handle 0x%x) of type %lu with access %lu\n",
Handle, Type, Access, ObjectEntry, HandleEntry, (ObjectEntry ? ObjectEntry->Type : 0), (HandleEntry ? HandleEntry->Access : 0));
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_INVALID_HANDLE;
}
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
// Status = ConDrvGetConsole(&ObjectConsole, ProcessData->ConsoleHandle, LockConsole);
// if (NT_SUCCESS(Status))
if (ConDrvValidateConsoleUnsafe(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole))
{
_InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
/* Return the objects to the caller */
*Object = ObjectEntry;
if (Entry) *Entry = HandleEntry;
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS;
}
else
{
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_INVALID_HANDLE;
}
}
VOID
FASTCALL
ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object,
BOOL IsConsoleLocked)
{
ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
}
NTSTATUS
FASTCALL
ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE pInputHandle,
PHANDLE pOutputHandle,
PHANDLE pErrorHandle,
PCONSOLE_START_INFO ConsoleStartInfo)
{
NTSTATUS Status = STATUS_SUCCESS;
HANDLE ConsoleHandle;
PCONSOLE Console;
/*
* We are about to create a new console. However when ConSrvNewProcess
* 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 the handles table so that we can recreate
* a new one later on.
*/
ConSrvFreeHandlesTable(ProcessData);
/* Initialize a new Console owned by this process */
Status = ConSrvInitConsole(&ConsoleHandle,
&Console,
ConsoleStartInfo,
HandleToUlong(ProcessData->Process->ClientId.UniqueProcess));
if (!NT_SUCCESS(Status))
{
DPRINT1("Console initialization failed\n");
return Status;
}
/* Assign the new console handle */
ProcessData->ConsoleHandle = ConsoleHandle;
/* Initialize the handles table */
Status = ConSrvInitHandlesTable(ProcessData,
Console,
pInputHandle,
pOutputHandle,
pErrorHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to initialize the handles table\n");
ConSrvDeleteConsole(Console);
ProcessData->ConsoleHandle = NULL;
return Status;
}
/* Duplicate the Input Event */
Status = NtDuplicateObject(NtCurrentProcess(),
Console->InputBuffer.ActiveEvent,
ProcessData->Process->ProcessHandle,
&ProcessData->ConsoleEvent,
EVENT_ALL_ACCESS, 0, 0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
ConSrvFreeHandlesTable(ProcessData);
ConSrvDeleteConsole(Console);
ProcessData->ConsoleHandle = NULL;
return Status;
}
/* Insert the process into the processes list of the console */
InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&Console->ReferenceCount);
/* Update the internal info of the terminal */
ConioRefreshInternalInfo(Console);
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE ConsoleHandle,
BOOL CreateNewHandlesTable,
PHANDLE pInputHandle,
PHANDLE pOutputHandle,
PHANDLE pErrorHandle)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE Console;
/* Validate and lock the console */
if (!ConDrvValidateConsole(&Console,
ConsoleHandle,
CONSOLE_RUNNING, TRUE))
{
// FIXME: Find another status code
return STATUS_UNSUCCESSFUL;
}
/* Inherit the console */
ProcessData->ConsoleHandle = ConsoleHandle;
if (CreateNewHandlesTable)
{
/*
* We are about to create a new console. However when ConSrvNewProcess
* 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 the handles table so that we can recreate
* a new one later on.
*/
ConSrvFreeHandlesTable(ProcessData);
/* Initialize the handles table */
Status = ConSrvInitHandlesTable(ProcessData,
Console,
pInputHandle,
pOutputHandle,
pErrorHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to initialize the handles table\n");
ProcessData->ConsoleHandle = NULL;
goto Quit;
}
}
/* Duplicate the Input Event */
Status = NtDuplicateObject(NtCurrentProcess(),
Console->InputBuffer.ActiveEvent,
ProcessData->Process->ProcessHandle,
&ProcessData->ConsoleEvent,
EVENT_ALL_ACCESS, 0, 0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
ProcessData->ConsoleHandle = NULL;
goto Quit;
}
/* Insert the process into the processes list of the console */
InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&Console->ReferenceCount);
/* Update the internal info of the terminal */
ConioRefreshInternalInfo(Console);
Status = STATUS_SUCCESS;
Quit:
/* Unlock the console and return */
LeaveCriticalSection(&Console->Lock);
return Status;
}
VOID
FASTCALL
ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
{
PCONSOLE Console;
DPRINT("ConSrvRemoveConsole\n");
// RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Validate and lock the console */
if (ConDrvValidateConsole(&Console,
ProcessData->ConsoleHandle,
CONSOLE_RUNNING, TRUE))
{
DPRINT("ConSrvRemoveConsole - Locking OK\n");
/* Close all console handles and free the handles table */
ConSrvFreeHandlesTable(ProcessData);
/* Detach the process from the console */
ProcessData->ConsoleHandle = NULL;
/* Remove ourselves from the console's list of processes */
RemoveEntryList(&ProcessData->ConsoleLink);
/* Update the internal info of the terminal */
ConioRefreshInternalInfo(Console);
/* Release the console */
DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
ConDrvReleaseConsole(Console, TRUE);
//CloseHandle(ProcessData->ConsoleEvent);
//ProcessData->ConsoleEvent = NULL;
}
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvOpenConsole)
{
/*
* This API opens a handle to either the input buffer or to
* a screen-buffer of the console of the current process.
*/
NTSTATUS Status;
PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
DWORD DesiredAccess = OpenConsoleRequest->Access;
DWORD ShareMode = OpenConsoleRequest->ShareMode;
PCONSOLE_IO_OBJECT Object;
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);
/*
* Open a handle to either the active screen buffer or the input buffer.
*/
if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
{
Object = &Console->ActiveBuffer->Header;
}
else // HANDLE_INPUT
{
Object = &Console->InputBuffer.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 = ConSrvInsertObject(ProcessData,
&OpenConsoleRequest->ConsoleHandle,
Object,
DesiredAccess,
OpenConsoleRequest->Inheritable,
ShareMode);
}
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvCloseHandle)
{
NTSTATUS Status;
PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->ConsoleHandle);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvVerifyConsoleIoHandle)
{
NTSTATUS Status;
PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
ULONG Index = HandleToULong(ConsoleHandle) >> 2;
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (!IsConsoleHandle(ConsoleHandle) ||
Index >= ProcessData->HandleTableSize ||
ProcessData->HandleTable[Index].Object == NULL)
{
DPRINT("SrvVerifyConsoleIoHandle failed\n");
Status = STATUS_INVALID_HANDLE;
}
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvDuplicateHandle)
{
NTSTATUS Status;
PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
ULONG Index = HandleToULong(ConsoleHandle) >> 2;
PCONSOLE_IO_HANDLE Entry;
DWORD DesiredAccess;
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if ( /** !IsConsoleHandle(ConsoleHandle) || **/
Index >= ProcessData->HandleTableSize ||
(Entry = &ProcessData->HandleTable[Index])->Object == NULL)
{
DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
Status = STATUS_INVALID_HANDLE;
goto Quit;
}
if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
{
DesiredAccess = Entry->Access;
}
else
{
DesiredAccess = DuplicateHandleRequest->Access;
/* Make sure the source handle has all the desired flags */
if ((Entry->Access & DesiredAccess) == 0)
{
DPRINT1("Handle %p only has access %X; requested %X\n",
ConsoleHandle, Entry->Access, DesiredAccess);
Status = STATUS_INVALID_PARAMETER;
goto Quit;
}
}
/* Insert the new handle inside the process handles table */
Status = ConSrvInsertObject(ProcessData,
&DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
Entry->Object,
DesiredAccess,
DuplicateHandleRequest->Inheritable,
Entry->ShareMode);
if (NT_SUCCESS(Status) &&
(DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE))
{
/* Close the original handle if needed */
ConSrvCloseHandleEntry(Entry);
}
Quit:
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
/* EOF */
@@ -0,0 +1,34 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/handle.h
* PURPOSE: Console I/O Handles functions
* PROGRAMMERS: David Welch
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
VOID FASTCALL ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object,
IN CONSOLE_IO_OBJECT_TYPE Type,
IN PCONSOLE Console);
NTSTATUS FASTCALL ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE Handle,
PCONSOLE_IO_OBJECT Object,
DWORD Access,
BOOL Inheritable,
DWORD ShareMode);
NTSTATUS FASTCALL ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE Handle);
NTSTATUS FASTCALL ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE Handle,
PCONSOLE_IO_OBJECT* Object,
PVOID* Entry OPTIONAL,
DWORD Access,
BOOL LockConsole,
CONSOLE_IO_OBJECT_TYPE Type);
VOID FASTCALL ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object,
BOOL IsConsoleLocked);
/* EOF */
@@ -0,0 +1,17 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/heap.h
* PURPOSE: Heap Helpers
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
/* See init.c */
extern HANDLE ConSrvHeap;
#define ConsoleAllocHeap(Flags, Size) RtlAllocateHeap(ConSrvHeap, Flags, Size)
#define ConsoleFreeHeap(HeapBase) RtlFreeHeap(ConSrvHeap, 0, HeapBase)
/* EOF */
@@ -0,0 +1,377 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/include/conio.h
* PURPOSE: Public Console I/O Interface
* PROGRAMMERS: Gé van Geldorp
* Jeffrey Morlan
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
#define CSR_DEFAULT_CURSOR_SIZE 25
/* Default attributes */
#define DEFAULT_SCREEN_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
#define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | \
BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
/* Object type magic numbers */
typedef enum _CONSOLE_IO_OBJECT_TYPE
{
// ANY_TYPE_BUFFER = 0x00, // --> Match any types of IO handles
TEXTMODE_BUFFER = 0x01, // --> Output-type handles for text SBs
GRAPHICS_BUFFER = 0x02, // --> Output-type handles for graphics SBs
SCREEN_BUFFER = 0x03, // --> Any SB type
INPUT_BUFFER = 0x04 // --> Input-type handles
} CONSOLE_IO_OBJECT_TYPE;
typedef struct _CONSOLE_IO_OBJECT
{
CONSOLE_IO_OBJECT_TYPE Type;
struct _CONSOLE* /* PCONSOLE */ Console;
LONG AccessRead, AccessWrite;
LONG ExclusiveRead, ExclusiveWrite;
LONG HandleCount;
} CONSOLE_IO_OBJECT, *PCONSOLE_IO_OBJECT;
/******************************************************************************\
|* *|
|* Abstract "class" for screen-buffers, be they text-mode or graphics *|
|* *|
\******************************************************************************/
/*
* See conoutput.c for the implementation
*/
typedef struct _CONSOLE_SCREEN_BUFFER CONSOLE_SCREEN_BUFFER,
*PCONSOLE_SCREEN_BUFFER;
typedef struct _CONSOLE_SCREEN_BUFFER_VTBL
{
CONSOLE_IO_OBJECT_TYPE (*GetType)(PCONSOLE_SCREEN_BUFFER This);
} CONSOLE_SCREEN_BUFFER_VTBL, *PCONSOLE_SCREEN_BUFFER_VTBL;
#define GetType(This) (This)->Vtbl->GetType(This)
struct _CONSOLE_SCREEN_BUFFER
{
CONSOLE_IO_OBJECT Header; /* Object header - MUST BE IN FIRST PLACE */
PCONSOLE_SCREEN_BUFFER_VTBL Vtbl; /* Virtual table */
LIST_ENTRY ListEntry; /* Entry in console's list of buffers */
COORD ScreenBufferSize; /* Size of this screen buffer. (Rows, Columns) for text-mode and (Width, Height) for graphics */
COORD ViewSize; /* Associated "view" (i.e. console) size */
COORD OldScreenBufferSize; /* Old size of this screen buffer */
COORD OldViewSize; /* Old associated view size */
COORD ViewOrigin; /* Beginning offset for the actual display area */
/***** Put that VV in TEXTMODE_SCREEN_BUFFER ?? *****/
USHORT VirtualY; /* Top row of buffer being displayed, reported to callers */
COORD CursorPosition; /* Current cursor position */
BOOLEAN CursorBlinkOn;
BOOLEAN ForceCursorOff;
// ULONG CursorSize;
CONSOLE_CURSOR_INFO CursorInfo; // FIXME: Keep this member or not ??
/*********************************************/
// WORD ScreenDefaultAttrib; /* Default screen char attribute */
// WORD PopupDefaultAttrib; /* Default popup char attribute */
USHORT Mode; /* Output buffer modes */
};
/******************************************************************************\
|* *|
|* Text-mode and graphics-mode screen-buffer "classes" *|
|* *|
\******************************************************************************/
/*
* See text.c for the implementation
*/
/************************************************************************
* Screen buffer structure represents the win32 screen buffer object. *
* Internally, the portion of the buffer being shown CAN loop past the *
* bottom of the virtual buffer and wrap around to the top. Win32 does *
* not do this. I decided to do this because it eliminates the need to *
* do a massive memcpy() to scroll the contents of the buffer up to *
* scroll the screen on output, instead I just shift down the position *
* to be displayed, and let it wrap around to the top again. *
* The VirtualY member keeps track of the top Y coord that win32 *
* clients THINK is currently being displayed, because they think that *
* when the display reaches the bottom of the buffer and another line *
* being printed causes another line to scroll down, that the buffer IS *
* memcpy()'s up, and the bottom of the buffer is still displayed, but *
* internally, I just wrap back to the top of the buffer. *
************************************************************************/
typedef struct _TEXTMODE_BUFFER_INFO
{
COORD ScreenBufferSize;
USHORT ScreenAttrib;
USHORT PopupAttrib;
BOOLEAN IsCursorVisible;
ULONG CursorSize;
} TEXTMODE_BUFFER_INFO, *PTEXTMODE_BUFFER_INFO;
typedef struct _TEXTMODE_SCREEN_BUFFER
{
CONSOLE_SCREEN_BUFFER; /* Screen buffer base class - MUST BE IN FIRST PLACE */
PCHAR_INFO Buffer; /* Pointer to UNICODE screen buffer (Buffer->Char.UnicodeChar only is valid, not Char.AsciiChar) */
WORD ScreenDefaultAttrib; /* Default screen char attribute */
WORD PopupDefaultAttrib; /* Default popup char attribute */
} TEXTMODE_SCREEN_BUFFER, *PTEXTMODE_SCREEN_BUFFER;
/*
* See graphics.c for the implementation
*/
typedef struct _GRAPHICS_BUFFER_INFO
{
CONSOLE_GRAPHICS_BUFFER_INFO Info;
} GRAPHICS_BUFFER_INFO, *PGRAPHICS_BUFFER_INFO;
typedef struct _GRAPHICS_SCREEN_BUFFER
{
CONSOLE_SCREEN_BUFFER; /* Screen buffer base class - MUST BE IN FIRST PLACE */
ULONG BitMapInfoLength; /* Real size of the structure pointed by BitMapInfo */
LPBITMAPINFO BitMapInfo; /* Information on the bitmap buffer */
ULONG BitMapUsage; /* See the uUsage parameter of GetDIBits */
HANDLE hSection; /* Handle to the memory shared section for the bitmap buffer */
PVOID BitMap; /* Our bitmap buffer */
PVOID ClientBitMap; /* A copy of the client view of our bitmap buffer */
HANDLE Mutex; /* Our mutex, used to synchronize read / writes to the bitmap buffer */
HANDLE ClientMutex; /* A copy of the client handle to our mutex */
HANDLE ClientProcess; /* Handle to the client process who opened the buffer, to unmap the view */
} GRAPHICS_SCREEN_BUFFER, *PGRAPHICS_SCREEN_BUFFER;
typedef struct _CONSOLE_INPUT_BUFFER
{
CONSOLE_IO_OBJECT Header; /* Object header - MUST BE IN FIRST PLACE */
ULONG InputBufferSize; /* Size of this input buffer */
LIST_ENTRY InputEvents; /* List head for input event queue */
HANDLE ActiveEvent; /* Event set when an input event is added in its queue */
LIST_ENTRY ReadWaitQueue; /* List head for the queue of read wait blocks */
USHORT Mode; /* Input buffer modes */
} CONSOLE_INPUT_BUFFER, *PCONSOLE_INPUT_BUFFER;
typedef struct _FRONTEND FRONTEND, *PFRONTEND;
/* HACK: */ typedef struct _CONSOLE_INFO *PCONSOLE_INFO;
typedef struct _FRONTEND_VTBL
{
/*
* Internal interface (functions called by the console server only)
*/
NTSTATUS (WINAPI *InitFrontEnd)(IN OUT PFRONTEND This,
IN struct _CONSOLE* Console);
VOID (WINAPI *DeinitFrontEnd)(IN OUT PFRONTEND This);
/* Interface used for both text-mode and graphics screen buffers */
VOID (WINAPI *DrawRegion)(IN OUT PFRONTEND This,
SMALL_RECT* Region);
/* Interface used only for text-mode screen buffers */
VOID (WINAPI *WriteStream)(IN OUT PFRONTEND This,
SMALL_RECT* Block,
SHORT CursorStartX,
SHORT CursorStartY,
UINT ScrolledLines,
PWCHAR Buffer,
UINT Length);
BOOL (WINAPI *SetCursorInfo)(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER ScreenBuffer);
BOOL (WINAPI *SetScreenInfo)(IN OUT PFRONTEND This,
PCONSOLE_SCREEN_BUFFER ScreenBuffer,
SHORT OldCursorX,
SHORT OldCursorY);
VOID (WINAPI *ResizeTerminal)(IN OUT PFRONTEND This);
BOOL (WINAPI *ProcessKeyCallback)(IN OUT PFRONTEND This,
MSG* msg,
BYTE KeyStateMenu,
DWORD ShiftState,
UINT VirtualKeyCode,
BOOL Down);
VOID (WINAPI *RefreshInternalInfo)(IN OUT PFRONTEND This);
/*
* External interface (functions corresponding to the Console API)
*/
VOID (WINAPI *ChangeTitle)(IN OUT PFRONTEND This);
BOOL (WINAPI *ChangeIcon)(IN OUT PFRONTEND This,
HICON hWindowIcon);
HWND (WINAPI *GetConsoleWindowHandle)(IN OUT PFRONTEND This);
VOID (WINAPI *GetLargestConsoleWindowSize)(IN OUT PFRONTEND This,
PCOORD pSize);
ULONG (WINAPI *GetDisplayMode)(IN OUT PFRONTEND This);
BOOL (WINAPI *SetDisplayMode)(IN OUT PFRONTEND This,
ULONG NewMode);
INT (WINAPI *ShowMouseCursor)(IN OUT PFRONTEND This,
BOOL Show);
BOOL (WINAPI *SetMouseCursor)(IN OUT PFRONTEND This,
HCURSOR hCursor);
HMENU (WINAPI *MenuControl)(IN OUT PFRONTEND This,
UINT cmdIdLow,
UINT cmdIdHigh);
BOOL (WINAPI *SetMenuClose)(IN OUT PFRONTEND This,
BOOL Enable);
#if 0 // Possible future front-end interface
BOOL (WINAPI *GetFrontEndProperty)(IN OUT PFRONTEND This,
ULONG Flag,
PVOID Info,
ULONG Size);
BOOL (WINAPI *SetFrontEndProperty)(IN OUT PFRONTEND This,
ULONG Flag,
PVOID Info /*,
ULONG Size */);
#endif
} FRONTEND_VTBL, *PFRONTEND_VTBL;
struct _FRONTEND
{
PFRONTEND_VTBL Vtbl; /* Virtual table */
struct _CONSOLE* Console; /* Console to which the frontend is attached to */
PVOID Data; /* Private data */
PVOID OldData; /* Reserved */
};
/*
* 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;
typedef struct _CONSOLE
{
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;
CONSOLE_STATE State; /* State of the console */
LIST_ENTRY ProcessList; /* List of processes owning the console. The first one is the so-called "Console Leader Process" */
FRONTEND TermIFace; /* Frontend-specific interface */
/**************************** Input buffer and data ***************************/
CONSOLE_INPUT_BUFFER InputBuffer; /* Input buffer of the console */
/** Put those things in TEXTMODE_SCREEN_BUFFER ?? **/
PWCHAR LineBuffer; /* Current line being input, in line buffered mode */
WORD LineMaxSize; /* Maximum size of line in characters (including CR+LF) */
WORD LineSize; /* Current size of line */
WORD LinePos; /* Current position within line */
BOOLEAN LineComplete; /* User pressed enter, ready to send back to client */
BOOLEAN LineUpPressed;
BOOLEAN LineInsertToggle; /* Replace character over cursor instead of inserting */
ULONG LineWakeupMask; /* Bitmap of which control characters will end line input */
/***************************************************/
BOOLEAN QuickEdit;
BOOLEAN InsertMode;
UINT CodePage;
CONSOLE_SELECTION_INFO Selection; /* Contains information about the selection */
COORD dwSelectionCursor; /* Selection cursor position, most of the time different from Selection.dwSelectionAnchor */
/******************************* Screen buffers *******************************/
LIST_ENTRY BufferList; /* List of all screen buffers for this console */
PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to currently active screen buffer */
BYTE PauseFlags;
HANDLE UnpauseEvent;
LIST_ENTRY WriteWaitQueue; /* List head for the queue of write wait blocks */
UINT OutputCodePage;
/**************************** Aliases and Histories ***************************/
struct _ALIAS_HEADER *Aliases;
LIST_ENTRY HistoryBuffers;
ULONG HistoryBufferSize; /* Size for newly created history buffers */
ULONG NumberOfHistoryBuffers; /* Maximum number of history buffers allowed */
BOOLEAN HistoryNoDup; /* Remove old duplicate history entries */
/****************************** Other properties ******************************/
UNICODE_STRING OriginalTitle; /* Original title of console, the one defined when the console leader is launched; it never changes. Always NULL-terminated */
UNICODE_STRING Title; /* Title of console. Always NULL-terminated */
COORD ConsoleSize; /* The current size of the console, for text-mode only */
BOOLEAN FixedSize; /* TRUE if the console is of fixed size */
COLORREF Colors[16]; /* Colour palette */
} CONSOLE, *PCONSOLE;
/* PauseFlags values (internal only) */
#define PAUSED_FROM_KEYBOARD 0x1
#define PAUSED_FROM_SCROLLBAR 0x2
#define PAUSED_FROM_SELECTION 0x4
/* console.c */
VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags);
VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags);
NTSTATUS NTAPI
ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
IN ULONG ProcessGroupId,
IN ULONG Event);
/* coninput.c */
VOID WINAPI ConioProcessKey(PCONSOLE Console, MSG* msg);
NTSTATUS FASTCALL ConioProcessInputEvent(PCONSOLE Console,
PINPUT_RECORD InputEvent);
/* conoutput.c */
#define ConioInitRect(Rect, top, left, bottom, right) \
do { \
((Rect)->Top) = top; \
((Rect)->Left) = left; \
((Rect)->Bottom) = bottom; \
((Rect)->Right) = right; \
} while (0)
#define ConioIsRectEmpty(Rect) \
(((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
#define ConioRectHeight(Rect) \
(((Rect)->Top) > ((Rect)->Bottom) ? 0 : ((Rect)->Bottom) - ((Rect)->Top) + 1)
#define ConioRectWidth(Rect) \
(((Rect)->Left) > ((Rect)->Right) ? 0 : ((Rect)->Right) - ((Rect)->Left) + 1)
#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
PCHAR_INFO ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y);
VOID FASTCALL ConioDrawConsole(PCONSOLE Console);
NTSTATUS ConioResizeBuffer(PCONSOLE Console,
PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
COORD Size);
NTSTATUS ConioWriteConsole(PCONSOLE Console,
PTEXTMODE_SCREEN_BUFFER Buff,
PWCHAR Buffer,
DWORD Length,
BOOL Attrib);
DWORD FASTCALL ConioEffectiveCursorSize(PCONSOLE Console,
DWORD Scale);
/* EOF */
@@ -0,0 +1,50 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/conio.h
* PURPOSE: Internal Console I/O Interface
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
/* Macros used to call functions in the FRONTEND_VTBL virtual table */
#define ConioDrawRegion(Console, Region) \
(Console)->TermIFace.Vtbl->DrawRegion(&(Console)->TermIFace, (Region))
#define ConioWriteStream(Console, Block, CurStartX, CurStartY, ScrolledLines, Buffer, Length) \
(Console)->TermIFace.Vtbl->WriteStream(&(Console)->TermIFace, (Block), (CurStartX), (CurStartY), \
(ScrolledLines), (Buffer), (Length))
#define ConioSetCursorInfo(Console, Buff) \
(Console)->TermIFace.Vtbl->SetCursorInfo(&(Console)->TermIFace, (Buff))
#define ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY) \
(Console)->TermIFace.Vtbl->SetScreenInfo(&(Console)->TermIFace, (Buff), (OldCursorX), (OldCursorY))
#define ConioResizeTerminal(Console) \
(Console)->TermIFace.Vtbl->ResizeTerminal(&(Console)->TermIFace)
#define ConioProcessKeyCallback(Console, Msg, KeyStateMenu, ShiftState, VirtualKeyCode, Down) \
(Console)->TermIFace.Vtbl->ProcessKeyCallback(&(Console)->TermIFace, (Msg), (KeyStateMenu), (ShiftState), (VirtualKeyCode), (Down))
#define ConioRefreshInternalInfo(Console) \
(Console)->TermIFace.Vtbl->RefreshInternalInfo(&(Console)->TermIFace)
#define ConioChangeTitle(Console) \
(Console)->TermIFace.Vtbl->ChangeTitle(&(Console)->TermIFace)
#define ConioChangeIcon(Console, hWindowIcon) \
(Console)->TermIFace.Vtbl->ChangeIcon(&(Console)->TermIFace, (hWindowIcon))
#define ConioGetConsoleWindowHandle(Console) \
(Console)->TermIFace.Vtbl->GetConsoleWindowHandle(&(Console)->TermIFace)
#define ConioGetLargestConsoleWindowSize(Console, pSize) \
(Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize(&(Console)->TermIFace, (pSize))
#define ConioGetDisplayMode(Console) \
(Console)->TermIFace.Vtbl->GetDisplayMode(&(Console)->TermIFace)
#define ConioSetDisplayMode(Console, NewMode) \
(Console)->TermIFace.Vtbl->SetDisplayMode(&(Console)->TermIFace, (NewMode))
#define ConioShowMouseCursor(Console, Show) \
(Console)->TermIFace.Vtbl->ShowMouseCursor(&(Console)->TermIFace, (Show))
#define ConioSetMouseCursor(Console, hCursor) \
(Console)->TermIFace.Vtbl->SetMouseCursor(&(Console)->TermIFace, (hCursor))
#define ConioMenuControl(Console, CmdIdLow, CmdIdHigh) \
(Console)->TermIFace.Vtbl->MenuControl(&(Console)->TermIFace, (CmdIdLow), (CmdIdHigh))
#define ConioSetMenuClose(Console, Enable) \
(Console)->TermIFace.Vtbl->SetMenuClose(&(Console)->TermIFace, (Enable))
/* EOF */
@@ -0,0 +1,54 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/include/console.h
* PURPOSE: Public Console Management Interface
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
VOID NTAPI
ConDrvInitConsoleSupport(VOID);
NTSTATUS NTAPI
ConDrvInitConsole(OUT PHANDLE NewConsoleHandle,
OUT PCONSOLE* NewConsole,
IN PCONSOLE_INFO ConsoleInfo,
IN ULONG ConsoleLeaderProcessId);
NTSTATUS NTAPI
ConDrvRegisterFrontEnd(IN PCONSOLE Console,
IN PFRONTEND FrontEnd);
NTSTATUS NTAPI
ConDrvDeregisterFrontEnd(IN PCONSOLE Console);
VOID NTAPI
ConDrvDeleteConsole(IN PCONSOLE Console);
BOOLEAN NTAPI
ConDrvValidateConsoleState(IN PCONSOLE Console,
IN CONSOLE_STATE ExpectedState);
BOOLEAN NTAPI
ConDrvValidateConsoleUnsafe(IN PCONSOLE Console,
IN CONSOLE_STATE ExpectedState,
IN BOOLEAN LockConsole);
BOOLEAN NTAPI
ConDrvValidateConsole(OUT PCONSOLE* Console,
IN HANDLE ConsoleHandle,
IN CONSOLE_STATE ExpectedState,
IN BOOLEAN LockConsole);
NTSTATUS NTAPI
ConDrvGetConsole(OUT PCONSOLE* Console,
IN HANDLE ConsoleHandle,
IN BOOLEAN LockConsole);
VOID NTAPI
ConDrvReleaseConsole(IN PCONSOLE Console,
IN BOOLEAN WasConsoleLocked);
/* EOF */
@@ -0,0 +1,93 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/include/settings.h
* PURPOSE: Public Console Settings Management Interface
* PROGRAMMERS: Johannes Anderwald
* Hermes Belusca-Maito ([email protected])
*/
#pragma once
/* STRUCTURES *****************************************************************/
/*
* Structure used to hold terminal-specific information
*/
typedef struct _TERMINAL_INFO
{
ULONG Size; /* Size of the memory buffer pointed by TermInfo */
PVOID TermInfo; /* Address (or offset when talking to console.dll) of the memory buffer holding terminal information */
} TERMINAL_INFO, *PTERMINAL_INFO;
/*
* Structure used to hold console information
*/
typedef struct _CONSOLE_INFO
{
ULONG HistoryBufferSize;
ULONG NumberOfHistoryBuffers;
BOOLEAN HistoryNoDup;
BOOLEAN QuickEdit;
BOOLEAN InsertMode;
ULONG InputBufferSize;
COORD ScreenBufferSize;
COORD ConsoleSize; /* The size of the console */
BOOLEAN CursorBlinkOn;
BOOLEAN ForceCursorOff;
ULONG CursorSize;
USHORT ScreenAttrib; // CHAR_INFO ScreenFillAttrib
USHORT PopupAttrib;
COLORREF Colors[16]; /* Color palette */
ULONG CodePage;
WCHAR ConsoleTitle[MAX_PATH + 1];
} CONSOLE_INFO, *PCONSOLE_INFO;
#define RGBFromAttrib(Console, Attribute) ((Console)->Colors[(Attribute) & 0xF])
#define TextAttribFromAttrib(Attribute) ((Attribute) & 0xF)
#define BkgdAttribFromAttrib(Attribute) (((Attribute) >> 4) & 0xF)
#define MakeAttrib(TextAttrib, BkgdAttrib) (DWORD)((((BkgdAttrib) & 0xF) << 4) | ((TextAttrib) & 0xF))
/*
* Structure used to communicate with console.dll
*/
typedef struct _CONSOLE_PROPS
{
HWND hConsoleWindow;
BOOL ShowDefaultParams;
BOOLEAN AppliedConfig;
DWORD ActiveStaticControl;
CONSOLE_INFO ci; /* Console-specific informations */
TERMINAL_INFO TerminalInfo; /* Frontend-specific parameters */
} CONSOLE_PROPS, *PCONSOLE_PROPS;
/* FUNCTIONS ******************************************************************/
#ifndef CONSOLE_H__ // If we aren't included by console.dll
BOOL ConSrvOpenUserSettings(DWORD ProcessId,
LPCWSTR ConsoleTitle,
PHKEY hSubKey,
REGSAM samDesired,
BOOL bCreate);
BOOL ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId);
BOOL ConSrvWriteUserSettings(IN PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId);
VOID ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId);
VOID ConSrvApplyUserSettings(IN PCONSOLE Console,
IN PCONSOLE_INFO ConsoleInfo);
#endif
/* EOF */
@@ -0,0 +1,531 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/init.c
* PURPOSE: Initialization
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "api.h"
#include "procinit.h"
#include "include/conio.h"
#include "include/console.h"
#include "console.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
HINSTANCE ConSrvDllInstance = NULL;
/* Memory */
HANDLE ConSrvHeap = NULL; // Our own heap.
// Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3
// plus a little bit of Windows 7.
PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
SrvOpenConsole,
SrvGetConsoleInput,
SrvWriteConsoleInput,
SrvReadConsoleOutput,
SrvWriteConsoleOutput,
SrvReadConsoleOutputString,
SrvWriteConsoleOutputString,
SrvFillConsoleOutput,
SrvGetConsoleMode,
// SrvGetConsoleNumberOfFonts,
SrvGetConsoleNumberOfInputEvents,
SrvGetConsoleScreenBufferInfo,
SrvGetConsoleCursorInfo,
// SrvGetConsoleMouseInfo,
// SrvGetConsoleFontInfo,
// SrvGetConsoleFontSize,
// SrvGetConsoleCurrentFont,
SrvSetConsoleMode,
SrvSetConsoleActiveScreenBuffer,
SrvFlushConsoleInputBuffer,
SrvGetLargestConsoleWindowSize,
SrvSetConsoleScreenBufferSize,
SrvSetConsoleCursorPosition,
SrvSetConsoleCursorInfo,
SrvSetConsoleWindowInfo,
SrvScrollConsoleScreenBuffer,
SrvSetConsoleTextAttribute,
// SrvSetConsoleFont,
SrvSetConsoleIcon,
SrvReadConsole,
SrvWriteConsole,
SrvDuplicateHandle,
// SrvGetHandleInformation,
// SrvSetHandleInformation,
SrvCloseHandle,
SrvVerifyConsoleIoHandle,
SrvAllocConsole,
SrvFreeConsole,
SrvGetConsoleTitle,
SrvSetConsoleTitle,
SrvCreateConsoleScreenBuffer,
SrvInvalidateBitMapRect,
// SrvVDMConsoleOperation,
SrvSetConsoleCursor,
SrvShowConsoleCursor,
SrvConsoleMenuControl,
// SrvSetConsolePalette,
SrvSetConsoleDisplayMode,
// SrvRegisterConsoleVDM,
SrvGetConsoleHardwareState,
SrvSetConsoleHardwareState,
SrvGetConsoleDisplayMode,
SrvAddConsoleAlias,
SrvGetConsoleAlias,
SrvGetConsoleAliasesLength,
SrvGetConsoleAliasExesLength,
SrvGetConsoleAliases,
SrvGetConsoleAliasExes,
SrvExpungeConsoleCommandHistory,
SrvSetConsoleNumberOfCommands,
SrvGetConsoleCommandHistoryLength,
SrvGetConsoleCommandHistory,
// SrvSetConsoleCommandHistoryMode,
SrvGetConsoleCP,
SrvSetConsoleCP,
// SrvSetConsoleKeyShortcuts,
SrvSetConsoleMenuClose,
// SrvConsoleNotifyLastClose,
SrvGenerateConsoleCtrlEvent,
// SrvGetConsoleKeyboardLayoutName,
SrvGetConsoleWindow,
// SrvGetConsoleCharType,
// SrvSetConsoleLocalEUDC,
// SrvSetConsoleCursorMode,
// SrvGetConsoleCursorMode,
// SrvRegisterConsoleOS2,
// SrvSetConsoleOS2OemFormat,
// SrvGetConsoleNlsMode,
// SrvSetConsoleNlsMode,
// SrvRegisterConsoleIME,
// SrvUnregisterConsoleIME,
// SrvGetConsoleLangId,
SrvAttachConsole,
SrvGetConsoleSelectionInfo,
SrvGetConsoleProcessList,
SrvGetConsoleHistory,
SrvSetConsoleHistory,
};
BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
FALSE, // SrvOpenConsole,
FALSE, // SrvGetConsoleInput,
FALSE, // SrvWriteConsoleInput,
FALSE, // SrvReadConsoleOutput,
FALSE, // SrvWriteConsoleOutput,
FALSE, // SrvReadConsoleOutputString,
FALSE, // SrvWriteConsoleOutputString,
FALSE, // SrvFillConsoleOutput,
FALSE, // SrvGetConsoleMode,
// FALSE, // SrvGetConsoleNumberOfFonts,
FALSE, // SrvGetConsoleNumberOfInputEvents,
FALSE, // SrvGetConsoleScreenBufferInfo,
FALSE, // SrvGetConsoleCursorInfo,
// FALSE, // SrvGetConsoleMouseInfo,
// FALSE, // SrvGetConsoleFontInfo,
// FALSE, // SrvGetConsoleFontSize,
// FALSE, // SrvGetConsoleCurrentFont,
FALSE, // SrvSetConsoleMode,
FALSE, // SrvSetConsoleActiveScreenBuffer,
FALSE, // SrvFlushConsoleInputBuffer,
FALSE, // SrvGetLargestConsoleWindowSize,
FALSE, // SrvSetConsoleScreenBufferSize,
FALSE, // SrvSetConsoleCursorPosition,
FALSE, // SrvSetConsoleCursorInfo,
FALSE, // SrvSetConsoleWindowInfo,
FALSE, // SrvScrollConsoleScreenBuffer,
FALSE, // SrvSetConsoleTextAttribute,
// FALSE, // SrvSetConsoleFont,
FALSE, // SrvSetConsoleIcon,
FALSE, // SrvReadConsole,
FALSE, // SrvWriteConsole,
FALSE, // SrvDuplicateHandle,
// FALSE, // SrvGetHandleInformation,
// FALSE, // SrvSetHandleInformation,
FALSE, // SrvCloseHandle,
FALSE, // SrvVerifyConsoleIoHandle,
FALSE, // SrvAllocConsole,
FALSE, // SrvFreeConsole,
FALSE, // SrvGetConsoleTitle,
FALSE, // SrvSetConsoleTitle,
FALSE, // SrvCreateConsoleScreenBuffer,
FALSE, // SrvInvalidateBitMapRect,
// FALSE, // SrvVDMConsoleOperation,
FALSE, // SrvSetConsoleCursor,
FALSE, // SrvShowConsoleCursor,
FALSE, // SrvConsoleMenuControl,
// FALSE, // SrvSetConsolePalette,
FALSE, // SrvSetConsoleDisplayMode,
// FALSE, // SrvRegisterConsoleVDM,
FALSE, // SrvGetConsoleHardwareState,
FALSE, // SrvSetConsoleHardwareState,
TRUE, // SrvGetConsoleDisplayMode,
FALSE, // SrvAddConsoleAlias,
FALSE, // SrvGetConsoleAlias,
FALSE, // SrvGetConsoleAliasesLength,
FALSE, // SrvGetConsoleAliasExesLength,
FALSE, // SrvGetConsoleAliases,
FALSE, // SrvGetConsoleAliasExes,
FALSE, // SrvExpungeConsoleCommandHistory,
FALSE, // SrvSetConsoleNumberOfCommands,
FALSE, // SrvGetConsoleCommandHistoryLength,
FALSE, // SrvGetConsoleCommandHistory,
// FALSE, // SrvSetConsoleCommandHistoryMode,
FALSE, // SrvGetConsoleCP,
FALSE, // SrvSetConsoleCP,
// FALSE, // SrvSetConsoleKeyShortcuts,
FALSE, // SrvSetConsoleMenuClose,
// FALSE, // SrvConsoleNotifyLastClose,
FALSE, // SrvGenerateConsoleCtrlEvent,
// FALSE, // SrvGetConsoleKeyboardLayoutName,
FALSE, // SrvGetConsoleWindow,
// FALSE, // SrvGetConsoleCharType,
// FALSE, // SrvSetConsoleLocalEUDC,
// FALSE, // SrvSetConsoleCursorMode,
// FALSE, // SrvGetConsoleCursorMode,
// FALSE, // SrvRegisterConsoleOS2,
// FALSE, // SrvSetConsoleOS2OemFormat,
// FALSE, // SrvGetConsoleNlsMode,
// FALSE, // SrvSetConsoleNlsMode,
// FALSE, // SrvRegisterConsoleIME,
// FALSE, // SrvUnregisterConsoleIME,
// FALSE, // SrvGetConsoleLangId,
FALSE, // SrvAttachConsole,
FALSE, // SrvGetConsoleSelectionInfo,
FALSE, // SrvGetConsoleProcessList,
FALSE, // SrvGetConsoleHistory,
FALSE, // SrvSetConsoleHistory
};
PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
"OpenConsole",
"GetConsoleInput",
"WriteConsoleInput",
"ReadConsoleOutput",
"WriteConsoleOutput",
"ReadConsoleOutputString",
"WriteConsoleOutputString",
"FillConsoleOutput",
"GetConsoleMode",
// "GetConsoleNumberOfFonts",
"GetConsoleNumberOfInputEvents",
"GetConsoleScreenBufferInfo",
"GetConsoleCursorInfo",
// "GetConsoleMouseInfo",
// "GetConsoleFontInfo",
// "GetConsoleFontSize",
// "GetConsoleCurrentFont",
"SetConsoleMode",
"SetConsoleActiveScreenBuffer",
"FlushConsoleInputBuffer",
"GetLargestConsoleWindowSize",
"SetConsoleScreenBufferSize",
"SetConsoleCursorPosition",
"SetConsoleCursorInfo",
"SetConsoleWindowInfo",
"ScrollConsoleScreenBuffer",
"SetConsoleTextAttribute",
// "SetConsoleFont",
"SetConsoleIcon",
"ReadConsole",
"WriteConsole",
"DuplicateHandle",
// "GetHandleInformation",
// "SetHandleInformation",
"CloseHandle",
"VerifyConsoleIoHandle",
"AllocConsole",
"FreeConsole",
"GetConsoleTitle",
"SetConsoleTitle",
"CreateConsoleScreenBuffer",
"InvalidateBitMapRect",
// "VDMConsoleOperation",
"SetConsoleCursor",
"ShowConsoleCursor",
"ConsoleMenuControl",
// "SetConsolePalette",
"SetConsoleDisplayMode",
// "RegisterConsoleVDM",
"GetConsoleHardwareState",
"SetConsoleHardwareState",
"GetConsoleDisplayMode",
"AddConsoleAlias",
"GetConsoleAlias",
"GetConsoleAliasesLength",
"GetConsoleAliasExesLength",
"GetConsoleAliases",
"GetConsoleAliasExes",
"ExpungeConsoleCommandHistory",
"SetConsoleNumberOfCommands",
"GetConsoleCommandHistoryLength",
"GetConsoleCommandHistory",
// "SetConsoleCommandHistoryMode",
"GetConsoleCP",
"SetConsoleCP",
// "SetConsoleKeyShortcuts",
"SetConsoleMenuClose",
// "ConsoleNotifyLastClose",
"GenerateConsoleCtrlEvent",
// "GetConsoleKeyboardLayoutName",
"GetConsoleWindow",
// "GetConsoleCharType",
// "SetConsoleLocalEUDC",
// "SetConsoleCursorMode",
// "GetConsoleCursorMode",
// "RegisterConsoleOS2",
// "SetConsoleOS2OemFormat",
// "GetConsoleNlsMode",
// "SetConsoleNlsMode",
// "RegisterConsoleIME",
// "UnregisterConsoleIME",
// "GetConsoleLangId",
"AttachConsole",
"GetConsoleSelectionInfo",
"GetConsoleProcessList",
"GetConsoleHistory",
"SetConsoleHistory",
};
/* FUNCTIONS ******************************************************************/
/* See handle.c */
NTSTATUS
ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
IN PCONSOLE_PROCESS_DATA TargetProcessData);
NTSTATUS
NTAPI
ConSrvNewProcess(PCSR_PROCESS SourceProcess,
PCSR_PROCESS TargetProcess)
{
/**************************************************************************
* This function is called whenever a new process (GUI or CUI) is created.
*
* Copy the parent's handles table here if both the parent and the child
* processes are CUI. If we must actually create our proper console (and
* thus do not inherit from the console handles of the parent's), then we
* will clean this table in the next ConSrvConnect call. Why we are doing
* this? It's because here, we still don't know whether or not we must create
* a new console instead of inherit it from the parent, and, because in
* ConSrvConnect we don't have any reference to the parent process anymore.
**************************************************************************/
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_PROCESS_DATA TargetProcessData;
/* An empty target process is invalid */
if (!TargetProcess) return STATUS_INVALID_PARAMETER;
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
/* Initialize the new (target) process */
RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
TargetProcessData->Process = TargetProcess;
TargetProcessData->ConsoleEvent = NULL;
TargetProcessData->ConsoleHandle = TargetProcessData->ParentConsoleHandle = NULL;
TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
/*
* The handles table gets initialized either when inheriting from
* another console process, or when creating a new console.
*/
TargetProcessData->HandleTableSize = 0;
TargetProcessData->HandleTable = NULL;
RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
/* Do nothing if the source process is NULL */
if (!SourceProcess) return STATUS_SUCCESS;
// SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
/*
* If the child process is a console application and the parent process is
* either a console application or just has a valid console (with a valid
* handles table: this can happen if it is a GUI application having called
* AllocConsole), then try to inherit handles from the parent process.
*/
if (TargetProcessData->ConsoleApp /* && SourceProcessData->ConsoleApp */)
{
PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
PCONSOLE SourceConsole;
/* Validate and lock the parent's console */
if (ConDrvValidateConsole(&SourceConsole,
SourceProcessData->ConsoleHandle,
CONSOLE_RUNNING, TRUE))
{
/* Inherit the parent's handles table */
Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
if (NT_SUCCESS(Status))
{
/* Temporary save the parent's console too */
TargetProcessData->ParentConsoleHandle = SourceProcessData->ConsoleHandle;
}
/* Unlock the parent's console */
LeaveCriticalSection(&SourceConsole->Lock);
}
}
return Status;
}
NTSTATUS
NTAPI
ConSrvConnect(IN PCSR_PROCESS CsrProcess,
IN OUT PVOID ConnectionInfo,
IN OUT PULONG ConnectionInfoLength)
{
/**************************************************************************
* This function is called whenever a CUI new process is created.
**************************************************************************/
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
if ( ConnectionInfo == NULL ||
ConnectionInfoLength == NULL ||
*ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
{
DPRINT1("CONSRV: Connection failed\n");
return STATUS_UNSUCCESSFUL;
}
/* If we don't need a console, then get out of here */
if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
{
return STATUS_SUCCESS;
}
/* If we don't have a console, then create a new one... */
if (!ConnectInfo->ConsoleHandle ||
ConnectInfo->ConsoleHandle != ProcessData->ParentConsoleHandle)
{
DPRINT("ConSrvConnect - Allocate a new console\n");
/*
* We are about to create a new console. However when ConSrvNewProcess
* 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.
*
* ConSrvAllocateConsole will free our old handles table
* and recreate a new valid one.
*/
/* Initialize a new Console owned by the Console Leader Process */
Status = ConSrvAllocateConsole(ProcessData,
&ConnectInfo->InputHandle,
&ConnectInfo->OutputHandle,
&ConnectInfo->ErrorHandle,
&ConnectInfo->ConsoleStartInfo);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console allocation failed\n");
return Status;
}
}
else /* We inherit it from the parent */
{
DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
/* Reuse our current console */
Status = ConSrvInheritConsole(ProcessData,
ConnectInfo->ConsoleHandle,
FALSE,
NULL, // &ConnectInfo->InputHandle,
NULL, // &ConnectInfo->OutputHandle,
NULL); // &ConnectInfo->ErrorHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console inheritance failed\n");
return Status;
}
}
/* Return the console handle and the input wait handle to the caller */
ConnectInfo->ConsoleHandle = ProcessData->ConsoleHandle;
ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
/* Set the Property-Dialog and Control-Dispatcher handlers */
ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
return STATUS_SUCCESS;
}
VOID
NTAPI
ConSrvDisconnect(PCSR_PROCESS Process)
{
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
/**************************************************************************
* This function is called whenever a new process (GUI or CUI) is destroyed.
**************************************************************************/
if ( ProcessData->ConsoleHandle != NULL ||
ProcessData->HandleTable != NULL )
{
DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
ConSrvRemoveConsole(ProcessData);
}
RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
}
CSR_SERVER_DLL_INIT(ConServerDllInitialization)
{
/* Initialize the memory */
ConSrvHeap = RtlGetProcessHeap();
/*
// We can use our own heap instead of the CSR heap to investigate heap corruptions :)
ConSrvHeap = RtlCreateHeap(HEAP_GROWABLE |
HEAP_PROTECTION_ENABLED |
HEAP_FREE_CHECKING_ENABLED |
HEAP_TAIL_CHECKING_ENABLED |
HEAP_VALIDATE_ALL_ENABLED,
NULL, 0, 0, NULL, NULL);
if (!ConSrvHeap) return STATUS_NO_MEMORY;
*/
ConDrvInitConsoleSupport();
/* Setup the DLL Object */
LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;
LoadedServerDll->HighestApiSupported = ConsolepMaxApiNumber;
LoadedServerDll->DispatchTable = ConsoleServerApiDispatchTable;
LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
LoadedServerDll->NameTable = ConsoleServerApiNameTable;
LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
LoadedServerDll->ConnectCallback = ConSrvConnect;
LoadedServerDll->DisconnectCallback = ConSrvDisconnect;
LoadedServerDll->NewProcessCallback = ConSrvNewProcess;
// LoadedServerDll->HardErrorCallback = ConSrvHardError;
LoadedServerDll->ShutdownProcessCallback = NULL;
ConSrvDllInstance = LoadedServerDll->ServerHandle;
/* All done */
return STATUS_SUCCESS;
}
/* EOF */
@@ -0,0 +1,6 @@
LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Eingabeaufforderung"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_HEBREW, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_INDONESIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "Konsola ReactOS"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,6 @@
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
STRINGTABLE
BEGIN
IDS_CONSOLE_TITLE "ReactOS Console"
END
@@ -0,0 +1,644 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/lineinput.c
* PURPOSE: Console line input functions
* PROGRAMMERS: Jeffrey Morlan
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "console.h"
#include "include/conio.h"
#include "include/conio2.h"
#define NDEBUG
#include <debug.h>
typedef struct _HISTORY_BUFFER
{
LIST_ENTRY ListEntry;
UINT Position;
UINT MaxEntries;
UINT NumEntries;
PUNICODE_STRING Entries;
UNICODE_STRING ExeName;
} HISTORY_BUFFER, *PHISTORY_BUFFER;
/* PRIVATE FUNCTIONS **********************************************************/
static PHISTORY_BUFFER
HistoryCurrentBuffer(PCONSOLE Console)
{
/* TODO: use actual EXE name sent from process that called ReadConsole */
UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" };
PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
PHISTORY_BUFFER Hist;
for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
{
Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
if (RtlEqualUnicodeString(&ExeName, &Hist->ExeName, FALSE))
return Hist;
}
/* Couldn't find the buffer, create a new one */
Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName.Length);
if (!Hist) return NULL;
Hist->MaxEntries = Console->HistoryBufferSize;
Hist->NumEntries = 0;
Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING));
if (!Hist->Entries)
{
ConsoleFreeHeap(Hist);
return NULL;
}
Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length;
Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
memcpy(Hist->ExeName.Buffer, ExeName.Buffer, ExeName.Length);
InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
return Hist;
}
static VOID
HistoryAddEntry(PCONSOLE Console)
{
UNICODE_STRING NewEntry;
PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console);
INT i;
if (!Hist) return;
NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
NewEntry.Buffer = Console->LineBuffer;
/* Don't add blank or duplicate entries */
if (NewEntry.Length == 0 || Hist->MaxEntries == 0 ||
(Hist->NumEntries > 0 &&
RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], &NewEntry, FALSE)))
{
return;
}
if (Console->HistoryNoDup)
{
/* Check if this line has been entered before */
for (i = Hist->NumEntries - 1; i >= 0; i--)
{
if (RtlEqualUnicodeString(&Hist->Entries[i], &NewEntry, FALSE))
{
/* Just rotate the list to bring this entry to the end */
NewEntry = Hist->Entries[i];
memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
(Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
Hist->Entries[Hist->NumEntries - 1] = NewEntry;
Hist->Position = Hist->NumEntries - 1;
return;
}
}
}
if (Hist->NumEntries == Hist->MaxEntries)
{
/* List is full, remove oldest entry */
RtlFreeUnicodeString(&Hist->Entries[0]);
memmove(&Hist->Entries[0], &Hist->Entries[1],
--Hist->NumEntries * sizeof(UNICODE_STRING));
}
if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry, &Hist->Entries[Hist->NumEntries])))
Hist->NumEntries++;
Hist->Position = Hist->NumEntries - 1;
}
static VOID
HistoryGetCurrentEntry(PCONSOLE Console, PUNICODE_STRING Entry)
{
PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console);
if (!Hist || Hist->NumEntries == 0)
Entry->Length = 0;
else
*Entry = Hist->Entries[Hist->Position];
}
static PHISTORY_BUFFER
HistoryFindBuffer(PCONSOLE Console, PUNICODE_STRING ExeName)
{
PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
while (Entry != &Console->HistoryBuffers)
{
/* For the history APIs, the caller is allowed to give only part of the name */
PHISTORY_BUFFER Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
if (RtlPrefixUnicodeString(ExeName, &Hist->ExeName, TRUE))
return Hist;
Entry = Entry->Flink;
}
return NULL;
}
static VOID
HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
{
if (!Hist) return;
while (Hist->NumEntries != 0)
RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
ConsoleFreeHeap(Hist->Entries);
RemoveEntryList(&Hist->ListEntry);
ConsoleFreeHeap(Hist);
}
VOID FASTCALL
HistoryDeleteBuffers(PCONSOLE Console)
{
PLIST_ENTRY CurrentEntry;
PHISTORY_BUFFER HistoryBuffer;
while (!IsListEmpty(&Console->HistoryBuffers))
{
CurrentEntry = RemoveHeadList(&Console->HistoryBuffers);
HistoryBuffer = CONTAINING_RECORD(CurrentEntry, HISTORY_BUFFER, ListEntry);
HistoryDeleteBuffer(HistoryBuffer);
}
}
static VOID
LineInputSetPos(PCONSOLE Console, UINT Pos)
{
if (Pos != Console->LinePos && Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
{
PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
SHORT OldCursorX = Buffer->CursorPosition.X;
SHORT OldCursorY = Buffer->CursorPosition.Y;
INT XY = OldCursorY * Buffer->ScreenBufferSize.X + OldCursorX;
XY += (Pos - Console->LinePos);
if (XY < 0)
XY = 0;
else if (XY >= Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X)
XY = Buffer->ScreenBufferSize.Y * Buffer->ScreenBufferSize.X - 1;
Buffer->CursorPosition.X = XY % Buffer->ScreenBufferSize.X;
Buffer->CursorPosition.Y = XY / Buffer->ScreenBufferSize.X;
ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
}
Console->LinePos = Pos;
}
static VOID
LineInputEdit(PCONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion)
{
PTEXTMODE_SCREEN_BUFFER ActiveBuffer;
UINT Pos = Console->LinePos;
UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
UINT i;
if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return;
ActiveBuffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
/* Make sure there's always enough room for ending \r\n */
if (NewSize + 2 > Console->LineMaxSize)
return;
memmove(&Console->LineBuffer[Pos + NumToInsert],
&Console->LineBuffer[Pos + NumToDelete],
(Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
{
for (i = Pos; i < NewSize; i++)
{
ConioWriteConsole(Console, ActiveBuffer, &Console->LineBuffer[i], 1, TRUE);
}
for (; i < Console->LineSize; i++)
{
ConioWriteConsole(Console, ActiveBuffer, L" ", 1, TRUE);
}
Console->LinePos = i;
}
Console->LineSize = NewSize;
LineInputSetPos(Console, Pos + NumToInsert);
}
static VOID
LineInputRecallHistory(PCONSOLE Console, INT Offset)
{
PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console);
UINT Position = 0;
if (!Hist || Hist->NumEntries == 0) return;
Position = Hist->Position + Offset;
Position = min(max(Position, 0), Hist->NumEntries - 1);
Hist->Position = Position;
LineInputSetPos(Console, 0);
LineInputEdit(Console, Console->LineSize,
Hist->Entries[Hist->Position].Length / sizeof(WCHAR),
Hist->Entries[Hist->Position].Buffer);
}
VOID FASTCALL
LineInputKeyDown(PCONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
{
UINT Pos = Console->LinePos;
PHISTORY_BUFFER Hist;
UNICODE_STRING Entry;
INT HistPos;
switch (KeyEvent->wVirtualKeyCode)
{
case VK_ESCAPE:
/* Clear entire line */
LineInputSetPos(Console, 0);
LineInputEdit(Console, Console->LineSize, 0, NULL);
return;
case VK_HOME:
/* Move to start of line. With ctrl, erase everything left of cursor */
LineInputSetPos(Console, 0);
if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
LineInputEdit(Console, Pos, 0, NULL);
return;
case VK_END:
/* Move to end of line. With ctrl, erase everything right of cursor */
if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
else
LineInputSetPos(Console, Console->LineSize);
return;
case VK_LEFT:
/* Move left. With ctrl, move to beginning of previous word */
if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
{
while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--;
}
else
{
Pos -= (Pos > 0);
}
LineInputSetPos(Console, Pos);
return;
case VK_RIGHT:
case VK_F1:
/* Move right. With ctrl, move to beginning of next word */
if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
{
while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
LineInputSetPos(Console, Pos);
return;
}
else
{
/* Recall one character (but don't overwrite current line) */
HistoryGetCurrentEntry(Console, &Entry);
if (Pos < Console->LineSize)
LineInputSetPos(Console, Pos + 1);
else if (Pos * sizeof(WCHAR) < Entry.Length)
LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
}
return;
case VK_INSERT:
/* Toggle between insert and overstrike */
Console->LineInsertToggle = !Console->LineInsertToggle;
ConioSetCursorInfo(Console, Console->ActiveBuffer);
return;
case VK_DELETE:
/* Remove character to right of cursor */
if (Pos != Console->LineSize)
LineInputEdit(Console, 1, 0, NULL);
return;
case VK_PRIOR:
/* Recall first history entry */
LineInputRecallHistory(Console, -((WORD)-1));
return;
case VK_NEXT:
/* Recall last history entry */
LineInputRecallHistory(Console, +((WORD)-1));
return;
case VK_UP:
case VK_F5:
/* Recall previous history entry. On first time, actually recall the
* current (usually last) entry; on subsequent times go back. */
LineInputRecallHistory(Console, Console->LineUpPressed ? -1 : 0);
Console->LineUpPressed = TRUE;
return;
case VK_DOWN:
/* Recall next history entry */
LineInputRecallHistory(Console, +1);
return;
case VK_F3:
/* Recall remainder of current history entry */
HistoryGetCurrentEntry(Console, &Entry);
if (Pos * sizeof(WCHAR) < Entry.Length)
{
UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
}
return;
case VK_F6:
/* Insert a ^Z character */
KeyEvent->uChar.UnicodeChar = 26;
break;
case VK_F7:
if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
HistoryDeleteBuffer(HistoryCurrentBuffer(Console));
return;
case VK_F8:
/* Search for history entries starting with input. */
Hist = HistoryCurrentBuffer(Console);
if (!Hist || Hist->NumEntries == 0) return;
/* Like Up/F5, on first time start from current (usually last) entry,
* but on subsequent times start at previous entry. */
if (Console->LineUpPressed)
Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
Console->LineUpPressed = TRUE;
Entry.Length = Console->LinePos * sizeof(WCHAR);
Entry.Buffer = Console->LineBuffer;
/* Keep going backwards, even wrapping around to the end,
* until we get back to starting point */
HistPos = Hist->Position;
do
{
if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE))
{
Hist->Position = HistPos;
LineInputEdit(Console, Console->LineSize - Pos,
Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
&Hist->Entries[HistPos].Buffer[Pos]);
/* Cursor stays where it was */
LineInputSetPos(Console, Pos);
return;
}
if (--HistPos < 0) HistPos += Hist->NumEntries;
} while (HistPos != Hist->Position);
return;
}
if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT)
{
/* backspace handling - if processed input enabled then we handle it here
* otherwise we treat it like a normal char. */
if (Pos > 0)
{
LineInputSetPos(Console, Pos - 1);
LineInputEdit(Console, 1, 0, NULL);
}
}
else if (KeyEvent->uChar.UnicodeChar == L'\r')
{
HistoryAddEntry(Console);
/* TODO: Expand aliases */
LineInputSetPos(Console, Console->LineSize);
Console->LineBuffer[Console->LineSize++] = L'\r';
if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
{
if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
{
ConioWriteConsole(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\r", 1, TRUE);
}
}
/* Add \n if processed input. There should usually be room for it,
* but an exception to the rule exists: the buffer could have been
* pre-filled with LineMaxSize - 1 characters. */
if (Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
Console->LineSize < Console->LineMaxSize)
{
Console->LineBuffer[Console->LineSize++] = L'\n';
if (Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
{
if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
{
ConioWriteConsole(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\n", 1, TRUE);
}
}
}
Console->LineComplete = TRUE;
Console->LinePos = 0;
}
else if (KeyEvent->uChar.UnicodeChar != L'\0')
{
if (KeyEvent->uChar.UnicodeChar < 0x20 &&
Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
{
/* Control key client wants to handle itself (e.g. for tab completion) */
Console->LineBuffer[Console->LineSize++] = L' ';
Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
Console->LineComplete = TRUE;
Console->LinePos = 0;
}
else
{
/* Normal character */
BOOL Overstrike = Console->LineInsertToggle && Console->LinePos != Console->LineSize;
LineInputEdit(Console, Overstrike, 1, &KeyEvent->uChar.UnicodeChar);
}
}
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvGetConsoleCommandHistory)
{
PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
NTSTATUS Status;
PHISTORY_BUFFER Hist;
PBYTE Buffer = (PBYTE)GetCommandHistoryRequest->History;
ULONG BufferSize = GetCommandHistoryRequest->Length;
UINT i;
if ( !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetCommandHistoryRequest->History,
GetCommandHistoryRequest->Length,
sizeof(BYTE)) ||
!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetCommandHistoryRequest->ExeName.Buffer,
GetCommandHistoryRequest->ExeName.Length,
sizeof(BYTE)) )
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (NT_SUCCESS(Status))
{
Hist = HistoryFindBuffer(Console, &GetCommandHistoryRequest->ExeName);
if (Hist)
{
for (i = 0; i < Hist->NumEntries; i++)
{
if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR)))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length);
Buffer += Hist->Entries[i].Length;
*(PWCHAR)Buffer = L'\0';
Buffer += sizeof(WCHAR);
}
}
GetCommandHistoryRequest->Length = Buffer - (PBYTE)GetCommandHistoryRequest->History;
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
CSR_API(SrvGetConsoleCommandHistoryLength)
{
PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryLengthRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
NTSTATUS Status;
PHISTORY_BUFFER Hist;
ULONG Length = 0;
UINT i;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetCommandHistoryLengthRequest->ExeName.Buffer,
GetCommandHistoryLengthRequest->ExeName.Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (NT_SUCCESS(Status))
{
Hist = HistoryFindBuffer(Console, &GetCommandHistoryLengthRequest->ExeName);
if (Hist)
{
for (i = 0; i < Hist->NumEntries; i++)
Length += Hist->Entries[i].Length + sizeof(WCHAR);
}
GetCommandHistoryLengthRequest->Length = Length;
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
CSR_API(SrvExpungeConsoleCommandHistory)
{
PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ExpungeCommandHistoryRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
PHISTORY_BUFFER Hist;
NTSTATUS Status;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ExpungeCommandHistoryRequest->ExeName.Buffer,
ExpungeCommandHistoryRequest->ExeName.Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (NT_SUCCESS(Status))
{
Hist = HistoryFindBuffer(Console, &ExpungeCommandHistoryRequest->ExeName);
HistoryDeleteBuffer(Hist);
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
CSR_API(SrvSetConsoleNumberOfCommands)
{
PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryNumberCommandsRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
PHISTORY_BUFFER Hist;
NTSTATUS Status;
UINT MaxEntries = SetHistoryNumberCommandsRequest->NumCommands;
PUNICODE_STRING OldEntryList, NewEntryList;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&SetHistoryNumberCommandsRequest->ExeName.Buffer,
SetHistoryNumberCommandsRequest->ExeName.Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (NT_SUCCESS(Status))
{
Hist = HistoryFindBuffer(Console, &SetHistoryNumberCommandsRequest->ExeName);
if (Hist)
{
OldEntryList = Hist->Entries;
NewEntryList = ConsoleAllocHeap(0, MaxEntries * sizeof(UNICODE_STRING));
if (!NewEntryList)
{
Status = STATUS_NO_MEMORY;
}
else
{
/* If necessary, shrink by removing oldest entries */
for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
{
RtlFreeUnicodeString(Hist->Entries++);
Hist->Position += (Hist->Position == 0);
}
Hist->MaxEntries = MaxEntries;
Hist->Entries = memcpy(NewEntryList, Hist->Entries,
Hist->NumEntries * sizeof(UNICODE_STRING));
ConsoleFreeHeap(OldEntryList);
}
}
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
CSR_API(SrvGetConsoleHistory)
{
PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
PCONSOLE Console;
NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (NT_SUCCESS(Status))
{
HistoryInfoRequest->HistoryBufferSize = Console->HistoryBufferSize;
HistoryInfoRequest->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
HistoryInfoRequest->dwFlags = Console->HistoryNoDup;
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
CSR_API(SrvSetConsoleHistory)
{
PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
PCONSOLE Console;
NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (NT_SUCCESS(Status))
{
Console->HistoryBufferSize = HistoryInfoRequest->HistoryBufferSize;
Console->NumberOfHistoryBuffers = HistoryInfoRequest->NumberOfHistoryBuffers;
Console->HistoryNoDup = HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG;
ConSrvReleaseConsole(Console, TRUE);
}
return Status;
}
/* EOF */
@@ -0,0 +1,14 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/lineinput.c
* PURPOSE: Console line input functions
* PROGRAMMERS: Jeffrey Morlan
*/
#pragma once
VOID FASTCALL HistoryDeleteBuffers(PCONSOLE Console);
VOID FASTCALL LineInputKeyDown(PCONSOLE Console, KEY_EVENT_RECORD *KeyEvent);
/* EOF */
@@ -0,0 +1,24 @@
/*
* LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/procinit.h
* PURPOSE: Functions for console processes initialization
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
*/
#pragma once
NTSTATUS FASTCALL ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE pInputHandle,
PHANDLE pOutputHandle,
PHANDLE pErrorHandle,
PCONSOLE_START_INFO ConsoleStartInfo);
NTSTATUS FASTCALL ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE ConsoleHandle,
BOOL CreateNewHandlesTable,
PHANDLE pInputHandle,
PHANDLE pOutputHandle,
PHANDLE pErrorHandle);
VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData);
/* EOF */
@@ -0,0 +1,12 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/resource.h
* PURPOSE: Resource #defines
*/
#pragma once
#define IDS_CONSOLE_TITLE 500
/* EOF */
@@ -0,0 +1,70 @@
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// UTF-8
#pragma code_page(65001)
#ifdef LANGUAGE_BG_BG
#include "lang/bg-BG.rc"
#endif
#ifdef LANGUAGE_CS_CZ
#include "lang/cs-CZ.rc"
#endif
#ifdef LANGUAGE_DE_DE
#include "lang/de-DE.rc"
#endif
#ifdef LANGUAGE_EL_GR
#include "lang/el-GR.rc"
#endif
#ifdef LANGUAGE_EN_US
#include "lang/en-US.rc"
#endif
#ifdef LANGUAGE_ES_ES
#include "lang/es-ES.rc"
#endif
#ifdef LANGUAGE_FR_FR
#include "lang/fr-FR.rc"
#endif
#ifdef LANGUAGE_HE_IL
#include "lang/he-IL.rc"
#endif
#ifdef LANGUAGE_ID_ID
#include "lang/id-ID.rc"
#endif
#ifdef LANGUAGE_IT_IT
#include "lang/it-IT.rc"
#endif
#ifdef LANGUAGE_JA_JP
#include "lang/ja-JP.rc"
#endif
#ifdef LANGUAGE_NB_NO
#include "lang/no-NO.rc"
#endif
#ifdef LANGUAGE_PL_PL
#include "lang/pl-PL.rc"
#endif
#ifdef LANGUAGE_PT_BR
#include "lang/pt-BR.rc"
#endif
#ifdef LANGUAGE_RO_RO
#include "lang/ro-RO.rc"
#endif
#ifdef LANGUAGE_RU_RU
#include "lang/ru-RU.rc"
#endif
#ifdef LANGUAGE_SK_SK
#include "lang/sk-SK.rc"
#endif
#ifdef LANGUAGE_SV_SE
#include "lang/sv-SE.rc"
#endif
#ifdef LANGUAGE_TR_TR
#include "lang/tr-TR.rc"
#endif
#ifdef LANGUAGE_UK_UA
#include "lang/uk-UA.rc"
#endif
#ifdef LANGUAGE_ZH_CN
#include "lang/zh-CN.rc"
#endif
#ifdef LANGUAGE_ZH_TW
#include "lang/zh-TW.rc"
#endif
@@ -0,0 +1,576 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/settings.c
* PURPOSE: Console settings management
* PROGRAMMERS: Johannes Anderwald
* Hermes Belusca-Maito ([email protected])
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "include/conio2.h"
#include "include/settings.h"
#include <stdio.h> // for swprintf
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
extern const COLORREF s_Colors[16];
/* FUNCTIONS ******************************************************************/
static VOID
TranslateConsoleName(OUT LPWSTR DestString,
IN LPCWSTR ConsoleName,
IN UINT MaxStrLen)
{
#define PATH_SEPARATOR L'\\'
UINT wLength;
if ( DestString == NULL || ConsoleName == NULL ||
*ConsoleName == L'\0' || MaxStrLen == 0 )
{
return;
}
wLength = GetWindowsDirectoryW(DestString, MaxStrLen);
if ((wLength > 0) && (_wcsnicmp(ConsoleName, DestString, wLength) == 0))
{
wcsncpy(DestString, L"%SystemRoot%", MaxStrLen);
// FIXME: Fix possible buffer overflows there !!!!!
wcsncat(DestString, ConsoleName + wLength, MaxStrLen);
}
else
{
wcsncpy(DestString, ConsoleName, MaxStrLen);
}
/* Replace path separators (backslashes) by underscores */
while ((DestString = wcschr(DestString, PATH_SEPARATOR))) *DestString = L'_';
}
static BOOL
OpenUserRegistryPathPerProcessId(DWORD ProcessId,
PHKEY hResult,
REGSAM samDesired)
{
BOOL bRet = TRUE;
HANDLE hProcessToken = NULL;
HANDLE hProcess;
BYTE Buffer[256];
DWORD Length = 0;
UNICODE_STRING SidName;
PTOKEN_USER TokUser;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId);
if (!hProcess)
{
DPRINT1("Error: OpenProcess failed(0x%x)\n", GetLastError());
return FALSE;
}
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
{
DPRINT1("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
CloseHandle(hProcess);
return FALSE;
}
if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length))
{
DPRINT1("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
CloseHandle(hProcessToken);
CloseHandle(hProcess);
return FALSE;
}
TokUser = ((PTOKEN_USER)Buffer)->User.Sid;
if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE)))
{
DPRINT1("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
CloseHandle(hProcessToken);
CloseHandle(hProcess);
return FALSE;
}
/*
* Might fail for LiveCD... Why ? Because only HKU\.DEFAULT exists.
*/
bRet = (RegOpenKeyExW(HKEY_USERS,
SidName.Buffer,
0,
samDesired,
hResult) == ERROR_SUCCESS);
RtlFreeUnicodeString(&SidName);
CloseHandle(hProcessToken);
CloseHandle(hProcess);
return bRet;
}
/*static*/ BOOL
ConSrvOpenUserSettings(DWORD ProcessId,
LPCWSTR ConsoleTitle,
PHKEY hSubKey,
REGSAM samDesired,
BOOL bCreate)
{
BOOL bRet = TRUE;
WCHAR szBuffer[MAX_PATH] = L"Console\\";
WCHAR szBuffer2[MAX_PATH] = L"";
HKEY hKey;
/*
* Console properties are stored under the HKCU\Console\* key.
*
* We use the original console title as the subkey name for storing
* console properties. We need to distinguish whether we were launched
* via the console application directly or via a shortcut.
*
* If the title of the console corresponds to a path (more precisely,
* if the title is of the form: C:\ReactOS\<some_path>\<some_app.exe>),
* then use the corresponding unexpanded path and with the backslashes
* replaced by underscores, to make the registry happy,
* i.e. %SystemRoot%_<some_path>_<some_app.exe>
*/
/* Open the registry key where we saved the console properties */
if (!OpenUserRegistryPathPerProcessId(ProcessId, &hKey, samDesired))
{
DPRINT1("OpenUserRegistryPathPerProcessId failed\n");
return FALSE;
}
/*
* Try to open properties via the console title:
* to make the registry happy, replace all the
* backslashes by underscores.
*/
TranslateConsoleName(szBuffer2, ConsoleTitle, MAX_PATH);
/* Create the registry path */
wcsncat(szBuffer, szBuffer2, MAX_PATH);
/* Create or open the registry key */
if (bCreate)
{
/* Create the key */
bRet = (RegCreateKeyExW(hKey,
szBuffer,
0, NULL,
REG_OPTION_NON_VOLATILE,
samDesired,
NULL,
hSubKey,
NULL) == ERROR_SUCCESS);
}
else
{
/* Open the key */
bRet = (RegOpenKeyExW(hKey,
szBuffer,
0,
samDesired,
hSubKey) == ERROR_SUCCESS);
}
/* Close the parent key and return success or not */
RegCloseKey(hKey);
return bRet;
}
BOOL
ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId)
{
BOOL RetVal = FALSE;
HKEY hKey;
DWORD dwNumSubKeys = 0;
DWORD dwIndex;
DWORD dwColorIndex = 0;
DWORD dwType;
WCHAR szValueName[MAX_PATH];
DWORD dwValueName;
WCHAR szValue[LF_FACESIZE] = L"\0";
DWORD Value;
DWORD dwValue;
if (!ConSrvOpenUserSettings(ProcessId,
ConsoleInfo->ConsoleTitle,
&hKey, KEY_READ,
FALSE))
{
DPRINT("ConSrvOpenUserSettings failed\n");
return FALSE;
}
if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{
DPRINT("ConSrvReadUserSettings: RegQueryInfoKey failed\n");
RegCloseKey(hKey);
return FALSE;
}
DPRINT("ConSrvReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
{
dwValue = sizeof(Value);
dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
{
if (dwType == REG_SZ)
{
/*
* Retry in case of string value
*/
dwValue = sizeof(szValue);
dwValueName = MAX_PATH; // sizeof(szValueName)/sizeof(szValueName[0])
if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
break;
}
else
{
break;
}
}
/* Maybe it is UI-specific ?? */
if (!wcsncmp(szValueName, L"ColorTable", wcslen(L"ColorTable")))
{
dwColorIndex = 0;
swscanf(szValueName, L"ColorTable%2d", &dwColorIndex);
if (dwColorIndex < sizeof(ConsoleInfo->Colors)/sizeof(ConsoleInfo->Colors[0]))
{
ConsoleInfo->Colors[dwColorIndex] = Value;
RetVal = TRUE;
}
}
else if (!wcscmp(szValueName, L"HistoryBufferSize"))
{
ConsoleInfo->HistoryBufferSize = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"NumberOfHistoryBuffers"))
{
ConsoleInfo->NumberOfHistoryBuffers = Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"HistoryNoDup"))
{
ConsoleInfo->HistoryNoDup = (BOOLEAN)Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"QuickEdit"))
{
ConsoleInfo->QuickEdit = (BOOLEAN)Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"InsertMode"))
{
ConsoleInfo->InsertMode = (BOOLEAN)Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"ScreenBufferSize"))
{
ConsoleInfo->ScreenBufferSize.X = LOWORD(Value);
ConsoleInfo->ScreenBufferSize.Y = HIWORD(Value);
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"WindowSize"))
{
ConsoleInfo->ConsoleSize.X = LOWORD(Value);
ConsoleInfo->ConsoleSize.Y = HIWORD(Value);
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"CursorSize"))
{
ConsoleInfo->CursorSize = min(max(Value, 0), 100);
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"ScreenColors"))
{
ConsoleInfo->ScreenAttrib = (USHORT)Value;
RetVal = TRUE;
}
else if (!wcscmp(szValueName, L"PopupColors"))
{
ConsoleInfo->PopupAttrib = (USHORT)Value;
RetVal = TRUE;
}
}
RegCloseKey(hKey);
return RetVal;
}
BOOL
ConSrvWriteUserSettings(IN PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId)
{
BOOL GlobalSettings = (ConsoleInfo->ConsoleTitle[0] == L'\0');
HKEY hKey;
DWORD Storage = 0;
#define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
do { \
if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
{ \
RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
} \
else \
{ \
RegDeleteValue(hKey, (SettingName)); \
} \
} while (0)
WCHAR szValueName[15];
UINT i;
if (!ConSrvOpenUserSettings(ProcessId,
ConsoleInfo->ConsoleTitle,
&hKey, KEY_WRITE,
TRUE))
{
return FALSE;
}
for (i = 0 ; i < sizeof(ConsoleInfo->Colors)/sizeof(ConsoleInfo->Colors[0]) ; ++i)
{
/*
* Write only the new value if we are saving the global settings
* or we are saving settings for a particular console, which differs
* from the default ones.
*/
swprintf(szValueName, L"ColorTable%02d", i);
SetConsoleSetting(szValueName, REG_DWORD, sizeof(DWORD), &ConsoleInfo->Colors[i], s_Colors[i]);
}
SetConsoleSetting(L"HistoryBufferSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->HistoryBufferSize, 50);
SetConsoleSetting(L"NumberOfHistoryBuffers", REG_DWORD, sizeof(DWORD), &ConsoleInfo->NumberOfHistoryBuffers, 4);
Storage = ConsoleInfo->HistoryNoDup;
SetConsoleSetting(L"HistoryNoDup", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
Storage = ConsoleInfo->QuickEdit;
SetConsoleSetting(L"QuickEdit", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
Storage = ConsoleInfo->InsertMode;
SetConsoleSetting(L"InsertMode", REG_DWORD, sizeof(DWORD), &Storage, TRUE);
Storage = MAKELONG(ConsoleInfo->ScreenBufferSize.X, ConsoleInfo->ScreenBufferSize.Y);
SetConsoleSetting(L"ScreenBufferSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 300));
Storage = MAKELONG(ConsoleInfo->ConsoleSize.X, ConsoleInfo->ConsoleSize.Y);
SetConsoleSetting(L"WindowSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 25));
SetConsoleSetting(L"CursorSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CursorSize, CSR_DEFAULT_CURSOR_SIZE);
Storage = ConsoleInfo->ScreenAttrib;
SetConsoleSetting(L"ScreenColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_SCREEN_ATTRIB);
Storage = ConsoleInfo->PopupAttrib;
SetConsoleSetting(L"PopupColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_POPUP_ATTRIB);
RegCloseKey(hKey);
return TRUE;
}
VOID
ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo,
IN DWORD ProcessId)
{
if (ConsoleInfo == NULL) return;
/// HKCU,"Console","LoadConIme",0x00010003,1
/*
* 1. Load the default values
*/
// #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
// #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
ConsoleInfo->HistoryBufferSize = 50;
ConsoleInfo->NumberOfHistoryBuffers = 4;
ConsoleInfo->HistoryNoDup = FALSE;
ConsoleInfo->QuickEdit = FALSE;
ConsoleInfo->InsertMode = TRUE;
// ConsoleInfo->InputBufferSize;
// Rule: ScreenBufferSize >= ConsoleSize
ConsoleInfo->ScreenBufferSize.X = 80;
ConsoleInfo->ScreenBufferSize.Y = 300;
ConsoleInfo->ConsoleSize.X = 80;
ConsoleInfo->ConsoleSize.Y = 25;
ConsoleInfo->CursorBlinkOn;
ConsoleInfo->ForceCursorOff;
ConsoleInfo->CursorSize = CSR_DEFAULT_CURSOR_SIZE; // #define SMALL_SIZE 25
ConsoleInfo->ScreenAttrib = DEFAULT_SCREEN_ATTRIB;
ConsoleInfo->PopupAttrib = DEFAULT_POPUP_ATTRIB;
memcpy(ConsoleInfo->Colors, s_Colors, sizeof(s_Colors));
// ConsoleInfo->CodePage;
ConsoleInfo->ConsoleTitle[0] = L'\0';
/*
* 2. Overwrite them with the ones stored in HKCU\Console.
* If the HKCU\Console key doesn't exist, create it
* and store the default values inside.
*/
if (!ConSrvReadUserSettings(ConsoleInfo, ProcessId))
{
ConSrvWriteUserSettings(ConsoleInfo, ProcessId);
}
}
VOID
ConSrvApplyUserSettings(IN PCONSOLE Console,
IN PCONSOLE_INFO ConsoleInfo)
{
PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
/*
* Apply terminal-edition settings:
* - QuickEdit and Insert modes,
* - history settings.
*/
Console->QuickEdit = ConsoleInfo->QuickEdit;
Console->InsertMode = ConsoleInfo->InsertMode;
/*
* Apply foreground and background colors for both screen and popup
* and copy the new palette.
*/
if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer;
Buffer->ScreenDefaultAttrib = ConsoleInfo->ScreenAttrib;
Buffer->PopupDefaultAttrib = ConsoleInfo->PopupAttrib;
}
else // if (Console->ActiveBuffer->Header.Type == GRAPHICS_BUFFER)
{
}
// FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors.
memcpy(Console->Colors, ConsoleInfo->Colors, sizeof(s_Colors));
// TODO: Really update the screen attributes as FillConsoleOutputAttribute does.
/* Apply cursor size */
ActiveBuffer->CursorInfo.bVisible = (ConsoleInfo->CursorSize != 0);
ActiveBuffer->CursorInfo.dwSize = min(max(ConsoleInfo->CursorSize, 0), 100);
if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer;
COORD BufSize;
/* Resize its active screen-buffer */
BufSize = ConsoleInfo->ScreenBufferSize;
if (Console->FixedSize)
{
/*
* The console is in fixed-size mode, so we cannot resize anything
* at the moment. However, keep those settings somewhere so that
* we can try to set them up when we will be allowed to do so.
*/
if (ConsoleInfo->ConsoleSize.X != Buffer->OldViewSize.X ||
ConsoleInfo->ConsoleSize.Y != Buffer->OldViewSize.Y)
{
Buffer->OldViewSize = ConsoleInfo->ConsoleSize;
}
/* Buffer size is not allowed to be smaller than the view size */
if (BufSize.X >= Buffer->OldViewSize.X && BufSize.Y >= Buffer->OldViewSize.Y)
{
if (BufSize.X != Buffer->OldScreenBufferSize.X ||
BufSize.Y != Buffer->OldScreenBufferSize.Y)
{
/*
* The console is in fixed-size mode, so we cannot resize anything
* at the moment. However, keep those settings somewhere so that
* we can try to set them up when we will be allowed to do so.
*/
Buffer->OldScreenBufferSize = BufSize;
}
}
}
else
{
BOOL SizeChanged = FALSE;
/* Resize the console */
if (ConsoleInfo->ConsoleSize.X != Buffer->ViewSize.X ||
ConsoleInfo->ConsoleSize.Y != Buffer->ViewSize.Y)
{
Buffer->ViewSize = ConsoleInfo->ConsoleSize;
SizeChanged = TRUE;
}
/* Resize the screen-buffer */
if (BufSize.X != Buffer->ScreenBufferSize.X ||
BufSize.Y != Buffer->ScreenBufferSize.Y)
{
if (NT_SUCCESS(ConioResizeBuffer(Console, Buffer, BufSize)))
SizeChanged = TRUE;
}
if (SizeChanged) ConioResizeTerminal(Console);
}
}
else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
{
PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer;
/*
* In any case we do NOT modify the size of the graphics screen-buffer.
* We just allow resizing the view only if the new size is smaller
* than the older one.
*/
if (Console->FixedSize)
{
/*
* The console is in fixed-size mode, so we cannot resize anything
* at the moment. However, keep those settings somewhere so that
* we can try to set them up when we will be allowed to do so.
*/
if (ConsoleInfo->ConsoleSize.X <= Buffer->ViewSize.X ||
ConsoleInfo->ConsoleSize.Y <= Buffer->ViewSize.Y)
{
Buffer->OldViewSize = ConsoleInfo->ConsoleSize;
}
}
else
{
/* Resize the view if its size is bigger than the specified size */
if (ConsoleInfo->ConsoleSize.X <= Buffer->ViewSize.X ||
ConsoleInfo->ConsoleSize.Y <= Buffer->ViewSize.Y)
{
Buffer->ViewSize = ConsoleInfo->ConsoleSize;
// SizeChanged = TRUE;
}
}
}
}
/* EOF */