[KERNEL32][CONSRV]: Implement a basic RegisterConsoleVDM (see revision 62371 for more details).

svn path=/branches/condrv_restructure/; revision=63849
This commit is contained in:
Hermès Bélusca-Maïto 2014-08-09 19:47:40 +00:00
parent 636d4cf0ce
commit cc85bc57af
7 changed files with 354 additions and 23 deletions

View file

@ -1640,26 +1640,101 @@ GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
/* /*
* @unimplemented * @implemented (undocumented)
*/ */
BOOL BOOL
WINAPI WINAPI
RegisterConsoleVDM ( RegisterConsoleVDM(IN DWORD dwRegisterFlags,
DWORD Unknown0, IN HANDLE hStartHardwareEvent,
DWORD Unknown1, IN HANDLE hEndHardwareEvent,
DWORD Unknown2, IN HANDLE hErrorHardwareEvent,
DWORD Unknown3, IN DWORD dwUnusedVar,
DWORD Unknown4, OUT LPDWORD lpVideoStateLength,
DWORD Unknown5, OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
DWORD Unknown6, IN PVOID lpUnusedBuffer,
DWORD Unknown7, IN DWORD dwUnusedBufferLength,
DWORD Unknown8, IN COORD dwVDMBufferSize,
DWORD Unknown9, OUT PVOID* lpVDMBuffer)
DWORD Unknown10
)
{ {
STUB; BOOL Success;
return FALSE; CONSOLE_API_MESSAGE ApiMessage;
PCONSOLE_REGISTERVDM RegisterVDMRequest = &ApiMessage.Data.RegisterVDMRequest;
PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
/* Set up the data to send to the Console Server */
RegisterVDMRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
RegisterVDMRequest->RegisterFlags = dwRegisterFlags;
if (dwRegisterFlags != 0)
{
RegisterVDMRequest->StartHardwareEvent = hStartHardwareEvent;
RegisterVDMRequest->EndHardwareEvent = hEndHardwareEvent;
RegisterVDMRequest->ErrorHardwareEvent = hErrorHardwareEvent;
RegisterVDMRequest->VDMBufferSize = dwVDMBufferSize;
#if 0
RegisterVDMRequest->UnusedBufferLength = dwUnusedBufferLength;
/* Allocate a Capture Buffer */
CaptureBuffer = CsrAllocateCaptureBuffer(1, dwUnusedBufferLength);
if (CaptureBuffer == NULL)
{
DPRINT1("CsrAllocateCaptureBuffer failed!\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/* Capture the buffer to write */
CsrCaptureMessageBuffer(CaptureBuffer,
(PVOID)lpUnusedBuffer,
dwUnusedBufferLength,
(PVOID*)&RegisterVDMRequest->UnusedBuffer);
#endif
}
else
{
// CaptureBuffer = NULL;
}
/* Call the server */
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
CaptureBuffer,
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepRegisterVDM),
sizeof(*RegisterVDMRequest));
/* Check for success */
Success = NT_SUCCESS(ApiMessage.Status);
/* Release the capture buffer if needed */
if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
/* Retrieve the results */
if (Success)
{
if (dwRegisterFlags != 0)
{
_SEH2_TRY
{
*lpVideoStateLength = RegisterVDMRequest->VideoStateLength;
*lpVideoState = RegisterVDMRequest->VideoState;
*lpVDMBuffer = RegisterVDMRequest->VDMBuffer;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_ACCESS);
Success = FALSE;
}
_SEH2_END;
}
}
else
{
BaseSetLastNTError(ApiMessage.Status);
}
/* Return success status */
return Success;
} }
@ -1756,9 +1831,8 @@ VDMOperationStarted(IN ULONG Unknown0)
{ {
DPRINT1("VDMOperationStarted(%d)\n", Unknown0); DPRINT1("VDMOperationStarted(%d)\n", Unknown0);
return return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler, NULL,
NULL, 0,
0, Unknown0);
Unknown0);
} }

View file

@ -618,6 +618,12 @@ BOOL WINAPI CloseConsoleHandle(_In_ HANDLE);
// BOOL WINAPI SetStdHandle(_In_ DWORD, _In_ HANDLE); // BOOL WINAPI SetStdHandle(_In_ DWORD, _In_ HANDLE);
/* Undocumented */ /* Undocumented */
BOOL WINAPI VerifyConsoleIoHandle(_In_ HANDLE); BOOL WINAPI VerifyConsoleIoHandle(_In_ HANDLE);
/* Undocumented */
BOOL
WINAPI
RegisterConsoleVDM(_In_ DWORD, _In_ HANDLE, _In_ HANDLE, _In_ HANDLE, _In_ DWORD,
_Out_ LPDWORD, _Out_ PVOID*, _In_ PVOID, _In_ DWORD, _In_ COORD,
_Out_ PVOID*);
BOOL BOOL
WINAPI WINAPI

