// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; using Vanara.PInvoke; using static Vanara.PInvoke.DwmApi; using static Vanara.PInvoke.User32; namespace AntdUI { public class Window : BaseForm, IMessageFilter { #region 属性 bool resizable = true; [Description("调整窗口大小"), Category("行为"), DefaultValue(true)] public bool Resizable { get => resizable; set { if (resizable == value) return; resizable = value; HandMessage(); } } WState winState = WState.Restore; WState WinState { set { if (winState == value) return; winState = value; if (IsHandleCreated) HandMessage(); EventHub.Dispatch(EventType.WINDOW_STATE, winState == WState.Maximize); } } protected virtual bool UseMessageFilter => false; void HandMessage() { ReadMessage = winState == WState.Restore && resizable; if (UseMessageFilter) IsAddMessage = true; else IsAddMessage = ReadMessage; } bool ReadMessage = false; bool _isaddMessage = false; bool IsAddMessage { set { if (_isaddMessage == value) return; _isaddMessage = value; if (value) Application.AddMessageFilter(this); else Application.RemoveMessageFilter(this); } } #endregion internal HWND handle { get; private set; } protected override void OnHandleCreated(EventArgs e) { handle = new HWND(Handle); base.OnHandleCreated(e); if (FormBorderStyle == FormBorderStyle.None) { SetTheme(); DisableProcessWindowsGhosting(); HandMessage(); DwmArea(); } else { Size max = MaximumSize, min = MinimumSize; sizeInit = ClientSize; MaximumSize = MinimumSize = ClientSize = sizeInit.Value; SetTheme(); DisableProcessWindowsGhosting(); HandMessage(); DwmArea(); ClientSize = sizeInit.Value; MinimumSize = min; MaximumSize = max; } } protected override void OnLoad(EventArgs e) { SetWindowPos(handle, HWND.NULL, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_FRAMECHANGED); base.OnLoad(e); } private void InvalidateNonclient() { if (!IsHandleCreated || IsDisposed) return; RedrawWindow(handle, null, HWND.NULL, RedrawWindowFlags.RDW_FRAME | RedrawWindowFlags.RDW_UPDATENOW | RedrawWindowFlags.RDW_VALIDATE); UpdateWindow(handle); SetWindowPos(handle, HWND.NULL, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOCOPYBITS | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOREPOSITION | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOZORDER); } protected override void WndProc(ref System.Windows.Forms.Message m) { var msg = (WindowMessage)m.Msg; switch (msg) { case WindowMessage.WM_ACTIVATE: DwmArea(); break; case WindowMessage.WM_NCCALCSIZE when m.WParam != IntPtr.Zero: if (WmNCCalcSize(ref m)) return; break; case WindowMessage.WM_NCACTIVATE: if (WmNCActivate(ref m)) return; break; case WindowMessage.WM_SIZE: WmSize(ref m); break; } if (WmGhostingHandler(m)) return; base.WndProc(ref m); } static IntPtr FALSE = new IntPtr(0); bool WmGhostingHandler(System.Windows.Forms.Message m) { switch (m.Msg) { case 0x00AE: case 0x00AF: case 0xC1BC: m.Result = FALSE; InvalidateNonclient(); break; } return false; } bool iszoomed = false; bool ISZoomed() { bool value = IsZoomed(handle); if (iszoomed == value) return value; iszoomed = value; DwmArea(); return value; } void DwmArea() { int margin; if (iszoomed) margin = 0; else margin = 1; DwmExtendFrameIntoClientArea(handle, new MARGINS(margin)); } #region 区域 /// /// 获取或设置窗体的位置 /// public new Point Location { get { if (winState == WState.Restore) return base.Location; return ScreenRectangle.Location; } set { sizeNormal = null; base.Location = value; } } /// /// 控件的顶部坐标 /// public new int Top { get => Location.Y; set { sizeNormal = null; base.Top = value; } } /// /// 控件的左侧坐标 /// public new int Left { get => Location.X; set { sizeNormal = null; base.Left = value; } } /// /// 控件的右坐标 /// public new int Right { get => ScreenRectangle.Right; } /// /// 控件的底部坐标 /// public new int Bottom { get => ScreenRectangle.Bottom; } /// /// 获取或设置窗体的大小 /// public new Size Size { get { if (winState == WState.Restore) return base.Size; return ScreenRectangle.Size; } set { sizeNormal = null; base.Size = value; sizeInit = ClientSize; } } /// /// 控件的宽度 /// public new int Width { get => Size.Width; set { sizeNormal = null; base.Width = value; sizeInit = ClientSize; } } /// /// 控件的高度 /// public new int Height { get => Size.Height; set { sizeNormal = null; base.Height = value; sizeInit = ClientSize; } } /// /// 获取或设置窗体屏幕区域 /// [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Always)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Rectangle ScreenRectangle { get { if (winState == WState.Restore) return new Rectangle(base.Location, base.Size); var rect = ClientRectangle; var point = RectangleToScreen(Rectangle.Empty); return new Rectangle(point.Location, rect.Size); } set { sizeNormal = null; base.Location = value.Location; base.Size = value.Size; sizeInit = ClientSize; } } #endregion #region 交互 #region 调整窗口大小 /// /// 调整窗口大小(鼠标移动) /// /// 可以调整 public override bool ResizableMouseMove() { var retval = HitTest(PointToClient(MousePosition)); if (retval != HitTestValues.HTNOWHERE) { var mode = retval; if (mode != HitTestValues.HTCLIENT && winState == WState.Restore) { SetCursorHit(mode); return true; } } return false; } /// /// 调整窗口大小(鼠标移动) /// /// 客户端坐标 /// 可以调整 public override bool ResizableMouseMove(Point point) { var retval = HitTest(point); if (retval != HitTestValues.HTNOWHERE) { var mode = retval; if (mode != HitTestValues.HTCLIENT && winState == WState.Restore) { SetCursorHit(mode); return true; } } return false; } #endregion #region 鼠标 public override bool IsMax { get => winState == WState.Maximize; } public static bool CanHandMessage = true; public bool PreFilterMessage(ref System.Windows.Forms.Message m) { if (is_resizable) return OnPreFilterMessage(m); if (CanHandMessage && ReadMessage) { switch (m.Msg) { case 0xa0: case 0x200: if (isMe(m.HWnd)) { if (ResizableMouseMove(PointToClient(MousePosition))) return true; } break; case 0xa1: case 0x201: if (isMe(m.HWnd)) { if (ResizableMouseDown()) return true; } break; } } return OnPreFilterMessage(m); } protected virtual bool OnPreFilterMessage(System.Windows.Forms.Message m) => false; bool isMe(IntPtr intPtr) { var frm = FromHandle(intPtr); if (frm == this || GetParent(frm) == this) return true; return false; } static Control? GetParent(Control? control) { try { if (control != null && control.IsHandleCreated && control.Parent != null) { if (control is Form) return control; return GetParent(control.Parent); } } catch { } return control; } #endregion #endregion #region WindowMessage Handlers const nint SIZE_RESTORED = 0; const nint SIZE_MINIMIZED = 1; const nint SIZE_MAXIMIZED = 2; void WmSize(ref System.Windows.Forms.Message m) { if (m.WParam == SIZE_MINIMIZED) WinState = WState.Minimize; else if (m.WParam == SIZE_MAXIMIZED) WinState = WState.Maximize; else if (m.WParam == SIZE_RESTORED) { sizeNormal = ClientSize; WinState = WState.Restore; InvalidateNonclient(); Invalidate(); } } bool WmNCCalcSize(ref System.Windows.Forms.Message m) { if (FormBorderStyle == FormBorderStyle.None) return false; if (ISZoomed()) { #if NET40 var nccsp = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT)); #else var nccsp = Marshal.PtrToStructure(m.LParam); #endif var borders = GetNonClientMetrics(); nccsp.top -= borders.Top; nccsp.top += borders.Bottom; Marshal.StructureToPtr(nccsp, m.LParam, false); return false; } else { m.Result = new IntPtr(1); return true; } } internal Size? sizeInit; Size? sizeNormal; bool WmNCActivate(ref System.Windows.Forms.Message m) { if (m.HWnd == IntPtr.Zero) return false; if (IsIconic(m.HWnd)) return false; m.Result = DefWindowProc(m.HWnd, (uint)m.Msg, m.WParam, new IntPtr(-1)); return true; } #endregion #region Frameless Crack protected override void SetClientSizeCore(int x, int y) { if (DesignMode) Size = new Size(x, y); else base.SetClientSizeCore(x, y); } protected Padding GetNonClientMetrics() { var screenRect = ClientRectangle; screenRect.Offset(-Bounds.Left, -Bounds.Top); var rect = new RECT(screenRect); AdjustWindowRectEx(ref rect, (WindowStyles)CreateParams.Style, false, (WindowStylesEx)CreateParams.ExStyle); return new Padding { Top = screenRect.Top - rect.top, Left = screenRect.Left - rect.left, Bottom = rect.bottom - screenRect.Bottom, Right = rect.right - screenRect.Right }; } protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { if (DesignMode) base.SetBoundsCore(x, y, width, height, specified); else if (WindowState == FormWindowState.Normal && sizeNormal.HasValue) base.SetBoundsCore(x, y, sizeNormal.Value.Width, sizeNormal.Value.Height, specified); else base.SetBoundsCore(x, y, width, height, specified); } #endregion } public enum WState { Restore, Maximize, Minimize } }