-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Open
Labels
🪲 bugProduct bug (most likely)Product bug (most likely)area-HDPI-SAIssues related to high DPI SystemAware modeIssues related to high DPI SystemAware mode
Milestone
Description
- .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]
public void Control_Parent_DifferentDpi_ThrowsWin32Exception()
{
Control childControl = 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(new IntPtr((int)DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2));
Assert.Equal(0, Marshal.GetLastWin32Error());
childControl = new Control();
childControl.CreateControl();
Assert.Equal(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
CommonUnsafeNativeMethods.GetDpiAwarenessContextForWindow(childControl.Handle));
CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(new IntPtr((int)DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE));
Assert.Equal(0, Marshal.GetLastWin32Error());
parentControl = new Control();
parentControl.CreateControl();
// [Below] Assertion failure: Expected: DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; Actual: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
Assert.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.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.- That's the blocking issue for adding UT for Check for the return value of native SetParent calls in Control class #2262 :
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
// And if we are WS_CHILD, ensure we have a parent handle. if (cp.Parent == IntPtr.Zero && (cp.Style & (int)User32.WS.CHILD) != 0) { 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 forDPI_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
using (DpiHelper.EnterDpiAwarenessScope(context)) { parkingWindow = new ParkingWindow(); }
In this case, I think we should retrieve the DPI awareness context for the current thread, then pass it as thedpiAwarenessContextargument when callingApplication.ParkHandle, so the created control will have the same DPI awareness context as the current thread.
Actual behavior:
Expected behavior:
Minimal repro:
jozefizso
Metadata
Metadata
Assignees
Labels
🪲 bugProduct bug (most likely)Product bug (most likely)area-HDPI-SAIssues related to high DPI SystemAware modeIssues related to high DPI SystemAware mode