Jacek Caban : server: Introduce IOCTL_CONDRV_READ_OUTPUT ioctl.

Alexandre Julliard julliard at winehq.org
Tue Jul 28 15:53:31 CDT 2020


Module: wine
Branch: master
Commit: 44052219aa0e6412a0f595f830c0cdf6e82ea70c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=44052219aa0e6412a0f595f830c0cdf6e82ea70c

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Jul 28 17:10:23 2020 +0200

server: Introduce IOCTL_CONDRV_READ_OUTPUT ioctl.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/wine/condrv.h |  3 +-
 server/console.c      | 90 +++++++++++++++++++++++++++++++++++++++++++++++++--
 server/trace.c        |  1 +
 3 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/include/wine/condrv.h b/include/wine/condrv.h
index a47a4f2775..839db84ea5 100644
--- a/include/wine/condrv.h
+++ b/include/wine/condrv.h
@@ -37,6 +37,7 @@
 #define IOCTL_CONDRV_SET_TITLE             CTL_CODE(FILE_DEVICE_CONSOLE, 16, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
 
 /* console output ioctls */
+#define IOCTL_CONDRV_READ_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_READ_DATA)
 #define IOCTL_CONDRV_WRITE_OUTPUT          CTL_CODE(FILE_DEVICE_CONSOLE, 31, METHOD_BUFFERED, FILE_WRITE_DATA)
 #define IOCTL_CONDRV_GET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 32, METHOD_BUFFERED, FILE_READ_PROPERTIES)
 #define IOCTL_CONDRV_SET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
@@ -83,7 +84,7 @@ struct condrv_input_info_params
     struct condrv_input_info info;    /* input_info */
 };
 
-/* IOCTL_CONDRV_WRITE_OUTPUT */
+/* IOCTL_CONDRV_WRITE_OUTPUT and IOCTL_CONDRV_READ_OUTPUT params */
 struct condrv_output_params
 {
     unsigned int  x;                  /* destination position */
diff --git a/server/console.c b/server/console.c
index 14fbd67e22..207e333ec3 100644
--- a/server/console.c
+++ b/server/console.c
@@ -1248,6 +1248,73 @@ static struct fd *screen_buffer_get_fd( struct object *obj )
     return NULL;
 }
 
+/* read data from a screen buffer */
+static void read_console_output( struct screen_buffer *screen_buffer, unsigned int x, unsigned int y,
+                                 enum char_info_mode mode, unsigned int width )
+{
+    unsigned int i, count;
+    char_info_t *src;
+
+    if (x >= screen_buffer->width || y >= screen_buffer->height)
+    {
+        if (width) set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+    src = screen_buffer->data + y * screen_buffer->width + x;
+
+    switch(mode)
+    {
+    case CHAR_INFO_MODE_TEXT:
+        {
+            WCHAR *data;
+            count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
+                         get_reply_max_size() / sizeof(*data) );
+            if ((data = set_reply_data_size( count * sizeof(*data) )))
+            {
+                for (i = 0; i < count; i++) data[i] = src[i].ch;
+            }
+        }
+        break;
+    case CHAR_INFO_MODE_ATTR:
+        {
+            unsigned short *data;
+            count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
+                         get_reply_max_size() / sizeof(*data) );
+            if ((data = set_reply_data_size( count * sizeof(*data) )))
+            {
+                for (i = 0; i < count; i++) data[i] = src[i].attr;
+            }
+        }
+        break;
+    case CHAR_INFO_MODE_TEXTATTR:
+        {
+            char_info_t *data;
+            SMALL_RECT *region;
+            if (!width || get_reply_max_size() < sizeof(*region))
+            {
+                set_error( STATUS_INVALID_PARAMETER );
+                return;
+            }
+            count  = min( (get_reply_max_size() - sizeof(*region)) / (width * sizeof(*data)), screen_buffer->height - y );
+            width  = min( width, screen_buffer->width - x );
+            if (!(region = set_reply_data_size( sizeof(*region) + width * count * sizeof(*data) ))) return;
+            region->Left   = x;
+            region->Top    = y;
+            region->Right  = x + width - 1;
+            region->Bottom = y + count - 1;
+            data = (char_info_t *)(region + 1);
+            for (i = 0; i < count; i++)
+            {
+                memcpy( &data[i * width], &src[i * screen_buffer->width], width * sizeof(*data) );
+            }
+        }
+        break;
+    default:
+        set_error( STATUS_INVALID_PARAMETER );
+        break;
+    }
+}
+
 /* write data into a screen buffer */
 static void write_console_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params,
                                   data_size_t size )
@@ -1378,8 +1445,8 @@ static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t
 }
 
 /* read data from a screen buffer */
-static void read_console_output( struct screen_buffer *screen_buffer, int x, int y,
-                                 enum char_info_mode mode, int wrap )
+static void read_console_output_req( struct screen_buffer *screen_buffer, int x, int y,
+                                     enum char_info_mode mode, int wrap )
 {
     int i;
     char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x;
@@ -1676,6 +1743,23 @@ static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *
         screen_buffer->mode = *(unsigned int *)get_req_data();
         return 1;
 
+    case IOCTL_CONDRV_READ_OUTPUT:
+        {
+            const struct condrv_output_params *params = get_req_data();
+            if (get_req_data_size() != sizeof(*params))
+            {
+                set_error( STATUS_INVALID_PARAMETER );
+                return 0;
+            }
+            if (console_input_is_bare( screen_buffer->input ))
+            {
+                set_error( STATUS_OBJECT_TYPE_MISMATCH );
+                return 0;
+            }
+            read_console_output( screen_buffer, params->x, params->y, params->mode, params->width );
+            return !get_error();
+        }
+
     case IOCTL_CONDRV_WRITE_OUTPUT:
         if (get_req_data_size() < sizeof(struct condrv_output_params) ||
             (get_reply_max_size() != sizeof(SMALL_RECT) && get_reply_max_size() != sizeof(unsigned int)))
@@ -2150,7 +2234,7 @@ DECL_HANDLER(read_console_output)
             release_object( screen_buffer );
             return;
         }
-        read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap );
+        read_console_output_req( screen_buffer, req->x, req->y, req->mode, req->wrap );
         reply->width  = screen_buffer->width;
         reply->height = screen_buffer->height;
         release_object( screen_buffer );
diff --git a/server/trace.c b/server/trace.c
index 7cff5bf5f4..ab5a40bef8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -124,6 +124,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code )
         CASE(IOCTL_CONDRV_GET_TITLE);
         CASE(IOCTL_CONDRV_PEEK);
         CASE(IOCTL_CONDRV_READ_INPUT);
+        CASE(IOCTL_CONDRV_READ_OUTPUT);
         CASE(IOCTL_CONDRV_SET_MODE);
         CASE(IOCTL_CONDRV_SET_OUTPUT_INFO);
         CASE(IOCTL_CONDRV_WRITE_INPUT);




More information about the wine-cvs mailing list