From cbe2f67d343c0a2e85dd30925f602712e766517a Mon Sep 17 00:00:00 2001 From: ema Date: Tue, 24 Sep 2024 09:59:58 +0800 Subject: [PATCH] feat: DpiAware --- src/Wpf.Ui.Violeta/Win32/DpiAware.cs | 27 ++++++++++++++++++++++ src/Wpf.Ui.Violeta/Win32/DpiHelper.cs | 32 +++++---------------------- src/Wpf.Ui.Violeta/Win32/NTdll.cs | 30 ++++++++++++++----------- src/Wpf.Ui.Violeta/Win32/SHCore.cs | 27 ++++++++++++++++++++++ src/Wpf.Ui.Violeta/Win32/User32.cs | 20 +++++++++++++++++ 5 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 src/Wpf.Ui.Violeta/Win32/DpiAware.cs create mode 100644 src/Wpf.Ui.Violeta/Win32/SHCore.cs diff --git a/src/Wpf.Ui.Violeta/Win32/DpiAware.cs b/src/Wpf.Ui.Violeta/Win32/DpiAware.cs new file mode 100644 index 0000000..c2fdd7b --- /dev/null +++ b/src/Wpf.Ui.Violeta/Win32/DpiAware.cs @@ -0,0 +1,27 @@ +using System; +using System.Windows.Media; + +namespace Wpf.Ui.Violeta.Win32; + +public static class DpiAware +{ + /// + /// + /// + public static bool SetProcessDpiAwareness() + { + if (NTdll.RtlGetVersion(out NTdll.OSVERSIONINFOEX osv) == NTdll.NTStatus.STATUS_SUCCESS) + { + Version osVersion = new(osv.MajorVersion, osv.MinorVersion, osv.BuildNumber, osv.PlatformId); + + if (Environment.OSVersion.Platform == PlatformID.Win32NT && osVersion >= new Version(6, 3)) + { + if (SHCore.SetProcessDpiAwareness(SHCore.PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE) == 0) + { + return true; + } + } + } + return false; + } +} diff --git a/src/Wpf.Ui.Violeta/Win32/DpiHelper.cs b/src/Wpf.Ui.Violeta/Win32/DpiHelper.cs index 328ec77..49553f7 100644 --- a/src/Wpf.Ui.Violeta/Win32/DpiHelper.cs +++ b/src/Wpf.Ui.Violeta/Win32/DpiHelper.cs @@ -1,7 +1,4 @@ -using System.Runtime.InteropServices; -using System.Security; - -namespace Wpf.Ui.Violeta.Win32; +namespace Wpf.Ui.Violeta.Win32; internal static class DpiHelper { @@ -10,29 +7,10 @@ internal static class DpiHelper private static (float X, float Y) GetScale() { - nint hdc = GetDC(0); - float scaleX = GetDeviceCaps(hdc, DeviceCap.LOGPIXELSX); - float scaleY = GetDeviceCaps(hdc, DeviceCap.LOGPIXELSY); - _ = ReleaseDC(0, hdc); + nint hdc = User32.GetDC(0); + float scaleX = User32.GetDeviceCaps(hdc, User32.DeviceCap.LOGPIXELSX); + float scaleY = User32.GetDeviceCaps(hdc, User32.DeviceCap.LOGPIXELSY); + _ = User32.ReleaseDC(0, hdc); return new(scaleX / 96f, scaleY / 96f); } - - [SecurityCritical] - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern nint GetDC(nint hWnd); - - [SecurityCritical] - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern int ReleaseDC(nint hWnd, nint hDC); - - [DllImport("gdi32.dll", SetLastError = false, ExactSpelling = true)] - private static extern int GetDeviceCaps(nint hdc, DeviceCap nIndex); - - private enum DeviceCap - { - LOGPIXELSX = 88, - LOGPIXELSY = 90, - } } diff --git a/src/Wpf.Ui.Violeta/Win32/NTdll.cs b/src/Wpf.Ui.Violeta/Win32/NTdll.cs index 6e85fa7..ddf2177 100644 --- a/src/Wpf.Ui.Violeta/Win32/NTdll.cs +++ b/src/Wpf.Ui.Violeta/Win32/NTdll.cs @@ -6,6 +6,21 @@ namespace Wpf.Ui.Violeta.Win32; internal static class NTdll { + [SecurityCritical] + [DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern int RtlGetVersion(out OSVERSIONINFOEX versionInfo); + + public static Version GetOSVersion() + { + if (RtlGetVersion(out OSVERSIONINFOEX osv) == 0) + { + return new Version(osv.MajorVersion, osv.MinorVersion, osv.BuildNumber, osv.Revision); + } + + return Environment.OSVersion.Version; + } + [StructLayout(LayoutKind.Sequential)] public struct OSVERSIONINFOEX { @@ -13,7 +28,6 @@ public struct OSVERSIONINFOEX public int MajorVersion; public int MinorVersion; public int BuildNumber; - public int Revision; public int PlatformId; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] @@ -26,18 +40,8 @@ public struct OSVERSIONINFOEX public byte Reserved; } - [SecurityCritical] - [DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern int RtlGetVersion(out OSVERSIONINFOEX versionInfo); - - public static Version GetOSVersion() + public static class NTStatus { - if (RtlGetVersion(out OSVERSIONINFOEX osv) == 0) - { - return new Version(osv.MajorVersion, osv.MinorVersion, osv.BuildNumber, osv.Revision); - } - - return Environment.OSVersion.Version; + public const int STATUS_SUCCESS = 0; } } diff --git a/src/Wpf.Ui.Violeta/Win32/SHCore.cs b/src/Wpf.Ui.Violeta/Win32/SHCore.cs new file mode 100644 index 0000000..a8f26c9 --- /dev/null +++ b/src/Wpf.Ui.Violeta/Win32/SHCore.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; + +namespace Wpf.Ui.Violeta.Win32; + +internal static class SHCore +{ + [DllImport("shcore.dll")] + public static extern uint SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness); + + [DllImport("shcore.dll")] + public static extern int GetDpiForMonitor(nint hmonitor, MONITOR_DPI_TYPE dpiType, out uint dpiX, out uint dpiY); + + public enum PROCESS_DPI_AWARENESS + { + PROCESS_DPI_UNAWARE, + PROCESS_SYSTEM_DPI_AWARE, + PROCESS_PER_MONITOR_DPI_AWARE, + } + + public enum MONITOR_DPI_TYPE + { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI, + MDT_RAW_DPI, + MDT_DEFAULT = MDT_EFFECTIVE_DPI, + } +} diff --git a/src/Wpf.Ui.Violeta/Win32/User32.cs b/src/Wpf.Ui.Violeta/Win32/User32.cs index b47c829..33820d2 100644 --- a/src/Wpf.Ui.Violeta/Win32/User32.cs +++ b/src/Wpf.Ui.Violeta/Win32/User32.cs @@ -1,10 +1,24 @@ using System; using System.Runtime.InteropServices; +using System.Security; namespace Wpf.Ui.Violeta.Win32; internal static class User32 { + [SecurityCritical] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern nint GetDC(nint hWnd); + + [SecurityCritical] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern int ReleaseDC(nint hWnd, nint hDC); + + [DllImport("gdi32.dll", SetLastError = false, ExactSpelling = true)] + public static extern int GetDeviceCaps(nint hdc, DeviceCap nIndex); + [DllImport("user32.dll", SetLastError = false, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetForegroundWindow(nint hWnd); @@ -31,4 +45,10 @@ public enum DialogBoxCommand : uint IDTRYAGAIN = 9, IDCONTINUE = 10, } + + public enum DeviceCap + { + LOGPIXELSX = 88, + LOGPIXELSY = 90, + } }