Last active
April 1, 2017 12:43
-
-
Save ahdung/3d8d70856c0b9cb997d571b39c7834c2 to your computer and use it in GitHub Desktop.
A MessageBox can center within Form
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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