Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crashes with Windows 8.1 due to recent DPI changes #1837

Merged
merged 1 commit into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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