From b0f8033223c889a42bf0259a760650ee7935f57d Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Mon, 30 Nov 2020 11:23:53 -0800 Subject: [PATCH] Fix crashes with Windows 8.1 due to recent DPI changes --- src/Eto.WinForms/Forms/ScreenHandler.cs | 4 ++-- src/Eto.WinForms/Win32.dpi.cs | 31 +++++++++++-------------- src/Eto.Wpf/Forms/MouseHandler.cs | 8 +++---- src/Eto.Wpf/Forms/ScreenHandler.cs | 4 ++-- src/Eto.Wpf/Forms/WpfWindow.cs | 8 +++---- 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/Eto.WinForms/Forms/ScreenHandler.cs b/src/Eto.WinForms/Forms/ScreenHandler.cs index 93f35daa34..4889bda583 100755 --- a/src/Eto.WinForms/Forms/ScreenHandler.cs +++ b/src/Eto.WinForms/Forms/ScreenHandler.cs @@ -43,14 +43,14 @@ public Image GetImage(RectangleF rect) if (hmonitor != IntPtr.Zero) { // get actual monitor dimentions - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE); var info = new Win32.MONITORINFOEX(); Win32.GetMonitorInfo(new HandleRef(null, hmonitor), info); realBounds = info.rcMonitor.ToSD().ToEto(); if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); } var adjustedRect = rect; diff --git a/src/Eto.WinForms/Win32.dpi.cs b/src/Eto.WinForms/Win32.dpi.cs index 13f2d02b24..87f8b5a724 100644 --- a/src/Eto.WinForms/Win32.dpi.cs +++ b/src/Eto.WinForms/Win32.dpi.cs @@ -18,9 +18,11 @@ namespace Eto { static partial class Win32 { + static Lazy perMonitorThreadDpiSupported = new Lazy(() => MethodExists("User32.dll", "SetThreadDpiAwarenessContext")); static Lazy perMonitorDpiSupported = new Lazy(() => MethodExists("shcore.dll", "SetProcessDpiAwareness")); static Lazy monitorDpiSupported = new Lazy(() => MethodExists("shcore.dll", "GetDpiForMonitor")); + public static bool PerMontiorThreadDpiSupported => perMonitorThreadDpiSupported.Value; public static bool PerMonitorDpiSupported => perMonitorDpiSupported.Value; public static bool MonitorDpiSupported => monitorDpiSupported.Value; @@ -145,18 +147,6 @@ public sd.Rectangle GetWorkingArea(swf.Screen screen) } - DPI_AWARENESS_CONTEXT? processDpiAwareness; - - public DPI_AWARENESS_CONTEXT ProcessDpiAwareness - { - get - { - if (processDpiAwareness == null) - processDpiAwareness = GetThreadDpiAwarenessContext(); - return processDpiAwareness.Value; - } - } - public override float GetLogicalPixelSize(swf.Screen screen) { if (!MonitorDpiSupported) @@ -171,13 +161,13 @@ public override float GetLogicalPixelSize(swf.Screen screen) var mon = MonitorFromPoint(screen.Bounds.Location, MONITOR.DEFAULTTONEAREST); // use per-monitor aware dpi awareness to get ACTUAL dpi here - var oldDpiAwareness = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); + var oldDpiAwareness = SetThreadDpiAwarenessContextSafe(DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); uint dpiX, dpiY; GetDpiForMonitor(mon, MDT.EFFECTIVE_DPI, out dpiX, out dpiY); if (oldDpiAwareness != DPI_AWARENESS_CONTEXT.NONE) - SetThreadDpiAwarenessContext(oldDpiAwareness); + SetThreadDpiAwarenessContextSafe(oldDpiAwareness); return dpiX / 96f; } @@ -199,12 +189,12 @@ public static void GetMonitorInfo(this swf.Screen screen, ref MONITORINFOEX info { var hmonitor = MonitorFromPoint(screen.Bounds.Location, 0); - var oldDpiAwareness = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); + var oldDpiAwareness = SetThreadDpiAwarenessContextSafe(DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); GetMonitorInfo(new HandleRef(null, hmonitor), info); if (oldDpiAwareness != DPI_AWARENESS_CONTEXT.NONE) - SetThreadDpiAwarenessContext(oldDpiAwareness); + SetThreadDpiAwarenessContextSafe(oldDpiAwareness); } @@ -230,7 +220,14 @@ public static void GetMonitorInfo(this swf.Screen screen, ref MONITORINFOEX info public static extern uint GetProcessDpiAwareness(IntPtr handle, out PROCESS_DPI_AWARENESS awareness); [DllImport("User32.dll")] - public static extern DPI_AWARENESS_CONTEXT SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext); + static extern DPI_AWARENESS_CONTEXT SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext); + + public static DPI_AWARENESS_CONTEXT SetThreadDpiAwarenessContextSafe(DPI_AWARENESS_CONTEXT dpiContext) + { + if (!PerMontiorThreadDpiSupported) + return DPI_AWARENESS_CONTEXT.NONE; + return SetThreadDpiAwarenessContext(dpiContext); + } [DllImport("User32.dll")] public static extern DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext(); diff --git a/src/Eto.Wpf/Forms/MouseHandler.cs b/src/Eto.Wpf/Forms/MouseHandler.cs index b8f58da7af..394e67b1ad 100755 --- a/src/Eto.Wpf/Forms/MouseHandler.cs +++ b/src/Eto.Wpf/Forms/MouseHandler.cs @@ -17,19 +17,19 @@ public PointF Position { get { - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); var result = swf.Control.MousePosition; if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); return result.ScreenToLogical(); } set { var pos = value.LogicalToScreen(); - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); swf.Cursor.Position = Point.Round(pos).ToSD(); if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); } } diff --git a/src/Eto.Wpf/Forms/ScreenHandler.cs b/src/Eto.Wpf/Forms/ScreenHandler.cs index 8dbbc7961c..56a048d71e 100755 --- a/src/Eto.Wpf/Forms/ScreenHandler.cs +++ b/src/Eto.Wpf/Forms/ScreenHandler.cs @@ -57,7 +57,7 @@ public Image GetImage(RectangleF rect) Win32.GetMonitorInfo(Control, ref info); adjustedRect.Location += info.rcMonitor.ToEto().Location; - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); var realRect = Rectangle.Ceiling(adjustedRect); using (var screenBmp = new sd.Bitmap(realRect.Width, realRect.Height, sd.Imaging.PixelFormat.Format32bppRgb)) { @@ -71,7 +71,7 @@ public Image GetImage(RectangleF rect) sw.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); return new Bitmap(new BitmapHandler(bitmapSource)); } diff --git a/src/Eto.Wpf/Forms/WpfWindow.cs b/src/Eto.Wpf/Forms/WpfWindow.cs index 6e7551ff11..f73f9b382c 100644 --- a/src/Eto.Wpf/Forms/WpfWindow.cs +++ b/src/Eto.Wpf/Forms/WpfWindow.cs @@ -596,7 +596,7 @@ System.Windows.Forms.Screen SwfScreen { Point? location = null; // Left/Top doesn't always report correct location when maximized, so use Win32 when we can. - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); try { Win32.RECT rect; @@ -606,7 +606,7 @@ System.Windows.Forms.Screen SwfScreen finally { if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); } if (location != null) @@ -657,14 +657,14 @@ void Control_SourceInitialized(object sender, EventArgs e) void SetLocation(PointF location) { - var oldDpiAwareness = Win32.PerMonitorDpiSupported ? Win32.SetThreadDpiAwarenessContext(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2) : Win32.DPI_AWARENESS_CONTEXT.NONE; + var oldDpiAwareness = Win32.SetThreadDpiAwarenessContextSafe(Win32.DPI_AWARENESS_CONTEXT.PER_MONITOR_AWARE_v2); var handle = WindowHandle; var loc = location.LogicalToScreen(); Win32.SetWindowPos(WindowHandle, IntPtr.Zero, loc.X, loc.Y, 0, 0, Win32.SWP.NOSIZE | Win32.SWP.NOACTIVATE); if (oldDpiAwareness != Win32.DPI_AWARENESS_CONTEXT.NONE) - Win32.SetThreadDpiAwarenessContext(oldDpiAwareness); + Win32.SetThreadDpiAwarenessContextSafe(oldDpiAwareness); } public WindowState WindowState