[PATCH 2/3] gdi32: Report correct HORZRES and VERTRES values for GetDeviceCaps() with DCs on a specific monitor.

Zhiyi Zhang zzhang at codeweavers.com
Wed Jan 20 02:39:59 CST 2021


Fix DLC Quest uses the primary monitor size to render when in fullscreen mode on non-primary monitors.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/gdi32/dc.c          | 18 +++++++++++
 dlls/gdi32/driver.c      | 64 ++++++++++++++++++++++++++++++++++++++--
 dlls/gdi32/gdi_private.h |  4 +++
 dlls/gdi32/tests/dc.c    |  4 ---
 4 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index a9a37d9efe7..830fabf6e78 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -623,6 +623,7 @@ BOOL WINAPI RestoreDC( HDC hdc, INT level )
 HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                       const DEVMODEW *initData )
 {
+    const WCHAR *display, *p;
     HDC hdc;
     DC * dc;
     const struct gdi_dc_funcs *funcs;
@@ -663,6 +664,23 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
         }
     }
 
+    if (is_display_device( driver ))
+        display = driver;
+    else if (is_display_device( device ))
+        display = device;
+    else
+        display = NULL;
+
+    if (display)
+    {
+        /* Copy only the display name. For example, \\.\DISPLAY1 in \\.\DISPLAY1\Monitor0 */
+        p = display + 12;
+        while (iswdigit( *p ))
+            ++p;
+        lstrcpynW( dc->display, display, p - display + 1 );
+        dc->display[p - display] = '\0';
+    }
+
     dc->vis_rect.left   = 0;
     dc->vis_rect.top    = 0;
     dc->vis_rect.right  = GetDeviceCaps( hdc, DESKTOPHORZRES );
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index e2528ece046..bb98c554238 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -81,7 +81,9 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
 };
 static CRITICAL_SECTION driver_section = { &critsect_debug, -1, 0, 0, 0, 0 };
 
+static BOOL (WINAPI *pEnumDisplayMonitors)(HDC, LPRECT, MONITORENUMPROC, LPARAM);
 static HWND (WINAPI *pGetDesktopWindow)(void);
+static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR, LPMONITORINFO);
 static INT (WINAPI *pGetSystemMetrics)(INT);
 static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
 
@@ -137,10 +139,13 @@ static const struct gdi_dc_funcs *get_display_driver(void)
 /**********************************************************************
  *	     is_display_device
  */