View file

@ -806,6 +806,28 @@ typedef struct
BOOL Ansi; BOOL Ansi;
} CONSOLE_GETKBDLAYOUTNAME, *PCONSOLE_GETKBDLAYOUTNAME; } CONSOLE_GETKBDLAYOUTNAME, *PCONSOLE_GETKBDLAYOUTNAME;
typedef struct
{
HANDLE ConsoleHandle;
ULONG RegisterFlags;
HANDLE StartHardwareEvent;
HANDLE EndHardwareEvent;
HANDLE ErrorHardwareEvent;
/* Unused member */
ULONG UnusedVar;
ULONG VideoStateLength;
PVOID VideoState; // PVIDEO_HARDWARE_STATE_HEADER
/* Unused members */
PVOID UnusedBuffer;
ULONG UnusedBufferLength;
COORD VDMBufferSize;
PVOID VDMBuffer;
} CONSOLE_REGISTERVDM, *PCONSOLE_REGISTERVDM;
typedef struct _CONSOLE_API_MESSAGE typedef struct _CONSOLE_API_MESSAGE
{ {
PORT_MESSAGE Header; PORT_MESSAGE Header;
@ -903,6 +925,9 @@ typedef struct _CONSOLE_API_MESSAGE
CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest; CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest; CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest; CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest;
/* Virtual DOS Machine */
CONSOLE_REGISTERVDM RegisterVDMRequest;
} Data; } Data;
} CONSOLE_API_MESSAGE, *PCONSOLE_API_MESSAGE; } CONSOLE_API_MESSAGE, *PCONSOLE_API_MESSAGE;

View file

