mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2822 lines
87 KiB
2822 lines
87 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
private.c
|
|
|
|
Abstract:
|
|
|
|
This file implements private APIs for Hardware Desktop Support.
|
|
|
|
Author:
|
|
|
|
Therese Stowell (thereses) 12-13-1991
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// initial palette registers
|
|
//
|
|
|
|
#define PAL_BLACK 0
|
|
#define PAL_BLUE 1
|
|
#define PAL_GREEN 2
|
|
#define PAL_RED 4
|
|
#define PAL_YELLOW (PAL_RED | PAL_GREEN)
|
|
#define PAL_CYAN (PAL_GREEN | PAL_BLUE)
|
|
#define PAL_MAGENTA (PAL_BLUE | PAL_RED)
|
|
#define PAL_WHITE (PAL_RED | PAL_GREEN | PAL_BLUE)
|
|
|
|
#define PAL_I_BLACK (PAL_BLACK + (PAL_WHITE << 3))
|
|
#define PAL_I_RED (PAL_RED + (PAL_RED << 3))
|
|
#define PAL_I_GREEN (PAL_GREEN + (PAL_GREEN << 3))
|
|
#define PAL_I_YELLOW (PAL_YELLOW + (PAL_YELLOW << 3))
|
|
#define PAL_I_BLUE (PAL_BLUE + (PAL_BLUE << 3))
|
|
#define PAL_I_CYAN (PAL_CYAN + (PAL_CYAN << 3))
|
|
#define PAL_I_MAGENTA (PAL_MAGENTA + (PAL_MAGENTA << 3))
|
|
#define PAL_I_WHITE (PAL_WHITE + (PAL_WHITE << 3))
|
|
|
|
#define INITIAL_PALETTE_SIZE 18
|
|
|
|
USHORT InitialPalette[INITIAL_PALETTE_SIZE] = {
|
|
|
|
16, // 16 entries
|
|
0, // start with first palette register
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
|
};
|
|
|
|
UCHAR ColorBuffer[] = {
|
|
|
|
16, // 16 entries
|
|
0,
|
|
0,
|
|
0, // start with first palette register
|
|
0x00, 0x00, 0x00, 0x00, // black
|
|
0x00, 0x00, 0x2A, 0x00, // blue
|
|
0x00, 0x2A, 0x00, 0x00, // green
|
|
0x00, 0x2A, 0x2A, 0x00, // cyan
|
|
0x2A, 0x00, 0x00, 0x00, // red
|
|
0x2A, 0x00, 0x2A, 0x00, // magenta
|
|
0x2A, 0x2A, 0x00, 0x00, // mustard/brown
|
|
0x36, 0x36, 0x36, 0x00, // light gray 39
|
|
0x28, 0x28, 0x28, 0x00, // dark gray 2A
|
|
0x00, 0x00, 0x3F, 0x00, // bright blue
|
|
0x00, 0x3F, 0x00, 0x00, // bright green
|
|
0x00, 0x3F, 0x3F, 0x00, // bright cyan
|
|
0x3F, 0x00, 0x00, 0x00, // bright red
|
|
0x3F, 0x00, 0x3F, 0x00, // bright magenta
|
|
0x3F, 0x3F, 0x00, 0x00, // bright yellow
|
|
0x3F, 0x3F, 0x3F, 0x00 // bright white
|
|
};
|
|
|
|
typedef struct _MODE_FONT_PAIR {
|
|
ULONG Height;
|
|
COORD Resolution;
|
|
COORD FontSize;
|
|
} MODE_FONT_PAIR, PMODE_FONT_PAIR;
|
|
|
|
#define NUMBER_OF_MODE_FONT_PAIRS 5
|
|
|
|
MODE_FONT_PAIR ModeFontPairs[NUMBER_OF_MODE_FONT_PAIRS] = {
|
|
{21, 640, 350, 8, 16},
|
|
{25, 720, 400, 8, 16},
|
|
{28, 720, 400, 8, 14},
|
|
{43, 640, 350, 8, 8 },
|
|
{50, 720, 400, 8, 8 }
|
|
};
|
|
|
|
|
|
HANDLE hCPIFile; // handle to font file
|
|
|
|
typedef struct _VGA_CHAR {
|
|
CHAR Char;
|
|
CHAR Attributes;
|
|
} VGA_CHAR, *PVGA_CHAR;
|
|
|
|
typedef struct _FONTFILEHEADER {
|
|
BYTE ffhFileTag[8]; // SHOULD BE 0FFH,"FONT___"
|
|
BYTE ffhReserved[8];
|
|
WORD ffhPointers;
|
|
BYTE ffhPointerType;
|
|
BYTE ffhOffset1;
|
|
WORD ffhOffset2;
|
|
BYTE ffhOffset3;
|
|
} FONTFILEHEADER, *LPFONTFILEHEADER;
|
|
|
|
typedef struct _FONTINFOHEADER {
|
|
WORD fihCodePages;
|
|
} FONTINFOHEADER, *LPFONTINFOHEADER;
|
|
|
|
typedef struct _CPENTRYHEADER {
|
|
WORD cpeLength;
|
|
WORD cpeNext1;
|
|
WORD cpeNext2;
|
|
WORD cpeDevType;
|
|
BYTE cpeDevSubtype[8];
|
|
WORD cpeCodepageID;
|
|
BYTE cpeReserved[6];
|
|
DWORD cpeOffset;
|
|
} CPENTRYHEADER, *LPCPENTRYHEADER;
|
|
|
|
typedef struct _FONTDATAHEADER {
|
|
WORD fdhReserved;
|
|
WORD fdhFonts;
|
|
WORD fdhLength;
|
|
} FONTDATAHEADER, *LPFONTDATAHEADER;
|
|
|
|
typedef struct _SCREENFONTHEADER {
|
|
BYTE sfhHeight;
|
|
BYTE sfhWidth;
|
|
WORD sfhAspect;
|
|
WORD sfhCharacters;
|
|
} SCREENFONTHEADER, *LPSCREENFONTHEADER;
|
|
|
|
#define CONSOLE_WINDOWS_DIR_LENGTH 256
|
|
#define CONSOLE_EGACPI_LENGTH 9 // includes NULL
|
|
#define CONSOLE_EGACPI "\\ega.cpi"
|
|
#define CONSOLE_FONT_BUFFER_LENGTH 50
|
|
#define CONSOLE_DEFAULT_ROM_FONT 437
|
|
|
|
|
|
#ifdef i386
|
|
VOID
|
|
ReverseMousePointer(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PSMALL_RECT Region
|
|
);
|
|
|
|
VOID
|
|
ReadRectFromScreenBuffer(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN COORD SourcePoint,
|
|
IN PCHAR_INFO Target,
|
|
IN COORD TargetSize,
|
|
IN PSMALL_RECT TargetRect
|
|
);
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
MapViewOfSection(
|
|
PHANDLE SectionHandle,
|
|
ULONG CommitSize,
|
|
PVOID *BaseAddress,
|
|
PULONG ViewSize,
|
|
HANDLE ClientHandle,
|
|
PVOID *BaseClientAddress
|
|
);
|
|
|
|
NTSTATUS
|
|
ConnectToEmulator(
|
|
IN BOOL Connect,
|
|
IN PCONSOLE_INFORMATION Console
|
|
);
|
|
|
|
|
|
|
|
ULONG
|
|
SrvSetConsoleCursor(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Sets the mouse pointer for the specified screen buffer.
|
|
|
|
Parameters:
|
|
|
|
hConsoleOutput - Supplies a console output handle.
|
|
|
|
hCursor - win32 cursor handle, should be NULL to set the default
|
|
cursor.
|
|
|
|
Return value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONSOLE_SETCURSOR_MSG a = (PCONSOLE_SETCURSOR_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_GRAPHICS_OUTPUT_HANDLE,
|
|
GENERIC_WRITE,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
if (a->CursorHandle == NULL) {
|
|
HandleData->Buffer.ScreenBuffer->CursorHandle = ghNormalCursor;
|
|
} else {
|
|
HandleData->Buffer.ScreenBuffer->CursorHandle = a->CursorHandle;
|
|
}
|
|
PostMessage(HandleData->Buffer.ScreenBuffer->Console->hWnd,
|
|
WM_SETCURSOR,
|
|
0,
|
|
-1
|
|
);
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
#ifdef i386
|
|
VOID
|
|
FullScreenCursor(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN BOOL On
|
|
)
|
|
{
|
|
if (On) {
|
|
if (ScreenInfo->CursorDisplayCount < 0) {
|
|
ScreenInfo->CursorDisplayCount = 0;
|
|
ReverseMousePointer(ScreenInfo, &ScreenInfo->Window);
|
|
}
|
|
} else {
|
|
if (ScreenInfo->CursorDisplayCount >= 0) {
|
|
ReverseMousePointer(ScreenInfo, &ScreenInfo->Window);
|
|
ScreenInfo->CursorDisplayCount = -1;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
ULONG
|
|
SrvShowConsoleCursor(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Sets the mouse pointer visibility counter. If the counter is less than
|
|
zero, the mouse pointer is not shown.
|
|
|
|
Parameters:
|
|
|
|
hOutput - Supplies a console output handle.
|
|
|
|
bShow - if TRUE, the display count is to be increased. if FALSE,
|
|
decreased.
|
|
|
|
Return value:
|
|
|
|
The return value specifies the new display count.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONSOLE_SHOWCURSOR_MSG a = (PCONSOLE_SHOWCURSOR_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_OUTPUT_HANDLE | CONSOLE_GRAPHICS_OUTPUT_HANDLE,
|
|
GENERIC_WRITE,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
if (!(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) ) {
|
|
if (a->bShow) {
|
|
HandleData->Buffer.ScreenBuffer->CursorDisplayCount += 1;
|
|
} else {
|
|
HandleData->Buffer.ScreenBuffer->CursorDisplayCount -= 1;
|
|
}
|
|
if (HandleData->Buffer.ScreenBuffer == Console->CurrentScreenBuffer) {
|
|
PostMessage(HandleData->Buffer.ScreenBuffer->Console->hWnd,
|
|
WM_SETCURSOR,
|
|
0,
|
|
-1
|
|
);
|
|
}
|
|
} else {
|
|
#ifdef i386
|
|
if (HandleData->HandleType != CONSOLE_GRAPHICS_OUTPUT_HANDLE &&
|
|
Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE &&
|
|
HandleData->Buffer.ScreenBuffer == Console->CurrentScreenBuffer) {
|
|
FullScreenCursor(HandleData->Buffer.ScreenBuffer,a->bShow);
|
|
}
|
|
#endif
|
|
}
|
|
a->DisplayCount = HandleData->Buffer.ScreenBuffer->CursorDisplayCount;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
ULONG
|
|
SrvConsoleMenuControl(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Sets the command id range for the current screen buffer and returns the
|
|
menu handle.
|
|
|
|
Parameters:
|
|
|
|
hConsoleOutput - Supplies a console output handle.
|
|
|
|
dwCommandIdLow - Specifies the lowest command id to store in the input buffer.
|
|
|
|
dwCommandIdHigh - Specifies the highest command id to store in the input
|
|
buffer.
|
|
|
|
Return value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONSOLE_MENUCONTROL_MSG a = (PCONSOLE_MENUCONTROL_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_OUTPUT_HANDLE | CONSOLE_GRAPHICS_OUTPUT_HANDLE,
|
|
GENERIC_WRITE,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
a->hMenu = HandleData->Buffer.ScreenBuffer->Console->hMenu;
|
|
HandleData->Buffer.ScreenBuffer->CommandIdLow = a->CommandIdLow;
|
|
HandleData->Buffer.ScreenBuffer->CommandIdHigh = a->CommandIdHigh;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
ULONG
|
|
SrvSetConsolePalette(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Sets the palette for the console screen buffer.
|
|
|
|
Parameters:
|
|
|
|
hOutput - Supplies a console output handle.
|
|
|
|
hPalette - Supplies a handle to the palette to set.
|
|
|
|
dwUsage - Specifies use of the system palette.
|
|
|
|
SYSPAL_NOSTATIC - System palette contains no static colors
|
|
except black and white.
|
|
|
|
SYSPAL_STATIC - System palette contains static colors
|
|
which will not change when an application
|
|
realizes its logical palette.
|
|
|
|
Return value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONSOLE_SETPALETTE_MSG a = (PCONSOLE_SETPALETTE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
HPALETTE hOldPalette;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_GRAPHICS_OUTPUT_HANDLE,
|
|
GENERIC_WRITE,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
BOOL bReset = FALSE;
|
|
|
|
/*
|
|
* Palette handle was converted in the client.
|
|
*/
|
|
if (GetCurrentThreadId() != HandleData->Buffer.ScreenBuffer->
|
|
Console->InputThreadInfo->ThreadId) {
|
|
bReset = TRUE;
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &HandleData->Buffer.ScreenBuffer->
|
|
Console->InputThreadInfo->ThreadHandle, sizeof(HANDLE));
|
|
}
|
|
|
|
NtUserConsoleControl(ConsolePublicPalette, &(a->hPalette), sizeof(HPALETTE));
|
|
|
|
hOldPalette = SelectPalette(
|
|
HandleData->Buffer.ScreenBuffer->Console->hDC,
|
|
a->hPalette,
|
|
FALSE);
|
|
|
|
if (hOldPalette == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
if ((HandleData->Buffer.ScreenBuffer->hPalette != NULL) &&
|
|
(a->hPalette != HandleData->Buffer.ScreenBuffer->hPalette)) {
|
|
DeleteObject(HandleData->Buffer.ScreenBuffer->hPalette);
|
|
}
|
|
HandleData->Buffer.ScreenBuffer->hPalette = a->hPalette;
|
|
HandleData->Buffer.ScreenBuffer->dwUsage = a->dwUsage;
|
|
if (!(HandleData->Buffer.ScreenBuffer->Console->Flags & CONSOLE_IS_ICONIC) &&
|
|
HandleData->Buffer.ScreenBuffer->Console->FullScreenFlags == 0) {
|
|
|
|
SetSystemPaletteUse(HandleData->Buffer.ScreenBuffer->Console->hDC,
|
|
HandleData->Buffer.ScreenBuffer->dwUsage);
|
|
RealizePalette(HandleData->Buffer.ScreenBuffer->Console->hDC);
|
|
}
|
|
if (HandleData->Buffer.ScreenBuffer->Console->hSysPalette == NULL) {
|
|
HandleData->Buffer.ScreenBuffer->Console->hSysPalette = hOldPalette;
|
|
}
|
|
}
|
|
|
|
if (bReset) {
|
|
HANDLE hNull = NULL;
|
|
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &hNull, sizeof(HANDLE));
|
|
}
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
VOID
|
|
SetActivePalette(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
{
|
|
BOOL bReset = FALSE;
|
|
|
|
if (GetCurrentThreadId() != ScreenInfo->Console->InputThreadInfo->ThreadId) {
|
|
bReset = TRUE;
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &ScreenInfo->Console->
|
|
InputThreadInfo->ThreadHandle, sizeof(HANDLE));
|
|
}
|
|
|
|
SetSystemPaletteUse(ScreenInfo->Console->hDC,
|
|
ScreenInfo->dwUsage
|
|
);
|
|
RealizePalette(ScreenInfo->Console->hDC);
|
|
|
|
if (bReset == TRUE) {
|
|
HANDLE hNull = NULL;
|
|
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &hNull, sizeof(HANDLE));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UnsetActivePalette(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
{
|
|
BOOL bReset = FALSE;
|
|
|
|
if (GetCurrentThreadId() != ScreenInfo->Console->InputThreadInfo->ThreadId) {
|
|
bReset = TRUE;
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &ScreenInfo->Console->
|
|
InputThreadInfo->ThreadHandle, sizeof(HANDLE));
|
|
}
|
|
|
|
SetSystemPaletteUse(ScreenInfo->Console->hDC,
|
|
SYSPAL_STATIC
|
|
);
|
|
RealizePalette(ScreenInfo->Console->hDC);
|
|
|
|
|
|
if (bReset == TRUE) {
|
|
HANDLE hNull = NULL;
|
|
|
|
NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop, &hNull, sizeof(HANDLE));
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
ConvertToFullScreen(
|
|
IN PCONSOLE_INFORMATION Console
|
|
)
|
|
{
|
|
#ifdef i386
|
|
PSCREEN_INFORMATION Cur;
|
|
COORD WindowedWindowSize, WindowSize;
|
|
|
|
// for each charmode screenbuffer
|
|
// match window size to a mode/font
|
|
// grow screen buffer if necessary
|
|
// save old window dimensions
|
|
// set new window dimensions
|
|
|
|
for (Cur=Console->ScreenBuffers;Cur!=NULL;Cur=Cur->Next) {
|
|
|
|
if (Cur->Flags & CONSOLE_GRAPHICS_BUFFER) {
|
|
continue;
|
|
}
|
|
|
|
// save old window dimensions
|
|
|
|
WindowedWindowSize.X = CONSOLE_WINDOW_SIZE_X(Cur);
|
|
WindowedWindowSize.Y = CONSOLE_WINDOW_SIZE_Y(Cur);
|
|
|
|
Cur->BufferInfo.TextInfo.WindowedWindowSize = WindowedWindowSize;
|
|
Cur->BufferInfo.TextInfo.WindowedScreenSize = Cur->ScreenBufferSize;
|
|
|
|
// match window size to a mode/font
|
|
|
|
Cur->BufferInfo.TextInfo.ModeIndex = MatchWindowSize(
|
|
Cur->ScreenBufferSize, &WindowSize);
|
|
|
|
// grow screen buffer if necessary
|
|
|
|
if (WindowSize.X > Cur->ScreenBufferSize.X ||
|
|
WindowSize.Y > Cur->ScreenBufferSize.Y) {
|
|
COORD NewScreenSize;
|
|
|
|
NewScreenSize.X = max(WindowSize.X,Cur->ScreenBufferSize.X);
|
|
NewScreenSize.Y = max(WindowSize.Y,Cur->ScreenBufferSize.Y);
|
|
ResizeScreenBuffer(Cur,
|
|
NewScreenSize,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
#if 0
|
|
DbgPrint("new window size is %d %d\n",WindowSize.X,WindowSize.Y);
|
|
DbgPrint("existing window size is %d %d\n",WindowedWindowSize.X,WindowedWindowSize.Y);
|
|
DbgPrint("existing window is %d %d %d %d\n",Cur->Window.Left,Cur->Window.Top,Cur->Window.Right,Cur->Window.Bottom);
|
|
DbgPrint("screenbuffersize is %d %d\n",Cur->ScreenBufferSize.X,Cur->ScreenBufferSize.Y);
|
|
#endif
|
|
// set new window dimensions
|
|
// we always resize horizontally from the right (change the
|
|
// right edge).
|
|
// we resize vertically from the bottom, keeping the cursor visible.
|
|
|
|
if (WindowedWindowSize.X != WindowSize.X) {
|
|
Cur->Window.Right -= WindowedWindowSize.X - WindowSize.X;
|
|
if (Cur->Window.Right >= Cur->ScreenBufferSize.X) {
|
|
Cur->Window.Left -= Cur->Window.Right - Cur->ScreenBufferSize.X + 1;
|
|
Cur->Window.Right -= Cur->Window.Right - Cur->ScreenBufferSize.X + 1;
|
|
}
|
|
}
|
|
if (WindowedWindowSize.Y > WindowSize.Y) {
|
|
Cur->Window.Bottom -= WindowedWindowSize.Y - WindowSize.Y;
|
|
if (Cur->Window.Bottom >= Cur->ScreenBufferSize.Y) {
|
|
Cur->Window.Top -= Cur->Window.Bottom - Cur->ScreenBufferSize.Y + 1;
|
|
Cur->Window.Bottom = Cur->ScreenBufferSize.Y - 1;
|
|
}
|
|
} else if (WindowedWindowSize.Y < WindowSize.Y) {
|
|
Cur->Window.Top -= WindowSize.Y - WindowedWindowSize.Y;
|
|
if (Cur->Window.Top < 0) {
|
|
Cur->Window.Bottom -= Cur->Window.Top;
|
|
Cur->Window.Top = 0;
|
|
}
|
|
}
|
|
if (Cur->BufferInfo.TextInfo.CursorPosition.Y > Cur->Window.Bottom) {
|
|
Cur->Window.Top += Cur->BufferInfo.TextInfo.CursorPosition.Y - Cur->Window.Bottom;
|
|
Cur->Window.Bottom = Cur->BufferInfo.TextInfo.CursorPosition.Y;
|
|
}
|
|
#if 0
|
|
DbgPrint("new window is %d %d %d %d\n",Cur->Window.Left,Cur->Window.Top,Cur->Window.Right,Cur->Window.Bottom);
|
|
DbgPrint("cursor is %d %d\n",Cur->BufferInfo.TextInfo.CursorPosition.X,Cur->BufferInfo.TextInfo.CursorPosition.Y);
|
|
#endif
|
|
ASSERT(WindowSize.X == CONSOLE_WINDOW_SIZE_X(Cur));
|
|
ASSERT(WindowSize.Y == CONSOLE_WINDOW_SIZE_Y(Cur));
|
|
Cur->BufferInfo.TextInfo.MousePosition.X = Cur->Window.Left;
|
|
Cur->BufferInfo.TextInfo.MousePosition.Y = Cur->Window.Top;
|
|
|
|
if (Cur->Flags & CONSOLE_OEMFONT_DISPLAY) {
|
|
DBGCHARS(("ConvertToFullScreen converts UnicodeOem -> Unicode\n"));
|
|
FalseUnicodeToRealUnicode(
|
|
Cur->BufferInfo.TextInfo.TextRows,
|
|
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
|
|
Console->OutputCP);
|
|
} else {
|
|
DBGCHARS(("ConvertToFullScreen needs no conversion\n"));
|
|
}
|
|
DBGCHARS(("Cur->BufferInfo.TextInfo.Rows = %lx\n",
|
|
Cur->BufferInfo.TextInfo.Rows));
|
|
DBGCHARS(("Cur->BufferInfo.TextInfo.TextRows = %lx\n",
|
|
Cur->BufferInfo.TextInfo.TextRows));
|
|
}
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ConvertToWindowed(
|
|
IN PCONSOLE_INFORMATION Console
|
|
)
|
|
{
|
|
#ifdef i386
|
|
PSCREEN_INFORMATION Cur;
|
|
SMALL_RECT WindowedWindow;
|
|
|
|
// for each charmode screenbuffer
|
|
// restore window dimensions
|
|
|
|
for (Cur=Console->ScreenBuffers;Cur!=NULL;Cur=Cur->Next) {
|
|
if ((Cur->Flags & CONSOLE_TEXTMODE_BUFFER) == 0) {
|
|
continue;
|
|
}
|
|
|
|
ResizeScreenBuffer(Cur,
|
|
Cur->BufferInfo.TextInfo.WindowedScreenSize,
|
|
FALSE);
|
|
WindowedWindow.Right = Cur->Window.Right;
|
|
WindowedWindow.Bottom = Cur->Window.Bottom;
|
|
WindowedWindow.Left = Cur->Window.Right + 1 -
|
|
Cur->BufferInfo.TextInfo.WindowedWindowSize.X;
|
|
WindowedWindow.Top = Cur->Window.Bottom + 1 -
|
|
Cur->BufferInfo.TextInfo.WindowedWindowSize.Y;
|
|
if (WindowedWindow.Left > Cur->Window.Left) {
|
|
WindowedWindow.Right -= WindowedWindow.Left - Cur->Window.Left;
|
|
WindowedWindow.Left = Cur->Window.Left;
|
|
}
|
|
if (WindowedWindow.Right < Cur->BufferInfo.TextInfo.CursorPosition.X) {
|
|
WindowedWindow.Left += Cur->BufferInfo.TextInfo.CursorPosition.X - WindowedWindow.Right;
|
|
WindowedWindow.Right = Cur->BufferInfo.TextInfo.CursorPosition.X;
|
|
}
|
|
if (WindowedWindow.Top > Cur->Window.Top) {
|
|
WindowedWindow.Bottom -= WindowedWindow.Top - Cur->Window.Top;
|
|
WindowedWindow.Top = Cur->Window.Top;
|
|
}
|
|
if (WindowedWindow.Bottom < Cur->BufferInfo.TextInfo.CursorPosition.Y) {
|
|
WindowedWindow.Top += Cur->BufferInfo.TextInfo.CursorPosition.Y - WindowedWindow.Bottom;
|
|
WindowedWindow.Bottom = Cur->BufferInfo.TextInfo.CursorPosition.Y;
|
|
}
|
|
ResizeWindow(Cur, &WindowedWindow, FALSE);
|
|
|
|
if (Cur->Flags & CONSOLE_OEMFONT_DISPLAY) {
|
|
DBGCHARS(("ConvertToWindowed converts Unicode -> UnicodeOem\n"));
|
|
RealUnicodeToFalseUnicode(
|
|
Cur->BufferInfo.TextInfo.TextRows,
|
|
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
|
|
Console->OutputCP);
|
|
} else {
|
|
DBGCHARS(("ConvertToWindowed needs no conversion\n"));
|
|
}
|
|
DBGCHARS(("Cur->BufferInfo.TextInfo.Rows = %lx\n",
|
|
Cur->BufferInfo.TextInfo.Rows));
|
|
DBGCHARS(("Cur->BufferInfo.TextInfo.TextRows = %lx\n",
|
|
Cur->BufferInfo.TextInfo.TextRows));
|
|
}
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
SrvSetConsoleDisplayMode(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This routine sets the console display mode for an output buffer.
|
|
This API is only supported on x86 machines. Jazz consoles are always
|
|
windowed.
|
|
|
|
Parameters:
|
|
|
|
hConsoleOutput - Supplies a console output handle.
|
|
|
|
dwFlags - Specifies the display mode. Options are:
|
|
|
|
CONSOLE_FULLSCREEN_MODE - data is displayed fullscreen
|
|
|
|
CONSOLE_WINDOWED_MODE - data is displayed in a window
|
|
|
|
lpNewScreenBufferDimensions - On output, contains the new dimensions of
|
|
the screen buffer. The dimensions are in rows and columns for
|
|
textmode screen buffers.
|
|
|
|
Return value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONSOLE_SETDISPLAYMODE_MSG a = (PCONSOLE_SETDISPLAYMODE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
PSCREEN_INFORMATION ScreenInfo;
|
|
UINT State;
|
|
HANDLE hEvent;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = NtDuplicateObject(CONSOLE_CLIENTPROCESSHANDLE(),
|
|
a->hEvent,
|
|
NtCurrentProcess(),
|
|
&hEvent,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UnlockConsole(Console);
|
|
return (ULONG) Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_OUTPUT_HANDLE | CONSOLE_GRAPHICS_OUTPUT_HANDLE,
|
|
GENERIC_WRITE,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
ScreenInfo = HandleData->Buffer.ScreenBuffer;
|
|
if (!ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
|
|
NtClose(hEvent);
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (a->dwFlags == CONSOLE_FULLSCREEN_MODE) {
|
|
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
|
|
if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
UnlockConsole(Console);
|
|
NtClose(hEvent);
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}
|
|
#else
|
|
if (!FullScreenInitialized) {
|
|
NtClose(hEvent);
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}
|
|
#endif
|
|
if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
|
|
KdPrint(("CONSRV: VDM converting to fullscreen twice\n"));
|
|
ASSERT(FALSE);
|
|
NtClose(hEvent);
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}
|
|
ConvertToFullScreen(Console);
|
|
Console->FullScreenFlags |= CONSOLE_FULLSCREEN;
|
|
State = FULLSCREEN;
|
|
} else {
|
|
if (Console->FullScreenFlags == 0) {
|
|
KdPrint(("CONSRV: VDM converting to windowed twice\n"));
|
|
ASSERT(FALSE);
|
|
NtClose(hEvent);
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_INVALID_PARAMETER;
|
|
}
|
|
ConvertToWindowed(Console);
|
|
Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN;
|
|
State = WINDOWED;
|
|
}
|
|
PostMessage(Console->hWnd,
|
|
CM_MODE_TRANSITION,
|
|
State,
|
|
(long)hEvent
|
|
);
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
VOID
|
|
UnregisterVDM(
|
|
IN PCONSOLE_INFORMATION Console
|
|
)
|
|
{
|
|
// williamh, Feb 2 1994.
|
|
// catch multiple calls to unregister vdm. Believe it or not, this could
|
|
// happen
|
|
ASSERT(Console->Flags & CONSOLE_VDM_REGISTERED);
|
|
if (!(Console->Flags & CONSOLE_VDM_REGISTERED))
|
|
return;
|
|
|
|
#ifdef i386
|
|
if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE &&
|
|
Console->Flags & CONSOLE_CONNECTED_TO_EMULATOR) {
|
|
NtUserConsoleControl(ConsoleSetVDMCursorBounds, NULL, 0);
|
|
// connect emulator
|
|
ConnectToEmulator(FALSE, Console);
|
|
}
|
|
|
|
if (FullScreenInitialized) {
|
|
CloseHandle(Console->VDMStartHardwareEvent);
|
|
CloseHandle(Console->VDMEndHardwareEvent);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),Console->StateBuffer);
|
|
NtUnmapViewOfSection(Console->VDMProcessHandle,Console->StateBufferClient);
|
|
NtClose(Console->StateSectionHandle);
|
|
Console->StateLength = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
Console->Flags &= ~CONSOLE_VDM_REGISTERED;
|
|
|
|
if (Console->Flags & CONSOLE_HAS_FOCUS) {
|
|
USERTHREAD_FLAGS Flags;
|
|
|
|
Flags.dwFlags = 0;
|
|
Flags.dwMask = (TIF_VDMAPP | TIF_DOSEMULATOR);
|
|
NtUserSetInformationThread(Console->InputThreadInfo->ThreadHandle,
|
|
UserThreadFlags, &Flags, sizeof(Flags));
|
|
}
|
|
Console->Flags &= ~CONSOLE_WOW_REGISTERED;
|
|
ASSERT(Console->VDMBuffer != NULL);
|
|
if (Console->VDMBuffer != NULL) {
|
|
NtUnmapViewOfSection(Console->VDMProcessHandle,Console->VDMBufferClient);
|
|
NtUnmapViewOfSection(NtCurrentProcess(),Console->VDMBuffer);
|
|
NtClose(Console->VDMBufferSectionHandle);
|
|
Console->VDMBuffer = NULL;
|
|
}
|
|
#ifdef i386
|
|
if (Console->CurrentScreenBuffer &&
|
|
Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
Console->CurrentScreenBuffer->BufferInfo.TextInfo.MousePosition.X = 0;
|
|
Console->CurrentScreenBuffer->BufferInfo.TextInfo.MousePosition.Y = 0;
|
|
}
|
|
#endif
|
|
ASSERT(Console->VDMProcessHandle);
|
|
CloseHandle(Console->VDMProcessHandle);
|
|
Console->VDMProcessHandle = NULL;
|
|
|
|
}
|
|
|
|
ULONG
|
|
SrvRegisterConsoleVDM(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
PCONSOLE_REGISTERVDM_MSG a = (PCONSOLE_REGISTERVDM_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
ULONG ViewSize;
|
|
#ifdef i386
|
|
VIDEO_REGISTER_VDM RegisterVdm;
|
|
ULONG RegisterVdmSize = sizeof(RegisterVdm);
|
|
VIDEO_VDM Vdm;
|
|
#endif //i386
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
|
|
if (!a->RegisterFlags) {
|
|
// williamh, Jan 28 1994
|
|
// do not do an assert here because we may have unregistered the ntvdm
|
|
// and the ntvdm doesn't necessarily know this(and it could post another
|
|
// unregistervdm). Return error here so NTVDM knows what to do
|
|
// ASSERT(Console->Flags & CONSOLE_VDM_REGISTERED);
|
|
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
ASSERT(!(Console->Flags & CONSOLE_FULLSCREEN_NOPAINT));
|
|
UnregisterVDM(Console);
|
|
#ifdef i386
|
|
if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE &&
|
|
Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
|
|
// SetVideoMode(Console->CurrentScreenBuffer);
|
|
//set up cursor
|
|
SetCursorInformationHW(Console->CurrentScreenBuffer,
|
|
Console->CurrentScreenBuffer->BufferInfo.TextInfo.CursorSize,
|
|
Console->CurrentScreenBuffer->BufferInfo.TextInfo.CursorVisible);
|
|
SetCursorPositionHW(Console->CurrentScreenBuffer,
|
|
Console->CurrentScreenBuffer->BufferInfo.TextInfo.CursorPosition);
|
|
}
|
|
#endif
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_ACCESS_DENIED;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
}
|
|
|
|
// check it out. A console should have only one VDM registered.
|
|
ASSERT(!(Console->Flags & CONSOLE_VDM_REGISTERED));
|
|
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
UnlockConsole(Console);
|
|
return (ULONG) STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
ASSERT(!Console->VDMProcessHandle);
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(), CONSOLE_CLIENTPROCESSHANDLE(),
|
|
NtCurrentProcess(), &Console->VDMProcessHandle,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
}
|
|
Console->VDMProcessId = CONSOLE_CLIENTPROCESSID();
|
|
|
|
#ifdef i386
|
|
|
|
Vdm.ProcessHandle = Console->VDMProcessHandle;
|
|
|
|
//
|
|
// Assume fullscreen initialization will fail.
|
|
// have state length set to zero so that NTVDM will know
|
|
// full screen is disabled.
|
|
//
|
|
|
|
a->StateLength = 0;
|
|
Console->StateLength = 0;
|
|
Console->StateBufferClient = NULL;
|
|
|
|
if (FullScreenInitialized) {
|
|
|
|
Status = NtDuplicateObject(CONSOLE_CLIENTPROCESSHANDLE(),
|
|
a->StartEvent,
|
|
NtCurrentProcess(),
|
|
&Console->VDMStartHardwareEvent,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtDuplicateObject(CONSOLE_CLIENTPROCESSHANDLE(),
|
|
a->EndEvent,
|
|
NtCurrentProcess(),
|
|
&Console->VDMEndHardwareEvent,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtUserFullscreenControl(FullscreenControlRegisterVdm,
|
|
&Vdm,
|
|
sizeof(Vdm),
|
|
&RegisterVdm,
|
|
&RegisterVdmSize
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// create state section and map a view of it into server and vdm.
|
|
// this section is used to get/set video hardware state during
|
|
// the fullscreen<->windowed transition. we create the section
|
|
// instead of the vdm for security purposes.
|
|
//
|
|
|
|
Status = MapViewOfSection(&Console->StateSectionHandle,
|
|
RegisterVdm.MinimumStateSize,
|
|
&Console->StateBuffer,
|
|
&ViewSize,
|
|
Console->VDMProcessHandle,
|
|
&a->StateBuffer
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
a->StateLength = RegisterVdm.MinimumStateSize;
|
|
Console->StateLength = RegisterVdm.MinimumStateSize;
|
|
Console->StateBufferClient = a->StateBuffer;
|
|
}
|
|
|
|
} else {
|
|
|
|
CloseHandle(Console->VDMStartHardwareEvent);
|
|
CloseHandle(Console->VDMEndHardwareEvent);
|
|
}
|
|
|
|
} else {
|
|
|
|
// ASSERT(FALSE);
|
|
CloseHandle(Console->VDMStartHardwareEvent);
|
|
CloseHandle(Console->VDMEndHardwareEvent);
|
|
}
|
|
|
|
} else {
|
|
CloseHandle(Console->VDMStartHardwareEvent);
|
|
}
|
|
//
|
|
// if failed to duplicate screen switch events or map view
|
|
// to video state shared buffer, fails this API
|
|
//
|
|
if (!NT_SUCCESS(Status)) {
|
|
UnlockConsole(Console);
|
|
return (Status);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
//
|
|
// create vdm char section and map a view of it into server and vdm.
|
|
// this section is used by the vdm to update the screen when in a
|
|
// charmode window. this is a performance optimization. we create
|
|
// the section instead of the vdm for security purposes.
|
|
//
|
|
|
|
Status = MapViewOfSection(&Console->VDMBufferSectionHandle,
|
|
#ifdef i386
|
|
a->VDMBufferSize.X*a->VDMBufferSize.Y*2,
|
|
#else //risc
|
|
a->VDMBufferSize.X*a->VDMBufferSize.Y*4,
|
|
#endif
|
|
&Console->VDMBuffer,
|
|
&ViewSize,
|
|
Console->VDMProcessHandle,
|
|
&a->VDMBuffer
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
Console->VDMBuffer = NULL;
|
|
|
|
#ifdef i386
|
|
|
|
if (FullScreenInitialized) {
|
|
|
|
NtUnmapViewOfSection(NtCurrentProcess(),Console->StateBuffer);
|
|
NtUnmapViewOfSection(Console->VDMProcessHandle,Console->StateBufferClient);
|
|
NtClose(Console->StateSectionHandle);
|
|
CloseHandle(Console->VDMStartHardwareEvent);
|
|
CloseHandle(Console->VDMEndHardwareEvent);
|
|
}
|
|
|
|
#endif
|
|
CloseHandle(Console->VDMProcessHandle);
|
|
Console->VDMProcessHandle = NULL;
|
|
UnlockConsole(Console);
|
|
return((ULONG) Status);
|
|
}
|
|
Console->VDMBufferClient = a->VDMBuffer;
|
|
|
|
Console->Flags |= CONSOLE_VDM_REGISTERED;
|
|
|
|
if (Console->Flags & CONSOLE_HAS_FOCUS) {
|
|
USERTHREAD_FLAGS Flags;
|
|
|
|
Flags.dwFlags = TIF_VDMAPP;
|
|
Flags.dwMask = TIF_VDMAPP;
|
|
NtUserSetInformationThread(Console->InputThreadInfo->ThreadHandle,
|
|
UserThreadFlags, &Flags, sizeof(Flags));
|
|
}
|
|
Console->VDMBufferSize = a->VDMBufferSize;
|
|
|
|
if (a->RegisterFlags & CONSOLE_REGISTER_WOW)
|
|
Console->Flags |= CONSOLE_WOW_REGISTERED;
|
|
else
|
|
Console->Flags &= ~CONSOLE_WOW_REGISTERED;
|
|
|
|
//
|
|
// if we're already in fullscreen and we run a DOS app for
|
|
// the first time, connect the emulator.
|
|
//
|
|
|
|
#ifdef i386
|
|
if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
|
|
RECT CursorRect;
|
|
CursorRect.left = -32767;
|
|
CursorRect.top = -32767;
|
|
CursorRect.right = 32767;
|
|
CursorRect.bottom = 32767;
|
|
NtUserConsoleControl(ConsoleSetVDMCursorBounds, &CursorRect, sizeof(RECT));
|
|
// connect emulator
|
|
ASSERT(!(Console->Flags & CONSOLE_CONNECTED_TO_EMULATOR));
|
|
ConnectToEmulator(TRUE, Console);
|
|
}
|
|
#endif
|
|
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
NTSTATUS
|
|
SrvConsoleNotifyLastClose(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
PCONSOLE_NOTIFYLASTCLOSE_MSG a = (PCONSOLE_NOTIFYLASTCLOSE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
// williamh, Feb 2 1994.
|
|
// this MIPS and ALPHA speical case is not necessary. We expect
|
|
// ntvdm to call RegisterConsoleVDM API and there we do duplicate
|
|
// the vdm process handle and grab its process id.
|
|
// If we continue to do this we may hit the assert below
|
|
// because when RegisterConsoleVDM failed(short of memory, for example)
|
|
// the VDMProcessHandle may have been set and next time a vdm application
|
|
// was launched from the same console(ntvdm will do the NotifyLastClose
|
|
// before RegisterConsoleVDM).
|
|
#if 0
|
|
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
|
|
ASSERT(Console->VDMProcessHandle == NULL);
|
|
Status = NtDuplicateObject(NtCurrentProcess(), CONSOLE_CLIENTPROCESSHANDLE(),
|
|
NtCurrentProcess(), &Console->VDMProcessHandle,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Console->VDMProcessId = CONSOLE_CLIENTPROCESSID();
|
|
#endif
|
|
#endif
|
|
// Doesn't allow two or more processes to have last-close notify on
|
|
// the same console
|
|
if (Console->Flags & CONSOLE_NOTIFY_LAST_CLOSE) {
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(), CONSOLE_CLIENTPROCESSHANDLE(),
|
|
NtCurrentProcess(),
|
|
&Console->hProcessLastNotifyClose,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
}
|
|
|
|
Console->Flags |= CONSOLE_NOTIFY_LAST_CLOSE;
|
|
Console->ProcessIdLastNotifyClose = CONSOLE_CLIENTPROCESSID();
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MapViewOfSection(
|
|
PHANDLE SectionHandle,
|
|
ULONG CommitSize,
|
|
PVOID *BaseAddress,
|
|
PULONG ViewSize,
|
|
HANDLE ClientHandle,
|
|
PVOID *BaseClientAddress
|
|
)
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER secSize;
|
|
|
|
//
|
|
// open section and map a view of it.
|
|
//
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
NULL,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
secSize.QuadPart = CommitSize;
|
|
Status = NtCreateSection (SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
&Obja,
|
|
&secSize,
|
|
PAGE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
*BaseAddress = 0;
|
|
*ViewSize = 0;
|
|
|
|
Status = NtMapViewOfSection(*SectionHandle,
|
|
NtCurrentProcess(),
|
|
BaseAddress, // Receives the base
|
|
// address of the section.
|
|
|
|
0, // No specific type of
|
|
// address required.
|
|
|
|
CommitSize, // Commit size. It was
|
|
// passed by the caller.
|
|
// NULL for a save, and
|
|
// size of the section
|
|
// for a set.
|
|
|
|
NULL, // Section offset it NULL;
|
|
// Map from the start.
|
|
|
|
ViewSize, // View Size is NULL since
|
|
// we want to map the
|
|
// entire section.
|
|
|
|
ViewUnmap,
|
|
0L,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(*SectionHandle);
|
|
return Status;
|
|
}
|
|
|
|
*BaseClientAddress = 0;
|
|
*ViewSize = 0;
|
|
Status = NtMapViewOfSection(*SectionHandle,
|
|
ClientHandle,
|
|
BaseClientAddress, // Receives the base
|
|
// address of the section.
|
|
|
|
0, // No specific type of
|
|
// address required.
|
|
|
|
CommitSize, // Commit size. It was
|
|
// passed by the caller.
|
|
// NULL for a save, and
|
|
// size of the section
|
|
// for a set.
|
|
|
|
NULL, // Section offset it NULL;
|
|
// Map from the start.
|
|
|
|
ViewSize, // View Size is NULL since
|
|
// we want to map the
|
|
// entire section.
|
|
|
|
ViewUnmap,
|
|
// williamh, Jan 28 1994
|
|
// This MEM_TOP_DOWN is necessary.
|
|
// if the console has VDM registered, ntvdm would have released its video memory
|
|
// address space(0xA0000 ~ 0xBFFFF). Without the MEM_TOP_DOWN, the
|
|
// NtMapViewOfSection can grab the address space and we will have trouble of
|
|
// mapping the address space to the physical video ram. We don't do a test
|
|
// for VDM because there is no harm of doing this for non-vdm application.
|
|
MEM_TOP_DOWN,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(*SectionHandle);
|
|
}
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
ConnectToEmulator(
|
|
IN BOOL Connect,
|
|
IN PCONSOLE_INFORMATION Console
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
FULLSCREENCONTROL fsctl;
|
|
VIDEO_VDM ConnectInfo;
|
|
HANDLE ProcessHandle = Console->VDMProcessHandle;
|
|
USERTHREAD_FLAGS Flags;
|
|
|
|
DBGFULLSCR(("ConnectToEmulator : %s - entering\n", Connect ? "CONNECT" : "DISCONNECT"));
|
|
|
|
Flags.dwMask = TIF_DOSEMULATOR;
|
|
if (Connect) {
|
|
fsctl = FullscreenControlEnable;
|
|
Console->Flags |= CONSOLE_CONNECTED_TO_EMULATOR;
|
|
Flags.dwFlags = TIF_DOSEMULATOR;
|
|
} else {
|
|
fsctl = FullscreenControlDisable;
|
|
Console->Flags &= ~CONSOLE_CONNECTED_TO_EMULATOR;
|
|
Flags.dwFlags = 0;
|
|
}
|
|
|
|
if (Console->Flags & CONSOLE_HAS_FOCUS) {
|
|
NtUserSetInformationThread(Console->InputThreadInfo->ThreadHandle,
|
|
UserThreadFlags, &Flags, sizeof(Flags));
|
|
}
|
|
|
|
ConnectInfo.ProcessHandle = ProcessHandle;
|
|
|
|
|
|
Status = NtUserFullscreenControl(fsctl,
|
|
&ConnectInfo,
|
|
sizeof(ConnectInfo),
|
|
NULL,
|
|
NULL);
|
|
|
|
if (Status != STATUS_SUCCESS && Status != STATUS_PROCESS_IS_TERMINATING) {
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
DBGFULLSCR(("ConnectToEmulator : leaving, staus = %08lx\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
#define CONSOLE_VDM_TIMEOUT 200000
|
|
|
|
NTSTATUS
|
|
DisplayModeTransition(
|
|
IN BOOL bForeground,
|
|
IN PCONSOLE_INFORMATION Console,
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
{
|
|
#ifdef i386
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER li;
|
|
|
|
if (!FullScreenInitialized)
|
|
return STATUS_SUCCESS;
|
|
|
|
if (bForeground) {
|
|
|
|
PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer;
|
|
LARGE_INTEGER li;
|
|
NTSTATUS Status;
|
|
|
|
KdPrint((" CONSRV - Display Mode transition to fullscreen \n"));
|
|
|
|
ASSERT (Console->FullScreenFlags & CONSOLE_FULLSCREEN);
|
|
|
|
Console->FullScreenFlags |= CONSOLE_FULLSCREEN_HARDWARE;
|
|
|
|
if (!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER)) {
|
|
#if 1
|
|
DEVMODEW Devmode;
|
|
ULONG Index;
|
|
|
|
KdPrint(("CONSRV: ChangeDispSettings fullscreen\n"));
|
|
|
|
Index = Console->CurrentScreenBuffer->BufferInfo.TextInfo.ModeIndex;
|
|
|
|
//
|
|
// set mode to go to full screen
|
|
//
|
|
|
|
ZeroMemory(&Devmode, sizeof(Devmode));
|
|
|
|
Devmode.dmSize = sizeof(Devmode);
|
|
Devmode.dmDriverExtra = 0;
|
|
Devmode.dmFields = DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT |
|
|
DM_DISPLAYFLAGS;
|
|
|
|
Devmode.dmBitsPerPel = 4;
|
|
Devmode.dmPelsWidth = ModeFontPairs[Index].Resolution.X;
|
|
Devmode.dmPelsHeight = ModeFontPairs[Index].Resolution.Y;
|
|
Devmode.dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE;
|
|
|
|
if (NT_SUCCESS(NtUserFullscreenControl(FullscreenControlSetMode,
|
|
&Devmode,
|
|
sizeof(Devmode),
|
|
NULL,
|
|
NULL)))
|
|
{
|
|
#endif
|
|
// set video mode and font
|
|
if (SetVideoMode(ScreenInfo)) {
|
|
|
|
//set up cursor
|
|
|
|
SetCursorInformationHW(ScreenInfo,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorSize,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorVisible);
|
|
SetCursorPositionHW(ScreenInfo,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
// tell VDM to unmap memory
|
|
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
NtSetEvent(Console->VDMStartHardwareEvent,NULL);
|
|
li.QuadPart = (LONGLONG)-10000 * CONSOLE_VDM_TIMEOUT;
|
|
Status = NtWaitForSingleObject(Console->VDMEndHardwareEvent,
|
|
FALSE, &li);
|
|
if (Status != 0) {
|
|
Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT;
|
|
UnregisterVDM(Console);
|
|
KdPrint(("CONSRV: VDM not responding.\n"));
|
|
}
|
|
}
|
|
|
|
if (!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER)) {
|
|
|
|
WriteRegionToScreen(ScreenInfo,&ScreenInfo->Window);
|
|
}
|
|
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
|
|
// connect emulator and map memory into the VDMs address space.
|
|
ASSERT(!(Console->Flags & CONSOLE_CONNECTED_TO_EMULATOR));
|
|
|
|
Status = ConnectToEmulator(TRUE, Console);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
VIDEO_HARDWARE_STATE State;
|
|
ULONG StateSize = sizeof(State);
|
|
|
|
State.StateHeader = Console->StateBuffer;
|
|
State.StateLength = Console->StateLength;
|
|
|
|
|
|
Status = NtUserFullscreenControl(FullscreenControlRestoreHardwareState,
|
|
&State,
|
|
StateSize,
|
|
&State,
|
|
&StateSize);
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT;
|
|
UnregisterVDM(Console);
|
|
KdPrint(("CONSRV: set hardware state failed.\n"));
|
|
} else {
|
|
|
|
//
|
|
// tell VDM that it's getting the hardware.
|
|
//
|
|
|
|
RECT CursorRect;
|
|
CursorRect.left = -32767;
|
|
CursorRect.top = -32767;
|
|
CursorRect.right = 32767;
|
|
CursorRect.bottom = 32767;
|
|
NtUserConsoleControl(ConsoleSetVDMCursorBounds,
|
|
&CursorRect, sizeof(RECT));
|
|
|
|
NtSetEvent(Console->VDMStartHardwareEvent,NULL);
|
|
// wait for vdm to say ok. We could initiate another switch
|
|
// (set hStartHardwareEvent which vdm is now waiting for to
|
|
// complete the handshaking) when we return(WM_FULLSCREEN
|
|
// could be in the message queue already). If we don't wait
|
|
// for vdm to get signaled here, the hStartHardwareEvent
|
|
// can get set twice and signaled once so the vdm will never
|
|
// gets the newly switch request we may post after return.
|
|
NtWaitForSingleObject(Console->VDMEndHardwareEvent,
|
|
FALSE, &li);
|
|
// no need to check time out here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// let the app know that it has the focus.
|
|
//
|
|
|
|
HandleFocusEvent(Console,TRUE);
|
|
|
|
// unset palette
|
|
|
|
if (ScreenInfo->hPalette != NULL) {
|
|
SelectPalette(ScreenInfo->Console->hDC,
|
|
ScreenInfo->Console->hSysPalette,
|
|
FALSE);
|
|
UnsetActivePalette(ScreenInfo);
|
|
}
|
|
SetConsoleReserveKeys(Console->hWnd, Console->ReserveKeys);
|
|
HandleFocusEvent(Console,TRUE);
|
|
|
|
} else {
|
|
|
|
KdPrint((" CONSRV - Display Mode transition to windowed \n"));
|
|
|
|
//
|
|
// Check first to see if we're not already fullscreen. If we aren't,
|
|
// don't allow this. Temporary BETA fix till USER gets fixed.
|
|
//
|
|
if (!(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE)) {
|
|
KdPrint(("CONSRV: received multiple windowed messages\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// turn off mouse pointer so VDM doesn't see it when saving
|
|
// hardware
|
|
if (!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER)) {
|
|
ReverseMousePointer(ScreenInfo, &ScreenInfo->Window);
|
|
}
|
|
|
|
|
|
Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN_HARDWARE;
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
|
|
//
|
|
// tell vdm that it's losing the hardware
|
|
//
|
|
|
|
NtSetEvent(Console->VDMStartHardwareEvent,NULL);
|
|
li.QuadPart = (LONGLONG)-10000 * CONSOLE_VDM_TIMEOUT;
|
|
Status = NtWaitForSingleObject(Console->VDMEndHardwareEvent,
|
|
FALSE, &li);
|
|
|
|
// if ntvdm didn't respond or we failed to save the video hardware
|
|
// states, kick ntvdm out of our world. The ntvdm process eventually
|
|
// would die but what choice do have here?
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
VIDEO_HARDWARE_STATE State;
|
|
ULONG StateSize = sizeof(State);
|
|
|
|
State.StateHeader = Console->StateBuffer;
|
|
State.StateLength = Console->StateLength;
|
|
|
|
|
|
Status = NtUserFullscreenControl(FullscreenControlSaveHardwareState,
|
|
&State,
|
|
StateSize,
|
|
&State,
|
|
&StateSize);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
NtUserConsoleControl(ConsoleSetVDMCursorBounds, NULL, 0);
|
|
|
|
// disconnect emulator and unmap video memory
|
|
|
|
ASSERT(Console->Flags & CONSOLE_CONNECTED_TO_EMULATOR);
|
|
ConnectToEmulator(FALSE, Console);
|
|
|
|
} else {
|
|
|
|
Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT;
|
|
UnregisterVDM(Console);
|
|
if (Status != 0) {
|
|
KdPrint(("CONSRV: VDM not responding.\n"));
|
|
}
|
|
else
|
|
KdPrint(("CONSRV: Save Video States Failed\n"));
|
|
|
|
}
|
|
}
|
|
|
|
// tell VDM to map memory
|
|
|
|
if (Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
|
|
// make a special case for ntvdm during switching because
|
|
// ntvdm has to make console api calls. We don't want to
|
|
// unlock the console at this moment because as soon as
|
|
// we release the lock, other theads which are waiting
|
|
// for the lock will claim the lock and the ntvdm thread doing
|
|
// the screen switch will have to wait for the lock. In an
|
|
// extreme case, the following NtWaitForSingleObject will time
|
|
// out because the ntvdm may be still waiting for the lock.
|
|
// We keep this thing in a single global variable because
|
|
// there is only one process who can own the screen at any moment.
|
|
|
|
RtlEnterCriticalSection(&ConsoleVDMCriticalSection);
|
|
ConsoleVDMOnSwitching = Console;
|
|
RtlLeaveCriticalSection(&ConsoleVDMCriticalSection);
|
|
NtSetEvent(Console->VDMStartHardwareEvent,NULL);
|
|
li.QuadPart = (LONGLONG)-10000 * CONSOLE_VDM_TIMEOUT;
|
|
Status = NtWaitForSingleObject(Console->VDMEndHardwareEvent,
|
|
FALSE, &li);
|
|
|
|
// time to go back to normal
|
|
RtlEnterCriticalSection(&ConsoleVDMCriticalSection);
|
|
ConsoleVDMOnSwitching = NULL;
|
|
RtlLeaveCriticalSection(&ConsoleVDMCriticalSection);
|
|
|
|
if (Status != 0) {
|
|
Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT;
|
|
UnregisterVDM(Console);
|
|
KdPrint(("CONSRV: VDM not responding. - second wait\n"));
|
|
return Status;
|
|
}
|
|
ScreenInfo = Console->CurrentScreenBuffer;
|
|
}
|
|
|
|
// set palette
|
|
|
|
if (ScreenInfo->hPalette != NULL) {
|
|
SelectPalette(ScreenInfo->Console->hDC,
|
|
ScreenInfo->hPalette,
|
|
FALSE);
|
|
SetActivePalette(ScreenInfo);
|
|
}
|
|
SetConsoleReserveKeys(Console->hWnd, CONSOLE_NOSHORTCUTKEY);
|
|
HandleFocusEvent(Console,FALSE);
|
|
|
|
}
|
|
|
|
/*
|
|
* Boost or lower the priority if we are going fullscreen or away.
|
|
*
|
|
* Note that console usually boosts and lowers its priority based
|
|
* on WM_FOCUSS and WM_KILLFOCUS but when you switch to full screen
|
|
* the implementation actually sends a WM_KILLFOCUS so we reboost the
|
|
* correct console here.
|
|
*/
|
|
ModifyConsoleProcessFocus(Console,
|
|
bForeground ? FOREGROUND_BASE_PRIORITY : NORMAL_BASE_PRIORITY);
|
|
|
|
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
|
|
BOOL
|
|
SetVideoMode(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UINT i, j;
|
|
|
|
//
|
|
// load ROM font
|
|
//
|
|
|
|
Status = SetROMFontCodePage(ScreenInfo->Console->OutputCP,
|
|
ScreenInfo->BufferInfo.TextInfo.ModeIndex);
|
|
|
|
if (Status == STATUS_INVALID_PARAMETER) {
|
|
Status = SetROMFontCodePage(GetOEMCP(),
|
|
ScreenInfo->BufferInfo.TextInfo.ModeIndex);
|
|
}
|
|
|
|
//
|
|
// initialize palette
|
|
//
|
|
|
|
Status = NtUserFullscreenControl(FullscreenControlSetPalette,
|
|
(PVOID) &InitialPalette,
|
|
sizeof (InitialPalette),
|
|
NULL,
|
|
NULL);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
KdPrint(("CONSRV: FullscreenControlSetPalette failed - status = %x\n",
|
|
Status));
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// initialize color table
|
|
//
|
|
|
|
for (i = 0, j = 4; i < 16; i++) {
|
|
ColorBuffer[j++] = ((((GetRValue(ScreenInfo->Console->ColorTable[i]) +
|
|
0x2A) * 0x02) / 0x55) * 0x15) / 0x02;
|
|
ColorBuffer[j++] = ((((GetGValue(ScreenInfo->Console->ColorTable[i]) +
|
|
0x2A) * 0x02) / 0x55) * 0x15) / 0x02;
|
|
ColorBuffer[j++] = ((((GetBValue(ScreenInfo->Console->ColorTable[i]) +
|
|
0x2A) * 0x02) / 0x55) * 0x15) / 0x02;
|
|
ColorBuffer[j++] = 0;
|
|
}
|
|
|
|
Status = NtUserFullscreenControl(FullscreenControlSetColors,
|
|
(PVOID) &ColorBuffer,
|
|
sizeof (ColorBuffer),
|
|
NULL,
|
|
NULL);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
KdPrint(("CONSRV: FullscreenControlSetColors failed - status = %x\n",
|
|
Status));
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if defined(_X86_)
|
|
|
|
LONG
|
|
ChangeDispSettings(
|
|
PCONSOLE_INFORMATION Console,
|
|
HWND hwnd,
|
|
DWORD dwFlags)
|
|
{
|
|
LONG dispStat;
|
|
DEVMODEW Devmode;
|
|
ULONG Index;
|
|
UNICODE_STRING vgaString;
|
|
|
|
RtlInitUnicodeString(&vgaString, L"VGACOMPATIBLE");
|
|
|
|
if (dwFlags == CDS_FULLSCREEN)
|
|
{
|
|
KdPrint(("CONSRV: ChangeDispSettings fullscreen\n"));
|
|
|
|
Index = Console->CurrentScreenBuffer->BufferInfo.TextInfo.ModeIndex;
|
|
|
|
//
|
|
// set mode to go to full screen
|
|
//
|
|
|
|
ZeroMemory(&Devmode, sizeof(Devmode));
|
|
|
|
Devmode.dmSize = sizeof(Devmode);
|
|
Devmode.dmDriverExtra = 0;
|
|
Devmode.dmFields = DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT |
|
|
DM_DISPLAYFLAGS;
|
|
|
|
Devmode.dmBitsPerPel = 4;
|
|
Devmode.dmPelsWidth = ModeFontPairs[Index].Resolution.X;
|
|
Devmode.dmPelsHeight = ModeFontPairs[Index].Resolution.Y;
|
|
Devmode.dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE;
|
|
|
|
dispStat = NtUserChangeDisplaySettings(&vgaString,
|
|
&Devmode,
|
|
hwnd,
|
|
CDS_FULLSCREEN | CDS_EXCLUSIVE,
|
|
NULL);
|
|
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("CONSRV: ChangeDispSettings windowed\n"));
|
|
|
|
ASSERT(dwFlags == 0);
|
|
|
|
//
|
|
// Reset the graphics device to it's normal state
|
|
//
|
|
|
|
dispStat = ChangeDisplaySettingsEx(NULL,
|
|
NULL,
|
|
hwnd,
|
|
CDS_RESET,
|
|
NULL);
|
|
|
|
}
|
|
|
|
return (dispStat);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL
|
|
InitializeFullScreen( VOID )
|
|
{
|
|
UNICODE_STRING vgaString;
|
|
DEVMODEW devmode;
|
|
ULONG i;
|
|
BOOLEAN mode1 = FALSE;
|
|
BOOLEAN mode2 = FALSE;
|
|
|
|
CHAR WindowsDir[CONSOLE_WINDOWS_DIR_LENGTH+CONSOLE_EGACPI_LENGTH];
|
|
UINT WindowsDirLength;
|
|
|
|
//
|
|
// query number of available modes
|
|
//
|
|
|
|
ZeroMemory(&devmode, sizeof(DEVMODEW));
|
|
devmode.dmSize = sizeof(DEVMODEW);
|
|
|
|
RtlInitUnicodeString(&vgaString, L"VGACOMPATIBLE");
|
|
|
|
for (i=0; ; i++)
|
|
{
|
|
if (!(NT_SUCCESS(NtUserEnumDisplaySettings(&vgaString,
|
|
i,
|
|
&devmode,
|
|
0))))
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT(devmode.dmDisplayFlags & DMDISPLAYFLAGS_TEXTMODE);
|
|
|
|
if (devmode.dmPelsWidth == 720 &&
|
|
devmode.dmPelsHeight == 400)
|
|
{
|
|
mode1 = TRUE;
|
|
}
|
|
if (devmode.dmPelsWidth == 640 &&
|
|
devmode.dmPelsHeight == 350)
|
|
{
|
|
mode2 = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(mode1 && mode2))
|
|
{
|
|
//
|
|
// One of the modes we expected to get was not returned.
|
|
// lets just fail fullscreen initialization.
|
|
//
|
|
|
|
KdPrint(("CONSRV: InitializeFullScreen Missing text mode\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// open ega.cpi
|
|
//
|
|
|
|
WindowsDirLength = GetSystemDirectoryA(WindowsDir,
|
|
CONSOLE_WINDOWS_DIR_LENGTH);
|
|
if (WindowsDirLength == 0)
|
|
{
|
|
KdPrint(("CONSRV: InitializeFullScreen Finding Font file failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(&WindowsDir[WindowsDirLength],
|
|
CONSOLE_EGACPI,
|
|
CONSOLE_EGACPI_LENGTH);
|
|
|
|
if ((hCPIFile = CreateFileA(WindowsDir,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL)) == (HANDLE)-1)
|
|
{
|
|
KdPrint(("CONSRV: InitializeFullScreen Opening Font file failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
SrvGetConsoleHardwareState(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
#ifdef i386
|
|
PCONSOLE_GETHARDWARESTATE_MSG a = (PCONSOLE_GETHARDWARESTATE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
PSCREEN_INFORMATION ScreenInfo;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_OUTPUT_HANDLE,
|
|
GENERIC_READ,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
ScreenInfo = HandleData->Buffer.ScreenBuffer;
|
|
if (ScreenInfo->BufferInfo.TextInfo.ModeIndex == -1) {
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_UNSUCCESSFUL;
|
|
}
|
|
a->Resolution = ModeFontPairs[ScreenInfo->BufferInfo.TextInfo.ModeIndex].Resolution;
|
|
a->FontSize = ModeFontPairs[ScreenInfo->BufferInfo.TextInfo.ModeIndex].FontSize;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
#else
|
|
return (ULONG)STATUS_UNSUCCESSFUL;
|
|
UNREFERENCED_PARAMETER(m); // get rid of unreferenced parameter warning message
|
|
#endif
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
ULONG
|
|
SrvSetConsoleHardwareState(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
#ifdef i386
|
|
PCONSOLE_SETHARDWARESTATE_MSG a = (PCONSOLE_SETHARDWARESTATE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
PHANDLE_DATA HandleData;
|
|
PSCREEN_INFORMATION ScreenInfo;
|
|
ULONG Index;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
if (!(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE)) {
|
|
UnlockConsole(Console);
|
|
return (ULONG)STATUS_UNSUCCESSFUL;
|
|
}
|
|
Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
|
|
a->OutputHandle,
|
|
CONSOLE_OUTPUT_HANDLE,
|
|
GENERIC_READ,
|
|
&HandleData
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
ScreenInfo = HandleData->Buffer.ScreenBuffer;
|
|
|
|
// match requested mode
|
|
|
|
for (Index=0;Index<NUMBER_OF_MODE_FONT_PAIRS;Index++) {
|
|
if (a->Resolution.X == ModeFontPairs[Index].Resolution.X &&
|
|
a->Resolution.Y == ModeFontPairs[Index].Resolution.Y &&
|
|
a->FontSize.Y == ModeFontPairs[Index].FontSize.Y &&
|
|
a->FontSize.X == ModeFontPairs[Index].FontSize.X) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == NUMBER_OF_MODE_FONT_PAIRS) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
// set requested mode
|
|
ScreenInfo->BufferInfo.TextInfo.ModeIndex = Index;
|
|
SetVideoMode(ScreenInfo);
|
|
}
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
#else
|
|
return (ULONG)STATUS_UNSUCCESSFUL;
|
|
UNREFERENCED_PARAMETER(m); // get rid of unreferenced parameter warning message
|
|
#endif
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
ULONG
|
|
SrvGetConsoleDisplayMode(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
PCONSOLE_GETDISPLAYMODE_MSG a = (PCONSOLE_GETDISPLAYMODE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
|
|
//
|
|
// If this API is being called from a server thread, don't try to
|
|
// lock the console handle table or we could deadlock.
|
|
//
|
|
|
|
if (m->h.ClientId.UniqueThread == NtCurrentTeb()->ClientId.UniqueThread) {
|
|
Status = DereferenceConsoleHandle(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
a->ModeFlags = Console->FullScreenFlags;
|
|
}
|
|
} else {
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
a->ModeFlags = Console->FullScreenFlags;
|
|
UnlockConsole(Console);
|
|
}
|
|
}
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus);
|
|
}
|
|
|
|
ULONG
|
|
SrvSetConsoleMenuClose(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
PCONSOLE_SETMENUCLOSE_MSG a = (PCONSOLE_SETMENUCLOSE_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
if (a->Enable) {
|
|
Console->Flags &= ~CONSOLE_DISABLE_CLOSE;
|
|
} else {
|
|
Console->Flags |= CONSOLE_DISABLE_CLOSE;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
DWORD
|
|
ConvertHotKey(
|
|
IN LPAPPKEY UserAppKey
|
|
)
|
|
{
|
|
DWORD wParam;
|
|
|
|
wParam = MapVirtualKey(UserAppKey->ScanCode,1);
|
|
if (UserAppKey->Modifier & CONSOLE_MODIFIER_SHIFT) {
|
|
wParam |= 0x0100;
|
|
}
|
|
if (UserAppKey->Modifier & CONSOLE_MODIFIER_CONTROL) {
|
|
wParam |= 0x0200;
|
|
}
|
|
if (UserAppKey->Modifier & CONSOLE_MODIFIER_ALT) {
|
|
wParam |= 0x0400;
|
|
}
|
|
return wParam;
|
|
}
|
|
|
|
ULONG
|
|
SrvSetConsoleKeyShortcuts(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus
|
|
)
|
|
{
|
|
PCONSOLE_SETKEYSHORTCUTS_MSG a = (PCONSOLE_SETKEYSHORTCUTS_MSG)&m->u.ApiMessageData;
|
|
NTSTATUS Status;
|
|
PCONSOLE_INFORMATION Console;
|
|
|
|
Status = ApiPreamble(a->ConsoleHandle,
|
|
&Console
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (a->NumAppKeys <= CONSOLE_MAX_APP_SHORTCUTS) {
|
|
Console->ReserveKeys = a->ReserveKeys;
|
|
if (Console->Flags & CONSOLE_HAS_FOCUS) {
|
|
if (!(SetConsoleReserveKeys(Console->hWnd,a->ReserveKeys))) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
if (a->NumAppKeys) {
|
|
PostMessage(Console->hWnd,
|
|
WM_SETHOTKEY,
|
|
ConvertHotKey(a->AppKeys),
|
|
0
|
|
);
|
|
}
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
UnlockConsole(Console);
|
|
return Status;
|
|
UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
#ifdef i386
|
|
ULONG
|
|
MatchWindowSize(
|
|
IN COORD WindowSize,
|
|
OUT PCOORD pWindowSize
|
|
)
|
|
|
|
/*++
|
|
|
|
find the best match font. it's the one that's the same size
|
|
or slightly larger than the window size.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
for (i=0;i<NUMBER_OF_MODE_FONT_PAIRS;i++) {
|
|
if (WindowSize.Y <= (SHORT)ModeFontPairs[i].Height) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == NUMBER_OF_MODE_FONT_PAIRS)
|
|
i-=1;
|
|
pWindowSize->X = 80;
|
|
pWindowSize->Y = (SHORT)ModeFontPairs[i].Height;
|
|
return i;
|
|
}
|
|
|
|
VOID
|
|
WriteRegionToScreenHW(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PSMALL_RECT Region
|
|
)
|
|
{
|
|
ULONG CurFrameBufPtr; // offset in frame buffer
|
|
SHORT ScreenY,ScreenX;
|
|
SHORT WindowY,WindowX,WindowSizeX;
|
|
PCHAR_INFO ScreenBufPtr,ScreenBufPtrTmp; // points to place to read in screen buffer
|
|
PCHAR_INFO ScreenBufSrc;
|
|
COORD TargetSize,SourcePoint;
|
|
SMALL_RECT Target;
|
|
COORD WindowOrigin;
|
|
|
|
if (ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
return;
|
|
}
|
|
|
|
TargetSize.X = Region->Right - Region->Left + 1;
|
|
TargetSize.Y = Region->Bottom - Region->Top + 1;
|
|
ScreenBufPtrTmp = ScreenBufPtr = (PCHAR_INFO)HeapAlloc(pConHeap,MAKE_TAG( TMP_TAG ),sizeof(CHAR_INFO) * TargetSize.X * TargetSize.Y);
|
|
if (ScreenBufPtr == NULL)
|
|
return;
|
|
SourcePoint.X = Region->Left;
|
|
SourcePoint.Y = Region->Top;
|
|
Target.Left = 0;
|
|
Target.Top = 0;
|
|
Target.Right = TargetSize.X-1;
|
|
Target.Bottom = TargetSize.Y-1;
|
|
ReadRectFromScreenBuffer(ScreenInfo,
|
|
SourcePoint,
|
|
ScreenBufPtr,
|
|
TargetSize,
|
|
&Target
|
|
);
|
|
|
|
//
|
|
// make sure region lies within window
|
|
//
|
|
|
|
if (Region->Bottom > ScreenInfo->Window.Bottom) {
|
|
WindowOrigin.X = 0;
|
|
WindowOrigin.Y = Region->Bottom - ScreenInfo->Window.Bottom;
|
|
SetWindowOrigin(ScreenInfo, FALSE, WindowOrigin);
|
|
}
|
|
|
|
WindowY = Region->Top - ScreenInfo->Window.Top;
|
|
WindowX = Region->Left - ScreenInfo->Window.Left;
|
|
WindowSizeX = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
ScreenY=Region->Top;
|
|
|
|
for (ScreenY = Region->Top;
|
|
ScreenY <= Region->Bottom;
|
|
ScreenY++, WindowY++) {
|
|
|
|
CurFrameBufPtr = SCREEN_BUFFER_POINTER(WindowX,
|
|
WindowY,
|
|
WindowSizeX,
|
|
sizeof(VGA_CHAR));
|
|
|
|
ScreenBufSrc = ScreenBufPtr;
|
|
|
|
for (ScreenX = Region->Left;
|
|
ScreenX <= Region->Right;
|
|
ScreenX++, ScreenBufPtr++) {
|
|
|
|
//
|
|
// if the char is > 127, we have to convert it back to OEM.
|
|
//
|
|
|
|
if (ScreenBufPtr->Char.UnicodeChar > 127) {
|
|
ScreenBufPtr->Char.AsciiChar = WcharToChar(
|
|
ScreenInfo->Console->OutputCP,
|
|
ScreenBufPtr->Char.UnicodeChar);
|
|
}
|
|
}
|
|
|
|
NtUserFullscreenControl(FullscreenControlWriteToFrameBuffer,
|
|
ScreenBufSrc,
|
|
(Region->Right - Region->Left + 1) *
|
|
sizeof(CHAR_INFO),
|
|
(PULONG) CurFrameBufPtr,
|
|
(PULONG) ((Region->Right - Region->Left + 1) *
|
|
sizeof(VGA_CHAR)));
|
|
|
|
}
|
|
|
|
HeapFree(pConHeap,0,ScreenBufPtrTmp);
|
|
|
|
ReverseMousePointer(ScreenInfo, Region);
|
|
|
|
}
|
|
|
|
VOID
|
|
ReadRegionFromScreenHW(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PSMALL_RECT Region,
|
|
IN PCHAR_INFO ReadBufPtr
|
|
)
|
|
{
|
|
ULONG CurFrameBufPtr; // offset in frame buffer
|
|
SHORT FrameY;
|
|
SHORT WindowY, WindowX, WindowSizeX;
|
|
|
|
//
|
|
// get pointer to start of region in frame buffer
|
|
//
|
|
|
|
WindowY = Region->Top - ScreenInfo->Window.Top;
|
|
WindowX = Region->Left - ScreenInfo->Window.Left;
|
|
WindowSizeX = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
|
|
//
|
|
// copy the chars and attrs from the frame buffer
|
|
//
|
|
|
|
for (FrameY = Region->Top;
|
|
FrameY <= Region->Bottom;
|
|
FrameY++, WindowY++) {
|
|
|
|
CurFrameBufPtr = SCREEN_BUFFER_POINTER(WindowX,
|
|
WindowY,
|
|
WindowSizeX,
|
|
sizeof(VGA_CHAR));
|
|
|
|
NtUserFullscreenControl(FullscreenControlReadFromFrameBuffer,
|
|
(PULONG) CurFrameBufPtr,
|
|
(Region->Right - Region->Left + 1) *
|
|
sizeof(VGA_CHAR),
|
|
ReadBufPtr,
|
|
(PULONG) ((Region->Right - Region->Left + 1) *
|
|
sizeof(CHAR_INFO)));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ReverseMousePointer(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PSMALL_RECT Region
|
|
)
|
|
{
|
|
ULONG CurFrameBufPtr; // offset in frame buffer
|
|
SHORT WindowSizeX;
|
|
|
|
// if (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
|
|
// ASSERT(FALSE);
|
|
// }
|
|
|
|
WindowSizeX = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.MousePosition.X < Region->Left ||
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.X > Region->Right ||
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.Y < Region->Top ||
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.Y > Region->Bottom ||
|
|
ScreenInfo->CursorDisplayCount < 0 ||
|
|
!(ScreenInfo->Console->InputBuffer.InputMode & ENABLE_MOUSE_INPUT) ||
|
|
ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED) {
|
|
return;
|
|
}
|
|
|
|
CurFrameBufPtr = SCREEN_BUFFER_POINTER(ScreenInfo->BufferInfo.TextInfo.MousePosition.X - ScreenInfo->Window.Left,
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.Y - ScreenInfo->Window.Top,
|
|
WindowSizeX,
|
|
sizeof(VGA_CHAR));
|
|
|
|
NtUserFullscreenControl(FullscreenControlReverseMousePointer,
|
|
(PULONG) CurFrameBufPtr,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
VOID
|
|
CopyVideoMemory(
|
|
SHORT SourceY,
|
|
SHORT TargetY,
|
|
SHORT Length,
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies rows of characters in video memory. It only copies
|
|
complete rows.
|
|
|
|
Arguments:
|
|
|
|
SourceY - Row to copy from.
|
|
|
|
TargetY - Row to copy to.
|
|
|
|
Length - Number of rows to copy.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG SourcePtr, TargetPtr;
|
|
SHORT WindowSizeX, WindowSizeY;
|
|
|
|
WindowSizeX = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
WindowSizeY = CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
|
|
|
|
if (max(SourceY, TargetY) + Length > WindowSizeY) {
|
|
Length = WindowSizeY - max(SourceY, TargetY);
|
|
if (Length <= 0 ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
SourcePtr = SCREEN_BUFFER_POINTER(0,
|
|
SourceY,
|
|
WindowSizeX,
|
|
sizeof(VGA_CHAR));
|
|
|
|
TargetPtr = SCREEN_BUFFER_POINTER(0,
|
|
TargetY,
|
|
WindowSizeX,
|
|
sizeof(VGA_CHAR));
|
|
|
|
NtUserFullscreenControl(FullscreenControlCopyFrameBuffer,
|
|
(PULONG) SourcePtr,
|
|
Length * WindowSizeX * sizeof(VGA_CHAR),
|
|
(PULONG) TargetPtr,
|
|
(PULONG) (Length * WindowSizeX * sizeof(VGA_CHAR)));
|
|
}
|
|
|
|
VOID
|
|
ScrollHW(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN PSMALL_RECT ScrollRect,
|
|
IN PSMALL_RECT MergeRect,
|
|
IN COORD TargetPoint
|
|
)
|
|
{
|
|
SMALL_RECT TargetRectangle;
|
|
if (ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)
|
|
return;
|
|
|
|
TargetRectangle.Left = TargetPoint.X;
|
|
TargetRectangle.Top = TargetPoint.Y;
|
|
TargetRectangle.Right = TargetPoint.X + ScrollRect->Right - ScrollRect->Left;
|
|
TargetRectangle.Bottom = TargetPoint.Y + ScrollRect->Bottom - ScrollRect->Top;
|
|
|
|
//
|
|
// if the scroll region is as wide as the screen, we can update
|
|
// the screen by copying the video memory. if we scroll this
|
|
// way, we then must clip and update the fill region.
|
|
//
|
|
|
|
if (ScrollRect->Left == ScreenInfo->Window.Left &&
|
|
TargetRectangle.Left == ScreenInfo->Window.Left &&
|
|
ScrollRect->Right == ScreenInfo->Window.Right &&
|
|
TargetRectangle.Right == ScreenInfo->Window.Right &&
|
|
ScrollRect->Top >= ScreenInfo->Window.Top &&
|
|
TargetRectangle.Top >= ScreenInfo->Window.Top &&
|
|
ScrollRect->Bottom <= ScreenInfo->Window.Bottom &&
|
|
TargetRectangle.Bottom <= ScreenInfo->Window.Bottom) {
|
|
|
|
//
|
|
// we must first make the mouse pointer invisible because
|
|
// otherwise it would get copied to another place on the
|
|
// screen if it were part of the scroll region.
|
|
//
|
|
|
|
ReverseMousePointer(ScreenInfo, &ScreenInfo->Window);
|
|
|
|
CopyVideoMemory((SHORT) (ScrollRect->Top - ScreenInfo->Window.Top),
|
|
(SHORT) (TargetRectangle.Top - ScreenInfo->Window.Top),
|
|
(SHORT) (TargetRectangle.Bottom - TargetRectangle.Top + 1),
|
|
ScreenInfo);
|
|
|
|
//
|
|
// update the fill region. first we ensure that the scroll and
|
|
// target regions aren't the same. if they are, we don't fill.
|
|
//
|
|
|
|
if (TargetRectangle.Top != ScrollRect->Top) {
|
|
|
|
//
|
|
// if scroll and target regions overlap, with scroll
|
|
// region above target region, clip scroll region.
|
|
//
|
|
|
|
if (TargetRectangle.Top <= ScrollRect->Bottom &&
|
|
TargetRectangle.Bottom >= ScrollRect->Bottom) {
|
|
ScrollRect->Bottom = (SHORT)(TargetRectangle.Top-1);
|
|
}
|
|
else if (TargetRectangle.Top <= ScrollRect->Top &&
|
|
TargetRectangle.Bottom >= ScrollRect->Top) {
|
|
ScrollRect->Top = (SHORT)(TargetRectangle.Bottom+1);
|
|
}
|
|
WriteToScreen(ScreenInfo,ScrollRect);
|
|
|
|
//
|
|
// WriteToScreen should take care of writing the mouse pointer.
|
|
// however, the update region may be clipped so that the
|
|
// mouse pointer is not written. in that case, we draw the
|
|
// mouse pointer here.
|
|
//
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.MousePosition.Y < ScrollRect->Top ||
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.Y > ScrollRect->Bottom) {
|
|
ReverseMousePointer(ScreenInfo, &ScreenInfo->Window);
|
|
}
|
|
}
|
|
if (MergeRect) {
|
|
WriteToScreen(ScreenInfo,MergeRect);
|
|
}
|
|
}
|
|
else {
|
|
if (MergeRect) {
|
|
WriteToScreen(ScreenInfo,MergeRect);
|
|
}
|
|
WriteToScreen(ScreenInfo,ScrollRect);
|
|
WriteToScreen(ScreenInfo,&TargetRectangle);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UpdateMousePosition(
|
|
PSCREEN_INFORMATION ScreenInfo,
|
|
COORD Position
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine moves the mouse pointer.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - Pointer to screen buffer information.
|
|
|
|
Position - Contains the new position of the mouse in screen buffer
|
|
coordinates.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
// Note: CurrentConsole lock must be held in share mode when calling this routine
|
|
{
|
|
SMALL_RECT CursorRegion;
|
|
|
|
if (ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)
|
|
return;
|
|
|
|
if (Position.X < ScreenInfo->Window.Left ||
|
|
Position.X > ScreenInfo->Window.Right ||
|
|
Position.Y < ScreenInfo->Window.Top ||
|
|
Position.Y > ScreenInfo->Window.Bottom) {
|
|
return;
|
|
}
|
|
|
|
if (Position.X == ScreenInfo->BufferInfo.TextInfo.MousePosition.X &&
|
|
Position.Y == ScreenInfo->BufferInfo.TextInfo.MousePosition.Y) {
|
|
return;
|
|
}
|
|
if (ScreenInfo->CursorDisplayCount < 0 || !(ScreenInfo->Console->InputBuffer.InputMode & ENABLE_MOUSE_INPUT)) {
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition = Position;
|
|
return;
|
|
}
|
|
|
|
// turn off old mouse position.
|
|
|
|
CursorRegion.Left = CursorRegion.Right = ScreenInfo->BufferInfo.TextInfo.MousePosition.X;
|
|
CursorRegion.Top = CursorRegion.Bottom = ScreenInfo->BufferInfo.TextInfo.MousePosition.Y;
|
|
|
|
// store new mouse position
|
|
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.X = Position.X;
|
|
ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = Position.Y;
|
|
WriteToScreen(ScreenInfo,&CursorRegion);
|
|
|
|
// turn on new mouse position
|
|
|
|
CursorRegion.Left = CursorRegion.Right = Position.X;
|
|
CursorRegion.Top = CursorRegion.Bottom = Position.Y;
|
|
WriteToScreen(ScreenInfo,&CursorRegion);
|
|
}
|
|
|
|
NTSTATUS
|
|
SetROMFontCodePage(
|
|
IN UINT wCodePage,
|
|
IN ULONG ModeIndex
|
|
)
|
|
|
|
/*
|
|
|
|
this function opens ega.cpi and looks for the desired font in the
|
|
specified codepage. if found, it loads it into the video ROM.
|
|
|
|
*/
|
|
|
|
{
|
|
BYTE Buffer[CONSOLE_FONT_BUFFER_LENGTH];
|
|
DWORD dwBytesRead;
|
|
LPFONTFILEHEADER lpFontFileHeader=(LPFONTFILEHEADER)Buffer;
|
|
LPFONTINFOHEADER lpFontInfoHeader=(LPFONTINFOHEADER)Buffer;
|
|
LPFONTDATAHEADER lpFontDataHeader=(LPFONTDATAHEADER)Buffer;
|
|
LPCPENTRYHEADER lpCPEntryHeader=(LPCPENTRYHEADER)Buffer;
|
|
LPSCREENFONTHEADER lpScreenFontHeader=(LPSCREENFONTHEADER)Buffer;
|
|
WORD NumEntries;
|
|
COORD FontDimensions;
|
|
NTSTATUS Status;
|
|
BOOL Found;
|
|
LONG FilePtr;
|
|
BOOL bDOS = FALSE;
|
|
|
|
FontDimensions = ModeFontPairs[ModeIndex].FontSize;
|
|
|
|
//
|
|
// read FONTINFOHEADER
|
|
//
|
|
// do {
|
|
// read CPENTRYHEADER
|
|
// if (correct codepage)
|
|
// break;
|
|
// } while (codepages)
|
|
// if (codepage found)
|
|
// read FONTDATAHEADER
|
|
//
|
|
|
|
// read FONTFILEHEADER
|
|
|
|
FilePtr = 0;
|
|
if (SetFilePointer(hCPIFile,FilePtr,NULL,FILE_BEGIN) == -1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
if (!ReadFile(hCPIFile,Buffer,sizeof(FONTFILEHEADER),&dwBytesRead,NULL) ||
|
|
dwBytesRead != sizeof(FONTFILEHEADER)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
// verify signature
|
|
|
|
if (memcmp(lpFontFileHeader->ffhFileTag, "\xFF""FONT.NT",8) ) {
|
|
if (memcmp(lpFontFileHeader->ffhFileTag, "\xFF""FONT ",8) ) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
} else {
|
|
bDOS = TRUE;
|
|
}
|
|
}
|
|
|
|
// seek to FONTINFOHEADER. jump through hoops to get the offset value.
|
|
|
|
FilePtr = lpFontFileHeader->ffhOffset1;
|
|
FilePtr |= (lpFontFileHeader->ffhOffset2 << 8);
|
|
FilePtr |= (lpFontFileHeader->ffhOffset3 << 24);
|
|
|
|
if (SetFilePointer(hCPIFile,FilePtr,NULL,FILE_BEGIN) == -1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
// read FONTINFOHEADER
|
|
|
|
if (!ReadFile(hCPIFile,Buffer,sizeof(FONTINFOHEADER),&dwBytesRead,NULL) ||
|
|
dwBytesRead != sizeof(FONTINFOHEADER)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
FilePtr += dwBytesRead;
|
|
NumEntries = lpFontInfoHeader->fihCodePages;
|
|
|
|
Found = FALSE;
|
|
while (NumEntries &&
|
|
ReadFile(hCPIFile,Buffer,sizeof(CPENTRYHEADER),&dwBytesRead,NULL) &&
|
|
dwBytesRead == sizeof(CPENTRYHEADER)) {
|
|
if (lpCPEntryHeader->cpeCodepageID == wCodePage) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
// seek to next CPEENTRYHEADER
|
|
|
|
if (bDOS) {
|
|
FilePtr = MAKELONG(lpCPEntryHeader->cpeNext1,lpCPEntryHeader->cpeNext2);
|
|
} else {
|
|
FilePtr += MAKELONG(lpCPEntryHeader->cpeNext1,lpCPEntryHeader->cpeNext2);
|
|
}
|
|
if (SetFilePointer(hCPIFile, FilePtr, NULL,FILE_BEGIN) == -1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
NumEntries-=1;
|
|
}
|
|
if (!Found) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
// seek to FONTDATAHEADER
|
|
|
|
if (bDOS) {
|
|
FilePtr = lpCPEntryHeader->cpeOffset;
|
|
} else {
|
|
FilePtr += lpCPEntryHeader->cpeOffset;
|
|
}
|
|
if (SetFilePointer(hCPIFile, FilePtr, NULL,FILE_BEGIN) == -1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
// read FONTDATAHEADER
|
|
|
|
if (!ReadFile(hCPIFile,Buffer,sizeof(FONTDATAHEADER),&dwBytesRead,NULL) ||
|
|
dwBytesRead != sizeof(FONTDATAHEADER)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
FilePtr += dwBytesRead;
|
|
|
|
NumEntries = lpFontDataHeader->fdhFonts;
|
|
|
|
while (NumEntries) {
|
|
if (!ReadFile(hCPIFile,Buffer,sizeof(SCREENFONTHEADER),&dwBytesRead,NULL) ||
|
|
dwBytesRead != sizeof(SCREENFONTHEADER)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
|
|
if (lpScreenFontHeader->sfhHeight == (BYTE)FontDimensions.Y &&
|
|
lpScreenFontHeader->sfhWidth == (BYTE)FontDimensions.X) {
|
|
PVIDEO_LOAD_FONT_INFORMATION FontInformation;
|
|
|
|
FontInformation = (PVIDEO_LOAD_FONT_INFORMATION)HeapAlloc(pConHeap,MAKE_TAG( TMP_TAG ),
|
|
lpScreenFontHeader->sfhCharacters*
|
|
lpScreenFontHeader->sfhHeight+
|
|
sizeof(VIDEO_LOAD_FONT_INFORMATION));
|
|
if (!ReadFile(hCPIFile,FontInformation->Font,
|
|
lpScreenFontHeader->sfhCharacters*lpScreenFontHeader->sfhHeight,
|
|
&dwBytesRead,NULL) ||
|
|
dwBytesRead != (DWORD)(lpScreenFontHeader->sfhCharacters*lpScreenFontHeader->sfhHeight)) {
|
|
HeapFree(pConHeap,0,FontInformation);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
FontInformation->WidthInPixels = FontDimensions.X;
|
|
FontInformation->HeightInPixels = FontDimensions.Y;
|
|
FontInformation->FontSize = lpScreenFontHeader->sfhCharacters*lpScreenFontHeader->sfhHeight;
|
|
|
|
Status = NtUserFullscreenControl(FullscreenControlLoadFont,
|
|
FontInformation,
|
|
lpScreenFontHeader->sfhCharacters*lpScreenFontHeader->sfhHeight+sizeof(VIDEO_LOAD_FONT_INFORMATION),
|
|
NULL,
|
|
NULL);
|
|
|
|
HeapFree(pConHeap,0,FontInformation);
|
|
return Status;
|
|
} else {
|
|
FilePtr = lpScreenFontHeader->sfhCharacters*lpScreenFontHeader->sfhHeight;
|
|
if (SetFilePointer(hCPIFile, FilePtr, NULL,FILE_CURRENT) == -1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto DoExit;
|
|
}
|
|
}
|
|
NumEntries -= 1;
|
|
}
|
|
DoExit:
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
HWINSTA
|
|
GetConsoleWindowStation(VOID)
|
|
{
|
|
PCONSOLE_PER_PROCESS_DATA ProcessData;
|
|
PCONSOLE_INFORMATION Console;
|
|
HWINSTA hwinsta;
|
|
|
|
ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(
|
|
CSR_SERVER_QUERYCLIENTTHREAD()->Process);
|
|
|
|
//
|
|
// If this process is a console app, return the
|
|
// handle to its windowstation. Otherwise, return NULL.
|
|
//
|
|
|
|
hwinsta = NULL;
|
|
if ( ProcessData->ConsoleHandle != NULL ) {
|
|
LockConsoleHandleTable();
|
|
if ( NT_SUCCESS(DereferenceConsoleHandle(
|
|
ProcessData->ConsoleHandle, &Console)) ) {
|
|
hwinsta = Console->hWinSta;
|
|
}
|
|
UnlockConsoleHandleTable();
|
|
}
|
|
|
|
return hwinsta;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetThreadConsoleDesktop(
|
|
DWORD dwThreadId,
|
|
HDESK *phdeskConsole)
|
|
{
|
|
PCSR_THREAD pcsrt;
|
|
PCONSOLE_PER_PROCESS_DATA ProcessData;
|
|
PCONSOLE_INFORMATION Console;
|
|
NTSTATUS Status;
|
|
|
|
*phdeskConsole = NULL;
|
|
Status = CsrLockThreadByClientId((HANDLE)dwThreadId, &pcsrt);
|
|
if (NT_SUCCESS(Status)) {
|
|
ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(pcsrt->Process);
|
|
|
|
//
|
|
// If this process is a console app, return the
|
|
// handle to its desktop. Otherwise, return NULL.
|
|
//
|
|
|
|
if ( ProcessData->ConsoleHandle != NULL ) {
|
|
LockConsoleHandleTable();
|
|
Status = DereferenceConsoleHandle(ProcessData->ConsoleHandle, &
|
|
Console);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
*phdeskConsole = Console->hDesk;
|
|
}
|
|
UnlockConsoleHandleTable();
|
|
}
|
|
CsrUnlockThread(pcsrt);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|