はじめに
VBAで、ユーザーに特定の操作を強制したい場合や、誤ってExcelを閉じられては困るような処理を実行している際に、「Excelウィンドウ右上の『閉じる』ボタン(×ボタン)を一時的に無効化したい」という、非常に高度な制御が必要になることがあります。
このようなExcelアプリケーション本体のウィンドウ操作は、Windows API関数を直接呼び出すことで実現可能です。この記事では、Excelのウィンドウメニューから「閉じる」項目を削除し、×ボタンをグレーアウトさせて無効化する、およびそれを元に戻すための、一連のテクニックを解説します。
【重要】 このマクロはExcelの基本的な動作を変更するため、使い方を誤るとExcelを正常に終了できなくなる可能性があります。必ず元に戻す方法とセットで、慎重に利用してください。
「閉じる」ボタンを無効化/有効化するVBAサンプルコード
APIを利用するためのDeclare
ステートメントやConst
(定数)は、モジュールの最上部(Sub
などのプロシージャよりも前)に記述する必要があります。
完成コード (API宣言 + 2つのマクロ)
'--- モジュールの最上部にAPI関数と定数を宣言 ---
' 64bit/32bit両対応
#If VBA7 Then
Private Declare PtrSafe Function GetSystemMenu Lib "user32" (ByVal hwnd As LongPtr, ByVal bRevert As Long) As LongPtr
Private Declare PtrSafe Function DeleteMenu Lib "user32" (ByVal hMenu As LongPtr, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As LongPtr) As Long
#Else
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
#End If
' DeleteMenuで使う定数
Private Const SC_CLOSE As Long = &HF060
Private Const MF_BYCOMMAND As Long = &H0
' --- マクロ1: Excelの「閉じる」ボタンを無効化する ---
Sub DisableExcelCloseButton()
Dim hMenu As LongPtr
' 1. Excelウィンドウのシステムメニューのハンドルを取得
hMenu = GetSystemMenu(Application.hwnd, 0&)
' 2. メニューから「閉じる」コマンドを削除
DeleteMenu hMenu, SC_CLOSE, MF_BYCOMMAND
' 3. メニューバーを再描画して変更を適用
DrawMenuBar Application.hwnd
MsgBox "「閉じる」ボタンを無効化しました。"
End Sub
' --- マクロ2: 無効化した「閉じる」ボタンを元に戻す(有効化する) ---
Sub EnableExcelCloseButton()
Dim hMenu As LongPtr
' 1. GetSystemMenuの第2引数を1にして、システムメニューを初期状態に戻す
hMenu = GetSystemMenu(Application.hwnd, 1&)
' 2. メニューバーを再描画して変更を適用
DrawMenuBar Application.hwnd
MsgBox "「閉じる」ボタンを有効化しました。"
End Sub
コードの解説
DisableExcelCloseButton
マクロ
hMenu = GetSystemMenu(Application.hwnd, 0&)
GetSystemMenu
: 指定したウィンドウのシステムメニュー(ウィンドウの左上アイコンクリックや、タイトルバーの右クリックで表示されるメニュー)への「ハンドル」(操作するための識別子)を取得します。Application.hwnd
: Excelアプリケーションのメインウィンドウのハンドルです。- 第2引数
0&
:False
と同じ意味で、「現在のメニューのハンドルを取得する」というモードです。
DeleteMenu hMenu, SC_CLOSE, MF_BYCOMMAND
DeleteMenu
: 指定したメニューから、特定のメニュー項目を削除します。- 第1引数
hMenu
: 操作対象のメニューのハンドル。 - 第2引数
SC_CLOSE
: 削除したいメニュー項目のIDです。SC_CLOSE
は「閉じる」コマンドのIDとしてWindowsに定義されています。 - 第3引数
MF_BYCOMMAND
: 第2引数がメニュー項目のIDであることを示します。
DrawMenuBar Application.hwnd
DrawMenuBar
: 指定したウィンドウのメニューバーを再描画する命令です。これを実行しないと、DeleteMenu
による変更が画面に反映されません。
EnableExcelCloseButton
マクロ
hMenu = GetSystemMenu(Application.hwnd, 1&)
:GetSystemMenu
の第2引数に1&
(True
) を渡すと、メニューが変更されていた場合に、それをオリジナルの初期状態にリセットする、という特別な動作をします。- これにより、削除した「閉じる」コマンドが元通りに復元されます。
まとめ
今回は、Windows APIを駆使して、Excelアプリケーションの「閉じる」ボタンを無効化、および有効化する方法を解説しました。
GetSystemMenu
でウィンドウのシステムメニューを取得。DeleteMenu
で「閉じる」コマンド (SC_CLOSE
) を削除。DrawMenuBar
で画面の表示を更新。- 元に戻すには、
GetSystemMenu
の第2引数を1
にして呼び出す。
このマクロは非常に強力なため、ユーザーがExcelを終了できなくなるリスクを常に伴います。必ず、EnableExcelCloseButton
のような復元マクロを用意し、Workbook_BeforeClose
イベントで自動的に有効化するなど、アプリケーションの終了を妨げないよう、慎重な設計を心がけてください。