diff --git a/src/System.Windows.Forms.Design.Editors/src/Misc/CommonUnsafeNativeMethods.cs b/src/System.Windows.Forms.Design.Editors/src/Misc/CommonUnsafeNativeMethods.cs
index 4a81b30e231..842d2092e14 100644
--- a/src/System.Windows.Forms.Design.Editors/src/Misc/CommonUnsafeNativeMethods.cs
+++ b/src/System.Windows.Forms.Design.Editors/src/Misc/CommonUnsafeNativeMethods.cs
@@ -63,76 +63,5 @@ public static IntPtr LoadLibraryFromSystemPathIfAvailable(string libraryName)
}
#endregion
-
- #region PInvoke DpiRelated
- // This section could go to Nativemethods.cs or Safenativemethods.cs but we have separate copies of them in each library (System.winforms, System.Design and System.Drawing).
- // Keeping them here will reduce duplicating code but may have to take care of security warnings (if any).
- // These APIs are available starting Windows 10, version 1607 only.
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- internal static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
-
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- internal static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext);
-
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool AreDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB);
-
- ///
- /// Tries to compare two DPIawareness context values. Return true if they were equal.
- /// Return false when they are not equal or underlying OS does not support this API.
- ///
- /// true/false
- public static bool TryFindDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB)
- {
- if (ApiHelper.IsApiAvailable(ExternDll.User32, "AreDpiAwarenessContextsEqual"))
- {
- return AreDpiAwarenessContextsEqual(dpiContextA, dpiContextB);
- }
-
- return false;
- }
-
- ///
- /// Tries to get thread dpi awareness context
- ///
- /// returns thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
- public static DpiAwarenessContext TryGetThreadDpiAwarenessContext()
- {
- if (ApiHelper.IsApiAvailable(ExternDll.User32, "GetThreadDpiAwarenessContext"))
- {
- return GetThreadDpiAwarenessContext();
- }
- else
- {
- // legacy OS that does not have this API available.
- return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
- }
- }
-
- ///
- /// Tries to set thread dpi awareness context
- ///
- /// returns old thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
- public static DpiAwarenessContext TrySetThreadDpiAwarenessContext(DpiAwarenessContext dpiCOntext)
- {
- if (ApiHelper.IsApiAvailable(ExternDll.User32, "SetThreadDpiAwarenessContext"))
- {
- return SetThreadDpiAwarenessContext(dpiCOntext);
- }
- else
- {
- // legacy OS that does not have this API available.
- return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
- }
- }
-/*
- // Dpi awareness context values. Matching windows values.
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_UNAWARE = (-1);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = (-2);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = (-3);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = (-4);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_UNSPECIFIED = (0);*/
- #endregion
}
}
diff --git a/src/System.Windows.Forms.Design.Editors/src/Misc/DpiHelper.cs b/src/System.Windows.Forms.Design.Editors/src/Misc/DpiHelper.cs
index cbbf420dae9..20315b6aa92 100644
--- a/src/System.Windows.Forms.Design.Editors/src/Misc/DpiHelper.cs
+++ b/src/System.Windows.Forms.Design.Editors/src/Misc/DpiHelper.cs
@@ -290,8 +290,8 @@ internal static bool EnableDpiChangedMessageHandling
{
// We can't cache this value because different top level windows can have different DPI awareness context
// for mixed mode applications.
- DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
- return CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+ DpiAwarenessContext dpiAwareness = DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext();
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else
{
diff --git a/src/System.Windows.Forms.Design.Editors/src/Misc/DpiUnsafeNativeMethods.cs b/src/System.Windows.Forms.Design.Editors/src/Misc/DpiUnsafeNativeMethods.cs
new file mode 100644
index 00000000000..42efcf70719
--- /dev/null
+++ b/src/System.Windows.Forms.Design.Editors/src/Misc/DpiUnsafeNativeMethods.cs
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Windows.Forms
+{
+ using Runtime.InteropServices;
+ using Runtime.Versioning;
+ using System;
+
+ internal class DpiUnsafeNativeMethods
+ {
+
+ // This section could go to Nativemethods.cs or Safenativemethods.cs but we have separate copies of them in each library (System.winforms, System.Design and System.Drawing).
+ // Keeping them here will reduce duplicating code but may have to take care of security warnings (if any).
+ // These APIs are available starting Windows 10, version 1607 only.
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ internal static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ internal static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext);
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool AreDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB);
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ internal static extern DpiAwarenessContext GetWindowDpiAwarenessContext(IntPtr hwnd);
+
+ ///
+ /// Tries to compare two DPIawareness context values. Return true if they were equal.
+ /// Return false when they are not equal or underlying OS does not support this API.
+ ///
+ /// true/false
+ public static bool TryFindDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB)
+ {
+ if(dpiContextA == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED && dpiContextB == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)
+ {
+ return true;
+ }
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(DpiUnsafeNativeMethods.AreDpiAwarenessContextsEqual)))
+ {
+ return AreDpiAwarenessContextsEqual(dpiContextA, dpiContextB);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Tries to get thread dpi awareness context
+ ///
+ /// returns thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
+ public static DpiAwarenessContext TryGetThreadDpiAwarenessContext()
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(DpiUnsafeNativeMethods.GetThreadDpiAwarenessContext)))
+ {
+ return GetThreadDpiAwarenessContext();
+ }
+ else
+ {
+ // legacy OS that does not have this API available.
+ return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
+ }
+ }
+
+ ///
+ /// Tries to set thread dpi awareness context
+ ///
+ /// returns old thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
+ public static DpiAwarenessContext TrySetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext)
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(DpiUnsafeNativeMethods.SetThreadDpiAwarenessContext)))
+ {
+ if (dpiContext == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)
+ {
+ throw new ArgumentException(nameof(dpiContext), dpiContext.ToString());
+ }
+ return SetThreadDpiAwarenessContext(dpiContext);
+ }
+ else
+ {
+ // legacy OS that does not have this API available.
+ return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
+ }
+ }
+
+ ///
+ /// Tries to get window dpi awareness context
+ ///
+ /// returns window dpi awareness context if API is available in this version of OS. otherwise, return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED.
+ public static DpiAwarenessContext TryGetWindowDpiAwarenessContext(IntPtr hwnd)
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, "GetWindowDpiAwarenessContext"))
+ {
+ return GetWindowDpiAwarenessContext(hwnd);
+ }
+ else
+ {
+ // legacy OS that does not have this API available.
+ return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs
index 54d3da5e1dc..acc22ab217f 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs
@@ -1242,7 +1242,7 @@ private static void RaiseThreadExit() {
/// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to
/// be parked.
///
- internal static void ParkHandle(HandleRef handle, DpiAwarenessContext dpiAwarenessContext = DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED) {
+ internal static void ParkHandle(HandleRef handle, DpiAwarenessContext? dpiAwarenessContext = null) {
Debug.Assert(UnsafeNativeMethods.IsWindow(handle), "Handle being parked is not a valid window handle");
Debug.Assert(((int)UnsafeNativeMethods.GetWindowLong(handle, NativeMethods.GWL_STYLE) & NativeMethods.WS_CHILD) != 0, "Only WS_CHILD windows should be parked.");
@@ -1257,7 +1257,7 @@ internal static void ParkHandle(HandleRef handle, DpiAwarenessContext dpiAwarene
///
/// create params for control handle
/// dpi awareness
- internal static void ParkHandle(CreateParams cp, DpiAwarenessContext dpiAwarenessContext = DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED) {
+ internal static void ParkHandle(CreateParams cp, DpiAwarenessContext? dpiAwarenessContext = null) {
ThreadContext cxt = ThreadContext.FromCurrent();
if (cxt != null) {
@@ -1289,7 +1289,7 @@ public static void OnThreadException(Exception t) {
/// "Unparks" the given HWND to a temporary HWND. This allows WS_CHILD windows to
/// be parked.
///
- internal static void UnparkHandle(HandleRef handle, DpiAwarenessContext context) {
+ internal static void UnparkHandle(HandleRef handle, DpiAwarenessContext? context) {
ThreadContext cxt = GetContextForHandle(handle);
if (cxt != null) {
cxt.GetParkingWindow(context).UnparkHandle(handle);
@@ -2493,7 +2493,7 @@ internal bool CustomThreadExceptionHandlerAttached {
/// if it needs to.
///
///
- internal ParkingWindow GetParkingWindow(DpiAwarenessContext context) {
+ internal ParkingWindow GetParkingWindow(DpiAwarenessContext? context) {
// Locking 'this' here is ok since this is an internal class.
lock(this) {
@@ -2507,7 +2507,6 @@ internal ParkingWindow GetParkingWindow(DpiAwarenessContext context) {
Debug.WriteLine(CoreSwitches.PerfTrack.Enabled, Environment.StackTrace);
}
#endif
-
using (DpiHelper.EnterDpiAwarenessScope(context)) {
parkingWindow = new ParkingWindow();
}
@@ -2522,7 +2521,7 @@ internal ParkingWindow GetParkingWindow(DpiAwarenessContext context) {
/// Returns parking window that matches dpi awareness context. return null if not found.
///
/// return matching parking window from list. returns null if not found
- internal ParkingWindow GetParkingWindowForContext(DpiAwarenessContext context) {
+ internal ParkingWindow GetParkingWindowForContext(DpiAwarenessContext? context) {
if (parkingWindows.Count == 0) {
return null;
@@ -2531,7 +2530,7 @@ internal ParkingWindow GetParkingWindowForContext(DpiAwarenessContext context) {
// Legacy OS/target framework scenario where ControlDpiContext is set to DPI_AWARENESS_CONTEXT.DPI_AWARENESS_CONTEXT_UNSPECIFIED
// because of 'ThreadContextDpiAwareness' API unavailability or this feature is not enabled.
- if (!DpiHelper.IsScalingRequirementMet || CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(context, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)) {
+ if (!DpiHelper.IsScalingRequirementMet || DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(context, null)) {
Debug.Assert(parkingWindows.Count == 1, "parkingWindows count can not be > 1 for legacy OS/target framework versions");
return parkingWindows[0];
@@ -2539,7 +2538,7 @@ internal ParkingWindow GetParkingWindowForContext(DpiAwarenessContext context) {
// Supported OS scenario.
foreach (var p in parkingWindows) {
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(p.DpiAwarenessContext, context)) {
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(p.DpiAwarenessContext, context)) {
return p;
}
}
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
index 52379575fb8..bf81bcdf249 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
@@ -577,7 +577,7 @@ public Control( Control parent, string text, int left, int top, int width, int h
///
/// gets or sets control Dpi awareness context value.
///
- internal DpiAwarenessContext DpiAwarenessContext {
+ internal DpiAwarenessContext? DpiAwarenessContext {
get {
return window.DpiAwarenessContext;
}
@@ -5617,7 +5617,7 @@ protected virtual void CreateHandle() {
//
if (cp.Parent == IntPtr.Zero && (cp.Style & NativeMethods.WS_CHILD) != 0) {
Debug.Assert((cp.ExStyle & NativeMethods.WS_EX_MDICHILD) == 0, "Can't put MDI child forms on the parking form");
- Application.ParkHandle(cp);
+ Application.ParkHandle(cp, window.DpiAwarenessContext);
}
window.CreateHandle(cp);
@@ -5638,6 +5638,11 @@ protected virtual void CreateHandle() {
}
}
+ protected void ApplicationParkHandleWithWindowContext(HandleRef handle)
+ {
+ Application.ParkHandle(handle, window.DpiAwarenessContext);
+ }
+
///
///
/// Forces the creation of the control. This includes the creation of the handle,
@@ -8096,7 +8101,7 @@ internal virtual void OnParentHandleRecreating() {
// use SetParent directly so as to not raise ParentChanged events
if (IsHandleCreated) {
- Application.ParkHandle(new HandleRef(this, this.Handle));
+ Application.ParkHandle(new HandleRef(this, this.Handle), window.DpiAwarenessContext);
}
}
@@ -11420,7 +11425,7 @@ private void SetParentHandle(IntPtr value) {
}
if (!GetTopLevel()) {
if (value == IntPtr.Zero) {
- Application.ParkHandle(new HandleRef(window, Handle));
+ Application.ParkHandle(new HandleRef(window, Handle), window.DpiAwarenessContext);
UpdateRoot();
}
else {
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/NativeMethods.cs b/src/System.Windows.Forms/src/System/Windows/Forms/NativeMethods.cs
index e9f9e1eda78..c80b2b4fbe3 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/NativeMethods.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/NativeMethods.cs
@@ -459,6 +459,7 @@ public const int
public const int E_NOTIMPL = unchecked((int)0x80004001),
E_OUTOFMEMORY = unchecked((int)0x8007000E),
E_INVALIDARG = unchecked((int)0x80070057),
+ E_ACCESSDENIED = unchecked((int)0x80070005),
E_NOINTERFACE = unchecked((int)0x80004002),
E_POINTER = unchecked((int)0x80004003),
E_FAIL = unchecked((int)0x80004005),
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs b/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
index 97708833de2..f71c424a1be 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
@@ -95,9 +95,9 @@ public class NativeWindow : MarshalByRefObject, IWin32Window {
NativeWindow previousWindow; // doubly linked list of subclasses.
NativeWindow nextWindow;
WeakReference weakThisPtr;
- private DpiAwarenessContext windowDpiAwarenessContext = DpiHelper.IsScalingRequirementMet ?
- CommonUnsafeNativeMethods.TryGetThreadDpiAwarenessContext() :
- DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
+ private DpiAwarenessContext? windowDpiAwarenessContext = DpiHelper.IsScalingRequirementMet ?
+ (DpiAwarenessContext?)DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext() :
+ null;
static NativeWindow() {
EventHandler shutdownHandler = new EventHandler(OnShutdown);
@@ -127,7 +127,7 @@ public NativeWindow() {
///
/// Cache window DpiContext awareness information that helps to create handle with right context at the later time.
///
- internal DpiAwarenessContext DpiAwarenessContext {
+ internal DpiAwarenessContext? DpiAwarenessContext {
get {
return windowDpiAwarenessContext;
}
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs
index 62056016b80..f5b51801406 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs
@@ -479,7 +479,7 @@ protected override void WndProc(ref Message m) {
if (this.ActiveXState >= WebBrowserHelper.AXState.InPlaceActive) {
IntPtr hwndInPlaceObject;
if (NativeMethods.Succeeded(this.AXInPlaceObject.GetWindow(out hwndInPlaceObject))) {
- Application.ParkHandle(new HandleRef(this.AXInPlaceObject, hwndInPlaceObject));
+ this.ApplicationParkHandleWithWindowContext(new HandleRef(this.AXInPlaceObject, hwndInPlaceObject));
}
}
diff --git a/src/System.Windows.Forms/src/misc/CommonUnsafeNativeMethods.cs b/src/System.Windows.Forms/src/misc/CommonUnsafeNativeMethods.cs
index 8529c0e69aa..c9905bbe699 100644
--- a/src/System.Windows.Forms/src/misc/CommonUnsafeNativeMethods.cs
+++ b/src/System.Windows.Forms/src/misc/CommonUnsafeNativeMethods.cs
@@ -22,6 +22,7 @@ internal class CommonUnsafeNativeMethods
[DllImport(ExternDll.Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern IntPtr GetProcAddress(HandleRef hModule, string lpProcName);
+
[DllImport(ExternDll.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string modName);
@@ -69,85 +70,5 @@ public static IntPtr LoadLibraryFromSystemPathIfAvailable(string libraryName)
#endregion
- #region PInvoke DpiRelated
- // This section could go to Nativemethods.cs or Safenativemethods.cs but we have separate copies of them in each library (System.winforms, System.Design and System.Drawing).
- // Keeping them here will reduce duplicating code but may have to take care of security warnings (if any).
- // These APIs are available starting Windows 10, version 1607 only.
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
-
- internal static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
-
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
-
- internal static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext);
-
- [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool AreDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB);
-
- ///
- /// Tries to compare two DPIawareness context values. Return true if they were equal.
- /// Return false when they are not equal or underlying OS does not support this API.
- ///
- /// true/false
- public static bool TryFindDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB)
- {
- if(dpiContextA == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED && dpiContextB == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)
- {
- return true;
- }
- if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.AreDpiAwarenessContextsEqual)))
- {
- return AreDpiAwarenessContextsEqual(dpiContextA, dpiContextB);
- }
-
- return false;
- }
-
- ///
- /// Tries to get thread dpi awareness context
- ///
- /// returns thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
- public static DpiAwarenessContext TryGetThreadDpiAwarenessContext()
- {
- if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext)))
- {
- return GetThreadDpiAwarenessContext();
- }
- else
- {
- // legacy OS that does not have this API available.
- return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
- }
- }
-
- ///
- /// Tries to set thread dpi awareness context
- ///
- /// returns old thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
- public static DpiAwarenessContext TrySetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext)
- {
- if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext)))
- {
- if (dpiContext == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)
- {
- throw new ArgumentException(nameof(dpiContext), dpiContext.ToString());
- }
- return SetThreadDpiAwarenessContext(dpiContext);
- }
- else
- {
- // legacy OS that does not have this API available.
- return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
- }
- }
-/*
- // Dpi awareness context values. Matching windows values.
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_UNAWARE = (-1);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = (-2);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = (-3);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = (-4);
- public static readonly DPI_AWARENESS_CONTEXT DPI_AWARENESS_CONTEXT_UNSPECIFIED = (0);*/
- #endregion
}
}
diff --git a/src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs b/src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs
index 164bdc05712..fb44571b645 100644
--- a/src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs
+++ b/src/System.Windows.Forms/src/misc/DpiHelper.DpiAwarenessContext.cs
@@ -17,7 +17,7 @@ internal static partial class DpiHelper
/// The new DPI awareness for the current thread
/// An object that, when disposed, will reset the current thread's
/// DPI awareness to the value it had when the object was created.
- public static IDisposable EnterDpiAwarenessScope(DpiAwarenessContext awareness)
+ public static IDisposable EnterDpiAwarenessScope(DpiAwarenessContext? awareness)
{
return new DpiAwarenessScope(awareness);
}
@@ -45,25 +45,28 @@ public static T CreateInstanceInSystemAwareContext(Func createInstance)
private class DpiAwarenessScope : IDisposable
{
private bool dpiAwarenessScopeIsSet = false;
- private DpiAwarenessContext originalAwareness = DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED;
+ private DpiAwarenessContext? originalAwareness = null;
///
/// Enters given Dpi awareness scope
///
- public DpiAwarenessScope(DpiAwarenessContext awareness)
+ public DpiAwarenessScope(DpiAwarenessContext? awareness)
{
try
{
- if (!CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(awareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED))
+ if (!DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(awareness, null))
{
- originalAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
+ originalAwareness = DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext();
- // If current process dpiawareness is SYSTEM_UNAWARE or SYSTEM_AWARE (must be equal to awareness), calling this method will be a no-op.
- if (!CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(originalAwareness, awareness) &&
- !CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(originalAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
+ // If desired awareness is not equal to current awareness
+ if (!DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(originalAwareness, awareness))
{
- originalAwareness = CommonUnsafeNativeMethods.SetThreadDpiAwarenessContext(awareness);
- dpiAwarenessScopeIsSet = true;
+ // Unaware is allowed to open Unaware only; System Aware may open System and Unaware; etc...
+ if (CanContextAParentContextB(originalAwareness, awareness))
+ {
+ originalAwareness = DpiUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(awareness);
+ dpiAwarenessScopeIsSet = true;
+ }
}
}
}
@@ -73,6 +76,47 @@ public DpiAwarenessScope(DpiAwarenessContext awareness)
}
}
+ ///
+ /// Returns whether or not a window in context A should be allowed to open a window in context B
+ /// Unaware windows may only open children in unaware mode; System Aware windows may open children in System Aware and Unaware;
+ /// PMV1 windows may open children in PMV1, System Aware, and Unaware; finally PMV2 windows may open children in PMV2, PMV1, System Aware, and Unaware
+ ///
+ ///
+ ///
+ ///
+ /// If a new member of the enumeration is added, this code will also have to change
+ /// It would be better if there was a way to convert from the bit-masked dpi awareness to our own enumeration and compare the magnitude
+ private bool CanContextAParentContextB(DpiAwarenessContext? dpiAwarenessContextA, DpiAwarenessContext? dpiAwarenessContextB)
+ {
+ if(dpiAwarenessContextA == null || dpiAwarenessContextB == null)
+ {
+ return false; // null indicates unspecified, which Windows will not understand
+ }
+ else if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextA, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+ {
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE);
+ }
+ else if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextA, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
+ {
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE);
+ }
+ else if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextA, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
+ {
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) ||
+ DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE);
+ }
+ else if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextA, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
+ {
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwarenessContextB, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE);
+ }
+ return false;
+ }
+
///
/// Dispose object and resources
///
@@ -88,7 +132,7 @@ private void ResetDpiAwarenessContextChanges()
{
if (dpiAwarenessScopeIsSet)
{
- CommonUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(originalAwareness);
+ DpiUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(originalAwareness);
dpiAwarenessScopeIsSet = false;
}
}
diff --git a/src/System.Windows.Forms/src/misc/DpiHelper.cs b/src/System.Windows.Forms/src/misc/DpiHelper.cs
index 660c7c880de..304bb90286e 100644
--- a/src/System.Windows.Forms/src/misc/DpiHelper.cs
+++ b/src/System.Windows.Forms/src/misc/DpiHelper.cs
@@ -5,6 +5,7 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
+using System.Diagnostics;
#if WINFORMS_NAMESPACE
using CAPS = System.Windows.Forms.NativeMethods;
@@ -70,7 +71,7 @@ internal static void InitializeDpiHelperForWinforms()
Initialize();
// We are in Windows 10/1603 or greater when this API is present.
- if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext)))
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.GetProcessDpiAwareness)))
{
// We are on Windows 10/1603 or greater all right, but we could still be DpiUnaware or SystemAware, so let's find that out...
@@ -105,10 +106,10 @@ internal static bool IsPerMonitorV2Awareness
InitializeDpiHelperForWinforms();
if (doesNeedQueryForPerMonitorV2Awareness)
{
- // We can't cache this value because different top level windows can have different DPI awareness context
- // for mixed mode applications.
- DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
- return CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+ // We can't cache this value because different top level windows can
+ // have different DPI awareness context for mixed mode applications.
+ DpiAwarenessContext? dpiAwareness = DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext();
+ return DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else
{
@@ -341,47 +342,61 @@ public static void ScaleButtonImageLogicalToDevice(Button button)
///
internal static bool FirstParkingWindowCreated {get; set;}
+
///
/// Gets the DPI awareness.
///
/// The thread's/process' current HighDpi mode
internal static HighDpiMode GetWinformsApplicationDpiAwareness()
+ {
+ return GetAppDpiAwarenessFromThread() ??
+ GetAppDpiAwarenessFromProcess() ??
+ GetAppDpiAwarenessFromIsDpiAware() ??
+ HighDpiMode.DpiUnaware;
+ }
+
+ // For Windows 10 RS2 and above
+ private static HighDpiMode? GetAppDpiAwarenessFromThread()
{
- // For Windows 10 RS2 and above
- if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext)))
+ if (DpiUnsafeNativeMethods.GetThreadDpiAwarenessContextIsAvailable())
{
- DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext();
+ DpiAwarenessContext? dpiAwareness = DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext();
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
{
- return HighDpiMode.SystemAware;
+ return HighDpiMode.DpiUnaware;
}
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE))
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
{
- return HighDpiMode.DpiUnaware;
+ return HighDpiMode.SystemAware;
}
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
{
return HighDpiMode.PerMonitorV2;
}
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
{
return HighDpiMode.PerMonitor;
}
- if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
+ if (DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
{
return HighDpiMode.DpiUnawareGdiScaled;
}
}
- // For operating systems windows 8.1 to Windows 10 redstone 1 version.
- else if (ApiHelper.IsApiAvailable(ExternDll.ShCore, nameof(SafeNativeMethods.GetProcessDpiAwareness)))
+ return null;
+ }
+
+ // For operating systems windows 8.1 to Windows 10 redstone 1 version.
+ private static HighDpiMode? GetAppDpiAwarenessFromProcess()
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.ShCore, nameof(SafeNativeMethods.GetProcessDpiAwareness)))
{
- CAPS.PROCESS_DPI_AWARENESS processDpiAwareness;
+ CAPS.PROCESS_DPI_AWARENESS processDpiAwareness = CAPS.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE;
SafeNativeMethods.GetProcessDpiAwareness(IntPtr.Zero, out processDpiAwareness);
switch (processDpiAwareness)
@@ -395,16 +410,20 @@ internal static HighDpiMode GetWinformsApplicationDpiAwareness()
}
}
- // For operating systems windows 7 to windows 8
- else if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.IsProcessDPIAware)))
+ return null;
+ }
+
+ // For operating systems windows 7 to windows 8
+ private static HighDpiMode? GetAppDpiAwarenessFromIsDpiAware()
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.IsProcessDPIAware)))
{
return SafeNativeMethods.IsProcessDPIAware() ?
- HighDpiMode.SystemAware :
- HighDpiMode.DpiUnaware;
+ HighDpiMode.SystemAware :
+ HighDpiMode.DpiUnaware;
}
- // We should never get here, except someone ported this with force to < Windows 7.
- return HighDpiMode.DpiUnaware;
+ return null;
}
///
@@ -412,10 +431,15 @@ internal static HighDpiMode GetWinformsApplicationDpiAwareness()
///
/// true/false - If the process DPI awareness is successfully set, returns true. Otherwise false.
internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode)
- {
- NativeMethods.PROCESS_DPI_AWARENESS dpiFlag = NativeMethods.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNINITIALIZED;
+ {
+ return SetAppDpiAwarenessWithAwarenessContext(highDpiMode) ||
+ SetAppDpiAwarenessWithAwareness(highDpiMode) ||
+ SetAppDpiAwarenessWithAware(highDpiMode);
+ }
- // For Windows 10 RS2 and above
+ // For Windows 10 RS2 and above
+ private static bool SetAppDpiAwarenessWithAwarenessContext(HighDpiMode highDpiMode)
+ {
if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.SetProcessDpiAwarenessContext)))
{
int rs2AndAboveDpiFlag;
@@ -446,9 +470,16 @@ internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode)
return SafeNativeMethods.SetProcessDpiAwarenessContext(rs2AndAboveDpiFlag);
}
- // For operating systems Windows 8.1 to Windows 10 RS1 version.
- else if (ApiHelper.IsApiAvailable(ExternDll.ShCore, nameof(SafeNativeMethods.SetProcessDpiAwareness)))
+ return false;
+ }
+
+ // For operating systems Windows 8.1 to Windows 10 RS1 version.
+ private static bool SetAppDpiAwarenessWithAwareness(HighDpiMode highDpiMode)
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.ShCore, nameof(SafeNativeMethods.SetProcessDpiAwareness)))
{
+ NativeMethods.PROCESS_DPI_AWARENESS dpiFlag = NativeMethods.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNINITIALIZED;
+
switch (highDpiMode)
{
case HighDpiMode.DpiUnaware:
@@ -467,11 +498,26 @@ internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode)
break;
}
- return SafeNativeMethods.SetProcessDpiAwareness(dpiFlag) == NativeMethods.S_OK;
+ int hResult = SafeNativeMethods.SetProcessDpiAwareness(dpiFlag);
+ if (hResult == NativeMethods.E_INVALIDARG)
+ {
+ throw new ArgumentException(string.Format("{0} is invalid for {1}",
+ dpiFlag.ToString(),
+ nameof(SafeNativeMethods.SetProcessDpiAwareness)));
+ }
+ Debug.Assert(hResult != NativeMethods.E_ACCESSDENIED,
+ "The DPI awareness is already set, either by calling this API previously or through the application (.exe) manifest.");
+
+ return hResult == NativeMethods.S_OK;
}
- // For operating systems windows 7 to windows 8
- else if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.SetProcessDPIAware)))
+ return false;
+ }
+
+ // For operating systems windows 7 to windows 8
+ private static bool SetAppDpiAwarenessWithAware(HighDpiMode highDpiMode)
+ {
+ if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.SetProcessDPIAware)))
{
switch (highDpiMode)
{
@@ -482,22 +528,16 @@ internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode)
case HighDpiMode.SystemAware:
case HighDpiMode.PerMonitor:
case HighDpiMode.PerMonitorV2:
- dpiFlag = NativeMethods.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE;
- break;
- }
-
- if (dpiFlag == NativeMethods.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE)
- {
- return SafeNativeMethods.SetProcessDPIAware();
+ return SafeNativeMethods.SetProcessDPIAware();
}
}
+
return false;
}
}
internal enum DpiAwarenessContext
{
- DPI_AWARENESS_CONTEXT_UNSPECIFIED = 0,
DPI_AWARENESS_CONTEXT_UNAWARE = -1,
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = -3,
diff --git a/src/System.Windows.Forms/src/misc/DpiUnsafeNativeMethods.cs b/src/System.Windows.Forms/src/misc/DpiUnsafeNativeMethods.cs
new file mode 100644
index 00000000000..4527320fcdb
--- /dev/null
+++ b/src/System.Windows.Forms/src/misc/DpiUnsafeNativeMethods.cs
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Windows.Forms
+{
+ using Runtime.InteropServices;
+ using Runtime.Versioning;
+ using System;
+
+ internal class DpiUnsafeNativeMethods
+ {
+
+ // This section could go to Nativemethods.cs or Safenativemethods.cs but we have separate copies of them in each library (System.winforms, System.Design and System.Drawing).
+ // Keeping them here will reduce duplicating code but may have to take care of security warnings (if any).
+ // These APIs are available starting Windows 10, version 1607 only.
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ private static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ private static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiContext);
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool AreDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB);
+
+ [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
+ [ResourceExposure(ResourceScope.None)]
+ private static extern DpiAwarenessContext GetWindowDpiAwarenessContext(IntPtr hwnd);
+
+ public static bool GetThreadDpiAwarenessContextIsAvailable()
+ {
+ return ApiHelper.IsApiAvailable(ExternDll.User32, nameof(GetThreadDpiAwarenessContext));
+ }
+
+ public static bool SetThreadDpiAwarenessContextIsAvailable()
+ {
+ return ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SetThreadDpiAwarenessContext));
+ }
+
+ public static bool AreDpiAwarenessContextsEqualIsAvailable()
+ {
+ return ApiHelper.IsApiAvailable(ExternDll.User32, nameof(AreDpiAwarenessContextsEqual));
+ }
+
+ public static bool GetWindowDpiAwarenessContextIsAvailable()
+ {
+ return ApiHelper.IsApiAvailable(ExternDll.User32, nameof(GetWindowDpiAwarenessContext));
+ }
+
+ ///
+ /// Tries to compare two DPIawareness context values. Return true if they were equal.
+ /// Return false when they are not equal or underlying OS does not support this API.
+ ///
+ /// true/false
+ public static bool TryFindDpiAwarenessContextsEqual(DpiAwarenessContext? dpiContextA, DpiAwarenessContext? dpiContextB)
+ {
+ if(dpiContextA == null)
+ {
+ return (dpiContextB == null); // true if both null but not either
+ }
+ else if (dpiContextB == null)
+ {
+ return false; // because we know A is not null
+ }
+
+ if (AreDpiAwarenessContextsEqualIsAvailable())
+ {
+ return AreDpiAwarenessContextsEqual((DpiAwarenessContext)dpiContextA, (DpiAwarenessContext)dpiContextB);
+ }
+
+ // legacy OS that does not have this API available.
+ return false;
+ }
+
+ ///
+ /// Tries to get thread dpi awareness context
+ ///
+ /// returns thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
+ public static DpiAwarenessContext? TryGetThreadDpiAwarenessContext()
+ {
+ if (GetThreadDpiAwarenessContextIsAvailable())
+ {
+ return GetThreadDpiAwarenessContext();
+ }
+ // legacy OS that does not have this API available.
+ return null;
+ }
+
+ ///
+ /// Tries to set thread dpi awareness context
+ ///
+ /// returns old thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.
+ public static DpiAwarenessContext? TrySetThreadDpiAwarenessContext(DpiAwarenessContext? dpiContext)
+ {
+ if (SetThreadDpiAwarenessContextIsAvailable())
+ {
+ if (dpiContext == null)
+ {
+ throw new ArgumentNullException();
+ }
+ return SetThreadDpiAwarenessContext((DpiAwarenessContext)dpiContext);
+ }
+ // legacy OS that does not have this API available.
+ return null;
+ }
+
+ ///
+ /// Tries to get window dpi awareness context
+ ///
+ /// returns window dpi awareness context if API is available in this version of OS. otherwise, return DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED.
+ public static DpiAwarenessContext? TryGetWindowDpiAwarenessContext(IntPtr hwnd)
+ {
+ if (GetWindowDpiAwarenessContextIsAvailable())
+ {
+ return GetWindowDpiAwarenessContext(hwnd);
+ }
+ // legacy OS that does not have this API available.
+ return null;
+ }
+ }
+}
diff --git a/src/System.Windows.Forms/tests/UnitTests/CommonUnsafenativeMethods.cs b/src/System.Windows.Forms/tests/UnitTests/CommonUnsafenativeMethods.cs
deleted file mode 100644
index f3c33a15cd7..00000000000
--- a/src/System.Windows.Forms/tests/UnitTests/CommonUnsafenativeMethods.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Xunit;
-using WinForms.Common.Tests;
-
-namespace System.Windows.Forms.Tests
-{
- public class CommonUnsafeNativeMethodsTests
- {
-
-
- /*///
- /// Data for the TryFindDpiAwarenessContextsEqual test
- ///
- public static TheoryData TryFindDpiAwarenessContextsEqualData =>
- CommonTestHelper.GetEnumTheoryData();
-
-
- Theory]
- [MemberData(nameof(TryFindDpiAwarenessContextsEqualData))]
- internal void CommonUnsafeNativeMathods_TryFindDpiAwarenessContextsEqual(DpiAwarenessContext item)
- {
- Assert.True(CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(item, item));
- }
-
-
- [Fact]
- public void CommonUnsafeNativeMethods_AreDpiAwarenessContextsEqualNotForUnspecified()
- {
- Assert.False(CommonUnsafeNativeMethods.AreDpiAwarenessContextsEqual(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED));
- }
-
- ///
- /// Data for the TrySetThreadDpiAwarenessContextGetSet test
- ///
- public static TheoryData TrySetThreadDpiAwarenessContextGetSetData =>
- CommonTestHelper.GetEnumTheoryData();
-
- [Theory]
- [MemberData(nameof(TrySetThreadDpiAwarenessContextGetSetData))]
- internal void CommonUnsafeNativeMethods_TrySetThreadDpiAwarenessContextGetSet(DpiAwarenessContext item)
- {
- if (item != DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED)
- {
- CommonUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(item);
-
- Assert.True(CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(item, CommonUnsafeNativeMethods.TryGetThreadDpiAwarenessContext()));
- }
- else
- {
- var ex = Assert.Throws(() => CommonUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED));
- Assert.Equal(DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED.ToString(), ex.ParamName);
- }
- }*/
-
- }
-}
diff --git a/src/System.Windows.Forms/tests/UnitTests/DpiUnsafeNativeMethodsTests.cs b/src/System.Windows.Forms/tests/UnitTests/DpiUnsafeNativeMethodsTests.cs
new file mode 100644
index 00000000000..c2c83561314
--- /dev/null
+++ b/src/System.Windows.Forms/tests/UnitTests/DpiUnsafeNativeMethodsTests.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+using WinForms.Common.Tests;
+
+namespace System.Windows.Forms.Tests
+{
+ public class DpiUnsafeNativeMethodsTests
+ {
+ ///
+ /// Data for the TryFindDpiAwarenessContextsEqual test
+ ///
+ public static TheoryData TryFindDpiAwarenessContextsEqualData =>
+ CommonTestHelper.GetEnumTheoryData();
+
+
+ [Theory]
+ [MemberData(nameof(TryFindDpiAwarenessContextsEqualData))]
+ internal void DpiUnsafeNativeMethods_TryFindDpiAwarenessContextsEqual(DpiAwarenessContext item)
+ {
+ Assert.True(DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(item, item));
+ }
+
+ [Theory]
+ [MemberData(nameof(TryFindDpiAwarenessContextsEqualData))]
+ internal void DpiUnsafeNativeMethods_TryFindDpiAwarenessContextsEqual_CompareToNull(DpiAwarenessContext item)
+ {
+ Assert.False(DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(item, null));
+ Assert.False(DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(null, item));
+ }
+
+ [Fact]
+ internal void DpiUnsafeNativeMethods_TryFindDpiAwarenessContextsEqual_BothNull()
+ {
+ Assert.True(DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(null, null));
+ }
+
+
+ ///
+ /// Data for the TrySetThreadDpiAwarenessContextGetSet test
+ ///
+ public static TheoryData TrySetThreadDpiAwarenessContextGetSetData =>
+ CommonTestHelper.GetEnumTheoryData();
+
+ [Theory]
+ [MemberData(nameof(TrySetThreadDpiAwarenessContextGetSetData))]
+ internal void DpiUnsafeNativeMethods_TrySetThreadDpiAwarenessContextGetSet(DpiAwarenessContext item)
+ {
+ DpiUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(item);
+
+ Assert.True(DpiUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(item, DpiUnsafeNativeMethods.TryGetThreadDpiAwarenessContext()));
+ }
+
+ [Fact]
+ internal void DPiUnsafeNativeMethods_TrySetThreadDpiAwarenessContext_Null()
+ {
+ Assert.Throws(() => DpiUnsafeNativeMethods.TrySetThreadDpiAwarenessContext(null));
+ }
+
+ }
+}