Windowsフォームの右上にある「閉じる」ボタン(Xボタン)を無効にする方法を幾つか紹介します。
まず一番単純なのは、フォームのControlBoxプロパティをFalseにしたり、FormBorderStyleプロパティをNoneにしたりすることにより、「閉じる」ボタンを消す方法です。この場合は、最小化、最大化ボタン、コントロールボックスも消えてしまうという欠点があります。
また、「フォームが閉じられる時その原因を知る」と「条件によりフォームが閉じられないようにする」により、「閉じる」ボタンが押されてフォームが閉じられる場合に、フォームを閉じないようにする方法もあります。
この方法を使った例は、次のようなものです。なおこの例では、システムメニューの「閉じる」や、「Alt」+「F4」キーも無効になります。
'Imports System.Security.Permissions <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) Const WM_SYSCOMMAND As Integer = &H112 Const SC_CLOSE As Long = &HF060L If m.Msg = WM_SYSCOMMAND AndAlso _ (m.WParam.ToInt64() And &HFFF0L) = SC_CLOSE Then Return End If MyBase.WndProc(m) End Sub
//using System.Security.Permissions; [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { const int WM_SYSCOMMAND = 0x112; const long SC_CLOSE = 0xF060L; if (m.Msg == WM_SYSCOMMAND && (m.WParam.ToInt64() & 0xFFF0L) == SC_CLOSE) { return; } base.WndProc(ref m); }
補足:上の例では「条件によりフォームが閉じられないようにする」は使いませんでした。これを使う場合は、「閉じる」ボタンが押された時にフラッグを立てて、Closingイベントで閉じないようにします。
補足:.NET Framework 2.0以降では、次のようにFormClosingイベントを使うと簡単そうに思われます。ただし、フォームのCloseメソッドで閉じる場合もCloseReasonがUserClosingとなりますので、Application.Exitメソッドなどで閉じなければならなくなります。
'フォームのFormClosingイベントハンドラ Private Sub Form1_FormClosing(ByVal sender As Object, _ ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing If e.CloseReason = CloseReason.UserClosing Then e.Cancel = True End If End Sub
//フォームのFormClosingイベントハンドラ private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) e.Cancel = true; }
さらに、GotDotNetの掲示板の「Disabling the close button?」(リンク切れ)にMickDohertyさんがとてもおもしろい投稿をされています。これはフォームのCreateParamsプロパティをオーバーライドするという方法で、「閉じる」ボタンが無効状態となり、押すことができなくなります。システムメニューの「閉じる」も表示されなくなり、「Alt」+「F4」キーも無効になります。 以下にそのコードを引用させていただきます。
'Imports System.Security.Permissions Protected Overrides ReadOnly Property CreateParams() As _ System.Windows.Forms.CreateParams <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Get Const CS_NOCLOSE As Integer = &H200 Dim cp As CreateParams = MyBase.CreateParams cp.ClassStyle = cp.ClassStyle Or CS_NOCLOSE Return cp End Get End Property
//using System.Security.Permissions; protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { const int CS_NOCLOSE = 0x200; CreateParams cp = base.CreateParams; cp.ClassStyle = cp.ClassStyle | CS_NOCLOSE; return cp; } }
最後にWin32 APIを使う方法も紹介しておきます。下記の方法では、「閉じる」ボタンが無効状態となり、システムメニューの「閉じる」が表示されなくなりますが、「Alt」+「F4」キーは有効です。
<System.Runtime.InteropServices.DllImport("user32.dll")> _ Shared Function GetSystemMenu(ByVal hWnd As IntPtr, _ ByVal bRevert As Boolean) As IntPtr End Function <System.Runtime.InteropServices.DllImport("user32.dll")> _ Shared Function GetMenuItemCount(ByVal hMenu As IntPtr) As Integer End Function <System.Runtime.InteropServices.DllImport("user32.dll")> _ Shared Function DrawMenuBar(ByVal hWnd As IntPtr) As Boolean End Function <System.Runtime.InteropServices.DllImport("user32.dll")> _ Shared Function RemoveMenu(ByVal hMenu As IntPtr, _ ByVal uPosition As Integer, _ ByVal uFlags As Integer) As Boolean End Function Protected Overrides Sub OnLoad(ByVal e As EventArgs) MyBase.OnLoad(e) Const MF_BYPOSITION As Int32 = &H400 Const MF_REMOVE As Int32 = &H1000 Dim menu As IntPtr = GetSystemMenu(Me.Handle, False) Dim menuCount As Integer = GetMenuItemCount(menu) If menuCount > 1 Then 'メニューの「閉じる」とセパレータを削除 RemoveMenu(menu, menuCount - 1, MF_BYPOSITION Or MF_REMOVE) RemoveMenu(menu, menuCount - 2, MF_BYPOSITION Or MF_REMOVE) DrawMenuBar(Me.Handle) End If End Sub
[System.Runtime.InteropServices.DllImport("user32.dll")] static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [System.Runtime.InteropServices.DllImport("user32.dll")] static extern int GetMenuItemCount(IntPtr hMenu); [System.Runtime.InteropServices.DllImport("user32.dll")] static extern bool DrawMenuBar(IntPtr hWnd); [System.Runtime.InteropServices.DllImport("user32.dll")] static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); protected override void OnLoad(EventArgs e) { base.OnLoad (e); const Int32 MF_BYPOSITION = 0x400; const Int32 MF_REMOVE = 0x1000; IntPtr menu = GetSystemMenu(this.Handle, false); int menuCount = GetMenuItemCount(menu); if (menuCount > 1) { //メニューの「閉じる」とセパレータを削除 RemoveMenu(menu, (uint) (menuCount - 1), MF_BYPOSITION | MF_REMOVE); RemoveMenu(menu, (uint) (menuCount - 2), MF_BYPOSITION | MF_REMOVE); DrawMenuBar(this.Handle); } }
(この記事は、「.NETプログラミング研究」で紹介したものを基にしています。)