【VBA×WindowsAPI】GetWindowText関数の使い方
GetWindowText関数
GetWindowText関数は指定したウィンドウのタイトルバーの文字列(キャプション)を取得するための関数です。たとえばGetWindowText関数でVBAのUserFormウィンドウのキャプションを取得すると「UserForm.Caption」で取得できる値と同じ結果を得ることができます。
ちなみにGetWindowText関数と関係性の深い関数として、指定ウィンドウのキャプションの文字数を取得するGetWindowTextLength関数や、対の存在となる指定したウィンドウのキャプションに指定の文字列を設定するSetWindowText関数が存在します。
使用方法
GetWindowText関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
Declare PtrSafe Function GetWindowText Lib “user32” Alias “GetWindowTextA” _
(ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowText Lib “user32” Alias “GetWindowTextA” _
(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。
1 2 3 4 5 |
#If VBA7 Then Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long #Else Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long #End If |
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。
・Public Declare PtrSafe Function~ :モジュール外で呼び出し有効
構文
GetWindowText関数の構文は下記のように書きます。
lRet = GetWindowText(hWnd, lpString, nMaxCount)
引数
hWnd (64bit:LongPtr型 / 32bit:Long型)
ウィンドウ名(キャプション)を取得したいウィンドウのハンドルを入力します。
ウィンドウハンドルを取得するための関数としてFindWindow関数やGetActiveWindow関数、GetNextWindow関数、GetParent関数など様々なものがあります。
開発(実行)環境によって変数の型が変わるので注意が必要です。
lpString (String型)
取得したウィンドウ名を格納するための空の固定長文字列を入力します。
一般的にString型は可変長文字列として扱われることが多いため、固定長文字列はあまり聞き馴染みのない言葉かもしれませんが、可変長と固定長の違いは文字通り文字列のサイズ(文字の入るサイズ)が決まっているか決まっていないかです。
String型の文字列を固定長文字列として扱うには「Dim 〇 As String * 7」のように記載して宣言します。この宣言文の場合、変数には最大7文字までの文字列しか入りませんし、7文字より少ない文字列を入れたとしても足りない分は空文字で7文字になるように補完されます。
つまりこの引数にはウィンドウ名がすべて収まるくらいの大きさを持った固定長文字列を宣言してそのまま入力するだけです。文字列の長さが短いと取得したウィンドウ名が途切れてしまう可能性があるので大きめにとっておく必要があります。(100文字分くらいあれば基本的にはすべて取得できます)
GetWindowTextLength関数を使うことで予め固定長文字列のサイズを決めることもできます。
nMaxCount (Long型)
取得するウィンドウ名の最大文字数を入力します。
第2引数と同じく小さく設定しすぎると取得したウィンドウ名が途切れてしまう可能性があるので、確実に取得するには大きめに設定しておく必要があります。VBAではLen関数を使って固定長文字列と同じ値になるようにしておくのが一般的です。
戻り値
lRet (Long型)
戻り値は関数が成功した場合、取得できたウィンドウ名の文字数が返ります。
(※文字が全角の場合は2文字分の扱いとなるので実際の文字数とは異なる場合があるので注意)
関数が失敗した場合の戻り値は0が返されます。
サンプルコード
以下はFindWindow関数とGetWindowText関数を使って、指定のウィンドウのキャプションを取得するサンプルコードです。下記コードではExcelのウィンドウのうち最前面にあるウィンドウのキャプションを取得することができます。ちなみに「XLMAIN」部分(クラス名)を書き換えることでExcel以外の任意のアプリケーションを指定することもできます。
詳しくはFindWindow関数/GetClassName関数ページを参照下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long Sub main() Dim hwnd As LongPtr Dim lRet As LongPtr Dim sBuf As String * 100 Dim sCap As String '最前面にあるExcelのウィンドウハンドルを取得 hwnd = FindWindow("XLMAIN", vbNullString) '取得したハンドルのウィンドウ名を取得(固定長文字列) lRet = GetWindowText(hwnd, sBuf, Len(sBuf)) '不要なバッファ分は削除 sCap = Left(sBuf, InStr(sBuf, vbNullChar) - 1) '取得したウィンドウ名をイミディエイトウィンドウに出力 Debug.Print sCap End Sub |
このコードで特筆すべき点は「不要なバッファ分は削除」の部分です。
GetWindowText関数実行の結果、固定長文字列である「sBuf」に指定ウィンドウのキャプションが格納されました。しかしVBEのローカルウィンドウで確認するとわかる通り「sBuf」の中にはウィンドウ名の後ろに「・・・」と謎の文字が続いています。この「・」はVBAではvbNullCharにあたります。
最終的には、この不要なデータであるvbNullChar部分を除去する必要があります。方法は様々ですがサンプルコード記載の方法がもっとも単純で汎用性もあります。これはVBAでは馴染みのある「特定文字より左側の文字列を取得する」という処理です。最も左側にあるvbNullChar(・表示)より左側にある文字列のみをすべて取得する方法です。
GetClassName関数の戻り値は文字数なのでそれを利用するというのも手ですが、全角文字が含まれている場合には文字数の調整が必要になるので注意が必要です。
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:GetWindowTextA 関数 (winuser.h) – Win32 apps