using GreenshotPlugin.Core.Enums;
using GreenshotPlugin.UnmanagedHelpers;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace GreenshotPlugin.Core
{
///
/// This handles DPI changes see
/// Writing DPI-Aware Desktop and Win32 Applications
///
public static class DpiHelper
{
private static readonly ILog Log = LogManager.GetLogger(typeof(DpiHelper));
///
/// This is the default DPI for the screen
///
public const uint DefaultScreenDpi = 96;
///
/// Retrieve the current DPI for the UI element which is related to this DpiHandler
///
public static uint Dpi { get; private set; } = GetDpiForSystem();
///
/// Calculate a DPI scale factor
///
/// uint
/// double
public static float DpiScaleFactor(uint dpi)
{
return (float)dpi / DefaultScreenDpi;
}
///
/// Scale the supplied number according to the supplied dpi
///
/// double with e.g. the width 16 for 16x16 images
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// double with the scaled number
public static float ScaleWithDpi(float someNumber, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return dpiScaleFactor * someNumber;
}
///
/// Scale the supplied number according to the supplied dpi
///
/// int with e.g. 16 for 16x16 images
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// Scaled width
public static int ScaleWithDpi(int number, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return (int)(dpiScaleFactor * number);
}
///
/// Scale the supplied Size according to the supplied dpi
///
/// Size to resize
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// NativeSize scaled
public static Size ScaleWithDpi(Size size, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new Size((int)(dpiScaleFactor * size.Width), (int)(dpiScaleFactor * size.Height));
}
///
/// Scale the supplied NativePoint according to the supplied dpi
///
/// NativePoint to resize
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// NativePoint scaled
public static Point ScaleWithDpi(Point size, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new Point((int)(dpiScaleFactor * size.X), (int)(dpiScaleFactor * size.Y));
}
///
/// Scale the supplied NativeSizeFloat according to the supplied dpi
///
/// PointF
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// PointF
public static PointF ScaleWithDpi(PointF point, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new PointF(dpiScaleFactor * point.X, dpiScaleFactor * point.Y);
}
///
/// Scale the supplied NativeSizeFloat according to the supplied dpi
///
/// NativeSizeFloat to resize
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// NativeSize scaled
public static SizeF ScaleWithDpi(SizeF size, uint dpi, Func scaleModifier = null)
{
var dpiScaleFactor = DpiScaleFactor(dpi);
if (scaleModifier != null)
{
dpiScaleFactor = scaleModifier(dpiScaleFactor);
}
return new SizeF(dpiScaleFactor * size.Width, dpiScaleFactor * size.Height);
}
///
/// Scale the supplied number to the current dpi
///
/// double with e.g. a width like 16 for 16x16 images
/// A function which can modify the scale factor
/// double with scaled number
public static float ScaleWithCurrentDpi(float someNumber, Func scaleModifier = null)
{
return ScaleWithDpi(someNumber, Dpi, scaleModifier);
}
///
/// Scale the supplied number to the current dpi
///
/// int with e.g. a width like 16 for 16x16 images
/// A function which can modify the scale factor
/// int with scaled number
public static int ScaleWithCurrentDpi(int someNumber, Func scaleModifier = null)
{
return ScaleWithDpi(someNumber, Dpi, scaleModifier);
}
///
/// Scale the supplied NativeSize to the current dpi
///
/// NativeSize to scale
/// A function which can modify the scale factor
/// NativeSize scaled
public static Size ScaleWithCurrentDpi(Size size, Func scaleModifier = null)
{
return ScaleWithDpi(size, Dpi, scaleModifier);
}
///
/// Scale the supplied NativeSizeFloat to the current dpi
///
/// NativeSizeFloat to scale
/// A function which can modify the scale factor
/// NativeSizeFloat scaled
public static SizeF ScaleWithCurrentDpi(SizeF size, Func scaleModifier = null)
{
return ScaleWithDpi(size, Dpi, scaleModifier);
}
///
/// Scale the supplied NativePoint to the current dpi
///
/// NativePoint to scale
/// A function which can modify the scale factor
/// NativePoint scaled
public static Point ScaleWithCurrentDpi(Point point, Func scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
///
/// Scale the supplied PointF to the current dpi
///
/// PointF to scale
/// A function which can modify the scale factor
/// PointF scaled
public static PointF ScaleWithCurrentDpi(PointF point, Func scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
///
/// Calculate a DPI unscale factor
///
/// uint
/// float
public static float DpiUnscaleFactor(uint dpi)
{
return (float)DefaultScreenDpi / dpi;
}
///
/// Unscale the supplied number according to the supplied dpi
///
/// double with e.g. the scaled width
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// double with the unscaled number
public static float UnscaleWithDpi(float someNumber, uint dpi, Func scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return dpiUnscaleFactor * someNumber;
}
///
/// Unscale the supplied number according to the supplied dpi
///
/// int with a scaled width
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// Unscaled width
public static int UnscaleWithDpi(int number, uint dpi, Func scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return (int)(dpiUnscaleFactor * number);
}
///
/// Unscale the supplied NativeSize according to the supplied dpi
///
/// NativeSize to unscale
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// Size unscaled
public static Size UnscaleWithDpi(Size size, uint dpi, Func scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new Size((int)(dpiUnscaleFactor * size.Width), (int)(dpiUnscaleFactor * size.Height));
}
///
/// Unscale the supplied Point according to the supplied dpi
///
/// Point to unscale
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// Point unscaled
public static Point UnscaleWithDpi(Point point, uint dpi, Func scaleModifier = null)
{
var dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new Point((int)(dpiUnscaleFactor * point.X), (int)(dpiUnscaleFactor * point.Y));
}
///
/// unscale the supplied NativeSizeFloat according to the supplied dpi
///
/// NativeSizeFloat to resize
/// current dpi, normal is 96.
/// A function which can modify the scale factor
/// SizeF unscaled
public static SizeF UnscaleWithDpi(SizeF size, uint dpi, Func scaleModifier = null)
{
float dpiUnscaleFactor = DpiUnscaleFactor(dpi);
if (scaleModifier != null)
{
dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor);
}
return new SizeF(dpiUnscaleFactor * size.Width, dpiUnscaleFactor * size.Height);
}
///
/// Unscale the supplied number to the current dpi
///
/// double with e.g. a width like 16 for 16x16 images
/// A function which can modify the scale factor
/// double with unscaled number
public static float UnscaleWithCurrentDpi(float someNumber, Func scaleModifier = null)
{
return UnscaleWithDpi(someNumber, Dpi, scaleModifier);
}
///
/// Unscale the supplied number to the current dpi
///
/// int with e.g. a width like 16 for 16x16 images
/// A function which can modify the scale factor
/// int with unscaled number
public static int UnscaleWithCurrentDpi(int someNumber, Func scaleModifier = null)
{
return UnscaleWithDpi(someNumber, Dpi, scaleModifier);
}
///
/// Unscale the supplied NativeSize to the current dpi
///
/// Size to unscale
/// A function which can modify the scale factor
/// Size unscaled
public static Size UnscaleWithCurrentDpi(Size size, Func scaleModifier = null)
{
return UnscaleWithDpi(size, Dpi, scaleModifier);
}
///
/// Unscale the supplied NativeSizeFloat to the current dpi
///
/// NativeSizeFloat to unscale
/// A function which can modify the scale factor
/// NativeSizeFloat unscaled
public static SizeF UnscaleWithCurrentDpi(SizeF size, Func scaleModifier = null)
{
return UnscaleWithDpi(size, Dpi, scaleModifier);
}
///
/// Unscale the supplied NativePoint to the current dpi
///
/// NativePoint to unscale
/// A function which can modify the scale factor
/// NativePoint unscaled
public static Point UnscaleWithCurrentDpi(Point point, Func scaleModifier = null)
{
return UnscaleWithDpi(point, Dpi, scaleModifier);
}
///
/// Unscale the supplied NativePointFloat to the current dpi
///
/// NativePointFloat to unscale
/// A function which can modify the scale factor
/// NativePointFloat unscaled
public static PointF UnscaleWithCurrentDpi(PointF point, Func scaleModifier = null)
{
return ScaleWithDpi(point, Dpi, scaleModifier);
}
///
/// public wrapper for EnableNonClientDpiScaling, this also checks if the function is available.
///
/// IntPtr
/// true if it worked
public static bool TryEnableNonClientDpiScaling(IntPtr hWnd)
{
// EnableNonClientDpiScaling is only available on Windows 10 and later
if (!WindowsVersion.IsWindows10OrLater)
{
return false;
}
var result = EnableNonClientDpiScaling(hWnd);
if (result.Succeeded())
{
return true;
}
var error = Win32.GetLastErrorCode();
if (Log.IsDebugEnabled)
{
Log.DebugFormat("Error enabling non client dpi scaling : {0}", Win32.GetMessage(error));
}
return false;
}
///
/// Make the current process DPI Aware, this should be done via the manifest but sometimes this is not possible.
///
/// bool true if it was possible to change the DPI awareness
public static bool EnableDpiAware()
{
// We can only test this for Windows 8.1 or later
if (!WindowsVersion.IsWindows81OrLater)
{
Log.Debug("An application can only be DPI aware starting with Window 8.1 and later.");
return false;
}
if (WindowsVersion.IsWindows10BuildOrLater(15063))
{
if (IsValidDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2))
{
SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2);
}
else
{
SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2);
}
return true;
}
return SetProcessDpiAwareness(DpiAwareness.PerMonitorAware).Succeeded();
}
///
/// Check if the process is DPI Aware, an DpiHandler doesn't make sense if not.
///
public static bool IsDpiAware
{
get
{
// We can only test this for Windows 8.1 or later
if (!WindowsVersion.IsWindows81OrLater)
{
Log.Debug("An application can only be DPI aware starting with Window 8.1 and later.");
return false;
}
using var process = Process.GetCurrentProcess();
GetProcessDpiAwareness(process.Handle, out var dpiAwareness);
if (Log.IsDebugEnabled)
{
Log.DebugFormat("Process {0} has a Dpi awareness {1}", process.ProcessName, dpiAwareness);
}
return dpiAwareness != DpiAwareness.Unaware && dpiAwareness != DpiAwareness.Invalid;
}
}
///
/// Retrieve the DPI value for the supplied window handle
///
/// IntPtr
/// dpi value
public static uint GetDpi(IntPtr hWnd)
{
if (!User32.IsWindow(hWnd))
{
return DefaultScreenDpi;
}
// Use the easiest method, but this only works for Windows 10
if (WindowsVersion.IsWindows10OrLater)
{
return GetDpiForWindow(hWnd);
}
// Use the second easiest method, but this only works for Windows 8.1 or later
if (WindowsVersion.IsWindows81OrLater)
{
var hMonitor = User32.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest);
// ReSharper disable once UnusedVariable
if (GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY))
{
return dpiX;
}
}
// Fallback to the global DPI settings
using var hdc = SafeWindowDcHandle.FromWindow(hWnd);
if (hdc == null)
{
return DefaultScreenDpi;
}
return (uint)GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX);
}
///
/// See details GetProcessDpiAwareness function
/// Retrieves the dots per inch (dpi) awareness of the specified process.
///
/// IntPtr with handle of the process that is being queried. If this parameter is NULL, the current process is queried.
/// out DpiAwareness - The DPI awareness of the specified process. Possible values are from the PROCESS_DPI_AWARENESS enumeration.
/// HResult
[DllImport("shcore")]
private static extern HResult GetProcessDpiAwareness(IntPtr processHandle, out DpiAwareness value);
///
/// Sets the current process to a specified dots per inch (dpi) awareness level. The DPI awareness levels are from the PROCESS_DPI_AWARENESS enumeration.
/// See SetProcessDpiAwareness function
///
/// DpiAwareness
/// HResult
[DllImport("shcore")]
private static extern HResult SetProcessDpiAwareness(DpiAwareness dpiAwareness);
///
/// It is recommended that you set the process-default DPI awareness via application manifest. See Setting the default DPI awareness for a process for more information. Setting the process-default DPI awareness via API call can lead to unexpected application behavior.
///
/// Sets the current process to a specified dots per inch (dpi) awareness context. The DPI awareness contexts are from the DPI_AWARENESS_CONTEXT value.
/// Remarks:
/// This API is a more advanced version of the previously existing SetProcessDpiAwareness API, allowing for the process default to be set to the finer-grained DPI_AWARENESS_CONTEXT values. Most importantly, this allows you to programmatically set Per Monitor v2 as the process default value, which is not possible with the previous API.
///
/// This method sets the default DPI_AWARENESS_CONTEXT for all threads within an application. Individual threads can have their DPI awareness changed from the default with the SetThreadDpiAwarenessContext method.
/// See SetProcessDpiAwarenessContext function
///
/// DpiAwarenessContext
/// bool
[DllImport("User32.dll", SetLastError = true)]
private static extern bool SetProcessDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
///
/// See more at GetDpiForWindow function
/// Returns the dots per inch (dpi) value for the associated window.
///
/// IntPtr
/// uint with dpi
[DllImport("User32.dll")]
private static extern uint GetDpiForWindow(IntPtr hWnd);
///
/// See
/// GetDpiForMonitor function
/// Queries the dots per inch (dpi) of a display.
///
/// IntPtr
/// MonitorDpiType
/// out int for the horizontal dpi
/// out int for the vertical dpi
/// true if all okay
[DllImport("shcore")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY);
///
/// See EnableNonClientDpiScaling function
///
/// IntPtr
/// bool
[DllImport("User32.dll", SetLastError = true)]
private static extern HResult EnableNonClientDpiScaling(IntPtr hWnd);
///
/// See GetDpiForSystem function
/// Returns the system DPI.
///
/// uint with the system DPI
[DllImport("User32.dll")]
private static extern uint GetDpiForSystem();
///
/// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS.
/// See more at LogicalToPhysicalPointForPerMonitorDPI function
///
/// IntPtr A handle to the window whose transform is used for the conversion.
/// A pointer to a POINT structure that specifies the logical coordinates to be converted. The new physical coordinates are copied into this structure if the function succeeds.
/// bool
[DllImport("User32.dll")]
private static extern bool LogicalToPhysicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point);
///
/// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS.
/// See more at PhysicalToLogicalPointForPerMonitorDPI function
///
/// IntPtr A handle to the window whose transform is used for the conversion.
/// NativePoint A pointer to a POINT structure that specifies the physical/screen coordinates to be converted. The new logical coordinates are copied into this structure if the function succeeds.
/// bool
[DllImport("User32.dll")]
private static extern bool PhysicalToLogicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point);
///
/// See SystemParametersInfo function
/// Retrieves the value of one of the system-wide parameters, taking into account the provided DPI value.
///
///
/// SystemParametersInfoActions The system-wide parameter to be retrieved.
/// This function is only intended for use with SPI_GETICONTITLELOGFONT, SPI_GETICONMETRICS, or SPI_GETNONCLIENTMETRICS. See SystemParametersInfo for more information on these values.
///
///
/// A parameter whose usage and format depends on the system parameter being queried or set. For more
/// information about system-wide parameters, see the uiAction parameter. If not otherwise indicated, you must specify
/// zero for this parameter.
///
/// IntPtr
/// SystemParametersInfoBehaviors
/// uint with dpi value
/// bool
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfoForDpi(SystemParametersInfoActions uiAction, uint uiParam, IntPtr pvParam, SystemParametersInfoBehaviors fWinIni, uint dpi);
///
/// See GetThreadDpiAwarenessContext function
/// Gets the DPI_AWARENESS_CONTEXT for the current thread.
///
/// This method will return the latest DPI_AWARENESS_CONTEXT sent to SetThreadDpiAwarenessContext. If SetThreadDpiAwarenessContext was never called for this thread, then the return value will equal the default DPI_AWARENESS_CONTEXT for the process.
///
/// DpiAwarenessContext
[DllImport("User32.dll")]
private static extern DpiAwarenessContext GetThreadDpiAwarenessContext();
///
/// Set the DPI awareness for the current thread to the provided value.
///
/// DpiAwarenessContext the new value for the current thread
/// DpiAwarenessContext previous value
[DllImport("User32.dll")]
private static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
///
/// Retrieves the DpiAwareness value from a DpiAwarenessContext.
///
/// DpiAwarenessContext
/// DpiAwareness
[DllImport("User32.dll")]
private static extern DpiAwareness GetAwarenessFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
///
/// Retrieves the DPI from a given DPI_AWARENESS_CONTEXT handle. This enables you to determine the DPI of a thread without needed to examine a window created within that thread.
///
/// DpiAwarenessContext
/// uint with dpi value
[DllImport("User32.dll")]
private static extern uint GetDpiFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
///
/// Determines if a specified DPI_AWARENESS_CONTEXT is valid and supported by the current system.
///
/// DpiAwarenessContext The context that you want to determine if it is supported.
/// bool true if supported otherwise false
[DllImport("User32.dll")]
private static extern bool IsValidDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext);
///
/// Returns the DPI_HOSTING_BEHAVIOR of the specified window.
///
/// This API allows you to examine the hosting behavior of a window after it has been created. A window's hosting behavior is the hosting behavior of the thread in which the window was created, as set by a call to SetThreadDpiHostingBehavior. This is a permanent value and cannot be changed after the window is created, even if the thread's hosting behavior is changed.
///
/// DpiHostingBehavior
[DllImport("User32.dll")]
private static extern DpiHostingBehavior GetWindowDpiHostingBehavior();
///
/// See more at SetThreadDpiHostingBehavior function
/// Sets the thread's DPI_HOSTING_BEHAVIOR. This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT.
///
/// DPI_HOSTING_BEHAVIOR enables a mixed content hosting behavior, which allows parent windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT value. This property only effects new windows created within this thread while the mixed hosting behavior is active. A parent window with this hosting behavior is able to host child windows with different DPI_AWARENESS_CONTEXT values, regardless of whether the child windows have mixed hosting behavior enabled.
///
/// This hosting behavior does not allow for windows with per-monitor DPI_AWARENESS_CONTEXT values to be hosted until windows with DPI_AWARENESS_CONTEXT values of system or unaware.
///
/// To avoid unexpected outcomes, a thread's DPI_HOSTING_BEHAVIOR should be changed to support mixed hosting behaviors only when creating a new window which needs to support those behaviors. Once that window is created, the hosting behavior should be switched back to its default value.
///
/// This API is used to change the thread's DPI_HOSTING_BEHAVIOR from its default value. This is only necessary if your app needs to host child windows from plugins and third-party components that do not support per-monitor-aware context. This is most likely to occur if you are updating complex applications to support per-monitor DPI_AWARENESS_CONTEXT behaviors.
///
/// Enabling mixed hosting behavior will not automatically adjust the thread's DPI_AWARENESS_CONTEXT to be compatible with legacy content. The thread's awareness context must still be manually changed before new windows are created to host such content.
///
/// DpiHostingBehavior
/// previous DpiHostingBehavior
[DllImport("User32.dll")]
private static extern DpiHostingBehavior SetThreadDpiHostingBehavior(DpiHostingBehavior dpiHostingBehavior);
///
///Retrieves the DPI_HOSTING_BEHAVIOR from the current thread.
///
/// DpiHostingBehavior
[DllImport("User32.dll")]
private static extern DpiHostingBehavior GetThreadDpiHostingBehavior();
///
/// Overrides the default per-monitor DPI scaling behavior of a child window in a dialog.
/// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError.
///
/// Possible errors are ERROR_INVALID_HANDLE if passed an invalid HWND, and ERROR_ACCESS_DENIED if the windows belongs to another process.
///
/// The behaviors are specified as values from the DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS enum. This function follows the typical two-parameter approach to setting flags, where a mask specifies the subset of the flags to be changed.
///
/// It is valid to set these behaviors on any window. It does not matter if the window is currently a child of a dialog at the point in time that SetDialogControlDpiChangeBehavior is called. The behaviors are retained and will take effect only when the window is an immediate child of a dialog that has per-monitor DPI scaling enabled.
///
/// This API influences individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior is controlled by SetDialogDpiChangeBehavior.
///
/// IntPtr A handle for the window whose behavior will be modified.
/// DialogScalingBehaviors A mask specifying the subset of flags to be changed.
/// DialogScalingBehaviors The desired value to be set for the specified subset of flags.
/// bool
[DllImport("User32.dll")]
private static extern bool SetDialogControlDpiChangeBehavior(IntPtr hWnd, DialogScalingBehaviors mask, DialogScalingBehaviors values);
///
/// Retrieves and per-monitor DPI scaling behavior overrides of a child window in a dialog.
/// The flags set on the given window. If passed an invalid handle, this function will return zero, and set its last error to ERROR_INVALID_HANDLE.
///
/// IntPtr A handle for the window whose behavior will be modified.
/// DialogScalingBehaviors
[DllImport("User32.dll")]
private static extern DialogScalingBehaviors GetDialogControlDpiChangeBehavior(IntPtr hWnd);
}
}