[KERNEL32][CONSRV]: Implement a basic RegisterConsoleVDM (see revision 62371 for...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 9 Aug 2014 19:47:40 +0000 (19:47 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 9 Aug 2014 19:47:40 +0000 (19:47 +0000)
svn path=/branches/condrv_restructure/; revision=63849

dll/win32/kernel32/client/vdm.c
include/psdk/wincon.h
include/reactos/subsys/win/conmsg.h
win32ss/user/winsrv/consrv/condrv/conoutput.c
win32ss/user/winsrv/consrv/condrv/text.c
win32ss/user/winsrv/consrv/include/conio.h
win32ss/user/winsrv/consrv/subsysreg.c

index 8b50319..3456dab 100644 (file)
@@ -1640,26 +1640,101 @@ GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
 
 
 /*
- * @unimplemented
+ * @implemented (undocumented)
  */
 BOOL
 WINAPI
-RegisterConsoleVDM (
-    DWORD   Unknown0,
-    DWORD   Unknown1,
-    DWORD   Unknown2,
-    DWORD   Unknown3,
-    DWORD   Unknown4,
-    DWORD   Unknown5,
-    DWORD   Unknown6,
-    DWORD   Unknown7,
-    DWORD   Unknown8,
-    DWORD   Unknown9,
-    DWORD   Unknown10
-    )
+RegisterConsoleVDM(IN DWORD dwRegisterFlags,
+                   IN HANDLE hStartHardwareEvent,
+                   IN HANDLE hEndHardwareEvent,
+                   IN HANDLE hErrorHardwareEvent,
+                   IN DWORD dwUnusedVar,
+                   OUT LPDWORD lpVideoStateLength,
+                   OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
+                   IN PVOID lpUnusedBuffer,
+                   IN DWORD dwUnusedBufferLength,
+                   IN COORD dwVDMBufferSize,
+                   OUT PVOID* lpVDMBuffer)
 {
-    STUB;
-    return FALSE;
+    BOOL Success;
+    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);
 
-    return
-    BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
-                       NULL,
-                       0,
-                       Unknown0);
+    return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
+                              NULL,
+                              0,
+                              Unknown0);
 }
index c44e478..2df5ef3 100644 (file)
@@ -618,6 +618,12 @@ BOOL WINAPI CloseConsoleHandle(_In_ HANDLE);
 // BOOL WINAPI SetStdHandle(_In_ DWORD, _In_ HANDLE);
 /* Undocumented */
 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
 WINAPI
index 0685357..1f04722 100644 (file)
@@ -806,6 +806,28 @@ typedef struct
     BOOL   Ansi;
 } 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
 {
     PORT_MESSAGE Header;
@@ -903,6 +925,9 @@ typedef struct _CONSOLE_API_MESSAGE
         CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
         CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
         CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest;
+
+        /* Virtual DOS Machine */
+        CONSOLE_REGISTERVDM RegisterVDMRequest;
     } Data;
 } CONSOLE_API_MESSAGE, *PCONSOLE_API_MESSAGE;
 
index 42d5cbf..8e15917 100644 (file)
@@ -207,6 +207,13 @@ ConDrvGetActiveScreenBuffer(IN PCONSOLE Console)
 
 /* 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
 ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
                            IN PCONSOLE_SCREEN_BUFFER Buffer,
@@ -218,6 +225,19 @@ ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
     /* Validity check */
     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 (Buffer == Console->ActiveBuffer) TermDrawRegion(Console, Region);
 
index 96e3003..6b8dbdc 100644 (file)
@@ -722,6 +722,68 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console,
     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
 ConDrvWriteConsole(IN PCONSOLE Console,
                    IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
index 90defe0..955a28a 100644 (file)
 #define DEFAULT_POPUP_ATTRIB    (FOREGROUND_BLUE | FOREGROUND_RED   | \
                                  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 */
 typedef enum _CONSOLE_IO_OBJECT_TYPE
 {
@@ -300,6 +309,17 @@ typedef struct _CONSOLE
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;    /* Pointer to currently active screen buffer */
     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 ******************************/
     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 */
index 0ba10af..40f9740 100644 (file)
 
 CSR_API(SrvRegisterConsoleVDM)
 {
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    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)