ショートカット Alt + F4 によるアプリ終了を無視する

アプリケーションによっては、Alt + F4 によるショートカットでアプリを終了させたくない場合があります。同様に、ウインドウ右上隅にある「閉じるボタン」でアプリを終了させたくない場合もあります。

スレッドを扱うプログラミングをしている場合や、パソコンの PCI-Express バスに拡張ボードなどを挿入して外部ハードウェアを制御するプログラミングをしている場合などがそれにあたります。多くの場合、そういう場合は終了処理が重要で、それをすっ飛ばしてしまうとシステムが破綻したりします。

本ページで紹介する二つの手法を同時に使って、そういう特殊な場合に対処します。

ショートカット Alt + F4 を無視する

昔なつかしいメッセージフックを使うしかありません。WindowsSDK や MFC を思い出してしまいますね。これしか方法がありません。下記のコードを Form のコードのどこかに入れてください。(ああ、めんどくさい~)

protected override void WndProc( ref Message m )
{
	
	const int WM_SYSCOMMAND = (int)( 0x0112 );
	const long SC_CLOSE = (long)( 0xf060 );

	if ( ( m.Msg ) == WM_SYSCOMMAND )
	{

		long wparam = m.WParam.ToInt64();

		long mask = (long)( 0xfff0 );

		if ( ( wparam & mask ) == SC_CLOSE )
		{
			MessageBox.Show( "[Alt] + [F4] は受け付けません." );
			return;
		}

	}

	base.WndProc( ref m );

}

閉じるボタンを無効化する

これまた、昔なつかしいコードを書かなければなりません。

GetSysmteMenu や RemoveMenu などは、kernel32.dll の中で定義されている APIですので、下記のようにして、DLLをインポート指定します。(ああ、めんどくさい~~)

using System.Runtime.InteropServices;

[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu( IntPtr hWnd, UInt32 bRevert );

[DllImport("user32.dll")]
private static extern UInt32 RemoveMenu( IntPtr hMenu, UInt32 nPosition, UInt32 wFlags );

それから下記のコードをフォーム(ウインドウ)の作成時にコールします。

private void Form1_Load( object sender, EventArgs e )
{

	// このウインドウのハンドルを取得する.
	IntPtr hwnd = this.Handle;

	// コントロールボックスの[閉じる]ボタンを無効化する.
	const UInt32 SC_CLOSE = 0x0000F060;
	const UInt32 MF_BYCOMMAND = 0x00000000;	
	IntPtr hmenu = GetSystemMenu( hwnd, 0 );
	RemoveMenu( hmenu, SC_CLOSE, MF_BYCOMMAND );

}

Alt+F4 を無視して閉じるボタンを無効化するコード

以上に述べた二つの手法を総合したコードが下記の Form1.cs になります。

using System;
using System.Runtime.InteropServices; // これをお忘れなく.
using System.Windows.Forms;

namespace aaa
{
	public partial class Form1 : Form
	{

		[DllImport("user32.dll")]
		private static extern IntPtr GetSystemMenu( IntPtr hWnd, UInt32 bRevert );

		[DllImport("user32.dll")]
		private static extern UInt32 RemoveMenu( IntPtr hMenu, UInt32 nPosition, UInt32 wFlags );

		protected override void WndProc( ref Message m )
		{
			
			const int WM_SYSCOMMAND = (int)( 0x0112 );
			const long SC_CLOSE = (long)( 0xf060 );

			if ( ( m.Msg ) == WM_SYSCOMMAND )
			{

				long wparam = m.WParam.ToInt64();

				long mask = (long)( 0xfff0 );

				if ( ( wparam & mask ) == SC_CLOSE )
				{
					MessageBox.Show( "[Alt] + [F4] は受け付けません." );
					return;
				}

			}

			base.WndProc( ref m );
		
		}

		public Form1()
		{
			InitializeComponent();
		}

		private void Form1_Load( object sender, EventArgs e )
		{

			// このウインドウのハンドルを取得する.
			IntPtr hwnd = this.Handle;

			// コントロールボックスの[閉じる]ボタンを無効化する.
			const UInt32 SC_CLOSE = 0x0000F060;
			const UInt32 MF_BYCOMMAND = 0x00000000;	
			IntPtr hmenu = GetSystemMenu( hwnd, 0 );
			RemoveMenu( hmenu, SC_CLOSE, MF_BYCOMMAND );

		}

		private void button1_Click( object sender, EventArgs e )
		{
			this.Close();
		}
	}
}

これを実行すると、右上隅の閉じるボタンが無効化されます。(淡色化してますよね)

Fig. 1 閉じるボタンが無効化されたウインドウ

左上隅でマウスをシングルクリックしてみてください、いつものメニューから「閉じる」が消えています。

Fig. 2 左上隅でマウスをシングルクリック

いちおう、通常の場合はこんな感じです。

Fig. 3 通常の場合