forked from anaisbetts/PerMonitorDpi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PerMonitorDpiBehavior.cs
130 lines (107 loc) · 4.67 KB
/
PerMonitorDpiBehavior.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
namespace PerMonitorDpi
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Runtime.InteropServices;
using System.Windows.Interactivity;
/// <summary>
/// Определяет поведение при изменении DPI на мониторе
/// </summary>
/// <remarks>https://github.com/anaisbetts/PerMonitorDpi</remarks>
public class PerMonitorDpiBehavior : Behavior<FrameworkElement>
{
private HwndSource _hwndSource;
private double _currentDpiRatio;
static PerMonitorDpiBehavior()
{
if (MonitorDpi.IsHighDpiMethodSupported())
{
// NB: We need to call this early before we start doing any
// fiddling with window coordinates / geometry
SafeNativeMethods.SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE);
}
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObjectOnLoaded;
AssociatedObject.Unloaded += AssociatedObjectOnUnloaded;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
AssociatedObject.Unloaded -= AssociatedObjectOnUnloaded;
}
private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs e)
{
if (AssociatedObject.IsInitialized)
AddHwndHook();
else
AssociatedObject.Initialized += AssociatedObject_SourceInitialized;
// NB: This allows us to drag-drop URLs from IE11, which would
// normally fail because we run at Medium integrity and most of
// IE runs at Low or AppContainer level.
EnableDragDropFromLowPrivUIPIProcesses();
}
private void AssociatedObjectOnUnloaded(object sender, RoutedEventArgs e)
{
RemoveHwndHook();
}
private void AddHwndHook()
{
_hwndSource = PresentationSource.FromVisual(AssociatedObject) as HwndSource;
_hwndSource?.AddHook(HwndHook);
}
private void RemoveHwndHook()
{
AssociatedObject.Initialized -= AssociatedObject_SourceInitialized;
_hwndSource.RemoveHook(HwndHook);
}
private void AssociatedObject_SourceInitialized(object sender, EventArgs e)
{
AddHwndHook();
UpdateDpiScaling(_currentDpiRatio);
}
static void EnableDragDropFromLowPrivUIPIProcesses()
{
// UIPI was introduced on Vista
if (Environment.OSVersion.Version.Major < 6)
return;
var msgs = new uint[]
{
0x233, // WM_DROPFILES
0x48, // WM_COPYDATA
0x49, // NOBODY KNOWS BUT EVERYONE SAYS TO DO IT
};
foreach (var msg in msgs)
SafeNativeMethods.ChangeWindowMessageFilter(msg, ChangeWindowMessageFilterFlags.Add);
}
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "GitHub.Extensions.Windows.Native.UnsafeNativeMethods.DwmExtendFrameIntoClientArea(System.IntPtr,GitHub.Extensions.Windows.Native.MARGINS@)")]
private IntPtr HwndHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (message)
{
case NativeConstants.WM_DPICHANGED:
var rect = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
SafeNativeMethods.SetWindowPos(hWnd, IntPtr.Zero,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SetWindowPosFlags.DoNotChangeOwnerZOrder | SetWindowPosFlags.DoNotActivate | SetWindowPosFlags.IgnoreZOrder);
var newDpiRatio = MonitorDpi.GetScaleRatioForWindow(AssociatedObject);
if (newDpiRatio != _currentDpiRatio)
UpdateDpiScaling(newDpiRatio);
break;
}
return IntPtr.Zero;
}
private void UpdateDpiScaling(double newDpiRatio)
{
_currentDpiRatio = newDpiRatio;
var firstChild = (Visual)VisualTreeHelper.GetChild(AssociatedObject, 0);
firstChild.SetValue(FrameworkElement.LayoutTransformProperty, new ScaleTransform(_currentDpiRatio, _currentDpiRatio));
}
}
}