Skip to content

Instantly share code, notes, and snippets.

@ryancheung
Created September 27, 2021 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryancheung/1b96eb98e2c07d1c95afd570f1e0eae2 to your computer and use it in GitHub Desktop.
Save ryancheung/1b96eb98e2c07d1c95afd570f1e0eae2 to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.InteropServices;
public static class SHCore
{
public enum PROCESS_DPI_AWARENESS : int
{
UNAWARE = 0,
SYSTEM_AWARE = 1,
PER_MONITOR_AWARE = 2
}
[DllImport("SHCore.dll", ExactSpelling = true)]
public static extern int SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value);
}
public static class User32
{
[DllImport("user32.dll", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetProcessDPIAware();
[DllImport("User32.dll", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetProcessDpiAwarenessContext(IntPtr value);
[DllImport("User32.dll", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsValidDpiAwarenessContext(IntPtr value);
public static IntPtr UNSPECIFIED_DPI_AWARENESS_CONTEXT = IntPtr.Zero;
public static class DPI_AWARENESS_CONTEXT
{
public static readonly IntPtr UNAWARE = (IntPtr)(-1);
public static readonly IntPtr SYSTEM_AWARE = (IntPtr)(-2);
public static readonly IntPtr PER_MONITOR_AWARE = (IntPtr)(-3);
public static readonly IntPtr PER_MONITOR_AWARE_V2 = (IntPtr)(-4);
public static readonly IntPtr UNAWARE_GDISCALED = (IntPtr)(-5);
}
}
public static class DpiHelper
{
/// <summary>
/// Sets the DPI awareness. If not available on the current OS, it falls back to the next possible.
/// </summary>
/// <returns>true/false - If the process DPI awareness is successfully set, returns true. Otherwise false.</returns>
public static bool SetApplicationDpiAwareness(HighDpiMode highDpiMode)
{
bool success = false;
if (OperatingSystem.IsWindowsVersionAtLeast(10))
{
// SetProcessIntPtr needs Windows 10 RS2 and above
IntPtr rs2AndAboveDpiFlag;
switch (highDpiMode)
{
case HighDpiMode.SystemAware:
rs2AndAboveDpiFlag = User32.DPI_AWARENESS_CONTEXT.SYSTEM_AWARE;
break;
case HighDpiMode.PerMonitor:
rs2AndAboveDpiFlag = User32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE;
break;
case HighDpiMode.PerMonitorV2:
// Necessary for RS1, since this SetProcessIntPtr IS available here.
rs2AndAboveDpiFlag = User32.IsValidDpiAwarenessContext(User32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_V2)
? User32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_V2
: User32.DPI_AWARENESS_CONTEXT.SYSTEM_AWARE;
break;
case HighDpiMode.DpiUnawareGdiScaled:
// Let's make sure, we do not try to set a value which has been introduced in later Windows releases.
rs2AndAboveDpiFlag = User32.IsValidDpiAwarenessContext(User32.DPI_AWARENESS_CONTEXT.UNAWARE_GDISCALED)
? User32.DPI_AWARENESS_CONTEXT.UNAWARE_GDISCALED
: User32.DPI_AWARENESS_CONTEXT.UNAWARE;
break;
default:
rs2AndAboveDpiFlag = User32.DPI_AWARENESS_CONTEXT.UNAWARE;
break;
}
success = User32.SetProcessDpiAwarenessContext(rs2AndAboveDpiFlag);
}
else if (OperatingSystem.IsWindowsVersionAtLeast(8))
{
// 8.1 introduced SetProcessDpiAwareness
SHCore.PROCESS_DPI_AWARENESS dpiFlag;
switch (highDpiMode)
{
case HighDpiMode.DpiUnaware:
case HighDpiMode.DpiUnawareGdiScaled:
dpiFlag = SHCore.PROCESS_DPI_AWARENESS.UNAWARE;
break;
case HighDpiMode.SystemAware:
dpiFlag = SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE;
break;
case HighDpiMode.PerMonitor:
case HighDpiMode.PerMonitorV2:
dpiFlag = SHCore.PROCESS_DPI_AWARENESS.PER_MONITOR_AWARE;
break;
default:
dpiFlag = SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE;
break;
}
success = SHCore.SetProcessDpiAwareness(dpiFlag) == 0;
}
else
{
// Vista or higher has SetProcessDPIAware
SHCore.PROCESS_DPI_AWARENESS dpiFlag = (SHCore.PROCESS_DPI_AWARENESS)(-1);
switch (highDpiMode)
{
case HighDpiMode.DpiUnaware:
case HighDpiMode.DpiUnawareGdiScaled:
// We can return, there is nothing to set if we assume we're already in DpiUnaware.
return true;
case HighDpiMode.SystemAware:
case HighDpiMode.PerMonitor:
case HighDpiMode.PerMonitorV2:
dpiFlag = SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE;
break;
}
if (dpiFlag == SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE)
{
success = User32.SetProcessDPIAware();
}
}
return success;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment