その他

VBA:ハンドル情報(hwnd)配列取得・一覧出力[No70]

スポンサーリンク

VBAでウィンドウハンドル(Window Handle、HWND)を操作するには、次の情報が1つ以上必要です。

  • ハンドル番号(HAND ID、Handle ID、hwnd ID、Hwnd No)
  • キャプション名(Caption Name、captionName)
  • クラス名(Class Name、className)

ネットに出回っている情報は、特定のハンドル情報を指定して取得するものしかなかったので、今回は「動作中のhandleを配列に格納するプログラム」を自作してみました。このプログラムを利用することによって、今まで以上にhandle情報の取得が容易になると思います。

プログラムを利用するメリット

今回私が自作したプログラムを利用するメリットは、少ない情報量で、必要な別の情報を取得できることです。自作プログラムは配列にhandle情報を格納しているので、例えばキャプション名の一部がわかっているだけでも、その配列をForで回し起動しているWindowのハンドルNoを取得することができます。

動作準備

  • 拡張子xlsmのExcelを新規作成し、「HWND」シートを用意する(シート名は半角文字)。
  • 次の内容の標準モジュールを用意する。

プログラム(モジュール名:GlobalManagement)


Option Explicit

Public Array_hwndTypeName() As Variant
Public Array_hwndNo()       As Variant
Public Array_captionName()  As Variant
Public Array_className()    As Variant

プログラム(モジュール名:Module_hwnd_01)

ソースコードが長いので分割しました。必ず結合させて1つのmoduleに入れて下さい。


Option Explicit

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 GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long

Const SHEET_HWND As String = "HWND"

Const HWND_TYPENO_NOW       As Integer = 0
Const HWND_TYPENO_LAST      As Integer = 1
Const HWND_TYPENO_NEXT      As Integer = 2

Const HWND_NAME_NOW         As String = "HWND_NOW"
Const HWND_NAME_NEXT        As String = "HWND_NEXT"
Const HWND_NAME_LAST        As String = "HWND_LAST"

Const HWND_FORNUM_NOW       As Long = 1
Const HWND_FORNUM_NEXT      As Long = 350
Const HWND_FORNUM_LAST      As Long = 50

Const CONST_STARTROW        As Long = 2

Dim Flg_Assigned            As Boolean
Dim dictionary              As Object

Public Sub ハンドル情報出力()
    Call InitSHEET
    Call GetAllParentHwnd
    
    Dim arrayElementsNum As Long
    arrayElementsNum = CountNumberOfArrayElements(Array_hwndTypeName)
    
    Dim startRow As Long: startRow = CONST_STARTROW
    Dim endRow As Long: endRow = startRow + arrayElementsNum - 1
    
    Dim i As Integer
    Dim j As Integer
    For i = startRow To endRow
        j = i - startRow
        With Worksheets(SHEET_HWND)
            .Select
            .Cells(i, 1) = Array_hwndTypeName(j)
            .Cells(i, 2) = Array_hwndNo(j)
            .Cells(i, 3) = Array_captionName(j)
            .Cells(i, 4) = Array_className(j)
        End With
    Next i
End Sub

Private Sub InitSHEET()
    With Worksheets(SHEET_HWND)
        .Select
        .Cells.Clear
        .Cells(1, 1) = "HAND種類"
        .Cells(1, 2) = "HANDID"
        .Cells(1, 3) = "captionName"
        .Cells(1, 4) = "className"
        
        .Range(.Cells(1, 1), .Cells(1, 4)).Font.Color = RGB(0, 0, 0)
        .Range(.Cells(1, 1), .Cells(1, 4)).Interior.Color = RGB(169, 208, 142)
        .Range(.Cells(1, 1), .Cells(1, 4)).Borders.LineStyle = True
        .Range(.Cells(1, 1), .Cells(1, 4)).BorderAround Weight:=xlMedium
    End With
End Sub

Public Sub GetAllParentHwnd()
    Erase Array_hwndTypeName
    Erase Array_hwndNo
    Erase Array_captionName
    Erase Array_className
    
    ReDim Preserve Array_hwndTypeName(0)
    ReDim Preserve Array_hwndNo(0)
    ReDim Preserve Array_captionName(0)
    ReDim Preserve Array_className(0)
    
    Flg_Assigned = False

    Dim hwndNo As Long
    hwndNo = GetForegroundWindow()
    
    Call FindHwnd(HWND_TYPENO_NOW, HWND_NAME_NOW, hwndNo, HWND_FORNUM_NOW)
    Call FindHwnd(HWND_TYPENO_NEXT, HWND_NAME_NEXT, hwndNo, HWND_FORNUM_NEXT)
    Call FindHwnd(HWND_TYPENO_LAST, HWND_NAME_LAST, hwndNo, HWND_FORNUM_LAST)
End Sub

スポンサーリンク


