Zhiyi Zhang : gdi32: Report correct HORZRES and VERTRES values for GetDeviceCaps() with DCs on a specific monitor.

Alexandre Julliard julliard at winehq.org
Wed Jan 27 15:35:04 CST 2021


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

Author: Zhiyi Zhang <zzhang at codeweavers.com>
Date:   Sun Jan 24 12:14:20 2021 +0800

gdi32: Report correct HORZRES and VERTRES values for GetDeviceCaps() with DCs on a specific monitor.

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>
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdi32/dc.c             | 18 +++++++++++++
 dlls/gdi32/driver.c         | 64 ++++++++++++++++++++++++++++++++++++++++++---
 dlls/gdi32/gdi_private.h    |  4 +++
 dlls/user32/tests/monitor.c |  4 +--
 4 files changed, 85 insertions(+), 5 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/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index ee435a4faf4..08557867566 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -2085,7 +2085,7 @@ static void test_display_dc(void)
         hdc = CreateDCA(dd.DeviceName, NULL, NULL, NULL);
         ok(!!hdc, "CreateDCA %s failed.\n", dd.DeviceName);
 
-        check_display_dc(hdc, &dm, TRUE);
+        check_display_dc(hdc, &dm, FALSE);
 
         /* Tests after mode changes */
         memset(&dm2, 0, sizeof(dm2));
@@ -2108,7 +2108,7 @@ static void test_display_dc(void)
             continue;
         }
 
-        check_display_dc(hdc, &dm2, TRUE);
+        check_display_dc(hdc, &dm2, FALSE);
 
         /* Tests after monitor detach */
         if (!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))




More information about the wine-cvs mailing list