フォームが閉じられる時その原因を知る
|
| CloseReasonのメンバ | フォームが閉じられる原因 |
|---|---|
| ApplicationExitCall | Application.Exitが呼び出された。 |
| FormOwnerClosing | このフォームを所有しているフォームが閉じられようとしている。 |
| MdiFormClosing | このフォームのMDI親フォームが閉じられようとしている。 |
| TaskManagerClosing | タスクマネージャーがアプリケーションを終了させようとしている。 |
| UserClosing | ユーザーが、ウィンドウの「閉じる」ボタン(ウィンドウの右上のXボタン)を押した、コントロールメニューの「閉じる」を選択した、Alt + F4キーを押したなど。フォームのCloseメソッドを呼び出したときも。 |
| WindowsShutDown | OSが終了するために、アプリケーションを終了させようとしている。 |
| None | 不明 |
フォームが閉じられるときにその理由を表示するサンプルを以下に示します。
'フォームのFormClosingイベントハンドラ Private Sub Form1_FormClosing(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.FormClosingEventArgs) _ Handles MyBase.FormClosing Select Case e.CloseReason Case CloseReason.ApplicationExitCall Console.WriteLine("Application.Exitによる") Case CloseReason.FormOwnerClosing Console.WriteLine("所有側のフォームが閉じられようとしている") Case CloseReason.MdiFormClosing Console.WriteLine("MDIの親フォームが閉じられようとしている") Case CloseReason.TaskManagerClosing Console.WriteLine("タスクマネージャによる") Case CloseReason.UserClosing Console.WriteLine("ユーザーインターフェイスによる") Case CloseReason.WindowsShutDown Console.WriteLine("OSのシャットダウンによる") Case CloseReason.None Console.WriteLine("未知の理由") Case Else Console.WriteLine("それ以外") End Select End Sub
//フォームのFormClosingイベントハンドラ private void Form1_FormClosing(object sender, FormClosingEventArgs e) { switch (e.CloseReason) { case CloseReason.ApplicationExitCall: Console.WriteLine("Application.Exitによる"); break; case CloseReason.FormOwnerClosing: Console.WriteLine("所有側のフォームが閉じられようとしている"); break; case CloseReason.MdiFormClosing: Console.WriteLine("MDIの親フォームが閉じられようとしている"); break; case CloseReason.TaskManagerClosing: Console.WriteLine("タスクマネージャによる"); break; case CloseReason.UserClosing: Console.WriteLine("ユーザーインターフェイスによる"); break; case CloseReason.WindowsShutDown: Console.WriteLine("OSのシャットダウンによる"); break; case CloseReason.None: default: Console.WriteLine("未知の理由"); break; } }
.NET Framework 1.1以前で最も一般的なのは、フォームのWndProcメソッドをオーバーライドし、送られてくるメッセージを調べるという方法です。次の例では、WM_ENDSESSION、WM_SYSCOMMAND、WM_CLOSEが送られてきたか調べ、フォームが閉じられる原因がOSのシャットダウンによるか、Xボタン(「閉じる」ボタン)やコントロールメニューによるか、コードによるか、判断しています。
<System.Security.Permissions.SecurityPermission( _
System.Security.Permissions.SecurityAction.LinkDemand, _
Flags:=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)> _
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_CLOSE As Integer = &H10
Const WM_ENDSESSION As Integer = &H16
Const WM_SYSCOMMAND As Integer = &H112
Const SC_CLOSE As Long = &HF060L
Select Case m.Msg
Case WM_ENDSESSION
'OSのシャットダウンで閉じられようとしている
Console.WriteLine("WM_ENDSESSION")
Exit Select
Case WM_SYSCOMMAND
If (m.WParam.ToInt64() And &HFFF0L) = SC_CLOSE Then
'Xボタン、コントロールメニューの「閉じる」、
'コントロールボックスのダブルクリック、
'Atl+F4などにより閉じられようとしている
Console.WriteLine("SC_CLOSE")
End If
Exit Select
Case WM_CLOSE
'Application.Exit以外で閉じられようとしている
Console.WriteLine("WM_CLOSE")
Exit Select
End Select
MyBase.WndProc(m)
End Sub
[System.Security.Permissions.SecurityPermission(
System.Security.Permissions.SecurityAction.LinkDemand,
Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
const int WM_CLOSE = 0x0010;
const int WM_ENDSESSION = 0x16;
const int WM_SYSCOMMAND = 0x112;
const long SC_CLOSE = 0xF060L;
switch (m.Msg)
{
case WM_ENDSESSION:
//OSのシャットダウンで閉じられようとしている
Console.WriteLine("WM_ENDSESSION");
break;
case WM_SYSCOMMAND:
if ((m.WParam.ToInt64() & 0xFFF0L) == SC_CLOSE)
//Xボタン、コントロールメニューの「閉じる」、
//コントロールボックスのダブルクリック、
//Atl+F4などにより閉じられようとしている
Console.WriteLine("SC_CLOSE");
break;
case WM_CLOSE:
//Application.Exit以外で閉じられようとしている
Console.WriteLine("WM_CLOSE");
break;
}
base.WndProc(ref m);
}
二番目の方法はStackFrameを使うというちょっと変わった方法で、「GotDotNet Message Boards - Form.Closing...」(リンク切れ)で紹介されています。
ここで紹介されているYeahIGotDotNetさん、MikeWill34さんの書いたコード及び、「The Code Project - Find out what's closing your application」で紹介されているEvilDoctorSmithさんのコードを参考にさせていただき、次のようなコードを書いてみました。詳しくは、これらのリンク先をご覧ください。
Private Sub Form1_Closing(ByVal sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles MyBase.Closing Dim stack As New System.Diagnostics.StackTrace(True) Dim frame7 As System.Diagnostics.StackFrame = stack.GetFrame(7) Select Case frame7.GetMethod().Name Case "DispatchMessageW" Console.WriteLine("タスクマネージャーによる") Case "SendMessage" Console.WriteLine("コードによる") Case "CallWindowProc" If stack.FrameCount > 14 Then Dim frame14 As System.Diagnostics.StackFrame = _ stack.GetFrame(14) If frame14.GetMethod().Name = "WmSysCommand" Then Console.WriteLine( _ "Xボタンまたはコントロールメニューによる") Else If frame14.GetMethod().Name = "WndProc" Then Console.WriteLine("OSのシャットダウンによる") End If End If End If Case "DefMDIChildProc" Console.WriteLine( _ "MDI子フォームのXボタンまたはコントロールメニューによる") Case "DefFrameProc" Console.WriteLine("MDI親フォームが閉じられたことによる") Case "ShowDialog" Console.WriteLine("モーダルダイアログが閉じられたことによる") Case Else Console.WriteLine("原因不明") End Select End Sub
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(true); System.Diagnostics.StackFrame frame7 = stack.GetFrame(7); switch (frame7.GetMethod().Name) { case "DispatchMessageW": Console.WriteLine("タスクマネージャーによる"); break; case "SendMessage": Console.WriteLine("コードによる"); break; case "CallWindowProc": if (stack.FrameCount > 14) { System.Diagnostics.StackFrame frame14 = stack.GetFrame(14); if (frame14.GetMethod().Name == "WmSysCommand") Console.WriteLine( "Xボタンまたはコントロールメニューによる"); else if (frame14.GetMethod().Name == "WndProc") Console.WriteLine("OSのシャットダウンによる"); } break; case "DefMDIChildProc": Console.WriteLine( "MDI子フォームのXボタンまたはコントロールメニューによる"); break; case "DefFrameProc": Console.WriteLine("MDI親フォームが閉じられたことによる"); break; case "ShowDialog": Console.WriteLine("モーダルダイアログが閉じられたことによる"); break; default: Console.WriteLine("原因不明"); break; } }
最後に紹介するのは、hidden windowを使った方法です。これは、「Visual Studio Magazine - Determine a Form's UnloadMode」(リンク切れ)で紹介されているものです。一番はじめに紹介したWndProcメソッドによる方法では判断できない原因を調べるために、隠れたフォームを使うという方法のようです。詳しくは、リンク先をご覧ください。
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。
|
Copyright(C) DOBON!. All rights reserved.
|