Skip to content

Commit

Permalink
Fix crashes with Windows 8.1 due to recent DPI changes
Browse files Browse the repository at this point in the history
  • Loading branch information
cwensley committed Nov 30, 2020
1 parent d8fc65e commit b0f8033
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/Eto.WinForms/Forms/ScreenHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
31 changes: 14 additions & 17 deletions src/Eto.WinForms/Win32.dpi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ namespace Eto
{
static partial class Win32
{
static Lazy<bool> perMonitorThreadDpiSupported = new Lazy<bool>(() => MethodExists("User32.dll", "SetThreadDpiAwarenessContext"));
static Lazy<bool> perMonitorDpiSupported = new Lazy<bool>(() => MethodExists("shcore.dll", "SetProcessDpiAwareness"));
static Lazy<bool> monitorDpiSupported = new Lazy<bool>(() => MethodExists("shcore.dll", "GetDpiForMonitor"));

public static bool PerMontiorThreadDpiSupported => perMonitorThreadDpiSupported.Value;
public static bool PerMonitorDpiSupported => perMonitorDpiSupported.Value;

public static bool MonitorDpiSupported => monitorDpiSupported.Value;
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand All @@ -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);
}


Expand All @@ -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();
Expand Down
8 changes: 4 additions & 4 deletions src/Eto.Wpf/Forms/MouseHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Eto.Wpf/Forms/ScreenHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand All @@ -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));
}
Expand Down
8 changes: 4 additions & 4 deletions src/Eto.Wpf/Forms/WpfWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b0f8033

Please sign in to comment.