はじめに
VBAマクロの実行中に、複数のメモ帳や電卓のウィンドウが開かれていると、作業の妨げになったり、処理の競合を引き起こしたりすることがあります。このような場合に、「起動している特定のアプリケーション(例: 全てのメモ帳)を、一度に全て閉じる」という処理を自動化できると非常に便利です。
このようなOSレベルのウィンドウ操作は、Windows API関数を組み合わせることで実現できます。
FindWindow
: 指定した条件のウィンドウを探し出す。SendMessage
: 見つけ出したウィンドウに対して、操作命令(メッセージ)を送信する。
この記事では、これらのAPI関数を使って、現在開いている全てのメモ帳のウィンドウを、ループ処理で一つずつ閉じていく、高度なテクニックを解説します。
全てのメモ帳を閉じるVBAサンプルコード
このマクロは、FindWindow
でメモ帳のウィンドウが見つからなくなるまで、SendMessage
で閉じる命令を送り続ける、という動作をします。
Declare
ステートメントや Const
は、モジュールの最上部(Sub
などのプロシージャよりも前)に記述する必要があります。
完成コード
'--- モジュールの最上部にAPI関数と定数を宣言 ---
' 64bit/32bit両対応
#If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
#Else
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#End If
' SendMessageで使う定数
Private Const WM_SYSCOMMAND As Long = &H112
Private Const SC_CLOSE As Long = &HF060&
' 起動している全てのメモ帳を閉じる
Sub CloseAllNotepadWindows()
Const APP_CLASS_NAME As String = "Notepad" ' メモ帳のウィンドウクラス名
Dim windowHandle As LongPtr
'--- 1. 最初のメモ帳ウィンドウを探す ---
windowHandle = FindWindow(APP_CLASS_NAME, vbNullString)
'--- 2. 見つからなかった場合の処理 ---
If windowHandle = 0 Then
MsgBox "メモ帳は起動していません。", vbInformation
Exit Sub
End If
'--- 3. ウィンドウが見つからなくなるまでループ ---
Do While windowHandle <> 0
'--- 4. SendMessageで閉じる命令を送信 ---
SendMessage windowHandle, WM_SYSCOMMAND, SC_CLOSE, 0
'--- 5. 次のメモ帳ウィンドウを探す ---
windowHandle = FindWindow(APP_CLASS_NAME, vbNullString)
' ExcelがフリーズしないようにCPUを解放
DoEvents
Loop
MsgBox "全てのメモ帳を閉じました。"
End Sub
コードの解説
FindWindow
API関数
FindWindow
は、指定したクラス名(例: "Notepad"
)やウィンドウタイトルに一致する、一番手前にあるウィンドウを探し出し、そのハンドル(識別子)を返します。見つからなければ 0
を返します。
SendMessage
API関数
SendMessage
は、指定したハンドルを持つウィンドウに対して、様々な**メッセージ(命令)**を送信するための、非常に強力なAPIです。
hwnd
: 命令を送る対象のウィンドウハンドル。wMsg
: 送信するメッセージの種類を指定します。WM_SYSCOMMAND
は、システムコマンド(最大化、最小化、閉じるなど)を送るためのメッセージです。wParam
: メッセージの追加情報です。SC_CLOSE
は、「ウィンドウを閉じる」という具体的なコマンドを指定する定数です。
つまり、SendMessage hwnd, WM_SYSCOMMAND, SC_CLOSE, 0
という一行は、「hwnd
で示されるウィンドウに対して、『閉じろ』というシステムコマンドを送りなさい」という意味になります。これは、ウィンドウの右上の「×」ボタンをクリックするのとほぼ同じ効果があります。
Do While windowHandle <> 0 ... Loop
これが、全てのウィンドウを閉じるためのループ処理です。
- まずループの前に
FindWindow
を実行し、メモ帳が一つでも存在するか確認します。 Do While
ループは、windowHandle
が0
でない限り(=メモ帳のウィンドウがまだ見つかる限り)続きます。- ループの中で、見つけ出したウィンドウを
SendMessage
で閉じます。 - そして、再び
FindWindow
を実行して、まだ他に残っているメモ帳がないかを探します。 - 全てのメモ帳が閉じられると、
FindWindow
は0
を返すため、ループが終了します。
まとめ
今回は、Windows APIの FindWindow
と SendMessage
を組み合わせて、起動中の特定のアプリケーションを全て閉じるという、高度なテクニックを解説しました。
FindWindow
で、目的のウィンドウのハンドルを取得する。SendMessage
にWM_SYSCOMMAND
とSC_CLOSE
を渡して、ウィンドウに閉じる命令を送る。- これを
Do While
ループで繰り返すことで、全てのウィンドウを閉じることができる。
このマクロを使えば、複数のファイルを開いて作業を開始する前に、前回の作業で開きっぱなしになっていた関連アプリケーションを一旦全てリセットする、といったクリーンアップ処理を自動化できます。