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