スポンサーリンク
動機
自宅にてアプリケーションの自動操作を行うプログラムを作成する機会がありました。
ほとんどのWindowsのアプリケーションは、管理番号がふられた部品で構成されています。
この管理番号はウィンドウハンドル(Handleまたはハンドル)と呼ばれており、"複数の情報から成る「ハンドル情報」"から取得することが可能です。
※「ハンドル情報」は「Window情報」と呼ばれることもあります。
アプリケーションの「ハンドル情報」を取得できれば、「ウィンドウハンドル」を取得でき、部品の操作が可能となります。コーディングする前にあらかじめ「ハンドル情報」を調べておく必要があります。
Visual StudioのSpy++ツールで「ハンドル情報」を取得することも可能ですが、そうするとVisual Studioをインストールしなくてはならなくなるし、無償で長く利用するにはMicroSoftアカウントでのログインが必要となって手間がかかってしまいます。そのようなときに次のサイトに出会いました。
出典
-
ウィンドウ情報列挙−VBパーツ
VisualBasicプログラムパーツ
続きを見る
この記事を書くにあたって、ダウンロードセンター様に掲載してあるツールが大変参考にさせて頂きました。ありがとうございます。記載できる範囲で引用にて紹介させて頂ければと思います。ダウンロードセンター様では、上記ツールの他にも色々なツールが紹介されているので、気になった方は是非チェックしてみて下さい。
-
ダウンロードセンター
続きを見る
スポンサーリンク
出典のツールを利用するために行ったこと
執筆時点では、私のPCではそのまま利用できませんでした。
VB6で開発されたツールのようで現在のVB7では上手くいかなかったです。
次の手順を行い動作することができました。
手順
私のWindows10 PCでは次のように手順を踏んで行いました。
手順1
次のサイトにあるソースを参考にするために、まずサンプルコードのダウンロードを行う。(VB6ソースのフォーム、標準モジュール)
-
ウィンドウ情報列挙−VBパーツ
VisualBasicプログラムパーツ
続きを見る
手順2
Excel(拡張子xlsm)を新規作成する。
※VBAの開発画面で「ヘルプ→バージョン情報」を確認してみると「Microsoft Visual Basic for Applications 7.1」となっていました。
手順3
ユーザーフォーム「UserForm1」を新規作成する。
フォームのデザインは手順1のサイトを参考に作成する。
※UserForm1の大枠サイズはHeight=400,Width=1050が良さそうです。
※作成はツールボックスだけで完結できます。ツールボックスにListViewがなければ、「その他のコントロール」から追加して使用して下さい。(Microsoft ListView Control, version 6.0)
手順4
UserForm1に、コマンドボタンをもう1つ作成する。
※この手順が完了すると、コマンドボタンは全部で2つになります。
手順5
UserForm1を、手順1で取得したコードを使用してVB6ソースのフォームとして上書きする。
手順6
標準モジュール「Module1」を新規作成する。
手順7
Module1を、手順1で取得したコードを使用してVB6ソースの標準モジュールとして上書きする。
手順8
もう1つの標準モジュール「Module2」を新規作成する。
手順9
Module2を次のコード(code_09-01)で上書きし、実行する。
※フォームが起動することを確認して下さい。
Option Explicit
Public Sub Open_form()
With UserForm1
.StartUpPosition = 0
.Top = 100
.Left = 100
.Show vbModeless
End With
End Sub
スポンサーリンク
手順10
フォーム起動後、手順1のサイトにある実行イメージのようになっておらず、ボタンを押しても反応がない場合は次のことを行う。
<UserForm1内のコードの変更>
- Command1をCommandButton1に全て置換する。
- Command2をCommandButton2に全て置換する。
- Option1をOptionButton1に全て置換する。
- Option2をOptionButton2に全て置換する。
- Form_ResizeをUserForm_Resizeに置換する。
- Form_LoadをUserForm_Initializeに置換する。
- UserForm_Initializeで設定している書式設定で、上から順番に幅を変更する。
※変更する幅は画面サイズによります。
例:110、110、110、150、150、300。 - 次のコード(code_10-01)のように、Form_Unloadの関数一式は、次のUserForm_QueryCloseに変更する。
- 次のコード(code_10-02)のように、UserForm_Resizeの関数内の「With」で挟まれた箇所を変更する。
- 次のコード(code_10-03)の定義を一番上のOption Explicitの次の行に追加する。
- 次のコード(code_10-04)の関数を追加する。
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then
End
End If
End Sub
.Width = Me.InsideWidth - .Left * 2
.Height = Me.InsideHeight - .Top * 2
Private Declare Function WindowFromAccessibleObject Lib "oleacc.dll" (ByVal IAcessible As Object, ByRef hWnd As Long) As Long
Public Property Get hWnd() As Long
WindowFromAccessibleObject Me, hWnd
End Property
手順11
Module2のOpen_formを実行し、手順1のサイト先の実行イメージのようになることを確認する。
スポンサーリンク
手順12
ThisWorkbookを次のコード(code_12-01)で上書きすると、起動したときにフォームが立ち上がることを確認する。
Option Explicit
Private Sub Workbook_Open()
UserForm1.Show vbModeless
End Sub
手順13(+αの手順:機能を追加)
追加で次のことを行うと利便性が向上します。
※ツールで表示されるHandleなどはHexの16進数となります。使用用途にあわせて10進も確認できるようにすると、より使いやすくなるのでおすすめです。
<マクロのExcelの設定>
1シート目に「Sheet1」、2シート目に「WriteSheet」、というシート名のシートを作成する。(後の処理で結構重要)
<UserForm1のデザイン>
- UserForm1にコマンドボタンを3つ追加。追加場所はコマンドボタン2つ目の右隣。(この手順でコマンドボタンは合計5つになる。)
- UserForm1にラベルを1つ追加。追加場所はラベル2つ目の右隣。(この手順でラベルは合計2つになる。)
<UserForm1内のコード>
- 次のコード(code_13-01)を一番上のOption Explicitの次の行に追加。
- CommandButton1_Clickの関数内(関数始め)に次のコード(code_13-02)を追加。
- SetListの関数内でフォームの一行目に表示されるhandleをHex16進数にしているFormatの箇所を「hWnd」に置換。(後の処理で結構重要)
- SetListの関数内(For文開始直後)に次のコード(code_13-03)を追加。
- 次のコード(code_13-04)の関数を追加。
- UserForm_Initializeの書式設定に次のコード(code_13-05)を追加。
- UserForm_Initializeの関数内(関数終わり)に次のコード(code_13-06)を追加。
Private Declare Function ShowWindow Lib "user32" (ByVal hwindow As Long, ByVal cmdshow As Long) As Long
If OptionButton2 Then
CommandButton3.Enabled = True
End If
CommandButton4.Enabled = True
CommandButton5.Enabled = True
Label2.Caption = "取得件数:" & UBound(hWndList) & "件"
Private Sub OptionButton1_Click()
LoopSw = False
ListView1.ListItems.Clear
CommandButton2.Enabled = False
CommandButton3.Enabled = False
CommandButton4.Enabled = False
End Sub
Private Sub OptionButton2_Click()
LoopSw = False
ListView1.ListItems.Clear
CommandButton2.Enabled = False
CommandButton3.Enabled = False
CommandButton4.Enabled = False
End Sub
'Flashボタン
Private Sub CommandButton3_Click()
If OptionButton2 Then
LoopSw = False
Dim handle As Long
With ListView1.SelectedItem
If ListView1.SelectedItem Is Nothing Then
Exit Sub
End If
handle = CLng(Trim((.Text)))
End With
ShowWindow handle, 0
Application.Wait Now() + TimeValue("00:00:01")
ShowWindow handle, 1
Application.Wait Now() + TimeValue("00:00:01")
ShowWindow handle, 0
Application.Wait Now() + TimeValue("00:00:01")
ShowWindow handle, 1
End If
End Sub
'Line Copyボタン
Private Sub CommandButton4_Click()
Dim handle As Long
Dim proccId As String
Dim threadId As String
Dim rect As String
Dim className As String
Dim winText As String
With ListView1.SelectedItem
If ListView1.SelectedItem Is Nothing Then
Exit Sub
End If
handle = CLng(Trim(.Text))
proccId = .SubItems(1)
threadId = .SubItems(2)
rect = .SubItems(3)
className = .SubItems(4)
winText = .SubItems(5)
End With
Open ThisWorkbook.Path & "\LineCopy.txt" For Output As #1
Print #1, "handle:"; "「" & handle & "」" & vbCrLf & _
"proccId:"; "「" & proccId & "」" & vbCrLf & _
"threadId:"; "「" & threadId & "」" & vbCrLf & _
"rect:"; "「" & rect & "」" & vbCrLf & _
"className:"; "「" & className & "」" & vbCrLf & _
"winText:"; "「" & winText & "」" & vbCrLf
Close #1
End Sub
'All Copyボタン
Private Sub CommandButton5_Click()
Dim handle As String
Dim proccId As String
Dim threadId As String
Dim rect As String
Dim className As String
Dim winText As String
If ListView1.ListItems.Count = 0 Then
Exit Sub
End If
Dim workSheetName As String
workSheetName = "WriteSheet"
Sheets(workSheetName).Select
Cells.Clear
With Worksheets(workSheetName)
.Range("A1") = "Handle"
.Range("B1") = "ProccId"
.Range("C1") = "ThreadId"
.Range("D1") = "Rect"
.Range("E1") = "ClassName"
.Range("F1") = "WinText"
End With
With ListView1
Dim i As Long
For i = 1 To .ListItems.Count Step 1
With .ListItems(i)
handle = .Text
proccId = .SubItems(1)
threadId = .SubItems(2)
rect = .SubItems(3)
className = .SubItems(4)
winText = .SubItems(5)
End With
With Worksheets(workSheetName)
.Range("A" & (1 + i)) = handle
.Range("B" & (1 + i)) = proccId
.Range("C" & (1 + i)) = threadId
.Range("D" & (1 + i)) = rect
.Range("E" & (1 + i)) = className
.Range("F" & (1 + i)) = winText
End With
Next i
End With
With Worksheets(workSheetName)
.Columns("A:F").EntireColumn.AutoFit
End With
Dim selectedOptionButtonName
If OptionButton1 Then
selectedOptionButtonName = "親"
ElseIf OptionButton2 Then
selectedOptionButtonName = "子"
End If
Sheets(workSheetName).Copy
Dim fileName As String
fileName = "ウィンドウ情報(" & Format(Now(), "YYYY年MM月DD日") & "(" & Format(Now(), "aaa") & ")" & "_" & Format(Now(), "hh時nn分ss秒出力") & ")(" & selectedOptionButtonName & ")"
ActiveWorkbook.SaveAs _
fileName:=ThisWorkbook.Path & "\" & fileName, _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
ActiveWorkbook.Close
Sheets(workSheetName).Select
Cells.Clear
Dim mainSheet As String
mainSheet = "Sheet1"
Sheets(mainSheet).Select
ThisWorkbook.Save
End Sub
CommandButton3.Caption = "Flash"
CommandButton4.Caption = "Line Copy"
CommandButton5.Caption = "All Copy"
Label2.Caption = ""
UserForm1.Caption = "Window情報取得ツール"
With ListView1
.Gridlines = True 'True:グリッド線追加
.FullRowSelect = True 'FullRowSelect:1行選択
.HideSelection = False 'False:選択行が常に強調表示
.LabelEdit = lvwManual 'lvwManual:編集許可しない
.AllowColumnReorder = True 'True:列幅変更許可する
End With
OptionButton1 = True
スポンサーリンク
完成イメージ
すべての手順を行うと次のフォームになるはずです。
スポンサーリンク
追加機能について
Flashボタン
Flashボタンは子ウィンドウ選択時のみ利用可能です。選択した子ウィンドウを点滅させ、場所を確認することができます。しかし、親ウィンドウ選択時にはFlashボタンは利用しないことを推奨します。間違って利用してしまった際は×ボタンで閉じないほうが良さそうです。
Line Copyボタン
実行Excelのファイルがある場所に、選択されている行の情報をテキストファイルで出力することができます。
All Copyボタン
実行Excelのファイルがある場所に、すべての行の情報をExcelファイルで出力する。
取得件数ラベル
一覧の取得件数を表示可能です。
ポイント
- 子ウィンドウでは、アプリケーション(ソフト)のタイトル部分にマウスを当てておくと、子ウィンドウの情報が取得しやすい。
- Line Copyで出力されたテキストファイルを開いた状態でLine Copyを押すとエラーになるので、開いたら閉じることを忘れずに!
追記
下記の記事で紹介している「要素確認ソフト(Inspect.exe)」を用いることでも確認することが可能なので、お時間のある方は是非こちらの記事も読んでみて頂けると嬉しいです。
-
【簡単!UIAutomation利用】VBAツールで画面操作して自動ログインする[No88]
毎日のように、複数環境にログインして作業しているシステムがあります。 本番環境、開発環境のように環境ごとにホスト名、ユーザ名、パスワードが異なるため、これまでは手作業で切り替えて利用 ...
関連記事
-
ウィンドウハンドル関連の記事一覧[No74]
記事一覧 ハンドル番号、キャプション名、クラス名について書かれた記事のまとめです。 最後までお付き合いいただきありがとうございます! この情報が誰かの役にたてれば幸 ...
雑記
最近よく思うことですが、何処でもいいからお出掛けしたいですよね。早くコロナが収まって、自由に街を出歩ける日常が戻ってくることを祈るばかりです。#stay home
最後までお付き合いいただきありがとうございます!
この情報が誰かの役にたてれば幸いです。