メッセージボックス
画面中央にしか表示できない。。
MessageBox.Show だと画面中央にメッセージボックスが表示され、オーナーフォーム (親ウィンドウ) の中央に表示するためのパラメーターは存在しない。
親の中央に表示するためのクラス
オーナーフォームの中央に表示するには、Win32 API を使う必要がある。
CustomMessageBox.cs
static class CustomMessageBox
{
static class Win32Native
{
#region GetWindowLong
[DllImport("user32.dll")]
static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
const int GWL_HINSTANCE = -6;
public static IntPtr GetWindowHInstance(IntPtr hWnd) => GetWindowLong(hWnd, GWL_HINSTANCE);
#endregion
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentThreadId();
#region WindowsHookEx
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, HOOKPROC lpfn, IntPtr hInstance, IntPtr threadId);
const int WH_CBT = 5;
public static IntPtr SetWindowsHookEx(HOOKPROC lpfn, IntPtr hInstance, IntPtr threadId) => SetWindowsHookEx(WH_CBT, lpfn, hInstance, threadId);
[DllImport("user32.dll")]
public static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
public delegate IntPtr HOOKPROC(int nCode, IntPtr wParam, IntPtr lParam);
public const int HCBT_ACTIVATE = 5;
#endregion
#region GetWindowRect
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public struct RECT
{
public int Left, Top, Right, Bottom;
public int Width => this.Right - this.Left;
public int Height => this.Bottom - this.Top;
}
public static RECT GetWindowRect(IntPtr hWnd)
{
RECT rc;
GetWindowRect(hWnd, out rc);
return rc;
}
#endregion
#region SetWindowPos
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
const uint SWP_NOACTIVATE = 0x0010;
public static bool SetWindowPos(IntPtr hWnd, int x, int y)
{
var flags = SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
return SetWindowPos(hWnd, 0, x, y, 0, 0, flags);
}
#endregion
}
public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
{
hOwner = owner.Handle;
var hInstance = Win32Native.GetWindowHInstance(owner.Handle);
var threadId = Win32Native.GetCurrentThreadId();
hHook = Win32Native.SetWindowsHookEx(new Win32Native.HOOKPROC(HookProc), hInstance, threadId);
return MessageBox.Show(owner, text, caption, buttons, icon);
}
private static IntPtr hOwner = (IntPtr)0;
private static IntPtr hHook = (IntPtr)0;
private static IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode == Win32Native.HCBT_ACTIVATE)
{
// オーナーウィンドウとメッセージボックスの領域を取得
var rcOwner = Win32Native.GetWindowRect(hOwner);
var rcMsgBox = Win32Native.GetWindowRect(wParam);
// メッセージボックスをオーナーウィンドウの中央位置に移動
var x = rcOwner.Left + (rcOwner.Width - rcMsgBox.Width) / 2;
var y = rcOwner.Top + (rcOwner.Height - rcMsgBox.Height) / 2;
Win32Native.SetWindowPos(wParam, x, y);
// フックを解除
Win32Native.UnhookWindowsHookEx(hHook);
hHook = (IntPtr)0;
}
return Win32Native.CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
使用方法
通常の MessageBox と同じく、CustomMessageBox クラスの Show メソッドを呼ぶ。
CustomMessageBox.Show(owner, "メッセージ", "タイトル", MessageBoxButtons.OK, MessageBoxIcon.Information);