You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
.NET Core Version: (e.g. 3.0 Preview1, or daily build number, use dotnet --info) 5.0-alpha1
Have you experienced this same bug with .NET Framework?: N/A
Problem description:
I came across the problem when trying to add a UT for System.Windows.Forms that involves controls of different DPI-awareness. The code is like this
[WinFormsFact]publicvoidControl_Parent_DifferentDpi_ThrowsWin32Exception(){ControlchildControl=null,parentControl=null;IntPtr?originalAwareness=null;try{try{// DpiHelper.EnterDpiAwarenessScope will do nothing if current process is SYSTEM_UNAWARE or SYSTEM_AWARE//// We cannot use DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE,// Somehow GetDpiAwarenessContextForWindow will return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 for such window.originalAwareness=CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(newIntPtr((int)DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2));Assert.Equal(0,Marshal.GetLastWin32Error());childControl=newControl();childControl.CreateControl();Assert.Equal(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,CommonUnsafeNativeMethods.GetDpiAwarenessContextForWindow(childControl.Handle));CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(newIntPtr((int)DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE));Assert.Equal(0,Marshal.GetLastWin32Error());parentControl=newControl();parentControl.CreateControl();// [Below] Assertion failure: Expected: DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; Actual: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2Assert.Equal(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,CommonUnsafeNativeMethods.GetDpiAwarenessContextForWindow(parentControl.Handle));}finally{if(originalAwareness!=null){CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(originalAwareness.Value);}}Assert.Throws<Win32Exception>(()=>childControl.Parent=parentControl);Assert.Null(childControl.Parent);}finally{childControl?.Dispose();parentControl?.Dispose();}}
There are actually three problems I have came across during writing this unit test.
DpiHelper.EnterDpiAwarenessScope will do nothing if the DPI-awareness of current process is SYSTEM_UNAWARE or SYSTEM_AWARE. I'm not sure if that's by design.
CommonUnsafeNativeMethods.GetDpiAwarenessContextForWindow is returning PER_MONITOR_AWARE_V2 for windows that is actually PER_MONITOR_AWARE. It seems that you will need to use AreDpiAwarenessContextsEqual and compare the target windows' DPI awareness context with IntPtr(-3) or IntPtr(-4) to determine whether it's V2 or not.
Debug.Assert((cp.ExStyle&(int)User32.WS_EX.MDICHILD)==0,"Can't put MDI child forms on the parking form");
Application.ParkHandle(cp);
}
This will cause the parked control having the same DPI awareness as the parking window for DPI_AWARENESS_CONTEXT_UNSPECIFIED, that is, actually the thread DPI awareness when creating the parking window.
In this case, I think we should retrieve the DPI awareness context for the current thread, then pass it as the dpiAwarenessContext argument when calling Application.ParkHandle, so the created control will have the same DPI awareness context as the current thread.
dotnet --info) 5.0-alpha1Problem description:
I came across the problem when trying to add a UT for
System.Windows.Formsthat involves controls of different DPI-awareness. The code is like thisThere are actually three problems I have came across during writing this unit test.
DpiHelper.EnterDpiAwarenessScopewill do nothing if the DPI-awareness of current process is SYSTEM_UNAWARE or SYSTEM_AWARE. I'm not sure if that's by design.CommonUnsafeNativeMethods.GetDpiAwarenessContextForWindowis returningPER_MONITOR_AWARE_V2for windows that is actuallyPER_MONITOR_AWARE. It seems that you will need to useAreDpiAwarenessContextsEqualand compare the target windows' DPI awareness context withIntPtr(-3)orIntPtr(-4)to determine whether it'sV2or not.Control.CreateHandleis callingApplication.ParkHandlewithout specifying the second parameter, leaving itsdpiAwarenessContextset toDPI_AWARENESS_CONTEXT_UNSPECIFIED.winforms/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
Lines 5022 to 5027 in 2392f41
This will cause the parked control having the same DPI awareness as the parking window for
DPI_AWARENESS_CONTEXT_UNSPECIFIED, that is, actually the thread DPI awareness when creating the parking window.winforms/src/System.Windows.Forms/src/System/Windows/Forms/Application.ThreadContext.cs
Lines 285 to 288 in 2392f41
In this case, I think we should retrieve the DPI awareness context for the current thread, then pass it as the
dpiAwarenessContextargument when callingApplication.ParkHandle, so the created control will have the same DPI awareness context as the current thread.Actual behavior:
Expected behavior:
Minimal repro: