[VBA,VB.NET,C#,PHP]プログラムTips集

[VBA,VB.NET,C#,PHP]プログラムのちょっとしたテクニック

EnumWindowsでウィンドウとコントロールの全ての情報を取得するモジュール:FindWindowExなどでうまく取得できないコントロールがある場合の最終手段

【対象】VB.NET
まずは、以下のようにModEnumWinモジュールを作成します。

''' <summary>
''' EnumWindows利用方法
''' 全てのウィンドウ情報を取得する
''' </summary>
Module ModEnumWin
	' APIの定義
	Private Const WM_GETTEXT = &HD
	Private Delegate Function D_EnumWindowsProc(
    	ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
	Private Delegate Function D_EnumChildWindowsProc(
    	ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
	Private Declare Function EnumWindows Lib "user32.dll" _
    	(ByVal lpEnumFunc As D_EnumWindowsProc, ByVal lParam As Integer) As Integer
	Private Declare Function EnumChildWindows Lib "user32.dll" _
    	(ByVal hwndParent As Integer, ByVal lpEnumFunc As D_EnumChildWindowsProc,
     	ByVal lParam As Integer) As Integer
	Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" _
    	(ByVal hWnd As Integer, ByVal lpClassName As Byte(),
     	ByVal nMaxCount As Integer) As Integer
	Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
    	(ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer,
     	ByVal lParam As Byte()) As Integer
 
	' コントロール毎の情報を設定するコレクション
	Private colWindows As New Collection
 
	' ウィンドウとコントロールを全て取得
	Public Function GetAllWindows() As Collection
    	On Error Resume Next
    	Dim i As Long
    	Dim lngRet As Long
 
    	' コントロール毎の情報を設定するコレクション生成
    	colWindows = New Collection
    	GetAllWindows = colWindows
 
    	' トップレベルウィンドウを全て取得
    	lngRet = EnumWindows(AddressOf EnumWindowsProc, 0)
 
    	' 親ウィンドウに属するコントロールを全て取得
    	For i = 1 To colWindows.Count
        	lngRet = EnumChildWindows(
            	colWindows.Item(i).Item(1)(0), AddressOf EnumChildWindowsProc, i)
    	Next i
	End Function
 
	' トップレベルウィンドウを全て取得
	Public Function EnumWindowsProc(
    	ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
    	On Error Resume Next
    	Dim lngRet As Long
    	Dim bytClass As Byte() = New Byte(255) {}
    	Dim bytTitle As Byte() = New Byte(255) {}
    	Dim strClass As String
    	Dim strTitle As String
 
    	' クラス名取得
    	lngRet = GetClassName(hWnd, bytClass, 255)
    	strClass = StripNulls(bytClass)
 
    	' ウィンドウのタイトル取得
    	lngRet = SendMessage(hWnd, WM_GETTEXT, 255, bytTitle)
    	strTitle = StripNulls(bytTitle)
 
    	' 取得した情報を配列に設定
    	Dim strDa(2) As Object
    	strDa(0) = hWnd
    	strDa(1) = strClass
    	strDa(2) = strTitle
 
    	' 取得した情報をコレクションに設定
    	Dim colDa As New Collection
    	colDa.Add(strDa)
 
    	' トップレベルウィンドウ毎のコレクションに追加
    	colWindows.Add(colDa)
 
    	' リターン
    	EnumWindowsProc = 1
	End Function
 
	' 指定された親ウィンドウに属するコントロールを全て取得
	Private Function EnumChildWindowsProc(
    	ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
    	On Error Resume Next
    	Dim lngRet As Long
    	Dim bytClass As Byte() = New Byte(255) {}
    	Dim bytTitle As Byte() = New Byte(255) {}
    	Dim strClass As String
    	Dim strTitle As String
 
    	' クラス名取得
    	lngRet = GetClassName(hWnd, bytClass, 255)
    	strClass = StripNulls(bytClass)
 
    	' ウィンドウのタイトル取得
    	lngRet = SendMessage(hWnd, WM_GETTEXT, 255, bytTitle)
    	strTitle = StripNulls(bytTitle)
 
    	' 取得した情報を配列に設定
    	Dim strDa(2) As Object
    	strDa(0) = hWnd
    	strDa(1) = strClass
    	strDa(2) = strTitle
 
    	' コントロール毎のコレクションに追加
    	colWindows.Item(lParam).Add(strDa)
 
    	' リターン
    	EnumChildWindowsProc = 1
	End Function
 
	' 文字列からNULL文字以降をカット
	Private Function StripNulls(ByVal bytOrg As Byte()) As String
    	On Error Resume Next
    	Dim strOrg As String =
        	System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(bytOrg)
    	If (InStr(strOrg, Chr(0)) > 0) Then
        	strOrg = Left(strOrg, InStr(strOrg, Chr(0)) - 1)
    	End If
    	StripNulls = strOrg
	End Function
End Module

【実際に呼び出す方法】
・例)フォームにTreeViewを配置してください。TreeViewの名称はTreeView1にします。
フォームにボタンなどを配置して、以下のExecuteEnumWinを呼び出します。
TreeViewに起動中のすべてのウィンドウとコントロールが表示されます。

	''' <summary>
	''' 【呼出し】実行処理
	''' </summary>
	Public Sub ExecuteEnumWin()
    	Dim i As Long
    	Dim j As Long
    	Dim bytClass As Byte()
    	Dim bytTitle As Byte()
    	Dim bytSpace As Byte()
 
    	' ウィンドウとコントロールの全ての情報を取得
    	Dim colWindows As Collection
    	colWindows = GetAllWindows()
 
    	' 親ウィンドウ毎のコレクションループ
    	For i = 1 To colWindows.Count
        	' 子コントロール毎のコレクション取得
        	Dim colChilds As Collection
        	colChilds = colWindows.Item(i)
 
        	'If colChilds.Count >= 1 Then   	' 全ての親ウィンドウを対象
        	If colChilds.Count > 1 Then     	' 子コントロールを持つ物のみ対象
            	' 子コントロール毎のコレクションループ
            	Dim treeNodeTop As TreeNode = Nothing
            	For j = 1 To colChilds.Count
                	bytSpace = System.Text.Encoding.GetEncoding(
                    	"SHIFT-JIS").GetBytes(New String(" ", 50))
 
                	' コレクションからクラス名取得
                	bytClass = System.Text.Encoding.GetEncoding(
                    	"SHIFT-JIS").GetBytes(colChilds.Item(j)(1))
                	If bytClass.Length < 30 Then
                    	Dim p As Integer = bytClass.Length
                    	ReDim Preserve bytClass(bytClass.Length + bytSpace.Length - 1)
                    	Array.Copy(bytSpace, 0, bytClass, p, bytSpace.Length)
                    	ReDim Preserve bytClass(30 - 1)
                	End If
    	            Dim strClass As String = System.Text.Encoding.GetEncoding(
                    	"SHIFT-JIS").GetString(bytClass)
 
                	' コレクションから文字列取得
                	bytTitle = System.Text.Encoding.GetEncoding(
                    	"SHIFT-JIS").GetBytes(colChilds.Item(j)(2))
                	If bytTitle.Length < 50 Then
                    	Dim p As Integer = bytTitle.Length
                    	ReDim Preserve bytTitle(bytTitle.Length + bytSpace.Length - 1)
               	     Array.Copy(bytSpace, 0, bytTitle, p, bytSpace.Length)
                    	ReDim Preserve bytTitle(50 - 1)
                	End If
                	Dim strTitle As String = System.Text.Encoding.GetEncoding(
                    	"SHIFT-JIS").GetString(bytTitle)
 
                	If j = 1 Then
                    	' 親ウィンドウの情報をツリービューへ追加
                    	treeNodeTop = New TreeNode(strClass & " - " & strTitle)
                        TreeView1.Nodes.Add(treeNodeTop)
            	    Else
                    	' 子コントロールの情報をツリービューへ追加
                    	Dim treeNodeSub As TreeNode =
                        	New TreeNode(strClass & " - " & strTitle)
                        treeNodeTop.Nodes.Add(treeNodeSub)
             	   End If
            	Next j
        	End If
    	Next i
	End Sub