// 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
}
}