/// <summary> /// 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. /// </summary> /// <returns>true/false</returns> 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); }
/// <summary> /// 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. /// </summary> /// <returns>true/false</returns> public static bool TryFindDpiAwarenessContextsEqual(DpiAwarenessContext dpiContextA, DpiAwarenessContext dpiContextB) { // User.32 AreDpiAwarenessContextsEqual API returns false when sent custom values like DPI_AWARENESS_CONTEXT_UNSPECIFIED, but it is true when both are equal to the same custom value. if (dpiContextA == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED && dpiContextB == DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED) { return(true); } if (ApiHelper.IsApiAvailable(ExternDll.User32, "AreDpiAwarenessContextsEqual")) { return(AreDpiAwarenessContextsEqual(dpiContextA, dpiContextB)); } return(false); }
/* * // 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);*/ internal static DpiAwarenessContext GetDpiAwarenessContextForWindow(IntPtr hWnd) { DpiAwarenessContext dpiAwarenessContext = DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNSPECIFIED; if (ApiHelper.IsApiAvailable(ExternDll.User32, "GetWindowDpiAwarenessContext") && ApiHelper.IsApiAvailable(ExternDll.User32, "GetAwarenessFromDpiAwarenessContext")) { // Works only >= Windows 10/1607 IntPtr awarenessContext = GetWindowDpiAwarenessContext(hWnd); DPI_AWARENESS awareness = GetAwarenessFromDpiAwarenessContext(awarenessContext); dpiAwarenessContext = ConvertToDpiAwarenessContext(awareness); } return(dpiAwarenessContext); }
/// <summary> /// Tries to set thread dpi awareness context /// </summary> /// <returns> returns old thread dpi awareness context if API is available in this version of OS. otherwise, return IntPtr.Zero.</returns> 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); } }
internal static void InitializeDpiHelperForWinforms() { if (isInitializeDpiHelperForWinforms) { return; } // initialize shared fields try { Initialize(); // We are in Windows 10/1603 or greater when this API is present. if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext))) { // We are on Windows 10/1603 or greater all right, but we could still be DpiUnaware or SystemAware, so let's find that out... NativeMethods.PROCESS_DPI_AWARENESS processDpiAwareness; var currentProcessId = SafeNativeMethods.GetCurrentProcessId(); IntPtr hProcess = SafeNativeMethods.OpenProcess(SafeNativeMethods.PROCESS_QUERY_INFORMATION, false, currentProcessId); var result = SafeNativeMethods.GetProcessDpiAwareness(hProcess, out processDpiAwareness); // Only if we're not, it makes sense to query for PerMonitorV2 awareness from now on, if needed. if (!(processDpiAwareness == CAPS.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE || processDpiAwareness == CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE)) { doesNeedQueryForPerMonitorV2Awareness = true; } } } catch (Exception e) { if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) { throw e; } else { Console.WriteLine($"Failed DpiHelper {e}"); } } if (IsScalingRequired || doesNeedQueryForPerMonitorV2Awareness) { isScalingRequirementMet = true; } isInitializeDpiHelperForWinforms = true; }
/// <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> internal static bool SetWinformsApplicationDpiAwareness(HighDpiMode highDpiMode) { CAPS.PROCESS_DPI_AWARENESS dpiFlag = CAPS.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNINITIALIZED; // For Windows 10 RS2 and above if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.SetProcessDpiAwarenessContext))) { int rs2AndAboveDpiFlag; switch (highDpiMode) { case HighDpiMode.SystemAware: rs2AndAboveDpiFlag = CAPS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; break; case HighDpiMode.PerMonitor: rs2AndAboveDpiFlag = CAPS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; break; case HighDpiMode.PerMonitorV2: // Necessary for RS1, since this SetProcessDpiAwarenessContext IS available here. rs2AndAboveDpiFlag = SafeNativeMethods.IsValidDpiAwarenessContext(CAPS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ? CAPS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : CAPS.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 = SafeNativeMethods.IsValidDpiAwarenessContext(CAPS.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) ? CAPS.DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED : CAPS.DPI_AWARENESS_CONTEXT_UNAWARE; break; default: rs2AndAboveDpiFlag = CAPS.DPI_AWARENESS_CONTEXT_UNAWARE; break; } return(SafeNativeMethods.SetProcessDpiAwarenessContext(rs2AndAboveDpiFlag)); } // For operating systems Windows 8.1 to Windows 10 RS1 version. else if (ApiHelper.IsApiAvailable(ExternDll.ShCore, nameof(SafeNativeMethods.SetProcessDpiAwareness))) { switch (highDpiMode) { case HighDpiMode.DpiUnaware: case HighDpiMode.DpiUnawareGdiScaled: dpiFlag = CAPS.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE; break; case HighDpiMode.SystemAware: dpiFlag = CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE; break; case HighDpiMode.PerMonitor: case HighDpiMode.PerMonitorV2: dpiFlag = CAPS.PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE; break; default: dpiFlag = CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE; break; } return(SafeNativeMethods.SetProcessDpiAwareness(dpiFlag) == CAPS.S_OK); } // For operating systems windows 7 to windows 8 else if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.SetProcessDPIAware))) { 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 = CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE; break; } if (dpiFlag == CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE) { return(SafeNativeMethods.SetProcessDPIAware()); } } return(false); }
/// <summary> /// Gets the DPI awareness. /// </summary> /// <returns>The thread's/process' current HighDpi mode</returns> internal static HighDpiMode GetWinformsApplicationDpiAwareness() { // For Windows 10 RS2 and above if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext))) { DpiAwarenessContext dpiAwareness = CommonUnsafeNativeMethods.GetThreadDpiAwarenessContext(); if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) { return(HighDpiMode.SystemAware); } if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_UNAWARE)) { return(HighDpiMode.DpiUnaware); } if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { return(HighDpiMode.PerMonitorV2); } if (CommonUnsafeNativeMethods.TryFindDpiAwarenessContextsEqual(dpiAwareness, DpiAwarenessContext.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) { return(HighDpiMode.PerMonitor); } if (CommonUnsafeNativeMethods.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))) { SafeNativeMethods.GetProcessDpiAwareness(IntPtr.Zero, out CAPS.PROCESS_DPI_AWARENESS processDpiAwareness); switch (processDpiAwareness) { case CAPS.PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE: return(HighDpiMode.DpiUnaware); case CAPS.PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE: return(HighDpiMode.SystemAware); case CAPS.PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE: return(HighDpiMode.PerMonitor); } } // For operating systems windows 7 to windows 8 else if (ApiHelper.IsApiAvailable(ExternDll.User32, nameof(SafeNativeMethods.IsProcessDPIAware))) { return(SafeNativeMethods.IsProcessDPIAware() ? HighDpiMode.SystemAware : HighDpiMode.DpiUnaware); } // We should never get here, except someone ported this with force to < Windows 7. return(HighDpiMode.DpiUnaware); }