VBAでウインドウを取得するのによく使うWindowsAPIとその使い方

スポンサーリンク

WindowsAPIを使用すると色々な手順でウインドウが取得できる

前回はAppActivateメソッドを用いて、操作対象のウインドウをアクティブにするVBAコードを紹介しました。

この方法はコードが簡単で記述しやすいのですが、キャプション名というウインドウに表示されている名称を正確に記載しなければエラーになる難点があり、キャプション名が不明な場合操作できない問題点があります。

WindowsAPIの関数を使用するとキャプション名がわからない場合やキャプション名の一部しかわからない場合でもウインドウを取得できるようになります。

今回はウインドウを取得するのによく使われるプロパティとWindowsAPIをいくつか紹介します。

ウインドウを取得するのに必要なプロパティ

ウインドウには「ウインドウハンドル」「クラス名」「キャプション名」のプロパティがあり、これらのうち最低1つか、場合によっては2つの値を把握することでウインドウを取得できます。

キャプション名を把握している場合は以前にご紹介したAppActivateでウインドウを取得できます。

その他のケースにおいてはどの情報を取得しているかで使用するWindowsAPIの関数が変わってきます。

①ウインドウハンドル

ウインドウごとに割り振られる固有の数値で、WindowsAPIを使用してのウインドウの取得に使う基本の値となります。

WindowsAPIではウインドウハンドルを取得して様々な処理行いますが、このウインドウハンドルはウインドウが開かれるたびに新しい値が割り振られるため、毎回値を取得しなおす必要があります。

ウインドウハンドルを取得している場合、「SetForegroundWindow」関数を用いて対象とするウインドウを最前面に表示する(=アクティブにする)ことができます。

②クラス名

アプリケーションごとに異なる文字列を表します。
エクスプローラーなら「CabinetWClass」、Excelなら「XLMAIN」となります。

同じアプリケーションのウインドウが1つだけの場合、クラス名を知っていれば「FindWindow」関数を使用してウインドウハンドルを取得することができます。

ウインドウハンドルを取得した後は①の通り「SetForegroundWindow」関数を使ってウインドウを最前面に表示することができます。

同じクラス名で複数のウインドウが起動されている場合はキャプション名が必要になります。
キャプション名が一部しかわからない場合は全部のウインドウハンドルとキャプションを取得し、該当するウインドウハンドルを選ぶ必要があります。

③キャプション名

キャプション名はほとんどの場合、アプリケーションウインドウの上部に表示される文字列です。
ほぼ固有の名称ですが、同じアプリで同じファイルを複数開いた場合などまれに重複することがあります。

アプリケーションウインドウの上部に表示されている場合はそのままでOK、表示がなかったり、スペースが半角か全角かわからないなどの場合は全部のウインドウハンドルとキャプション名を取得してその中から該当するウインドウハンドルを決定します。

スポンサーリンク

ウインドウを取得するのによく使うWindowsAPI関数

ウインドウを取得するのによく使うWindowsAPIの関数は以下のようなものがあります。
それぞれの使い方を記載します。

①SetForegroundWindow

引数に指定したハンドルのウインドウを最前面に表示するAPIです。
引数がウインドウハンドル一つで使い方がわかりやすいAPIです。

構文:SetForegroundWindow (ウインドウハンドル)
宣言部分:Declare Sub SetForegroundWindow Lib “user32” (ByVal hWnd As Long)

Declare Sub SetForegroundWindow Lib “user32” (ByVal hWnd As Long)

Sub ウインドウハンドルで取得したウインドウを最前面にする関数()

SetForegroundWindow 263636

End Sub

上記は私の現在の環境でのウインドウハンドルを記入してウインドウを取得しています。

ウインドウハンドルの数字がそのままわかることはあまりないので、通常はSetForegroundWindowを使用する前にウインドウハンドルを取得するステップを行っていると思います。

②FindWindow

ウインドウハンドルを取得するAPI関数です。

①のSetForegroundWindowとは異なり関数としての戻り値があり、ウインドウハンドルが返されます。

構文:ウインドウハンドル = FindWindow(“クラス名”, “キャプション名”)
宣言部分:Declare Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

クラス名・キャプション名が不明な場合、「VbNullString」と記入すると複数あるウインドウのうち、ウインドウハンドルの値が最も小さいものを取得するようです。

クラス名・キャプション名をどちらも「VbNullString」にすると一番最初のウインドウを取得することができます。

③GetWindowText

ウインドウハンドルからキャプション名を取得するAPI関数です。

