VBAでウィンドウ名(キャプション)をまとめて取得する方法【GetWindowText関数(API)】
VBAでマクロを作っている時に「今表示してるウィンドウ名(キャプション)をまとめて取得したいな」という場面に出くわすことはないでしょうか?
通常、VBAの機能だけでは取得することはできませんが、Windowsに標準装備されているWindows APIというものを利用すれば、VBAでもウィンドウ名を取得する取得することが可能になります。
という訳で今回はWindows APIを利用してウィンドウ名(キャプション)をまとめて取得する方法を解説していきます。今回学ぶことのできる内容は以下のとおりです。
Windows APIについて
GetWindowText関数の使い方
FindWindow関数の使い方
GetNextWindow関数の使い方
IsWindowVisible関数の使い方
上記の4つの関数で表示されているウィンドウ名(キャプション)を取得する方法
GetWindowText関数とは
VBAでウィンドウ名を取得するにはWindows APIのGetWindowText関数を使います。
ただ、GetWindowText関数はウィンドウ名を取得する関数ですが、それ以前にウィンドウそのものを取得する必要があります。そこで、ここではウィンドウ名を取得する際に必要もしくはあると便利なWindows APIの関数をまとめて紹介します。
・GetWindowText関数 :指定したウィンドウのウィンドウ名(キャプション)を返す
・FindWindow関数 :指定したクラス名/ウィンドウ名を持つウィンドウのハンドルを返す
・GetNextWindow関数:指定したウィンドウの次のウィンドウのハンドルを返す
・IsWindowVisible関数:指定したウィンドウの表示状態を返す
ウィンドウのハンドルとは各ウィンドウをそれぞれ個別に識別するための値で、このハンドルを引数として上記の関数を使うことで、任意のウィンドウに対してそれぞれの関数の操作を行うことが可能になります。
上記の通り、ウィンドウ名の取得自体はGetWindowText関数を使いますが、どのウィンドウかを指定するためにウィンドウのハンドルを取得する必要があります。このウィンドウのハンドルはFindWindow関数とGetNextWindow関数で取得することができます。
Windows APIとは
これらの関数はWindows APIで用意されているものでVBAとは別のものです。Windows APIとは簡単にいえばWindowsに用意されている機能がまとまっているセットのようなものです。
Windows APIには上記の関数以外にも様々な関数があり、VBA上でそれらを呼び出すことで、Windowsに用意されている様々な機能を使用することができます。(たとえばマウスを操作したり、指定した秒数だけ処理を止めることができます)
ちなみに名前からわかると思いますが、Windows APIではWindowsの機能を呼び出しているだけので基本的にはWindows以外のOSでは使用することはできません。
ウィンドウ名取得用の各関数の使い方
各関数を使うにははじめに「Windows APIの関数を使うよ」と宣言する必要があります。
※宣言をしないと各関数は使えずエラーになるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く内容が変わってきます。
以下のどちらかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
‘【GetNextWindow関数】
Declare PtrSafe Function GetNextWindow Lib “user32” Alias “GetWindow” _
(ByVal hwnd As LongPtr, ByVal wFlag As Long) As LongPtr
‘【IsWindowVisible関数】
Declare PtrSafe Function IsWindowVisible Lib “user32” _
(ByVal hwnd As LongPtr) As LongPtr
‘【GetWindowText関数】
Declare PtrSafe Function GetWindowText Lib “user32” Alias “GetWindowTextA” _
(ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As LongPtr
‘【FindWindow関数】
Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
‘【GetNextWindow関数】
Declare Function GetNextWindow Lib “user32” Alias “GetWindow” _
(ByVal hwnd As Long, ByVal wFlag As Long) As Long
‘【IsWindowVisible関数】
Declare Function IsWindowVisible Lib “user32” _
(ByVal hwnd As Long) As Long
‘【GetWindowText関数】
Declare Function GetWindowText Lib “user32” Alias “GetWindowTextA” _
(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
‘【FindWindow関数】
Declare Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
※操作環境のbitと構文があっていないとエラーになるので注意しましょう。
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部(Option Explicitの次あたり)に書いておきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#If Win64 Then '【GetNextWindow関数】 Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" _ (ByVal hwnd As LongPtr, ByVal wFlag As Long) As LongPtr '【IsWindowVisible関数】 Declare PtrSafe Function IsWindowVisible Lib "user32" _ (ByVal hwnd As LongPtr) As LongPtr '【GetWindowText関数】 Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" _ (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As LongPtr '【FindWindow関数】 Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Dim hwnd As LongPtr #Else '【GetNextWindow関数】 Declare Function GetNextWindow Lib "user32" Alias "GetWindow" _ (ByVal hwnd As Long, ByVal wFlag As Long) As Long '【IsWindowVisible関数】 Declare Function IsWindowVisible Lib "user32" _ (ByVal hwnd As Long) As Long '【GetWindowText関数】 Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _ (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long '【FindWindow関数】 Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Dim hwnd As Long #End If |
また、これらの関数は「ウィンドウハンドル(hwnd)」というものを引数で使用します。
ただ、この「hwnd」は64bitと32bitで型が変わってしまうため、上記ではそれぞれに合わせた変数を宣言しています。(64bit:LongPtr型、32bit:Long型)
GetWindowText関数の構文
ウィンドウ名を取得するためのGetWindowText関数の構文は以下のように書きます。
GetWindowText ハンドル, ウィンドウ名, 文字数
第一引数にはどのウィンドウかを指示するための「ハンドル」、
第二引数には「ウィンドウ名」を取得する用の空の変数、
第三引数には取得するキャプションの最大の「文字数」をそれぞれ入力します。
たとえば「ウィンドウ名=”Microsoft”」「文字数=5」の場合、「Micro」までが取得されます。
そのため「文字数=Len(ウィンドウ名)」としておけばウィンドウ名の全文字が取得できます。
GetWindowText関数 – Win32 apps | Microsoft Learn
FindWindow関数の構文
指定したウィンドウのハンドルを取得するためのFindWindow関数の構文は以下のように書きます。
ハンドル = FindWindow(クラス名, ウィンドウ名)
第一引数には「クラス名」、第二引数には「ウィンドウ名」をそれぞれ入力します。
これにより入力したクラス名/ウィンドウ名をもつウィンドウのハンドルを取得することができます。
特にクラス名/ウィンドウ名を指定しない場合は空の文字列を入力します。
FindWindowA 関数 (winuser.h) – Win32 apps | Microsoft Learn
GetNextWindow関数の構文
指定したウィンドウの次のウィンドウのハンドルを取得するための
GetNextWindow関数の構文は以下のように書きます。
ハンドル’ = GetNextWindow(ハンドル, フラグ)
第一引数には基準ウィンドウとなるウィンドウの「ハンドル」、
第二引数には「フラグ」にはウィンドウの検索方法に合わせて下表の定数を入力します。
定数 | 値 | 内容 |
GW_HWNDFIRST | 0 | 最前面のウィンドウを検索 |
GW_HWNDLAST | 1 | 最背面のウィンドウを検索 |
GW_HWNDNEXT | 2 | 基準ウィンドウの次のウィンドウを検索 |
GW_HWNDPREV | 3 | 基準ウィンドウの前のウィンドウを検索 |
GW_OWNER | 4 | 基準ウィンドウのオーナーウィンドウを検索 |
GW_CHILD | 5 | 基準ウィンドウの子ウィンドウのうちトップレベルのウィンドウを検索 |
結果として2つの引数により検索されたウィンドウのハンドル(ハンドル’)が返ってきます。
GetNextWindow マクロ (winuser.h) – Win32 – Microsoft Learn
IsWindowVisible関数の構文
ウィンドウの表示状態を取得するためのIsWindowVisible関数の構文は以下のように書きます。
IsWindowVisible(ハンドル)
第一引数には表示状態を確認するウィンドウの「ハンドル」を入力します。
指定したウィンドウが表示状態の場合は「0以外」、非表示状態の場合は「0」が返ります。
表示状態の場合にのみ何かしらの処理を行いたい場合は、
「If IsWindowVisible(ハンドル) Then ~ End If」の条件分岐を入れればOKです。
IsWindowVisible 関数 (winuser.h) – Win32 apps – Microsoft Learn
ウィンドウ名(キャプション)取得サンプルコード
これまでの内容をまとめてVBAマクロとして使用する場合は以下のように書きます。
以下のコードを実行すると、現在表示されていウィンドウ名をすべて取得することができます。
取得したウィンドウ名はすべて「caps」というコレクションに文字列として格納されます。サンプルコードでは「Debug.Print」を使って取得結果をイミディエイトウィンドウに出力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
Option Explicit #If Win64 Then '【GetNextWindow関数】 Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" _ (ByVal hwnd As LongPtr, ByVal wFlag As Long) As LongPtr '【IsWindowVisible関数】 Declare PtrSafe Function IsWindowVisible Lib "user32" _ (ByVal hwnd As LongPtr) As LongPtr '【GetWindowText関数】 Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" _ (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As LongPtr '【FindWindow関数】 Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Dim hwnd As LongPtr #Else '【GetNextWindow関数】 Declare Function GetNextWindow Lib "user32" Alias "GetWindow" _ (ByVal hwnd As Long, ByVal wFlag As Long) As Long '【IsWindowVisible関数】 Declare Function IsWindowVisible Lib "user32" _ (ByVal hwnd As Long) As Long '【GetWindowText関数】 Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _ (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long '【FindWindow関数】 Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Dim hwnd As Long #End If Const GW_HWNDLAST = 1 Const GW_HWNDNEXT = 2 '------------------------------------------------------------------------------------- Sub main() Dim strCaption As String * 500 hwnd = FindWindow(vbNullString, vbNullString) Dim caps As Collection Set caps = New Collection Dim cap 'As String Do If IsWindowVisible(hwnd) Then GetWindowText hwnd, strCaption, Len(strCaption) cap = Left(strCaption, InStr(strCaption, vbNullChar) - 1) If cap <> "" Then caps.Add cap End If End If hwnd = GetNextWindow(hwnd, GW_HWNDNEXT) Loop Until hwnd = GetNextWindow(hwnd, GW_HWNDLAST) For Each cap In caps Debug.Print cap Next cap End Sub |
まとめ
今回はWindows APIを使ってウィンドウ名を取得する方法についてでした。
指定したウィンドウを最前面に表示することができる関数もあるので、そういった関数と今回の内容を組み合わせることでExcelやAccessのようなアプリケーションの領域外の操作をすることも可能になります。
Windows APIは今回のもの以外にも多くのものがあるため、知識として頭に入れておくだけでもマクロで作成できる幅が増えます。興味がある方はぜひ他のWindows APIの関数も調べてみてください。