Win32API を呼び出してウィンドウの操作をする場合、操作したいウィンドウのハンドルを取得する必要がある。
たいていはウィンドウのタイトル文字列を頼りにハンドル(hWnd)を取得するのだが、完全なタイトル文字列(title_str)がわかっている場合は、API の FindWindow
関数で
hWnd = FindWindow(vbNullString, title_str)
と、簡単にハンドルを取得できる。が、タイトル文字列の一部を頼りにウィンドウハンドルを取得する場合は、ちょっと面倒くさくなる。
流れとしては、
- 基準となるウィンドウ(最前面の)ハンドルを取得する。
FindWindow
- 基準ウィンドウからスタートして、現在開いているすべての可視ウィンドウをループし、ウィンドウのタイトルを調べる。
GetWindowText
- タイトルの中に指定した文字が含まれている可視ウィンドウ
IsWindowVisible
があれば、ループを終了しウィンドウハンドルを取得する。GetWindow
WindowModule.bas
Option Explicit
'// API呼び出し(Declare)宣言
#If VBA7 Then
'// Office2010以降で64/32bit共通の宣言
'// 指定されたクラス名(lpClassName)とウィンドウ名(lpWindowName)を持つウィンドウのハンドルを返す
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
'// 指定されたウィンドウ(hWnd)と指定された関係(wCmd)にあるウィンドウのハンドルを返す
Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As LongPtr, ByVal wCmd As Long) As LongPtr
'// ウィンドウ(hWnd)のタイトルをバッファ(lpString)に格納する
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
'// ウィンドウの可視状態を取得する
Public Declare PtrSafe Function IsWindowVisible Lib "user32" (ByVal hWnd As LongPtr) As Long
#Else
'// Office2007以前での宣言
'// 指定されたクラス名(lpClassName)とウィンドウ名(lpWindowName)を持つウィンドウのハンドルを返す
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'// 指定されたウィンドウ(hWnd)と指定された関係(wCmd)にあるウィンドウのハンドルを返す
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
'// ウィンドウ(hWnd)のタイトル(lpString)を取得する
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
'// ウィンドウの可視状態を取得する
Public Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As Long) As Long
#End If
Private Const GW_HWNDNEXT As Long = 2
Private Const ERROR_SUCCESS As Long = 0
'// タイトルに cap_str が含まれるウィンドウのハンドルを返す
Function GetHwnd(ByVal cap_str As String) As LongPtr
Dim hWnd As LongPtr
Dim wCaption As String * 255
'// 基準となるウィンドウハンドルを取得
'// FindWindow は、どちらの引数にも vbNullString を指定すると
'// 最前面のウィンドウのハンドルを返す
hWnd = FindWindow(vbNullString, vbNullString)
Do Until hWnd = ERROR_SUCCESS
'// 可視ウィンドウのみ
If CBool(IsWindowVisible(hWnd)) Then
'// ウィンドウのキャプション(タイトル文字列)を取得
'// GetWindowText は、ウィンドウタイトルをバッファ(wCaption)に格納する
GetWindowText hWnd, wCaption, Len(wCaption)
If InStr(wCaption, cap_str) > 0 Then Exit Do
End If
'// 次のウィンドウのウィンドウハンドルを取得
'// GetWindow は、第二引数に GW_HWNDNEXT(=2)をして指定すると
'// 次のウィンドウのハンドルを返す
hWnd = GetWindow(hWnd, GW_HWNDNEXT)
Loop
GetHwnd = hWnd
End Function
逆に、ウィドウハンドル(hWnd)がわかっている場合にウィンドウタイトルを取得するのは比較的簡単である。
ウィンドウタイトルをバッファ(wCaption)に格納する GetWindowText
関数の動き(引数)を理解しよう。
'// 指定したハンドルのウィンドウタイトルを返す
' GetWindowText は、バッファ(wCaption)にウィンドウタイトルを格納する
' 255文字分のバッファを取っておいたのでバッファの後半(タイトル文字列以降)は
' Null文字になるため、Left関数で Null文字より前の文字列を取り出す。
Function GetWindowTitle(ByVal hWnd As LongPtr) As String
Dim wCaption As String * 255
GetWindowText hWnd, wCaption, Len(wCaption)
GetWindowTitle = Left(wCaption, InStr(wCaption, vbNullChar) - 1)
End Function
<参考サイト>