internal void Initialize(Window window, FrameworkElement element = null) { if (window == null) { throw new ArgumentNullException(nameof(window)); } if (!window.IsInitialized) { throw new InvalidOperationException("Target Window has not been initialized."); } _targetWindow = window; _targetElement = element; ForbearScaling = WillForbearScalingIfUnnecessary && BuiltinFunction.IsScalingSupported(_targetWindow); if (IsPerMonitorDpiAware) { MonitorDpi = DpiChecker.GetDpiFromVisual(_targetWindow); if (MonitorDpi.Equals(SystemDpi) || ForbearScaling) { WindowDpi = MonitorDpi; } else { var newInfo = new WindowInfo { Dpi = MonitorDpi, Width = _targetWindow.Width * (double)MonitorDpi.X / SystemDpi.X, Height = _targetWindow.Height * (double)MonitorDpi.Y / SystemDpi.Y, }; Interlocked.Exchange(ref _dueInfo, newInfo); ChangeDpi(); } } else { MonitorDpi = SystemDpi; WindowDpi = MonitorDpi; } ColorProfilePath = ColorProfileChecker.GetColorProfilePath(_targetWindow); _targetSource = PresentationSource.FromVisual(_targetWindow) as HwndSource; _targetSource?.AddHook(WndProc); }
/// <summary> /// Handles window messages. /// </summary> /// <param name="hwnd">The window handle</param> /// <param name="msg">The message ID</param> /// <param name="wParam">The message's wParam value</param> /// <param name="lParam">The message's lParam value</param> /// <param name="handled">Whether the message was handled</param> /// <returns>Return value depending on the particular message</returns> /// <remarks>This is an implementation of System.Windows.Interop.HwndSourceHook.</remarks> protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case (int)WindowMessage.WM_DPICHANGED: var newDpi = new Dpi( NativeMacro.GetLoWord((uint)wParam), NativeMacro.GetHiWord((uint)wParam)); Debug.WriteLine($"DPICHANGED: {MonitorDpi.X} -> {newDpi.X}"); if (MonitorDpi.Equals(newDpi)) { break; } var oldDpi = MonitorDpi; MonitorDpi = newDpi; if (ForbearScaling) { WindowDpi = MonitorDpi; break; } _isDpiChanged = true; var newInfo = new WindowInfo { Dpi = MonitorDpi }; switch (_currentStatus) { case WindowStatus.None: case WindowStatus.LocationChanged: if ((_baseSize == Size.Empty) || (_currentStatus == WindowStatus.None)) { _baseSize = new Size(_targetWindow.Width, _targetWindow.Height); } _baseSize = new Size( _baseSize.Width * (double)MonitorDpi.X / oldDpi.X, _baseSize.Height * (double)MonitorDpi.Y / oldDpi.Y); newInfo.Size = _baseSize; break; case WindowStatus.SizeChanged: // None. break; } Interlocked.Exchange(ref _dueInfo, newInfo); switch (_currentStatus) { case WindowStatus.None: ChangeDpi(); break; case WindowStatus.LocationChanged: // None. break; case WindowStatus.SizeChanged: ChangeDpi(WindowStatus.SizeChanged); break; } handled = true; break; case (int)WindowMessage.WM_ENTERSIZEMOVE: Debug.WriteLine("ENTERSIZEMOVE"); if (!IsPerMonitorDpiAware || ForbearScaling) { break; } _baseSize = new Size(_targetWindow.Width, _targetWindow.Height); _isEnteredSizeMove = true; _isDpiChanged = false; _countLocationChanged = 0; _countSizeChanged = 0; break; case (int)WindowMessage.WM_EXITSIZEMOVE: Debug.WriteLine("EXITSIZEMOVE"); if (_isEnteredSizeMove) { _isEnteredSizeMove = false; // Last stand!!! if (_isDpiChanged && (_currentStatus == WindowStatus.LocationChanged)) { var lastInfo = new WindowInfo { Dpi = MonitorDpi, Size = _baseSize, }; Interlocked.Exchange(ref _dueInfo, lastInfo); ChangeDpi(WindowStatus.LocationChanged); } _currentStatus = WindowStatus.None; } ChangeColorProfilePath(); break; case (int)WindowMessage.WM_MOVE: Debug.WriteLine("MOVE"); if (_isEnteredSizeMove) { _countLocationChanged++; if (_countLocationChanged > _countSizeChanged) { _currentStatus = WindowStatus.LocationChanged; } ChangeDpi(WindowStatus.LocationChanged); } break; case (int)WindowMessage.WM_SIZE: if ((uint)wParam != NativeMethod.SIZE_RESTORED) { break; } Debug.WriteLine("SIZE"); if (_isEnteredSizeMove) { _countSizeChanged++; if (_countLocationChanged < _countSizeChanged) { _currentStatus = WindowStatus.SizeChanged; } // DPI change by resize will be managed when WM_DPICHANGED comes. } break; } return(IntPtr.Zero); }