123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Windows;
- using System.Windows.Interop;
- using HandyControl.Controls;
- using HandyControl.Tools.Extension;
- using HandyControl.Tools.Helper;
- using HandyControl.Tools.Interop;
- using Window = System.Windows.Window;
- namespace HandyControl.Tools;
- public static class WindowHelper
- {
- /// <summary>
- /// 获取当前应用中处于激活的一个窗口
- /// </summary>
- /// <returns></returns>
- public static Window GetActiveWindow()
- {
- var activeWindow = InteropMethods.GetActiveWindow();
- return Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.GetHandle() == activeWindow);
- }
- private static readonly BitArray _cacheValid = new((int) InteropValues.CacheSlot.NumSlots);
- private static bool _setDpiX = true;
- private static bool _dpiInitialized;
- private static readonly object _dpiLock = new();
- private static int _dpi;
- internal static int Dpi
- {
- [SecurityCritical, SecuritySafeCritical]
- get
- {
- if (!_dpiInitialized)
- {
- lock (_dpiLock)
- {
- if (!_dpiInitialized)
- {
- var desktopWnd = new HandleRef(null, IntPtr.Zero);
- // Win32Exception will get the Win32 error code so we don't have to
- var dc = InteropMethods.GetDC(desktopWnd);
- // Detecting error case from unmanaged call, required by PREsharp to throw a Win32Exception
- if (dc == IntPtr.Zero)
- {
- throw new Win32Exception();
- }
- try
- {
- _dpi = InteropMethods.GetDeviceCaps(new HandleRef(null, dc), InteropValues.LOGPIXELSY);
- _dpiInitialized = true;
- }
- finally
- {
- InteropMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
- }
- }
- }
- }
- return _dpi;
- }
- }
- private static int _dpiX;
- internal static int DpiX
- {
- [SecurityCritical, SecuritySafeCritical]
- get
- {
- if (_setDpiX)
- {
- lock (_cacheValid)
- {
- if (_setDpiX)
- {
- _setDpiX = false;
- var desktopWnd = new HandleRef(null, IntPtr.Zero);
- var dc = InteropMethods.GetDC(desktopWnd);
- if (dc == IntPtr.Zero)
- {
- throw new Win32Exception();
- }
- try
- {
- _dpiX = InteropMethods.GetDeviceCaps(new HandleRef(null, dc), InteropValues.LOGPIXELSX);
- _cacheValid[(int) InteropValues.CacheSlot.DpiX] = true;
- }
- finally
- {
- InteropMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
- }
- }
- }
- }
- return _dpiX;
- }
- }
- private static Thickness _windowResizeBorderThickness;
- internal static Thickness WindowResizeBorderThickness
- {
- [SecurityCritical]
- get
- {
- lock (_cacheValid)
- {
- while (!_cacheValid[(int) InteropValues.CacheSlot.WindowResizeBorderThickness])
- {
- _cacheValid[(int) InteropValues.CacheSlot.WindowResizeBorderThickness] = true;
- var frameSize = new Size(InteropMethods.GetSystemMetrics(InteropValues.SM.CXSIZEFRAME), InteropMethods.GetSystemMetrics(InteropValues.SM.CYSIZEFRAME));
- var frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize, DpiX / 96.0, Dpi / 96.0);
- _windowResizeBorderThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height, frameSizeInDips.Width, frameSizeInDips.Height);
- }
- }
- return _windowResizeBorderThickness;
- }
- }
- public static Thickness WindowMaximizedPadding
- {
- get
- {
- InteropValues.APPBARDATA appBarData = default;
- var autoHide = InteropMethods.SHAppBarMessage(4, ref appBarData) != 0;
- #if NET40
- return WindowResizeBorderThickness.Add(new Thickness(autoHide ? -8 : 0));
- #elif NETCOREAPP
- var hdc = InteropMethods.GetDC(IntPtr.Zero);
- var scale = InteropMethods.GetDeviceCaps(hdc, InteropValues.DESKTOPVERTRES) / (float) InteropMethods.GetDeviceCaps(hdc, InteropValues.VERTRES);
- InteropMethods.ReleaseDC(IntPtr.Zero, hdc);
- return WindowResizeBorderThickness.Add(new Thickness((autoHide ? -4 : 4) * scale));
- #else
- return WindowResizeBorderThickness.Add(new Thickness(autoHide ? -4 : 4));
- #endif
- }
- }
- public static IntPtr CreateHandle() => new WindowInteropHelper(new Window()).EnsureHandle();
- public static IntPtr GetHandle(this Window window) => new WindowInteropHelper(window).EnsureHandle();
- public static HwndSource GetHwndSource(this Window window) => HwndSource.FromHwnd(window.GetHandle());
- /// <summary>
- /// 让窗口激活作为前台最上层窗口
- /// </summary>
- /// <param name="window"></param>
- public static void SetWindowToForeground(Window window)
- {
- // [WPF 让窗口激活作为前台最上层窗口的方法 - lindexi - 博客园](https://www.cnblogs.com/lindexi/p/12749671.html)
- var interopHelper = new WindowInteropHelper(window);
- var thisWindowThreadId = InteropMethods.GetWindowThreadProcessId(interopHelper.Handle, out _);
- var currentForegroundWindow = InteropMethods.GetForegroundWindow();
- var currentForegroundWindowThreadId = InteropMethods.GetWindowThreadProcessId(currentForegroundWindow, out _);
- // [c# - Bring a window to the front in WPF - Stack Overflow](https://stackoverflow.com/questions/257587/bring-a-window-to-the-front-in-wpf )
- // [SetForegroundWindow的正确用法 - 子坞 - 博客园](https://www.cnblogs.com/ziwuge/archive/2012/01/06/2315342.html )
- /*
- 1.得到窗口句柄FindWindow
- 2.切换键盘输入焦点AttachThreadInput
- 3.显示窗口ShowWindow(有些窗口被最小化/隐藏了)
- 4.更改窗口的Z Order,SetWindowPos使之最上,为了不影响后续窗口的Z Order,改完之后,再还原
- 5.最后SetForegroundWindow
- */
- InteropMethods.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);
- window.Show();
- window.Activate();
- // 去掉和其他线程的输入链接
- InteropMethods.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);
- // 用于踢掉其他的在上层的窗口
- if (window.Topmost != true)
- {
- window.Topmost = true;
- window.Topmost = false;
- }
- }
- /// <summary>
- /// 开始使用触摸拖动窗口,在触摸抬起后自动结束
- /// </summary>
- public static void TouchDragMove(this Window window) => new TouchDragMoveWindowHelper(window).Start();
- public static void StartFullScreen(this Window window) => FullScreenHelper.StartFullScreen(window);
- public static void EndFullScreen(this Window window) => FullScreenHelper.EndFullScreen(window);
- }
|