Skip to content

Instantly share code, notes, and snippets.

@ahdung
Last active April 1, 2017 12:43
Show Gist options
  • Save ahdung/3d8d70856c0b9cb997d571b39c7834c2 to your computer and use it in GitHub Desktop.
Save ahdung/3d8d70856c0b9cb997d571b39c7834c2 to your computer and use it in GitHub Desktop.
A MessageBox can center within Form
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace AhDung.WinForm
{
/// <summary>
/// 能相对owner居中的消息框
/// <para>- 对于MDI,是相对子窗体居中,如果希望相对于MDI,请指定owner参数为MDI</para>
/// </summary>
public static class MessageBoxCenter
{
/// <summary>
/// 记录传入的owner,优先依据这个居中
/// </summary>
static IWin32Window _owner;
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMethodReturnValue.Global
public static DialogResult Show(string text)
{
Prepare(null);
return MessageBox.Show(text);
}
public static DialogResult Show(string text, string caption)
{
Prepare(null);
return MessageBox.Show(text, caption);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton, options);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator, param);
}
public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword)
{
Prepare(null);
return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, keyword);
}
public static DialogResult Show(IWin32Window owner, string text)
{
Prepare(owner);
return MessageBox.Show(owner, text);
}
public static DialogResult Show(IWin32Window owner, string text, string caption)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options, helpFilePath);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator, param);
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword)
{
Prepare(owner);
return MessageBox.Show(owner, text, caption, buttons, icon, defaultButton, options, helpFilePath, keyword);
}
// ReSharper restore UnusedMethodReturnValue.Global
// ReSharper restore UnusedMember.Global
private static void Prepare(IWin32Window owner)
{
if (_hook == IntPtr.Zero)
{
// ReSharper disable once CSharpWarnings::CS0618
_hook = SetWindowsHookEx(5/*WH_CBT*/, _proc, IntPtr.Zero, AppDomain.GetCurrentThreadId());
if (_hook == IntPtr.Zero)
{
return;
}
}
_owner = owner;
}
static IntPtr _hook;
static readonly HookProcDelegate _proc = HookProc;
/// <summary>
/// 钩子消息处理过程
/// </summary>
private static IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
Debug.WriteLine(wParam.ToString("X8") + "\thooking");
if (nCode != 5/*HCBT_ACTIVATE*/)//仅处理窗体激活消息
{
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
try
{
//确保操作的是消息框
if (GetClassName(wParam) != "#32770" || !HasStyle(wParam, unchecked((int)0x80000000)))
{
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
//确定相对其居中的窗体,优先取传入的owner
Form f = null;
if (_owner != null)
{
f = Control.FromHandle(_owner.Handle) as Form;
}
if (f == null)//不行再取消息框的owner
{
var owner = GetParent(wParam);
if (owner == IntPtr.Zero)//再不行,取消息中记录的刚刚丢失焦点的窗体
{
owner = ((CBTACTIVATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CBTACTIVATESTRUCT))).hWndActive;
}
if (owner != IntPtr.Zero)
{
f = Control.FromHandle(owner) as Form;
if (f != null && f.IsMdiContainer)//若窗体是MDI父窗体,取活动子窗体
{
f = f.ActiveMdiChild ?? f;
}
}
}
//如果最终都不能确定该窗体,则不移动
if (f != null)
{
var rcMsg = GetWindowRECT(wParam);
var rcOwn = GetWindowRECT(f.Handle);
var x = rcOwn.Left + (rcOwn.Width - rcMsg.Width) / 2;// rcPrv.Width / 2 - rcMsg.Width / 2;
var y = rcOwn.Top + (rcOwn.Height - rcMsg.Height) / 2;
MoveWindow(wParam, x, y, rcMsg.Width, rcMsg.Height, false);
}
return IntPtr.Zero;//无需再调CallNextHookEx,因为finally中已经卸载勾子,返回0表示不拦截消息,catch中同
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return IntPtr.Zero;
}
finally
{
if (UnhookWindowsHookEx(_hook))
{
_hook = IntPtr.Zero;
Debug.WriteLine("hook unloaded.");
}
else
{
Debug.WriteLine(new Win32Exception());
}
}
}
#region Win32 API
// ReSharper disable FieldCanBeMadeReadOnly.Local
// ReSharper disable MemberCanBePrivate.Local
/// <summary>
/// 检查窗口是否含有指定样式
/// </summary>
private static bool HasStyle(IntPtr hWnd, int style, bool isExStyle = false)
{
var s = unchecked((int)(long)GetWindowLong(hWnd, isExStyle ? -20 /*GWL_EXSTYLE*/ : -16 /*GWL_STYLE*/));
return (s & style) == style;
}
private static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
{
return IntPtr.Size == 4
? GetWindowLong32(hWnd, nIndex)
: GetWindowLongPtr64(hWnd, nIndex);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
/// <summary>
/// 获取窗口类名
/// </summary>
/// <exception cref="Win32Exception"/>
private static string GetClassName(IntPtr hWnd)
{
var sb = new StringBuilder(255);
if (GetClassName(hWnd, sb, sb.Capacity) == 0)
{
throw new Win32Exception();
}
return sb.ToString();
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetParent(IntPtr hWnd);
private delegate IntPtr HookProcDelegate(int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
private struct CBTACTIVATESTRUCT
{
public bool fMouse;
public IntPtr hWndActive;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProcDelegate lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wparam, IntPtr lparam);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
/// <summary>
/// 获取窗口屏幕区块
/// </summary>
/// <exception cref="Win32Exception"/>
private static RECT GetWindowRECT(IntPtr hWnd)
{
RECT rect = new RECT();
if (GetWindowRect(hWnd, ref rect))
{
return rect;
}
throw new Win32Exception();
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public int Width
{
get { return Right - Left; }
}
public int Height
{
get { return Bottom - Top; }
}
public static explicit operator Rectangle(RECT rect)
{
return new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
}
public static explicit operator RECT(Rectangle rect)
{
return new RECT { Left = rect.Left, Top = rect.Top, Right = rect.Right, Bottom = rect.Bottom };
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}, {3}", Left, Top, Width, Height);
}
}
// ReSharper restore MemberCanBePrivate.Local
// ReSharper restore FieldCanBeMadeReadOnly.Local
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment