// 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.Windows.Forms; using Vanara.PInvoke; using static Vanara.PInvoke.DwmApi; using static Vanara.PInvoke.User32; namespace AntdUI { public class BorderlessForm : BaseForm, IMessageFilter { public BorderlessForm() { SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer, true); UpdateStyles(); base.FormBorderStyle = FormBorderStyle.None; } #region 属性 [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new FormBorderStyle FormBorderStyle { get => base.FormBorderStyle; } bool CanMessageFilter => DwmEnabled || shadow < 4; int shadow = 10; /// /// 阴影大小 /// [Description("阴影大小"), Category("外观"), DefaultValue(10)] public int Shadow { get => shadow; set { if (shadow == value) return; shadow = value; if (DwmEnabled) return; if (value > 0) { ShowSkin(); skin?.ISize(); skin?.ClearShadow(); skin?.Print(); } else { skin?.Close(); skin = null; } } } /// /// 使用DWM阴影 /// [Description("使用DWM阴影"), Category("行为"), DefaultValue(true)] public bool UseDwm { get; set; } = true; [Description("鼠标穿透"), Category("行为"), DefaultValue(false)] public bool ShadowPierce { get; set; } Color shadowColor = Color.FromArgb(100, 0, 0, 0); /// /// 阴影颜色 /// [Description("阴影颜色"), Category("外观"), DefaultValue(typeof(Color), "100, 0, 0, 0")] public Color ShadowColor { get => shadowColor; set { if (shadowColor == value) return; shadowColor = value; skin?.ClearShadow(); skin?.Print(); } } int borderWidth = 1; [Description("边框宽度"), Category("外观"), DefaultValue(1)] public int BorderWidth { get => borderWidth; set { if (borderWidth == value) return; borderWidth = value; skin?.Print(); } } Color borderColor = Color.FromArgb(180, 0, 0, 0); /// /// 边框颜色 /// [Description("边框颜色"), Category("外观"), DefaultValue(typeof(Color), "180, 0, 0, 0")] public Color BorderColor { get => borderColor; set { if (borderColor == value) return; borderColor = value; skin?.Print(); } } int radius = 0; /// /// 圆角 /// [Description("圆角"), Category("外观"), DefaultValue(0)] public int Radius { get => radius; set { if (radius == value) return; radius = value; SetReion(); skin?.ClearShadow(); skin?.Print(); } } #endregion #region 重载事件 bool DwmEnabled = false; protected override void OnCreateControl() { base.OnCreateControl(); SetReion(); ShowSkin(); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); skin?.Close(); skin = null; } protected override void OnVisibleChanged(EventArgs e) { if (Visible && shadow > 0 && !DesignMode) ShowSkin(); else { if (skin != null) skin.Visible = false; } base.OnVisibleChanged(e); } BorderlessFormShadow? skin = null; void ShowSkin() { if (DwmEnabled) return; if (Visible && WindowState == FormWindowState.Normal && shadow > 0 && !DesignMode) { if (skin != null) skin.Visible = true; else { skin = new BorderlessFormShadow(this); skin.Show(this); } } } protected override void OnLocationChanged(EventArgs e) { skin?.OnLocationChange(); base.OnLocationChanged(e); } protected override void OnSizeChanged(EventArgs e) { skin?.OnSizeChange(); SetReion(); base.OnSizeChanged(e); } internal HWND handle { get; private set; } readonly IntPtr TRUE = new IntPtr(1); protected override void WndProc(ref System.Windows.Forms.Message m) { var msg = (WindowMessage)m.Msg; switch (msg) { case WindowMessage.WM_ERASEBKGND: m.Result = IntPtr.Zero; return; case WindowMessage.WM_ACTIVATE: case WindowMessage.WM_NCPAINT: DwmArea(); break; case WindowMessage.WM_NCHITTEST: m.Result = TRUE; return; case WindowMessage.WM_SIZE: WmSize(ref m); break; case WindowMessage.WM_MOUSEMOVE: case WindowMessage.WM_NCMOUSEMOVE: if (!is_resizable && ReadMessage) ResizableMouseMove(PointToClient(MousePosition)); break; case WindowMessage.WM_LBUTTONDOWN: case WindowMessage.WM_NCLBUTTONDOWN: if (!is_resizable && ReadMessage) ResizableMouseDown(); break; } base.WndProc(ref m); } int oldm = 0; void DwmArea() { if (DwmEnabled && shadow > 0) { int margin; if (WindowState == FormWindowState.Normal) margin = 1; else margin = 0; if (oldm == margin) return; oldm = margin; var v = 2; DarkUI.DwmSetWindowAttribute(Handle, 2, ref v, 4); DwmExtendFrameIntoClientArea(handle, new MARGINS(margin)); } } 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) WinState = WState.Restore; } #endregion protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.Style |= (int)WindowStyles.WS_MINIMIZEBOX; return cp; } } /// /// 窗体圆角 /// void SetReion() { if (Region != null) Region.Dispose(); var rect = ClientRectangle; if (rect.Width > 0 && rect.Height > 0) { if (IsMax) Region = new Region(rect); else { if (UseDwm && OS.Win11) return; using (var path = rect.RoundPath(radius * Config.Dpi)) { var region = new Region(path); path.Widen(Pens.White); region.Union(path); Region = region; } } } } #region BASE #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(); SetReion(); } } } void HandMessage() { ReadMessage = CanMessageFilter && winState == WState.Restore && resizable; 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 protected override void OnHandleCreated(EventArgs e) { handle = new HWND(Handle); base.OnHandleCreated(e); if (UseDwm && OS.Version.Major >= 6) { try { int enabled = 0; DarkUI.DwmIsCompositionEnabled(ref enabled); DwmEnabled = enabled == 1; } catch { } } SetTheme(); DisableProcessWindowsGhosting(); HandMessage(); } #region 交互 #region 拖动窗口 /// /// 拖动窗口(鼠标按下) /// public override void DraggableMouseDown() { var mouseOffset = MousePosition; bool end = true, handmax = false; Size min = MinimumSize, max = MaximumSize; if (DwmEnabled && WindowState == FormWindowState.Maximized) { ITask.Run(() => { while (end) { var mousePosition = MousePosition; if (mouseOffset != mousePosition) { if ((Math.Abs(mousePosition.X - mouseOffset.X) >= 6 || Math.Abs(mousePosition.Y - mouseOffset.Y) >= 6)) { handmax = true; Invoke(new Action(() => { WindowState = FormWindowState.Normal; isMax = false; })); return; } } else System.Threading.Thread.Sleep(10); } }); } ReleaseCapture(); SendMessage(Handle, 0x0112, 61456 | 2, IntPtr.Zero); end = false; if (handmax) { MaximumSize = max; MinimumSize = min; return; } else { var mousePosition = MousePosition; var screen = Screen.FromPoint(mousePosition); if (mousePosition.Y == screen.WorkingArea.Top && MaximizeBox) Max(); } } #endregion #region 调整窗口大小 /// /// 调整窗口大小(鼠标移动) /// /// 可以调整 public override bool ResizableMouseMove() { if (winState == WState.Restore) { var retval = HitTest(PointToClient(MousePosition)); if (retval != HitTestValues.HTNOWHERE) { var mode = retval; if (mode != HitTestValues.HTCLIENT) { SetCursorHit(mode); return true; } } } return false; } /// /// 调整窗口大小(鼠标移动) /// /// 客户端坐标 /// 可以调整 public override bool ResizableMouseMove(Point point) { if (winState == WState.Restore) { var retval = HitTest(point); if (retval != HitTestValues.HTNOWHERE) { var mode = retval; if (mode != HitTestValues.HTCLIENT) { SetCursorHit(mode); return true; } } } return false; } #endregion #region 鼠标 public bool PreFilterMessage(ref System.Windows.Forms.Message m) { if (is_resizable) return OnPreFilterMessage(m); if (Window.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 程序 /// /// 最大化/还原 /// public override bool MaxRestore() { if (WindowState == FormWindowState.Maximized) { WindowState = FormWindowState.Normal; isMax = false; return false; } else { Screen screen = Screen.FromPoint(Location); if (screen.Primary) MaximizedBounds = screen.WorkingArea; else MaximizedBounds = new Rectangle(0, 0, 0, 0); WindowState = FormWindowState.Maximized; isMax = true; return true; } } bool ismax = false; bool isMax { get => ismax; set { if (ismax == value) return; ismax = value; if (value) { if (skin != null) skin.Visible = false; } else ShowSkin(); DwmArea(); } } /// /// 最大化 /// public override void Max() { if (ismax) return; Screen screen = Screen.FromPoint(Location); if (screen.Primary) MaximizedBounds = screen.WorkingArea; else MaximizedBounds = new Rectangle(0, 0, 0, 0); WindowState = FormWindowState.Maximized; isMax = true; } /// /// 全屏/还原 /// public override bool FullRestore() { if (WindowState == FormWindowState.Maximized) { WindowState = FormWindowState.Normal; isMax = false; return false; } else { WindowState = FormWindowState.Maximized; isMax = true; return true; } } /// /// 全屏 /// public override void Full() { WindowState = FormWindowState.Maximized; isMax = true; } public override void NoFull() { WindowState = FormWindowState.Normal; isMax = false; } #endregion #endregion } }