.NETのFormClosingとFormClosed

フォームが閉じられるときの動作の覚書。

ユーザが閉じたとき

ユーザがフォームの右上のXをクリックした場合、WM_CLOSEが送られ、FormClosingが呼ばれる。引数のFormClosingEventArgのCloseReasonにはUserClosingが設定される。Cancelプロパティをtrueに設定すると閉じるのをやめることができる。
Cancelをtrueにしなければ続いてFormClosedが呼ばれる。この時点ではフォームはまだ生きているが閉じるのをやめることはできない。FormClosedの後にDisposeが呼ばれる。

タスクマネージャから閉じられたとき(タスクマネージャのアプリケーションタグからのときで、プロセスタブのときは違うと思われる)はCloseResonにTaskManagerClosingが設定される。

タスクマネージャはWM_CLOSEを送るだけだと思うが、アプリから終了した場合はSC_CLOSEが先に来るのでそこで分けられると思われる。

システムがシャットダウンするとき

Win32の整理。システムがシャットダウンするときまずアプリにWM_QUERYENDSESSIONが送れられる。誰かが0を返すと送るのをやめる(途中で0が来たら残りのアプリには送らないと思われる)。次にWM_ENDSESSIONを送る。これを送るアプリはWM_QUERYENDSESSIONを送ったアプリと思われる。つまりWM_QUERYENDSESSIONを送ったときすべてのアプリが非ゼロを返せばすべてのアプリということになる。このときこの2つのメッセージは一気に送るのか、1つのアプリに対して毎に2つ送るのかはよくわからない。WM_ENDSESSIONのWParamはWM_QUERYENDSESSIONの戻り値が返るのでアプリはシャットダウンするのかしないのか判断できると思われる。これら2つのメッセージにはLparamもあるがここでは0(シャットダウンORリスタート)を考える。

WM_QUERYENDSESSIONが送られるとFormClosingが呼ばれる。CloseReasonはWindowsShutDown。Cancelをtrueにすると。メッセージの戻り値が0に設定される(つまりシャットダウンがキャンセルされる)。この時点では当然FormClosedは呼ばれない。

次にWM_ENDSESSIONが送られる。WParamが非ゼロの時(シャットダウン実行)はFormClosedが呼ばれる。

フローチャート

[OSがシャットダウン開始]
       ↓
[WM_QUERYENDSESSION送られてFormClosing呼ばれる]
       ↓
[Cancel=falseのまま?]→NO[WM_ENDSESSION送られる]→[なにもなし]
       ↓ YES
[WM_ENDSESSION送られる]
       ↓
[FormClosed呼ばれる]
       ↓
[シャットダウン]

なので注意すべき点はFormClosingでCancel=trueするときは、最初にCancelすべきかどうかを済ませて、内部の変更を行うコードはそれ以降に書く、ということかな。

Leave a Reply

Your email address will not be published. Required fields are marked *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)