【VBA】起動している全てのメモ帳を一度に閉じるマクロ (Windows API)

目次

はじめに

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

これが、全てのウィンドウを閉じるためのループ処理です。

  1. まずループの前に FindWindow を実行し、メモ帳が一つでも存在するか確認します。
  2. Do While ループは、windowHandle0 でない限り(=メモ帳のウィンドウがまだ見つかる限り)続きます。
  3. ループの中で、見つけ出したウィンドウを SendMessage で閉じます。
  4. そして、再び FindWindow を実行して、まだ他に残っているメモ帳がないかを探します。
  5. 全てのメモ帳が閉じられると、FindWindow0 を返すため、ループが終了します。

まとめ

今回は、Windows APIの FindWindowSendMessage を組み合わせて、起動中の特定のアプリケーションを全て閉じるという、高度なテクニックを解説しました。

  • FindWindow で、目的のウィンドウのハンドルを取得する。
  • SendMessageWM_SYSCOMMANDSC_CLOSE を渡して、ウィンドウに閉じる命令を送る。
  • これを Do While ループで繰り返すことで、全てのウィンドウを閉じることができる。

このマクロを使えば、複数のファイルを開いて作業を開始する前に、前回の作業で開きっぱなしになっていた関連アプリケーションを一旦全てリセットする、といったクリーンアップ処理を自動化できます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次