VBAで指定したウィンドウを最前面に表示する【SetForegroundWindow関数(API)】
VBAでマクロを作っている時に「指定したウィンドウを最前面に表示したいな」という場面に出くわすことはないでしょうか?
たとえばWindows APIのマウス操作を可能にするmouse_event関数などでウィンドウ内の何かをクリックさせる場合には必ずそのウィンドウを最前面に持ってきておく必要があります。この他にも処理終わりに結果を最前面に表示するなど、指定したウィンドウを最前面にしたい場面は数多く存在すると思います。
という訳で今回はWindows APIを利用して指定したウィンドウを最前面に表示する方法を解説していきます。今回学ぶことのできる内容は以下のとおりです。
Windows APIについて
SetForegroundWindow関数の使い方
FindWindow関数の使い方
上記の関数で指定したウィンドウを最前面に表示する方法
指定したウィンドウを”常に”最前面表示させたい場合は下記ページを参照下さい。
SetForegroundWindow関数とは
VBAで指定のウィンドウを最前面に表示するにはWindows APIのSetForegroundWindow関数を使います。ただ、SetForegroundWindow関数を使用するには、最前面に表示させたいウィンドウ”そのもの”を取得する必要があります。
ウィンドウを取得する方法はいくつかありますが、ここではその代表格のFindWindow関数を使ってウィンドウを取得します。(FindWindow関数もWindows APIの関数)
・SetForegroundWindow関数 :指定したウィンドウを最前面に表示
・FindWindow関数 :指定したクラス名/ウィンドウ名を持つウィンドウのハンドルを返す
FindWindow関数の説明にあるウィンドウのハンドルとは各ウィンドウをそれぞれ個別に識別するための値で、このハンドルを引数としてSetForegroundWindow関数を使うことで、任意のウィンドウを最前面に表示するという操作を行うことが可能になります。
Windows APIとは
これらの関数はWindows APIで用意されているものでVBAとは別のものです。Windows APIとは簡単にいえばWindowsに用意されている機能がまとまっているセットのようなものです。
Windows APIには上記の関数以外にも様々な関数があり、VBA上でそれらを呼び出すことで、Windowsに用意されている様々な機能を使用することができます。(たとえばマウスを操作したり、指定した秒数だけ処理を止めることができます)
ちなみに名前からわかると思いますが、Windows APIではWindowsの機能を呼び出しているだけので基本的にはWindows以外のOSでは使用することはできません。
ウィンドウ名取得用の各関数の使い方
各関数を使うにははじめに「Windows APIの関数を使うよ」と宣言する必要があります。
※宣言をしないと各関数は使えずエラーになるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く内容が変わってきます。
以下のどちらかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
‘【SetForegroundWindow関数】
Declare PtrSafe Sub SetForegroundWindow Lib “user32” (ByVal hwnd As LongPtr)
‘【FindWindow関数】
Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
‘【SetForegroundWindow関数】
Declare Sub SetForegroundWindow Lib “user32” (ByVal hwnd 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 |
#If Win64 Then '【SetForegroundWindow関数】 Declare PtrSafe Sub SetForegroundWindow Lib "user32" (ByVal hwnd 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 '【SetForegroundWindow関数】 Declare Sub SetForegroundWindow Lib "user32" (ByVal hwnd 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 ERROR_SUCCESS = &H0 |
SetForegroundWindow関数は「ウィンドウハンドル(hwnd)」というものを引数で使用します。
ただ、この「hwnd」は64bitと32bitで型が変わってしまうため、上記ではそれぞれに合わせた変数を宣言しています。(64bit:LongPtr型、32bit:Long型)
また、ここではウィンドウハンドルが取得できなかった場合の戻り値となる「ERROR_SUCCESS」という定数を合わせて定義しています。値としては「0」ですが、正式にいえば16進数の「0x0」のため、ここでは「&H0」として定義しています。
SetForegroundWindow関数の構文
ウィンドウ名を取得するためのSetForegroundWindow関数の構文は以下のように書きます。
SetForegroundWindow ハンドル
引数として最前面に表示したいウィンドウの「ハンドル」を入力するだけです。
ウィンドウのハンドルを取得するには下記の「FindWindow関数」や「GetNextWindow関数」などのWindows API関数を利用することで取得することができます。
SetForegroundWindow 関数 (winuser.h) – Win32 apps
FindWindow関数の構文
指定したウィンドウのハンドルを取得するためのFindWindow関数の構文は以下のように書きます。
ハンドル = FindWindow(クラス名, ウィンドウ名)
第一引数には「クラス名」、第二引数には「ウィンドウ名」をそれぞれ入力します。
これにより入力したクラス名/ウィンドウ名をもつウィンドウのハンドルを取得することができます。
クラス名/ウィンドウ名を指定しない場合は空の文字列(vbNullString)を入力します。
たとえば「メモ帳」ウィンドウのハンドルを取得したい場合、メモ帳を開いた状態で
hwnd = FindWindow(“Notepad”, vbNullString) もしくは、
hwnd = FindWindow(vbNullString, “無題 – メモ帳”) のいずれかで取得できます。
ウィンドウ名はウィンドウに表示されているキャプション名、クラス名はアプリケーションごとに特定の名前が付けられています。ウィンドウ名はそのウィンドウを見ればすぐに調べることができますが、クラス名はそれ用のツールを使って調べる必要があります。詳しくは「(アプリケーション名) クラス名」などで検索してみて下さい。
FindWindowA 関数 (winuser.h) – Win32 apps | Microsoft Learn
ウィンドウ最前面表示サンプルコード
これまでの内容をまとめてVBAマクロとして使用する場合は以下のように書きます。
以下のコードを実行すると、現在開いている「メモ帳」(“無題 – メモ帳”というキャプション) のウィンドウを取得して最前面に表示することができます。
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 |
Option Explicit #If Win64 Then '【SetForegroundWindow関数】 Declare PtrSafe Sub SetForegroundWindow Lib "user32" (ByVal hwnd 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 '【SetForegroundWindow関数】 Declare Sub SetForegroundWindow Lib "user32" (ByVal hwnd 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 ERROR_SUCCESS = &H0 '------------------------------------------------------------------------------------- Sub main() 'クラス名からハンドルを取得する場合 hwnd = FindWindow("Notepad", vbNullString) 'ウィンドウ名からハンドルを取得する場合 hwnd = FindWindow(vbNullString, "無題 - メモ帳") 'ハンドルが取得できなかった場合 If hwnd = ERROR_SUCCESS Then MsgBox "該当のウィンドウが開かれていません。" Exit Sub End If '取得したハンドルのウィンドウを最前面表示 SetForegroundWindow hwnd End Sub |
上記のコードで気を付けないといけないのは、「メモ帳」が画面上にある必要があるという点です。ウィンドウが最小化されている場合は最前面に表示しても画面には表示されないなので注意して下さい。
まとめ
今回はWindows APIを使って指定したウィンドを最前面に表示する方法についてでした。
この関数を使うことでExcelやAccess以外のアプリケーションのウィンドウも操作することが可能になります。あとはmouse_event関数などその他のAPIと連携させることでRPAのようなことを実現することも可能です。(少し不安定ではありますが)
Windows APIは今回のもの以外にも多くのものがあるため、知識として頭に入れておくだけでもマクロで作成できる幅が増えます。興味がある方はぜひ他のWindows APIの関数も調べてみてください。