2014年3月6日木曜日

MessageBoxをプログラムから閉じたい

WPFではまってみたのでメモを(多分WinFormsでもWin32でも通じる話?)


◆やりたい事

MessageBox.Showしている時に割り込み処理をしたい。つまりMessageBoxをユーザー操作無しで閉じたい。


◆はまった背景

まず、普通のWindowをダイアログとして表示している場合はとても簡単。Closeしてやるだけです。が、MessageBox.Showは同期処理になっている上に元々Closeというメソッドも存在しません。

じゃー、どうすんのって話でちょっと考えてみた&調べてみた結果

1.カスタムMessageBoxを実装する

 これが間違いないけど作るのも差し替えるのも面倒くさい(いや、それほどでもないか)

2.MessageBoxのcaptionを使ってFindWindow -> SendMessageでWM_CLOSEする

 Win32なアプローチ・・・.NET的には美しくないけど基本的にこれしか無さそうです


◆さらにズブズブはまる

で、2番のアプローチで検討してみるという事でサクサクっと人様のコードをコピペしてみます。


public class MessageBoxEx
{
    private const int WM_CLOSE = 0x0010;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
    internal static extern int SendMessage(IntPtr hwnd,
                                           int msg,
                                           IntPtr wParam,
                                           IntPtr lParam);
   
    public static void Close(string caption)
    {
        IntPtr mbWnd = FindWindow(null, caption);
        if (mbWnd != IntPtr.Zero)
        {
            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        }
    }
}


こやつ(MessageBoxEx.Close("hoge");)を呼んでみると・・・閉じない!


~~ ここでしばらくハマる ~~


◆結論として

まぁ、結局何が問題だったのかというと今回対象となるアプリはMessageBoxを

・単にメッセージを表示
・YesNoで選択させる

という2つの使い方をしています。この後者が曲者だった様です。

というのもYesNoの二択の場合双方に対して処理が必要となる選択なのでただ閉じるという選択肢はユルサン!って事らしいのです。(良く見てみるとYesNoの時はクローズボタン押せなくなってマス)

OKCancelやYesNoCancelなどCancel(やっぱやーめた)という選択肢を与えてやると上記のWM_CLOSEで閉じられるようになるという話みたいです。

言われてみれば、あーなるほど!って話なんだけど分からないよねぇ・・・。


◆でもやっぱりYesNoのMessageBoxを使いたい!

んー、やっぱCancel入ってくると少し意味合い変わるし、OKCancelも違うし・・・。という訳でどうすべきかという話。

話は簡単。


ならNoを押せば良いじゃない


というわけで、こんなんなりました。


private const int WM_COMMAND = 0x00000111;
private const int ID_NO = 7;

SendMessage(mbWnd, WM_COMMAND, new IntPtr(ID_NO), IntPtr.Zero);


このコード「」呼んであげればどちらでも閉められますな!


0 件のコメント:

コメントを投稿