using System; using System.Runtime.InteropServices; using System.ComponentModel; namespace PCL.Core.Utils.OS; public static partial class WindowInterop { // ReSharper disable InconsistentNaming UnusedMember.Local // DWM 外边缘结构定义 [StructLayout(LayoutKind.Sequential)] private struct MARGINS { public int leftWidth, rightWidth, topHeight, bottomHeight; } [LibraryImport("dwmapi.dll")] private static partial int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); [LibraryImport("dwmapi.dll")] private static partial int DwmIsCompositionEnabled([MarshalAs(UnmanagedType.Bool)] out bool pfEnabled); // Win32 矩形结构定义 [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [LibraryImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static partial bool GetWindowRect(IntPtr hWnd, out RECT lpRect); // MONITOR_DPI_TYPE enum private enum MONITOR_DPI_TYPE { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } [LibraryImport("user32.dll")] private static partial IntPtr MonitorFromWindow(IntPtr hWnd, uint dwFlags); // Get the primary monitor handle private const int MONITOR_DEFAULTTOPRIMARY = 1; [LibraryImport("shcore.dll", EntryPoint = "GetDpiForMonitor")] private static partial int GetDpiForMonitor( IntPtr hMonitor, MONITOR_DPI_TYPE dpiType, out uint dpiX, out uint dpiY ); // ReSharper enable InconsistentNaming UnusedMember.Local /// /// 检测 DWM 组合是否可用 /// public static bool IsCompositionEnabled() { var hResult = DwmIsCompositionEnabled(out var enabled); return hResult != 0 ? throw new Win32Exception(hResult, "Failed to check DWM status") : enabled; } /// /// 设置 DWM 窗口边框到客户区域的扩展大小 /// public static void ExtendFrameIntoClientArea( IntPtr hWnd, int marginLeft, int marginTop, int marginRight, int marginBottom) { MARGINS margins = new() { leftWidth = marginLeft, rightWidth = marginRight, topHeight = marginTop, bottomHeight = marginBottom }; if (!IsCompositionEnabled()) return; var hResult = DwmExtendFrameIntoClientArea(hWnd, ref margins); if (hResult != 0) throw new Win32Exception(hResult, "Failed to extend frame into client area"); } /// /// See /// public static void ExtendFrameIntoClientArea(IntPtr hWnd, int margin) => ExtendFrameIntoClientArea(hWnd, margin, margin, margin, margin); /// /// 获取 Win32 窗口矩形定义 /// public static (int Left, int Top, int Right, int Bottom) GetWindowRectangle(IntPtr hWnd) { var hResult = GetWindowRect(hWnd, out var rect); return hResult ? (rect.left, rect.top, rect.right, rect.bottom) : throw new Win32Exception("Failed to get window rectangle"); } /// /// 获取 Win32 窗口位置与大小 /// public static (int X, int Y, int Width, int Height) ToWindowBounds( this (int Left, int Top, int Right, int Bottom) rect) { var (l, t, r, b) = rect; var x = l; var y = t; var width = r - l; var height = b - t; return (x, y, width, height); } /// /// 获取指定屏幕的系统 DPI /// /// 位于指定屏幕上的任意窗口句柄,默认指定主屏 public static int GetSystemDpi(IntPtr hWnd = 0) { // Get the monitor handle var hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY); // 0 is S_OK var hr = GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out _); if (hr == 0) return (int)dpiX; // fallback to default DPI (96) return 96; } }