@ -207,6 +207,13 @@ ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
/* PUBLIC DRIVER APIS *********************************************************/ /* PUBLIC DRIVER APIS *********************************************************/
NTSTATUS NTAPI
ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCHAR_CELL CharInfo/*Buffer*/,
IN COORD CharInfoSize,
IN OUT PSMALL_RECT WriteRegion,
IN BOOLEAN DrawRegion);
NTSTATUS NTAPI NTSTATUS NTAPI
ConDrvInvalidateBitMapRect(IN PCONSOLE Console, ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
IN PCONSOLE_SCREEN_BUFFER Buffer, IN PCONSOLE_SCREEN_BUFFER Buffer,
@ -218,6 +225,19 @@ ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
/* Validity check */ /* Validity check */
ASSERT(Console == Buffer->Header.Console); ASSERT(Console == Buffer->Header.Console);
/* In text-mode only, draw the VDM buffer if present */
if (GetType(Buffer) == TEXTMODE_BUFFER)
{
PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
/*Status =*/ ConDrvWriteConsoleOutputVDM(Buffer->Header.Console,
TextBuffer,
Console->VDMBuffer,
Console->VDMBufferSize,
Region,
FALSE);
}
/* If the output buffer is the current one, redraw the correct portion of the screen */ /* If the output buffer is the current one, redraw the correct portion of the screen */
if (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region); if (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region);

View file

@ -722,6 +722,68 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/*
* NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
*/
NTSTATUS NTAPI
ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER Buffer,
IN PCHAR_CELL CharInfo/*Buffer*/,
IN COORD CharInfoSize,
IN OUT PSMALL_RECT WriteRegion,
IN BOOLEAN DrawRegion)
{
SHORT X, Y;
SMALL_RECT ScreenBuffer;
PCHAR_CELL CurCharInfo;
SMALL_RECT CapturedWriteRegion;
PCHAR_INFO Ptr;
if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
{
return STATUS_INVALID_PARAMETER;
}
/* Validity check */
ASSERT(Console == Buffer->Header.Console);
CapturedWriteRegion = *WriteRegion;
/* Make sure WriteRegion is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0,
Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
{
/*
* It is okay to have a WriteRegion completely outside
* the screen buffer. No data is written then.
*/
return STATUS_SUCCESS;
}
// CurCharInfo = CharInfo;
for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
{
/**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
{
ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
Ptr->Attributes = CurCharInfo->Attributes;
++Ptr;
++CurCharInfo;
}
}
if (DrawRegion) TermDrawRegion(Console, &CapturedWriteRegion);
*WriteRegion = CapturedWriteRegion;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console, ConDrvWriteConsole(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer, IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,

View file

@ -19,6 +19,15 @@
#define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | \ #define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | \
BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY) BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
/* VGA character cell */
typedef struct _CHAR_CELL
{
CHAR Char;
BYTE Attributes;
} CHAR_CELL, *PCHAR_CELL;
C_ASSERT(sizeof(CHAR_CELL) == 2);
/* Object type magic numbers */ /* Object type magic numbers */
typedef enum _CONSOLE_IO_OBJECT_TYPE typedef enum _CONSOLE_IO_OBJECT_TYPE
{ {
@ -300,6 +309,17 @@ typedef struct _CONSOLE
PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to currently active screen buffer */ PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to currently active screen buffer */
UINT OutputCodePage; UINT OutputCodePage;
/**** Per-console Virtual DOS Machine Text-mode Buffer ****/
COORD VDMBufferSize; /* Real size of the VDM buffer, in units of ??? */
HANDLE VDMBufferSection; /* Handle to the memory shared section for the VDM buffer */
PVOID VDMBuffer; /* Our VDM buffer */
PVOID ClientVDMBuffer; /* A copy of the client view of our VDM buffer */
HANDLE VDMClientProcess; /* Handle to the client process who opened the buffer, to unmap the view */
HANDLE StartHardwareEvent;
HANDLE EndHardwareEvent;
HANDLE ErrorHardwareEvent;
/****************************** Other properties ******************************/ /****************************** 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 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 */ UNICODE_STRING Title; /* Title of console. Always NULL-terminated */

View file

@ -21,8 +21,132 @@
CSR_API(SrvRegisterConsoleVDM) CSR_API(SrvRegisterConsoleVDM)
{ {
DPRINT1("%s not yet implemented\n", __FUNCTION__); NTSTATUS Status;
return STATUS_NOT_IMPLEMENTED; PCONSOLE_REGISTERVDM RegisterVDMRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.RegisterVDMRequest;
PCONSOLE Console;
DPRINT1("SrvRegisterConsoleVDM(%d)\n", RegisterVDMRequest->RegisterFlags);
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
&Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
if (RegisterVDMRequest->RegisterFlags != 0)
{
LARGE_INTEGER SectionSize;
ULONG Size, ViewSize = 0;
HANDLE ProcessHandle;
/*
* 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;
Console->VDMClientProcess = ProcessHandle;
Console->VDMBufferSize = RegisterVDMRequest->VDMBufferSize;
Size = Console->VDMBufferSize.X * Console->VDMBufferSize.Y
* sizeof(CHAR_CELL);
/*
* Create a memory section for the VDM buffer, to share with the client.
*/
SectionSize.QuadPart = Size;
Status = NtCreateSection(&Console->VDMBufferSection,
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);
goto Quit;
}
/*
* Create a view for our needs.
*/
ViewSize = 0;
Console->VDMBuffer = NULL;
Status = NtMapViewOfSection(Console->VDMBufferSection,
NtCurrentProcess(),
(PVOID*)&Console->VDMBuffer,
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(Console->VDMBufferSection);
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 VDM buffer.
*/
ViewSize = 0;
Console->ClientVDMBuffer = NULL;
Status = NtMapViewOfSection(Console->VDMBufferSection,
ProcessHandle,
(PVOID*)&Console->ClientVDMBuffer,
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(), Console->VDMBuffer);
NtClose(Console->VDMBufferSection);
goto Quit;
}
// TODO: Duplicate the event handles.
RegisterVDMRequest->VDMBuffer = Console->ClientVDMBuffer;
Status = STATUS_SUCCESS;
}
else
{
/* RegisterFlags == 0 means we are unregistering the VDM */
// TODO: Close the duplicated handles.
if (Console->VDMBuffer)
{
/*
* Uninitialize the graphics screen buffer
* in the reverse way we initialized it.
*/
NtUnmapViewOfSection(Console->VDMClientProcess, Console->ClientVDMBuffer);
NtUnmapViewOfSection(NtCurrentProcess(), Console->VDMBuffer);
NtClose(Console->VDMBufferSection);
}
Console->VDMBuffer = Console->ClientVDMBuffer = NULL;
Console->VDMBufferSize.X = Console->VDMBufferSize.Y = 0;
}
Quit:
ConSrvReleaseConsole(Console, TRUE);
return Status;
} }
CSR_API(SrvVDMConsoleOperation) CSR_API(SrvVDMConsoleOperation)