QA@IT

MessageBox を表示中に、その MessageBox のインスタンスにアクセスしたい

8155 PV

Visual C# 2010 Express で Windows Forms Application を作っています。

MessageBox を表示中に、そのインスタンスにアクセスしたいのですがその方法が分かりません。アクセスして MessageBox に表示している文字列を取得したり、MessageBox の中のボタンを押したりしたいと思っています。せめて MessageBox を表示中かそれとも表示していないのかだけでも知りたいです。なお MessageBox はモーダルですがタイマーのイベントハンドラーからは、(インスタンスさえ分かれば)アクセスだと思います。

なぜこういうことをしたいかというと、すでに .NET 作られたアプリケーションのプログラムがあり、そのプログラムが MessageBox を出しているらしく、そこに自分の処理を新たに挟み込みたいためです。すでにあるプログラムはコードをいじることができません。

私が技術的につまずいている点ですが、アクセスする対象が Form であればできています。アクセスする対象が MessageBox だとできていません。Form であれば OwnedForms というプロパティーを辿って行くとインスタンスを見つけることができました。しかし MessageBox だとそのような方法では辿れないようです。
なお、今までもこういうことをしたい場合は、Windows API を使い、FindWindow などの API で MessageBox のウィンドウハンドルを取得してそれに対して操作するということはできていて、今回の場合も最悪、それと同じことはできると考えています。ただ、今回は .NET で MessageBox を出しているので、できたら .NET で全部やりたいと思っていて Windows API を使わない方法を探しています。

サンプルコードはつぎのようになります。この中の timer1_Tick というイベントハンドラーの中で MessageBox のインスタンスにアクセスしたいです。ヒント等、よろしくお願いいたします。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // timer1 は、Form1 に貼った System.Windows.Forms.Timer クラスのインスタンスです。
            timer1.Interval = 5000;
            timer1.Start();
            MessageBox.Show(this, "Hello");
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Stop();

            // ここで MessageBox のインスタンスにアクセスしたい。
        }
    }
}
  • APIを使うしかないと思います。WinFormsのコントロールでもUnsafeNativeMethods.EnumChildWindowsは結構使われてますし、Processをつかって対象のプロセスを特定した後はWin32APIに頼ることになると思います。 -
  • コメントありがとうございます。質問にはっきり書かなかったのですが、すでにあるプログラムはいわゆるプラグインをロードできるようになっていて、自分が作っているプログラムはそのプラグインにあたり、同一プロセスで動作します。ただし、プラグインであるかどうかはあまり重要ではなく、質問で書いたようなサンプルプログラムと同じようなコンテキストで動く状況です。 -
  • アクセスという目的を達成できなくても良いのですがつぎの疑問があります。画面上で見える MessageBox は、.NET のインスタンスとして存在しているのでしょうか?仮に、.NET のプロセス内のインスタンスをすべて列挙できる方法があったら、MessageBox のインスタンスは列挙されるでしょうか?列挙されるとしたらインスタンスにアクセスできますよね。アクセスできないとしたら列挙もできない? -
  • 自プロセスでも、外部プロセスでも取れるのはMainWindowTitleぐらいで、その先はAPIに頼るぐらいしかないという意味です。「.NETのインスタンスとして存在しているか」という事の意味がわかりませんが、最終的に表示されるダイアログはただのWindows APIのメッセージボックスです。SPY++で見る限り VB6で出したものと変わりません(少なくともWinXPでは)。 -
  • .NETのWindowsアプリケーションで作成したウィンドウの(SPY++上の)クラス名は.NET独自の名前と思われます。「.NETのインスタンス」がそういう意味であればMessageBox.Showで出てくるメッセージボックスは.NETではなく、Win32APIのMessageBoxです。 -
  • .NET の System.Windows.Forms.MessageBox クラスに関連するクラスが Windows API を使って生成した MessageBox のウィンドウハンドルを保持して管理しているのかなと思っていたのですが、そもそも Windows API の MessageBox 関数は、自分が作ったウィンドウのハンドルを教えてくれない仕様ですね。 -
  • 「.NET のインスタンス」とは上記のような”管理”するクラスのようなものを想定して書きました。
    しかし、ウィンドウハンドルが分からない以上、MessageBox のウィンドウの管理のしようがないですから、これは .NET の問題というよりも Windows API の問題だと思いました。
    私がやりたいことは無理ですね。ありがとうございました。
    -

回答

やりたいことと合っているのか分かりませんが
MessageBoxを使用しているソースを含むプロジェクトに
新たにソースを含めることは可能なのでしょうか?
サンプルからすると可能なように見えます。

だとすると
MessageBoxをWindowsFormsApplication1内に
定義してしまってその中でForms.MessageBoxを呼ぶようにしてみてはどうでしょう?
表示前と表示後に処理をするのは可能になります。表示中は無理ですが。

編集 履歴 (0)
  • 質問者じゃないのに横槍失礼。質問を見るに、コードが書ける範囲はReflectionで読まれて特定のメソッドが呼ばれるだけのようなものだと思うので、既存コードを上書きするのは難しいんじゃないですかね。MessageBoxをデコレートできたら面白いんですがね。 -
  • ご回答・コメントありがとうございます。プラグインを呼ぶ側は EXE になっていていじることはできません。サンプルコードはこういうコンテキストで MessageBox にアクセスしたい(アクセスできれば目的を達成できる)という、コンテキストを説明するためのものです。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。