-static BOOL is_display_device( LPCWSTR name )
+BOOL is_display_device( LPCWSTR name )
 {
     const WCHAR *p = name;
 
+    if (!name)
+        return FALSE;
+
     if (wcsnicmp( name, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") )) return FALSE;
 
     p += lstrlenW(L"\\\\.\\DISPLAY");
@@ -237,10 +242,33 @@ void CDECL __wine_set_display_driver( HMODULE module )
         HeapFree( GetProcessHeap(), 0, driver );
 
     user32 = LoadLibraryA( "user32.dll" );
+    pGetMonitorInfoW = (void *)GetProcAddress( user32, "GetMonitorInfoW" );
     pGetSystemMetrics = (void *)GetProcAddress( user32, "GetSystemMetrics" );
+    pEnumDisplayMonitors = (void *)GetProcAddress( user32, "EnumDisplayMonitors" );
     pSetThreadDpiAwarenessContext = (void *)GetProcAddress( user32, "SetThreadDpiAwarenessContext" );
 }
 
+struct monitor_info
+{
+    const WCHAR *name;
+    RECT rect;
+};
+
+static BOOL CALLBACK monitor_enum_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lparam )
+{
+    struct monitor_info *info = (struct monitor_info *)lparam;
+    MONITORINFOEXW mi;
+
+    mi.cbSize = sizeof(mi);
+    pGetMonitorInfoW( monitor, (MONITORINFO *)&mi );
+    if (!lstrcmpiW( info->name, mi.szDevice ))
+    {
+        info->rect = mi.rcMonitor;
+        return FALSE;
+    }
+
+    return TRUE;
+}
 
 static INT CDECL nulldrv_AbortDoc( PHYSDEV dev )
 {
@@ -378,8 +406,38 @@ static INT CDECL nulldrv_GetDeviceCaps( PHYSDEV dev, INT cap )
                                          GetDeviceCaps( dev->hdc, LOGPIXELSX ) * 10 );
     case VERTSIZE:        return MulDiv( GetDeviceCaps( dev->hdc, VERTRES ), 254,
                                          GetDeviceCaps( dev->hdc, LOGPIXELSY ) * 10 );
-    case HORZRES:         return pGetSystemMetrics ? pGetSystemMetrics( SM_CXSCREEN ) : 640;
-    case VERTRES:         return pGetSystemMetrics ? pGetSystemMetrics( SM_CYSCREEN ) : 480;
+    case HORZRES:
+    {
+        DC *dc = get_nulldrv_dc( dev );
+        struct monitor_info info;
+
+        if (dc->display[0] && pEnumDisplayMonitors && pGetMonitorInfoW)
+        {
+            info.name = dc->display;
+            SetRectEmpty( &info.rect );
+            pEnumDisplayMonitors( NULL, NULL, monitor_enum_proc, (LPARAM)&info );
+            if (!IsRectEmpty( &info.rect ))
+                return info.rect.right - info.rect.left;
+        }
+
+        return pGetSystemMetrics ? pGetSystemMetrics( SM_CXSCREEN ) : 640;
+    }
+    case VERTRES:
+    {
+        DC *dc = get_nulldrv_dc( dev );
+        struct monitor_info info;
+
+        if (dc->display[0] && pEnumDisplayMonitors && pGetMonitorInfoW)
+        {
+            info.name = dc->display;
+            SetRectEmpty( &info.rect );
+            pEnumDisplayMonitors( NULL, NULL, monitor_enum_proc, (LPARAM)&info );
+            if (!IsRectEmpty( &info.rect ))
+                return info.rect.bottom - info.rect.top;
+        }
+
+        return pGetSystemMetrics ? pGetSystemMetrics( SM_CYSCREEN ) : 480;
+    }
     case BITSPIXEL:       return 32;
     case PLANES:          return 1;
     case NUMBRUSHES:      return -1;
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 8d917a795c0..2bf16e8eaf8 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -84,6 +84,7 @@ typedef struct tagDC
     int          pixel_format;     /* pixel format (for memory DCs) */
     UINT         aa_flags;         /* anti-aliasing flags to pass to GetGlyphOutline for current font */
     FLOAT        miterLimit;
+    WCHAR        display[CCHDEVICENAME]; /* Display name when created for a specific display device */
 
     int           flags;
     DWORD         layout;
@@ -487,6 +488,9 @@ typedef struct
 
 #define WMFC_MAGIC 0x43464d57
 
+/* driver.c */
+extern BOOL is_display_device( LPCWSTR name ) DECLSPEC_HIDDEN;
+
 /* path.c */
 
 extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN;
diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c
index aa6917d432d..963b62f4e15 100644
--- a/dlls/gdi32/tests/dc.c
+++ b/dlls/gdi32/tests/dc.c
@@ -1769,11 +1769,9 @@ static void test_multi_monitor_dc(void)
         ok(!!hdc, "CreateDCA %s failed.\n", dd.DeviceName);
 
         value = GetDeviceCaps(hdc, HORZRES);
-        todo_wine_if(dm.dmPelsWidth != GetSystemMetrics(SM_CXSCREEN))
         ok(value == dm.dmPelsWidth, "Expected %d, got %d.\n", dm.dmPelsWidth, value);
 
         value = GetDeviceCaps(hdc, VERTRES);
-        todo_wine_if(dm.dmPelsHeight != GetSystemMetrics(SM_CYSCREEN))
         ok(value == dm.dmPelsHeight, "Expected %d, got %d.\n", dm.dmPelsHeight, value);
 
         value = GetDeviceCaps(hdc, DESKTOPHORZRES);
@@ -1813,11 +1811,9 @@ static void test_multi_monitor_dc(void)
         }
 
         value = GetDeviceCaps(hdc, HORZRES);
-        todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXSCREEN))
         ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value);
 
         value = GetDeviceCaps(hdc, VERTRES);
-        todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYSCREEN))
         ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value);
 
         value = GetDeviceCaps(hdc, DESKTOPHORZRES);
-- 
2.27.0




More information about the wine-devel mailing list