Windowsフォーム画面の最上部に表示される「タイトル・バー(別名:キャプション・バー)」には、小さなアイコン(例えば次の画面の(1))が左端に表示され、それに続いてタイトル文字列があり、右端には[最小化]ボタン(3)、[最大化/元に戻す]ボタン(4)、[閉じる]ボタン(5)がある。
Windowsフォームのタイトル・バーこのうち、右側の[最小化]ボタンを無効にするにはフォームのMinimizeBoxプロパティを、[最大化]ボタンを無効にするにはMaximizeBoxプロパティを、それぞれfalseに設定すればよい。しかし一番右端の[閉じる]ボタンを無効にするためのプロパティは用意されていない。では、この[閉じる]ボタンを無効にするにはどうすればよいのだろうか。
1つの解決策としては、フォームのControlBoxプロパティをfalseにすればよい。ControlBoxプロパティは、コントロールボックス(別名:システム・メニュー)を有効(true)/無効(false)にするためのプロパティである。ただし、このControlBoxプロパティをfalseにすれば、コントロールボックスだけでなく、左端のアイコン、[閉じる]ボタン、[最小化]ボタン、[最大化/元に戻す]ボタンなど、すべてのボタンとアイコンが非表示になってしまう。このとき、タイトル・バーを右クリックしてもコントロールボックス(システム・メニュー)は表示されない。
コントロールボックスを無効に設定したWindowsフォームしかしこのようにすべてのボタンを非表示にするのではなく、無効化するのは[閉じる]ボタンだけで、そのほかの小さなアイコン、[最大化/元に戻す]ボタン、[最小化]ボタンはそのまま残しておきたい場合もあるだろう。そのような場合は、Win32 APIを使う必要がある。
Win32 APIで[閉じる]ボタンの無効化を実装するには、フォームのコントロールボックス(システム・メニュー)を取得して、その中の[閉じる]メニュー項目(先ほどの画面「Windowsフォームのタイトル・バー」の(7))を削除すればよい。そうすれば、タイトル・バーの[閉じる]ボタンも自動的に無効化されるようになっている。
具体的には、Win32 APIのGetSystemMenu関数を呼び出してシステム・メニューのハンドルを取得し、RemoveMenu関数を呼び出してシステム・メニューから[閉じる]メニュー項目を削除する。
これらの関数の構文について簡単に説明する。なお、これらの関数のより詳しい説明は、MSDNの「プラットフォームSDK」を参照していただきたい。
IntPtr GetSystemMenu(IntPtr hWnd, UInt32 bRevert)
UInt32 RemoveMenu(IntPtr hMenu, UInt32 nPosition, UInt32 wFlags)
以上のWin32 API関数を使えば[閉じる]ボタンだけを無効化できるが、これだけではまだ完璧ではない。Windowsシステムには、アプリケーションを閉じるためのショートカット・キー「Altキー+F4キー」というものが存在する。このショートカット・キーを使えば、[閉じる]ボタンが無効であっても、右端にあった[閉じる]ボタンを押したのと同じようにWindowsフォームが閉じられてしまう。
よって、ショートカット・キーによりフォームが閉じられるのを阻止しなければ、[閉じる]ボタンを無効にした意味がない。次にその方法を解説しよう。ちなみに、ControlBoxプロパティをfalseにした場合も、アプリケーションを閉じるためのショートカット・キーは有効である。このため、その場合にも同じように次の処理が必要になるので注意していただきたい。
ショートカット・キーによってWindowsフォームが閉じられるのを防止するには、フォームが閉じられる直前に発生するClosingイベントのハンドラ・メソッドをまず追加する。そして、Closingイベント・ハンドラの第2パラメータであるCancelEventArgsクラス(System.ComponentModel名前空間)のオブジェクトのCancelプロパティにtrueを設定するだけでよい。
以上の内容を実装したサンプル・プログラムを次に示す。このプログラムでは、フォーム上に配置した[終了]ボタンがクリックされた場合にのみフォームを閉じるようにするため、フラグによりClosingイベント・ハンドラでの処理を制御している。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
  // Windowsフォームのクラス
  public class Form1 : System.Windows.Forms.Form
  {
    private System.Windows.Forms.Button button1;
    private System.ComponentModel.Container components = null;
    // コンストラクタ(初期化処理などを呼び出す)
    public Form1()
    {
      // 初期化処理
      InitializeComponent();
      // コントロールボックスの[閉じる]ボタンの無効化
      IntPtr hMenu = GetSystemMenu(this.Handle, 0);
      RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
    }
    // Win32 APIのインポート
    [ 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 const UInt32 SC_CLOSE = 0x0000F060;
    private const UInt32 MF_BYCOMMAND = 0x00000000;
    // 後処理(使用されているリソースの解放など)
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if(components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }
    // 初期化処理(コントロール属性の設定など)
    private void InitializeComponent()
    {
      // [閉じる]ボタンの追加
      this.button1 = new System.Windows.Forms.Button();
      // フォームとコントロールの属性を調整するため、
      // フォームのレイアウト処理を一時停止する
      this.SuspendLayout();
      //
      // button1
      //
      this.button1.Location = new System.Drawing.Point(104, 136);
      this.button1.Name = "button1";
      this.button1.TabIndex = 0;
      this.button1.Text = "終了";
      this.button1.Click += new System.EventHandler(this.button1_Click);
      //
      // Form1
      //
      this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
      this.ClientSize = new System.Drawing.Size(292, 182);
      this.Controls.Add(this.button1);
      this.Name = "Form1";
      this.Text = "Form1";
      this.Closing +=
        new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
      // フォームとコントロールの初期化が終わったので、
      // レイアウト処理の一時停止を解除する
      this.ResumeLayout(false);
    }
    // アプリケーションのメイン・エントリ・ポイント
    [STAThread]
    static void Main()
    {
      Application.Run(new Form1());
    }
    // [終了]ボタンが押されたかどうかの終了フラグ
    private bool bFinished = false;
    // [終了]ボタンを押されたとき、Windowsフォームを閉じる
    private void button1_Click(object sender, System.EventArgs e)
    {
      bFinished = true;  // 終了のためのフラグを立てる
      this.Close();  // Windowsフォームを閉じる
    }
    // Windowsフォームが閉じられる直前に呼ばれるイベント・ハンドラ
    private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
      // 終了フラグを立ってなければ、フォームが閉じられるのを阻止
      if (bFinished == true)
      {
        e.Cancel = false;
      }
      else
      {
        e.Cancel = true;
      }
    }
  }
}
これを実行すると、表示されるフォームは次のような画面になる。
[閉じる]ボタンだけが無効化されているWindowsフォームなお、.NETプログラムからWin32 APIを呼び出す方法については、別稿「TIPS:Win32 APIやDLL関数を呼び出すには?」を参照していただきたい。
カテゴリ:Windowsフォーム 処理対象:ダイアログ・ボックス
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
使用ライブラリ:CancelEventArgsクラス(System.ComponentModel名前空間)
関連TIPS:Win32 APIやDLL関数を呼び出すには?
Copyright© Digital Advantage Corp. All Rights Reserved.