diff --git a/src/System.Windows.Forms/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/System/Windows/Forms/Control.cs index 4ca37ec84f1..14efc5014ff 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Control.cs @@ -11563,7 +11563,9 @@ private void WmDpiChangedBeforeParent(ref Message m) { DefWndProc(ref m); + // Cache the current DPI before updating DeviceDpiInternal. OriginalDeviceDpiInternal = DeviceDpiInternal; + int oldDeviceDpi = DeviceDpiInternal; // In order to support tests, will be querying Dpi from the message first. int newDeviceDpi = (short)m.WParamInternal.LOWORD; @@ -11582,6 +11584,8 @@ private void WmDpiChangedBeforeParent(ref Message m) Font localFont = GetCurrentFontAndDpi(out int fontDpi); DeviceDpiInternal = newDeviceDpi; + // Preserve the old DPI as the "original" DPI for subsequent scaling logic. + OriginalDeviceDpiInternal = oldDeviceDpi; if (fontDpi == DeviceDpiInternal) { diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Internals.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Internals.cs index 5ddaf37ce6a..04ff2e98d81 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Internals.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Internals.cs @@ -421,4 +421,41 @@ static void CreateAndDispose(Control control) Assert.NotNull(control.TestAccessor.Dynamic.ReflectParent); } } + + [WinFormsFact] + public void Control_WndProc_WmDpiChangedBeforeParent_DpiChanged_RescaleConstantsForDpiReceivesDistinctValues() + { + using IDisposable dpiScope = ScaleHelper.EnterDpiAwarenessScope(DPI_AWARENESS_CONTEXT.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + using DpiRescaleTrackingControl control = new(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + int newDpi = control.DeviceDpi == 96 ? 120 : 96; + Message message = Message.Create((HWND)control.Handle, PInvokeCore.WM_DPICHANGED_BEFOREPARENT, (WPARAM)newDpi, (LPARAM)0); + + control.WndProc(ref message); + + Assert.Equal(1, control.RescaleConstantsForDpiCallCount); + Assert.Equal(newDpi, control.DeviceDpiNew); + Assert.NotEqual(control.DeviceDpiOld, control.DeviceDpiNew); + } + + private sealed class DpiRescaleTrackingControl : Control + { + public int DeviceDpiOld { get; private set; } + + public int DeviceDpiNew { get; private set; } + + public int RescaleConstantsForDpiCallCount { get; private set; } + + protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) + { + DeviceDpiOld = deviceDpiOld; + DeviceDpiNew = deviceDpiNew; + RescaleConstantsForDpiCallCount++; + + base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew); + } + + public new void WndProc(ref Message m) => base.WndProc(ref m); + } }