Private Sub FindHwnd(ByVal hwndType As Integer, _
                     ByVal hwndTypeName As String, _
                     ByVal hwndNo As Long, _
                     ByVal forNum As Long)

    Dim captionName01 As String
    Dim captionName02 As String
    Dim className01   As String
    Dim className02   As String
                     
    Dim arrayMaxSubscripts As Long
    arrayMaxSubscripts = UBound(Array_hwndTypeName)
    
    Dim fromNo As Long
    If Flg_Assigned = False Then
        fromNo = arrayMaxSubscripts
        Set dictionary = CreateObject("scripting.dictionary")
    ElseIf Flg_Assigned = True Then
        fromNo = arrayMaxSubscripts + 1
    Else
        MsgBox "Error. FindHwnd"
        Exit Sub
    End If

    Dim connectString As String
    Dim n As Long: n = fromNo

    Dim i As Long
    For i = 1 To forNum
    
        captionName01 = String(200, vbNullChar)
        className01 = String(200, vbNullChar)
        
        hwndNo = GethwndNo(hwndType, hwndNo)
        GetWindowText hwndNo, captionName01, Len(captionName01)
        GetClassName hwndNo, className01, Len(className01)
        captionName02 = Left(captionName01, InStr(captionName01, vbNullChar) - 1)
        className02 = Left(className01, InStr(className01, vbNullChar) - 1)

        'connectString = hwndTypeName & hwndNo & captionName02 & className02
        connectString = hwndNo & captionName02 & className02

        If (hwndNo <> 0) And (Not dictionary.Exists(connectString)) Then
            dictionary.Add connectString, 0
            
            ReDim Preserve Array_hwndTypeName(n)
            ReDim Preserve Array_hwndNo(n)
            ReDim Preserve Array_captionName(n)
            ReDim Preserve Array_className(n)
            
            Array_hwndTypeName(n) = hwndTypeName
            Array_hwndNo(n) = hwndNo
            Array_captionName(n) = captionName02
            Array_className(n) = className02
            
            n = n + 1
            
            Flg_Assigned = True
        End If
    Next i
    Call CheckNumberOfArrayElements
End Sub

Private Function GethwndNo(ByVal hwndType As Integer, _
                         ByVal hwndNo As Long) As Long
    If hwndType = HWND_TYPENO_NOW Then
        GethwndNo = hwndNo
    ElseIf hwndType = HWND_TYPENO_NEXT Or _
           hwndType = HWND_TYPENO_LAST Then
        GethwndNo = GetNextWindow(hwndNo, hwndType)
    End If
End Function

Private Sub CheckNumberOfArrayElements()
    If (dictionary.Count = CountNumberOfArrayElements(Array_hwndTypeName)) And _
       (dictionary.Count = CountNumberOfArrayElements(Array_hwndNo)) And _
       (dictionary.Count = CountNumberOfArrayElements(Array_captionName)) And _
       (dictionary.Count = CountNumberOfArrayElements(Array_className)) Then
    Else
        MsgBox "Error. GethwndNo"
        Exit Sub
    End If
End Sub

Private Function CountNumberOfArrayElements(ByVal Array_Temp As Variant) As Long
    CountNumberOfArrayElements = UBound(Array_Temp) - LBound(Array_Temp) + 1
End Function

スポンサーリンク

プログラムについて

メインプログラム

「GetAllParentHwnd」と「ハンドル情報出力」の関数がメインプログラムです。

それぞれの意味は次のようになっています。

  • GetAllParentHwnd関数:起動中のWindowハンドル情報を配列で取得する。
  • ハンドル情報出力関数:GetAllParentHwnd関数で格納した情報を「HWND」シートに出力する。プログラム内で「GetAllParentHwnd」を実行してその情報を書き出す。

配列

そして、配列は「Array_hwndTypeName」、「Array_hwndNo」、「Array_captionName」、「Array_className」の4つあります。

各配列の同じ要素番号に、同じハンドル情報が入っています。

例えば、ハンドル情報が45個あったら、配列は配列名(0)から配列名(44)まであります。そして、「Array_hwndTypeName(28)」、「Array_hwndNo(28)」、「Array_captionName(28)」、「Array_className(28)」は同じハンドルの情報ということになります。

それぞれの配列に格納されているものは以下の通りです。

  • 「Array_hwndTypeName」には、「GetNextWindow」APIを使う際に利用する文字列「HWND_NOW」、「HWND_NEXT」、「HWND_LAST」のどれかが格納。
  • 「Array_hwndNo」には、ハンドル番号が格納。
  • 「Array_captionName」には、キャプション名が格納。
  • 「Array_className」には、クラス名が格納。

その他

重複データは削除し、除外してます。ハンドル0番は格納していません。

親ハンドルしか対象にしていません。

実行イメージ

Sub「GetAllParentHwnd」実行の場合

Sub「ハンドル情報出力」実行の場合

おすすめの使い方

長くなりましたので別記事で紹介します。

no image
VBA:親ウィンドウハンドルの配列からハンドル情報を取得[No71]
動作準備 今回は、前回の記事で扱ったエクセル、プログラムを利用することを前提とした「親ウィンドウハンドルの配列からハンドル情報を取得する方法」を紹介します。 まだ前回の記事を読まれて ...

以前ご紹介したこちらのツールを利用することもおすすめです。フォームを利用している処理方法など、興味のある方は是非こちらも目を通してみて下さい。

no image
VBAでHandle等を用いて他のアプリケーションを操作する方法[No20]
VBAでIE(Internet Explorer)の操作ができるようになり、次は他のアプリケーションを操作する方法について自分用のメモとして残しておくので、定期的な確認作業をオートメ ...
no image
Windowsアプリケーション(ソフトウェア)のハンドル情報まとめ[No21]
Windowsのアプリケーションはハンドル(Hadle)で構成されています。今回はアプリケーションのハンドル情報を記載していきたいと思います。 徐々に追記していきます。 Window ...

関連記事

no image
ウィンドウハンドル関連の記事一覧[No74]
記事一覧 ハンドル番号、キャプション名、クラス名について書かれた記事のまとめです。 最後までお付き合いいただきありがとうございます! この情報が誰かの役にたてれば幸 ...

最後までお付き合いいただきありがとうございます!

この情報が誰かの役にたてれば幸いです。

スポンサーリンク

-その他