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プログラミング研究」で紹介したものを基にしています。)