Fix incorrect ClientSize calculation in PerMonitorV2 mode when form moves between monitors with different DPI#14277
Conversation
…oves between monitors with different DPI
There was a problem hiding this comment.
Pull request overview
This PR fixes a long-standing bug in PerMonitorV2 DPI scaling where forms moving between monitors with different DPI settings would have incorrect ClientSize values. The issue was that the original code applied the font-based autoScaleFactor to the entire window size (including non-client area), but Windows actually scales the non-client area (title bar, borders) linearly by DPI ratio, not by the font-based factor.
Changes:
- Modified
OnGetDpiScaledSizemethod to separately calculate non-client area sizes at both old and new DPI values - Changed calculation to apply
autoScaleFactoronly to the client area, not the entire window - Added
Math.Roundto minimize rounding errors during DPI transitions
| } | ||
|
|
||
| // Calculate client area at old DPI |
There was a problem hiding this comment.
According to the C# coding guidelines for this codebase, there should be an empty line after structure blocks (like if/else) for clarity. An empty line should be inserted between the closing brace of the else block and the comment that follows.
| Debug.WriteLine($"AutoScaleFactor computed for new DPI = {autoScaleFactor.Width} - {autoScaleFactor.Height}"); | ||
|
|
||
| // Notify Windows that the top-level window size should be based on AutoScaleMode value. |
There was a problem hiding this comment.
According to the C# coding guidelines for this codebase, there should be an empty line before return statements for clarity. An empty line should be inserted between line 4625 (Debug.WriteLine) and line 4627 (the comment before return).
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #14277 +/- ##
===================================================
- Coverage 77.18395% 77.17894% -0.00501%
===================================================
Files 3279 3279
Lines 645138 645154 +16
Branches 47730 47731 +1
===================================================
- Hits 497943 497923 -20
- Misses 143503 143539 +36
Partials 3692 3692
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Fixes #12132
Root Cause
The original code in
OnGetDpiScaledSizeapplied the font-basedautoScaleFactorto the entire window Size (including non-client area):However, the non-client area (title bar, borders) is scaled linearly by DPI ratio by Windows, not by the font-based auto scale factor. This mismatch caused incorrect ClientSize calculations when forms transitioned between monitors with different DPI settings.
Proposed changes
When calculating the desired window size during DPI transitions in
OnGetDpiScaledSize, the non-client area (title bar and window borders) should be excluded from theautoScaleFactorcalculation since Windows scales them linearly by DPI ratio, not by the font-based auto scale factor.The fix:
AdjustWindowRectExForDpito calculate the non-client area size at both old and new DPIautoScaleFactorCustomer Impact
ClientSizedifference is reduced to 0-1 pixels (the remaining 1 pixel is an inherent rounding error from font measurement inAutoScaleMode.Font).Regression?
Risk
Screenshots
Before
After
Test methodology
Test environment(s)
Microsoft Reviewers: Open in CodeFlow