アドベントカレンダー 14日目
クラス名がわかっていれば、FindWindow関数でも使ってハンドル取得すりゃいい話なんですが
わからん時は、いちいちEnumWindows関数で全ハンドル取得してウィンドウ名を取得して
該当するハンドルを見つけりゃいいわけですが、ちょいとめんどくさいから関数作ってしまいましょ。
関数の仕様としては、欲しいウィンドウハンドルの名前を指定します。
指定の仕方は正規表現で指定できます。
返り値は、DictionaryのObjectが返ってきます。
Dictionaryの構造は、ハンドルをキーに値にDicitionaryを持ちます。
そのDicitionaryは
ClassName という文字列をキーにクラス名を値に
WIndowName という文字列をキーにウィンドウ名を値に持ちます。
コードは以下の通りです。
こんな感じで値が取れます。
メモ帳を2つ起動した状態で、メモ帳のハンドルを取得したいとします。
実行結果
クラス名がわかっていれば、FindWindow関数でも使ってハンドル取得すりゃいい話なんですが
わからん時は、いちいちEnumWindows関数で全ハンドル取得してウィンドウ名を取得して
該当するハンドルを見つけりゃいいわけですが、ちょいとめんどくさいから関数作ってしまいましょ。
関数の仕様としては、欲しいウィンドウハンドルの名前を指定します。
指定の仕方は正規表現で指定できます。
返り値は、DictionaryのObjectが返ってきます。
Dictionaryの構造は、ハンドルをキーに値にDicitionaryを持ちます。
そのDicitionaryは
ClassName という文字列をキーにクラス名を値に
WIndowName という文字列をキーにウィンドウ名を値に持ちます。
(Dictionary) = Hwnd => (Dictionary)
"ClassName" => [クラス名],
"WIndowName" => [ウィンドウ名]
コードは以下の通りです。
Option Explicit
Private Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As Long, lParam As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal MSG As Long, _
ByVal wParam As Long, ByVal lParam As String) As Long
Private Const WM_GETTEXT = &HD
Private Const WM_GETTEXTLENGTH = &HE
Private DicHwnd As Object
Private RegWindowTitle As Object
Public Function GetHwnd(ByVal RegPattern As String) As Object
Dim Ret As Long
'FileNameに一致するハンドルをキーにタイトルを値に格納する変数
'CallBack関数とやりとりするのでGlobal領域で宣言しておく
Set DicHwnd = CreateObject("Scripting.Dictionary")
Set RegWindowTitle = CreateObject("VBScript.RegExp")
RegWindowTitle.Global = False
RegWindowTitle.IgnoreCase = True
RegWindowTitle.Pattern = EscapeRegString(RegPattern)
'必ずエラーになるので止まらないよう処理しておく
On Error Resume Next
Ret = EnumWindows(AddressOf EnumWindowsProc, 0)
On Error GoTo 0 '問題の部分を過ぎたのでエラー処理をもとに戻す
Set GetHwnd = DicHwnd
Set DicHwnd = Nothing
End Function
Private Function EnumWindowsProc(ByVal hwnd As Long) As Long
Dim ClassName As String
Dim length As Integer
Dim Ret As Integer
Dim str As String
Dim WindowTitle As String
EnumWindowsProc = 1
'ハンドルに該当する文字列数を取得(注:Null文字は含まない)
length = SendMessageStr(hwnd, WM_GETTEXTLENGTH, 0, 0)
length = length + 1 'Null文字分1つ増やす
'Null文字分一つ多く領域を確保
str = String(length, vbNullChar)
'Null文字も含め受取る
Ret = SendMessageStr(hwnd, WM_GETTEXT, length, str)
'文字列を出力(NULL文字分1つ削って出力)
WindowTitle = Left(str, Len(str) - 1)
'取得したウィンドウ名がGetHwndの引数に指定された正規表現がマッチしたら取得しておく
If RegWindowTitle.Test(WindowTitle) Then
'クラス名が何文字か不明なので大きめの領域を確保しておく
ClassName = String(255, vbNullChar)
Ret = GetClassName(hwnd, ClassName, 255)
ClassName = Replace(ClassName, vbNullChar, "")
DicHwnd.Add CStr(hwnd), CreateObject("Scripting.Dictionary")
DicHwnd(CStr(hwnd)).Add "ClassName", ClassName
DicHwnd(CStr(hwnd)).Add "WindowName", WindowTitle
End If
End Function
Private Function EscapeRegString(ByVal RegHwnd As String)
RegHwnd = Replace(RegHwnd, "(", "\(")
RegHwnd = Replace(RegHwnd, ")", "\)")
RegHwnd = Replace(RegHwnd, ".", "\.")
RegHwnd = Replace(RegHwnd, "[", "\[")
EscapeRegString = RegHwnd
End Functionこんな感じで値が取れます。
メモ帳を2つ起動した状態で、メモ帳のハンドルを取得したいとします。
Option Explicit
Sub SampleCode()
Dim hwnd As Variant
Dim HashHwnd As Object
Set HashHwnd = GetHwnd("メモ帳$")
For Each hwnd In HashHwnd
Debug.Print "ハンドル:" & hwnd
Debug.Print "クラス名:" & HashHwnd(hwnd)("ClassName")
Debug.Print "タイトル:" & HashHwnd(hwnd)("WindowName")
Debug.Print "---"
Next
End Sub実行結果
ハンドル:197350 クラス名:Notepad タイトル:無題 - メモ帳 --- ハンドル:262876 クラス名:Notepad タイトル:無題 - メモ帳 ---
0 件のコメント:
コメントを投稿