Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

メッセージボックスをオーナーフォームの中央に表示

メッセージボックス

画面中央にしか表示できない。。

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);
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
9
Help us understand the problem. What are the problem?