構文:GetWindowText ウインドウハンドル, キャプション名を格納する変数, Len(キャプション名を格納する変数)
宣言部分:Declare Function GetClassName Lib “user32” Alias “GetClassNameA” (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount 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

Sub ウインドウハンドルからキャプション名を取得する()

Dim strCaption As String * 80 ’最大文字数80の文字列型変数 関数で取得した加工前のキャプション名を格納する
GetWindowText 263636, strCaption, Len(strCaption)

Dim キャプション名 ’加工後のキャプション名
キャプション名 = Left(strCaption, InStr(strCaption, vbNullChar) – 1)

MsgBox キャプション名

End Sub

少し不思議な感じがするのですが、
GetWindowText 263636, strCaption, Len(strCaption)
と記入するとウインドウハンドル「263636」のウインドウのタイトルがstrCaptionという変数に格納されます。

この関数自体の戻り値をrc= GetWindowText 263636, strCaption, Len(strCaption) のように設定してrcがキャプション名になるわけではないので注意が必要です。

私はこのイメージがなかなかつかめなくてなかなか使いこなせませんでした。

また、GetWindowTextで取得したキャプション名には文字がなくなった後にNull値が含まれているらしく、そのNull値を除くためにLeft関数でNull値が出てくる直前までの文字数を抜き出す必要があります。

④GetClassName

ウインドウハンドルからクラス名を取得するAPIです。
使い方はキャプション名を取得するGetWindowTextとほぼ同じです。

構文:GetClassName ウインドウハンドル, クラス名を格納する変数, Len(クラス名を格納する変数)
宣言部分:Declare Function GetClassName Lib “user32” Alias “GetClassNameA” (ByVal hWnd As Long, 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

Sub ウインドウハンドルからクラス名を取得する()

Dim strClassName As String * 80 ’最大文字数80の文字列型変数 関数で取得した加工前のクラス名を格納する
GetClassName 263636, strClassName, Len(strClassName)

Dim クラス名 ’加工後のクラス名
クラス名 = Left(strClassName, InStr(strClassName, vbNullChar) – 1)

MsgBox クラス名

End Sub

⑤IsWindowVisible

引数に指定したウインドウハンドルを持つウインドウが可視かどうか判定します。
可視の場合「1」、不可視の(見えない)場合「0」を返します。

これはC言語のTRUE、FALSEに相当する値ですが、VBAとは正の場合の値が異なります。
VBAでのTrueは「-1」なので「If~End If」を使用した条件分岐ではTrueを使ってもきちんと判定できません。

C言語、VBAで共通の値である「False(0)」を用いて判定するようにしてください。

構文:IsWindowVisible(ウインドウハンドル)
宣言部分:Declare Function IsWindowVisible Lib “user32” (ByVal hWnd As Long) As Long

Declare Function IsWindowVisible Lib “user32” (ByVal hWnd As Long) As Long

Sub ウインドウが可視か確認する()

If IsWindowVisible(263636) <> False Then
MsgBox “可視”
Else
MsgBox “不可視”
End If

End Sub

「If IsWindowVisible(263636) <> False Then」の部分は「If IsWindowVisible(263636) Then」とすることでも判定可能です。
慣れてくればこちらの使い方の方が本来の使い方の気がします。

この関数も①SetForegroundWindowと同じくウインドウハンドルが必要なので、他のAPIなどでウインドウハンドルを取得した上で使用したり、他のAPIを用いて、開いているウインドウの情報をすべて取得する場合などに使用するもので、このAPI関数単独で使用する機会はほぼないと思います。

⑥GetNextWindow

構文①:ウインドウハンドル = GetNextWindow(ウインドウハンドル, GW_HWNDNEXT)
構文②:ウインドウハンドル = GetNextWindow(ウインドウハンドル, GW_HWNDLAST)
宣言部分:Declare Function GetNextWindow Lib “user32” Alias “GetWindow” (ByVal hWnd As Long, ByVal wFlag As Long) As Long
Const GW_HWNDLAST = 1
Const GW_HWNDNEXT = 2

指定したウインドウハンドルの次のウインドウハンドルを取得します。

Do~loopを用いて開いているウインドウのウインドウハンドルをすべて取得する場合などに重宝するAPIです。

定数部分は宣言せずに第二引数に数字を入力しても動作しますが、数字だけだとわかりにくくなるので宣言しておく方がおすすめです。
最初のウインドウを指定することもできますが、最初の指定はウインドウハンドルを必要としない「FindWindow(vbNullString, vbNullString)」の方が便利です。

今回紹介したウインドウ取得に関するAPIを使用して実際にウインドウハンドルを取得したり、ウインドウを最前面に移動する方法はこちらの記事で紹介します。

おすすめ書籍 (広告)

コメント