0

次のコードスニペットは奇妙に見えるかもしれませんが、別のアプリケーションとの複雑な相互作用の問題を再現するための非常に簡単な方法です。

サンプルアプリケーションには2つのフォームがあり、どちらのフォームもFormClosingイベントとFormClosedイベントを登録し、そこでDebug.WriteLineを実行するだけです。

Main関数は次のことを行います。

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Form2 form2 = new Form2();
    form2.Show();
    Application.Run(new Form1());
}

Form2を閉じると、期待どおりにイベントを受け取ります。Form1を閉じると、アプリケーションが終了し、Form2も閉じられます。ただし、Form2のイベントは発生しません。

Form2のWndProcを上書きしました。Form2を閉じると、

15.10.2012 10:25:04 WndProc - WM_CLOSE
15.10.2012 10:25:04 OnClosing
15.10.2012 10:25:04 Form2_FormClosing
15.10.2012 10:25:04 OnClosed
15.10.2012 10:25:04 Form2_FormClosed
...
15.10.2012 10:25:04 WndProc - WM_DESTROY
...
15.10.2012 10:25:04 WndProc - WM_NCDESTROY

Form1を閉じると、Form2はWM_CLOSEを受け取りません。ただし、WM_DESTROYとWM_NCDESTROYは受信されます。

編集:この奇妙な動作を取得する別の方法は次のとおりです。プロジェクトには3つのフォームがあり、Form1とForm2にはそれぞれ次のフォームを開くためのボタンがあります。form2のボタンクリックイベントで、次の手順を実行します。

Form3 frm3 = new Form3();
frm3.Parent = null;
frm3.Show(null);

ここでも、上記のようにイベントハンドラーを登録します。form2を閉じると、アプリケーションは実行されたままになります(form1は引き続き表示されます)が、form3も閉じられ、WM_CLOSEイベントは受信されません。フォームの親と所有者の両方をすでにnullに設定していることに注意してください。

その奇妙な行動の理由は何ですか?

4

1 に答える 1

3

WM_CLOSEメッセージが送信され、クローズをキャンセルするオプションが与えられます。このフローチャートを参照してください。

ここに画像の説明を入力

したがって、とにかくウィンドウが破棄されようとしている場合、このメッセージは必要ありません。これは仕様による動作です。アプリケーションのメイン フォームを閉じるときに、Application.ThreadExitメソッドが呼び出されます。次のように説明しました。

現在のスレッドのメッセージ ループを終了し、スレッドのすべてのウィンドウを閉じます。

WM_CLOSE開いているすべてのフォームでメッセージを受け取りたい場合は、Application.Exit代わりに次を使用する必要があります。

すべてのメッセージ ポンプに終了する必要があることを通知し、メッセージが処理された後にすべてのアプリケーション ウィンドウを閉じます。

したがって、単純にイベントをサブスクライブしForm1_FormClosing、開いているすべてのウィンドウに閉じることを通知します。

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Application.Exit();
}
于 2012-10-15T08:51:56.637 に答える