Jump to content

Per-Monitor V2 DPI handling: maximized window placed off-screen on monitor with negative origin, and layout not recalculated on DPI change


Recommended Posts

Posted

Wise Care 365 version: 8.0.5 PRO
OS: Windows 10 22H2, build 19041


SETUP

Primary monitor: 900x1600 portrait, 150% scaling, origin (0,0), logical size 600x1067
Secondary monitor: 1920x1080 landscape, 100% scaling, origin (-1920, 0)

GetSystemMetrics in a Per-Monitor-V2 context returns SM_XVIRTUALSCREEN = -1920,
SM_YVIRTUALSCREEN = 0, SM_CXVIRTUALSCREEN = 2820, SM_CYVIRTUALSCREEN = 1600, so the
virtual desktop spans X from -1920 to 900 and Y from 0 to 1600 in physical pixels.

No compatibility overrides are set. Task Manager reports the process as Per-Monitor (V2),
so Windows performs no DPI virtualization or bitmap stretching here.

Both issues below were observed on the secondary monitor, the one at 100% scaling with
origin (-1920, 0).


ISSUE 1: MAXIMIZED WINDOW LANDS OUTSIDE THE VIRTUAL DESKTOP

Symptom

Maximizing the main window on the secondary monitor places it almost entirely outside the
virtual desktop. It becomes unreachable: the process has no taskbar button, and Alt+Tab
does not restore it. Recovery requires an external tool to move the window back.

Measurement

GetWindowRect on the maximized window:

    Left   -3850
    Top      -10
    Right  -1910
    Bottom  1090
    Size    1940 x 1100

Analysis

The size is correct: 1920x1080 plus the 10px invisible resize border on each edge. The
vertical axis is correct: Top -10, Bottom 1090 match the monitor's 0..1080 range plus
border.

Only the X axis is wrong, and it is wrong by exactly -1920, which is the secondary
monitor's origin. Expected Left is -1930 (monitor left -1920 minus 10px border). Actual is
-1930 + (-1920) = -3850.

The overlap with the virtual desktop is 10 pixels wide (-1920 to -1910), entirely inside
the invisible resize border, which is why nothing is visible on screen.

Probable cause

The MINMAXINFO.ptMaxPosition field returned from WM_GETMINMAXINFO is defined in
coordinates relative to the target monitor's upper-left corner, not in virtual-screen
coordinates. If the application writes the absolute value from GetMonitorInfo
(rcWork.left = -1920) into ptMaxPosition.x, Windows adds the monitor origin a second time,
producing -3840, and the border adjustment gives the observed -3850.

This reproduces only when the target monitor has a non-zero origin. On a single-monitor
system, or when maximizing on the primary monitor, the origin is (0,0) and the double
offset is invisible. That is likely why this has not been caught in testing.

Suggested fix

Set ptMaxPosition relative to the monitor:

    ptMaxPosition.x = rcWork.left - rcMonitor.left
    ptMaxPosition.y = rcWork.top  - rcMonitor.top

with rcWork and rcMonitor obtained from GetMonitorInfo on the handle returned by
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST). For a monitor without a taskbar this
evaluates to (0,0).

As a safety net, clamp the final window rect against the virtual desktop bounds
(SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN) so the
window can never end up unreachable.

Reference:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-minmaxinfo


ISSUE 2: LAYOUT IS NOT RECALCULATED WHEN THE WINDOW MOVES BETWEEN MONITORS

Screenshot attached, captured on the 100% monitor after moving the window there from the
150% monitor.

In the Utilities panel on the right, every icon caption is clipped. Captions are truncated
horizontally ("Imag...", "Zorla Sili...") and are also cut off vertically by the following
row of icons. The right-hand panel itself is clipped at the window edge.

This suggests the grid cell height and the panel width are fixed pixel values computed for
96 DPI, while the font is rendered at the current scale factor. The text then overflows the
cell and is clipped by the next row.

Starting the application directly on the 100% monitor renders correctly, so the layout
appears to be computed once at startup and never recalculated when the window changes
monitors.

Since the process declares Per-Monitor (V2), Windows expects the application to redraw
itself on WM_DPICHANGED, including recreating fonts and bitmap resources at the new scale
factor, and to use the suggested rectangle passed in lParam.


I have this monitor configuration available and can test a build.

WiseCare365_distorted.png

WiseCare365_normal.png

Posted

Thank you for your very detailed feedback. I have reported it to our development department. If there is a reply, I will send it to you promptly.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...