【VBA×WindowsAPI】FindWindow関数の使い方

FindWindow関数

FindWindow関数は指定したウィンドウ名(キャプション名)もしくはクラス名を持つウィンドウへのハンドルを取得するための関数です。

ウィンドウハンドルは、ウィンドウを識別するための特別な識別子です。
ウィンドウを開いたり閉じたり、移動させたり、サイズを変えたり、テキストを変更したりするなど、ウィンドウに対して行いたい様々な操作を指示する際に使用します。このウィンドウに対する操作もWindowAPIに用意されている何種類もの関数で行うことが可能です。

ウィンドウハンドルはC++では「HWND型」という型で扱いますが、中身としては長整数型の値であるためVBAではLongPtr型(32bitではLong型)を使用します。VBAでウィンドウハンドルを格納する変数はC++の型に合わせてhWndなどと記載することが多いです。

ウィンドウハンドルは、ウィンドウが作成されるときに自動的に割り当てられます。
そして、そのウィンドウが存在している間は一貫して有効ですが、ウィンドウが閉じられると無効になります。つまりハンドルを取得すると毎回値が違うウィンドウも存在するということです。

VBAにおいてはUserFormもウィンドウであるため、たとえばUserFormを最前面に移動させたり、サイズを変更できるようにしたり、半透明にしたりと様々な操作を行うことが可能になります。このとき、その操作の対象となるUserFormへのハンドルを取得するための関数がFindWindow関数という訳です。この他にもGetActiveWindow関数GetNextWindow関数GetParent関数といったウィンドウハンドルを取得するための関数は何種類も存在します。

“どの条件で取得するか”という状況に合わせて柔軟に取得方法を変える必要がありますが、ウィンドウハンドルを取得する最も一般的な手法の一つがFindWindow関数です。

 

使用方法

FindWindow関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。

使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。

 icon-code  64bit  

Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

icon-code  32bit  

Declare Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。

 
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。

Private Declare PtrSafe Function~ :モジュール内でのみ呼び出し有効
Public Declare PtrSafe Function~ :モジュール外で呼び出し有効

 
 

構文

FindWindow関数の構文は下記のように書きます。

icon-code FindWindow関数 

hwnd = FindWindow(lpClassName, lpWindowName)

引数

 lpClassName   (String型) 

ハンドルを取得したいウィンドウのクラス名を入力します。
クラス名(ウィンドウクラス名)とはウィンドウを区別するためにつけられている名前です。アプリケーションごとに違った名前がつけられているので、ハンドルを取得したいウィンドウが何のアプリケーションによって開かれているかをクラス名で指定します。

下記はVBA操作でよく利用されるアプリケーションのウィンドウクラス名です。
その他のアプリケーションのクラス名はGetClassName関数で調べることが可能です。

アプリケーション ウィンドウクラス名
Excel XLMAIN
PowerPoint PPTFrameClass
Word OpusApp
メモ帳 Notepad
エクスプローラー CabinetWClass
UserForm ThunderDFrame

本引数にNULL値(vbNullString)を入力した場合、lpWindowNameで取得できる全てのウィンドウがハンドルの取得対象となります。lpWindowNameだけで確実に指定のウィンドウハンドルが取得できるという場合はvbNullStringを入力していても問題ありません。
 

 lpWindowName   (String型) 

ハンドルを取得したいウィンドウのキャプション名を入力します。
UserFormもウィンドウ扱いのため、下記のように書くことでUserForm1のウィンドウハンドルを取得することが可能です。(これによりUserFormの可変化や透明化などの操作が行えます)

NULL値(vbNullString)の場合、全てのウィンドウハンドルが取得対象となります。 
  

戻り値

 hwnd    (64bit:LongPtr型 / 32bit:Long型) 

戻り値は関数が成功した場合、引数で指定したクラス名とウィンドウ名を持つウィンドウへのハンドルです。(条件に当てはまるウィンドウが複数ある場合は、より前面にあるもの)

関数が失敗した場合の戻り値はNULL値(0)となります。
引数と同じく開発(実行)環境によって戻り値の型が変化するので注意が必要です。
  

―  icon-edit  取得ウィンドウの優先順位  ―画面に表示されているウィンドウは奥行きというものが存在しています。
ウィンドウの並び順は内部で情報として保持されており、最前面を切り替えるたびにリアルタイムで更新されています。これは基本的には画面上に表示されているとおりの並びです。
  
FindWindow関数はこの並び順の前面にあるものから優先して取得していきます。
たとえばlpClassNameに”XLMAIN”と入力している場合は、最も前面にあるExcelウィンドウのハンドルが取得できます。また、この優先順位はlpClassName, lpWindowNameのいずれもを”vbNullString”とした場合でも同じです。つまり両方の引数が”vbNullString”の場合は最前面にあるウィンドウのハンドルが取得できるということです。

 

サンプルコード

以下はFindWindow関数GetWindowText関数のそれぞれを使って、特定のウィンドウのキャプション名を取得するサンプルコードです。Excelを開いている場合は、その中でも最前面にいるウィンドウのキャプションが取得できます。

また、逆パターンとして以下はFindWindow関数GetClassName関数を使って、特定のウィンドウのクラス名を取得するサンプルコードです。コマンドプロンプトを開いている状態で実行すると、コマンドプロンプトのクラス名を取得することができます。こちらのサンプルの場合はウィンドウをキャプション名から探索しているので、同名のウィンドウがより前面に存在した場合はそちらへのハンドルが取得されてしまうので注意が必要です。

いずれもFindWindow関数で特定のウィンドウへのハンドルを取得できていることが確認できます。

 

 icon-share-square  VBA×WindowsAPIまとめページ

その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。

 icon-share-square  参考

Microsoft公式:FindWindowA 関数 (winuser.h) – Win32 apps

2023年7月16日Excel, VBA, Windows API

Posted by Lic