先日、UI Automation UDFの記事を書きましたが、中身はSetFocus()後Send()していたりと、簡単に使える分ちょっとな・・というところもありました。
今回は、IUIAutomation Interfaceを使う=Microsoft UIAutomationを直接使うことを行います。高速ですが、その分多少複雑。だけどUI Automation UDFには実装されていないものも当然使えます。慣れたらこっちのほうが良いかもしれませんね。
こっちだと、vba uiautomationとかで出てきたサンプルをほぼそのまま使えることになると思います。
1. Using UI Automation Code in AutoIt
元記事です。junkew氏のUIAutomation UDFに刺激され、LarsJ氏がよりInspect.exeに近いspyツールと一緒に解説しています。
UIA Spyを作成した時のコメントに刺激され、UIA Spyを使ってUIAutomation利用のコードの書き方を詳しく書いています。
2. UIA Spy.exeを作成し開く
下記から、UIASpy.7zをダウンロードする
(5/4 ぽよん氏コメントの指摘で間違った情報を書いていたのを修正しました。ありがとうございます!)

展開すると下記のようなファイル・フォルダ構成になっているので、まずはUIASpy.au3をビルドしUIASpy.exeを作成。これがInspect.exeのようなツールになる。

早速UIASpy.exeを立ち上げてみると下記画面が出る。

2.1 UIASpy.ini 初期設定ファイル
ダブルクリックしてメモ帳などで開くと、[Options]に2つのパラメータがあります。
いずれも、アプリのメニュー「Options」にある文字列をそのままお使いの環境に合わせて設定しておきましょう。
- DisplayScale Windowsのディスプレイ設定のパーセントを書く
- WindowsMode 筆者はWindows10 Pro 64bitなので”Windows 10 Last”にした
3. UIA Spy.exeの使い方
画面のどこでもいいので、マウスがあるところでF1~F8を押す(Includes/UIASpy_Menu.au3参照)と要素に関する操作、右側にその情報が表示される。
左側:開いているWindowやプログラム
右側:選択している要素の情報をリストで
3.1 要素情報の取得はF1,F2
- コントロール上にマウスを合わせF1を押すとコントロール情報取得
- ウィンドウタイトルバー上にマウスを合わせF2を押すとウィンドウ(親コントロール)情報取得
エクスプローラのタイトルバーにマウスを合わせ、F1,F2を押してみると、取得するクラスが変わるのがわかると思います。

右パネルの5行目、$UIA_ClassNamePropertyIdの値は下記のようになり、赤枠も変わる。
F1: TitleBar
F2: CabinetWClass
赤枠を消したい時は、UIASpyの左パネルをクリックするとかしてください。
3.2 サンプルコード生成機能を使う
3通りあるとのこと。まだ使い慣れていないせいか下記のような感じでやるものだと思っています。
- メニュー「Sample Code->Initial Code->Complete Code」でUIAutomationオブジェクトを取得するコードテンプレート取得
- 右パネル(詳細パネル)での行で右クリックし「Create sample code」でコントロールやウィンドウの取得サンプル
- 制御したいコントロール・ウィンドウを選択した状態でメニュー「Sample code->code snippets」で出てきたリストの中で右クリックし「create sample code」
例えばクリックのサンプルコードが出る。(UIA_Functions.au3内に関数あり)
3.3 出来たコードをコピーしau3ファイル作成実行
生成されたコード上で右クリックしコピー、新規ファイルにペーストしau3実行するといった流れです。
まずは動作確認で、メニュー「Sample Code->Initial Code->Complete Code」でUIAutomationオブジェクトを取得するコードテンプレート取得し、それをau3ファイルにして実行しましょう。UIA_Constants.au3のincludeが必要なので、パスを修正して。
実行すると、SciTEのOutput(F8)に$oUIAutomation OK, $oDesktop OKと出ると思います。
これでUIAUtomationのオブジェクトとデスクトップオブジェクト取得できたコードが出来ました。
あとはこれらオブジェクトをベースに、各ウィンドウ、コントロールを取得し操作していくの繰り返しですね。
めちゃくちゃ便利。
(余談)
この使い方に慣れるとGUIベースの有料RPAツールよりカスタマイズ性もあるし、プログラム知識もそこまで必要なく出来そうな感じです。GUIベースのRPAツールも結局は変数や関数の知識が必要になるし、そこまで勉強するならVBAか何か勉強したほうが早いってなると思いますね。
4. UIをコントロールするのであって、データをコントロールしない
当たり前の話ですが、UIAutomationはUIをコントロールするのであって、データをコントロールするものではありません。
したがって、Excelのシート1->C14に今日の日付をセットする、のはUIAutomationの仕事ではなく、Excel UDFなどを使ってコントロールすることです。
Excelの印刷ダイアログで「このボタンを押す必要ある」とか「プリンタを変更」する。基幹システムの各コントロールを操作する、ようなことにUIAutomationを使います。
5. Automationg Notepadを日本語訳し、実際に手順を真似てみる
このスレッドの2つ目、メモ帳にHelloWorldを書き「名前をつけて保存」でファイルに保存するサンプルをやってみます。下記の3つを学べます。
- 一般的なエディットコントロールの操作
- メニュー操作
- 保存ダイアログ操作
5.1 UIAutomationオブジェクトを取得したテンプレートを用意
メニュー「Sample Code->Initial Code->Complete Code」を実行して、UIAutomationオブジェクトとデスクトップオブジェクト取得をしておきます。そのコードにメモ帳起動コードを追記。
#include "Includes\UIA_Constants.au3" Example() Func Example() ;; メモ帳開く Run("notepad") Sleep(1000) ; UIAutomation オブジェクト生成 Local $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation8, $sIID_IUIAutomation6, $dtag_IUIAutomation6 ) If Not IsObj( $oUIAutomation ) Then Return ConsoleWrite( "$oUIAutomation ERR" & @CRLF ) ConsoleWrite( "$oUIAutomation OK" & @CRLF ) ; デスクトップ 取得 Local $pDesktop, $oDesktop $oUIAutomation.GetRootElement( $pDesktop ) $oDesktop = ObjCreateInterface( $pDesktop, $sIID_IUIAutomationElement9, $dtag_IUIAutomationElement9 ) If Not IsObj( $oDesktop ) Then Return ConsoleWrite( "$oDesktop ERR" & @CRLF ) ConsoleWrite( "$oDesktop OK" & @CRLF ) EndFunc
ビルドし実行すると、メモ帳が出てきて終了します。
5.2 UIASpyでメモ帳オブジェクト取得コード
メモ帳が開いた状態で、UIASpyツールでタイトルバーにマウスを合わせF2を押してメモ帳Windowオブジェクトを取得。
$UIA_ClassNamePropertyId = Notepadですね。
Notepadのところで右クリック「Create Sample Code」でコードが出てきます。

コードのところで右クリック「Copy All Items」でコードをコピー、ペーストしましょう。

変数名Notepadに変更しました。
$pCondition0 -> $pCondition
$pWindow1 -> $pNotepad
$oWindow1 -> $oNotepad
実行し、Notepadオブジェクトを取得出来ていることを確認。
実際は下記の3つを繰り返すだけです。
- 対象PropertyIdのコンディション取得
- UIAutometion要素を取得
- 上記要素の情報取得or何かアクション
; メモ帳オブジェクト取得 ConsoleWrite( "--- Find Notepad ---" & @CRLF ) Local $pCondition $oUIAutomation.CreatePropertyCondition( $UIA_ClassNamePropertyId, "Notepad", $pCondition ) If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ConsoleWrite( "$pCondition OK" & @CRLF ) Local $pNotepad, $oNotepad $oDesktop.FindFirst( $TreeScope_Children, $pCondition, $pNotepad ) $oNotepad = ObjCreateInterface( $pNotepad, $sIID_IUIAutomationElement9, $dtag_IUIAutomationElement9 ) If Not IsObj( $oNotepad ) Then Return ConsoleWrite( "$oNotepad ERR" & @CRLF ) ConsoleWrite( "$oNotepad OK" & @CRLF )
実行し、SciTEのOutput(画面下)に以下が出ていればNotepadオブジェクトも取得出来ています。
$oUIAutomation OK
$oDesktop OK
$pCondition OK
$oNotepad OK
5.3 テキストえでぃたーコントロールを取得しHelloWorldを記入
UIASpyでエディたーコントロール(文章書くところ)にマウスを合わせF1でコントロール情報がわかります。(もしくは左パネルのツリーを辿ってもOK)
$UIA_AutomationIdPropertId=15です。

ここで、先ほどのようにコードを取得しても良いですが、テキストエディターコントロールはツリーで見るとメモ帳の下にぶら下がっています。
「メモ帳windowがデスクトップの下にぶら下がっているのと同じです」
つまり「先ほどのコードをコピペし、必要部分だけ変更」で対応できる。ということです。
- 対象PropertyIdのコンディション取得
エディターコントロール=15のコンディション - UIAutomation要素を取得
親のoNotepad.FindFirst()で。
pEditでポインタ取得し、ObjCreateInterfaceで要素オブジェクト取得=oEdit - oEditに対して何かする(次)
; --- メモ帳のエディターコントロール取得 ConsoleWrite( "--- Find edit control ---" & @CRLF ) $oUIAutomation.CreatePropertyCondition( $UIA_AutomationIdPropertyId, "15", $pCondition ) If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ConsoleWrite( "$pCondition OK" & @CRLF ) Local $pEdit, $oEdit $oNotepad.FindFirst( $TreeScope_Descendants, $pCondition, $pEdit ) $oEdit = ObjCreateInterface( $pEdit, $sIID_IUIAutomationElement9, $dtag_IUIAutomationElement9 ) If Not IsObj( $oEdit ) Then Return ConsoleWrite( "$oEdit ERR" & @CRLF ) ConsoleWrite( "$oEdit OK" & @CRLF )
実行するとoutputの最後2つに$pCOndition OK $oEdit OK が出ます。
5.4 エディターコントロールに文字入力
エディターを選択した状態で、右パネル(詳細パネル)で下までスクロールし「Control Patterns (element actions)の $UIA_IsValuePatternAvailablePropertyIdを選択、右クリックで「Create sample code」を選択しサンプルコードを出しコピペします。

出来たコードをまた置換しましょう。
$oDocument -> $oEdit
$pLegacyIAccessiblePattern1 -> $pVal
$oLegacyIAccessiblePattern1 -> $oVal
文字書き込むのは、$oVal.SetValue(“ハローワールド”) です。
ちなみに何が使えるかはエディタコントロールの右パネル「Control Pattern Methods」にあります。
DoDefaultAction(),Select(long),SetValue(wstr),などがありますね。
; --- 文字書き込み --- ConsoleWrite( "--- LegacyIAccessible Pattern (action) Object ---" & @CRLF ) Local $pVal, $oVal $oEdit.GetCurrentPattern( $UIA_LegacyIAccessiblePatternId, $pVal ) $oVal = ObjCreateInterface( $pVal, $sIID_IUIAutomationLegacyIAccessiblePattern, $dtag_IUIAutomationLegacyIAccessiblePattern ) If Not IsObj( $oVal ) Then Return ConsoleWrite( "$oVal ERR" & @CRLF ) ConsoleWrite( "$oVal OK" & @CRLF ) $oVal.SetValue("ハローワールド\n") Sleep(100)

ただこれだけだと、UIAutomation使わないで普通にnotepadをSetFocus()しSend()したほうが早いし楽ですね。
ではメニューを操作しましょうか。
6. UIAutomationでメニューを操作する
ここからが本番といったところです。メニューを制御していきます。
6.1 メニュー「ファイル」をクリック(Invoke)
メモ帳のメニュー「ファイル」にカーソルを合わせF1を押します。下記3つに対してcreate sample codeしておきましょう。


$oParent -> $oNotepad
$pMenuItem2 -> $pMenuFile
$oMenuItem2 -> $oMenuFile
$pInvokePattern1 -> $pInvokeFile
$oInvokePattern1 -> $oInvokeFile
ConsoleWrite( "--- Find window/control ---" & @CRLF ) Local $pCondition1 $oUIAutomation.CreatePropertyCondition( $UIA_NamePropertyId, "ファイル(F)", $pCondition1 ) If Not $pCondition1 Then Return ConsoleWrite( "$pCondition1 ERR" & @CRLF ) ConsoleWrite( "$pCondition1 OK" & @CRLF ) Local $pMenuFile, $oMenuFile $oNotepad.FindFirst( $TreeScope_Descendants, $pCondition1, $pMenuFile ) $oMenuFile = ObjCreateInterface( $pMenuFile, $sIID_IUIAutomationElement9, $dtag_IUIAutomationElement9 ) If Not IsObj( $oMenuFile ) Then Return ConsoleWrite( "$oMenuFile ERR" & @CRLF ) ConsoleWrite( "$oMenuFile OK" & @CRLF ) ; --- Invoke Pattern (action) メニュー「ファイル」クリック --- ConsoleWrite( "--- Invoke Pattern (action) Object ---" & @CRLF ) Local $pInvokeFile, $oInvokeFile $oMenuFile.GetCurrentPattern( $UIA_InvokePatternId, $pInvokeFile ) $oInvokeFile = ObjCreateInterface( $pInvokeFile, $sIID_IUIAutomationInvokePattern, $dtag_IUIAutomationInvokePattern ) If Not IsObj( $oInvokeFile ) Then Return ConsoleWrite( "$oInvokeFile ERR" & @CRLF ) ConsoleWrite( "$oInvokeFile OK" & @CRLF ) $oInvokeFile.Invoke() Sleep(1000)
最後に$oInvokeFile.Invoke()でメニューの「ファイル」をクリックします。
実行してみましょう。メニュー「ファイル」が開かれました。

6.2 メニュー「名前をつけて保存(A)…」を選択
メモ帳のメニュー「ファイル->名前をつけて保存」にカーソルを合わせF1

入れ替えてInvoke()すると、保存ダイアログが出てきます。
7. 保存ダイアログの操作
最後に保存ダイアログです。ダイアログはウィンドウなので、タイトルバーの空欄でF2(ウィンドウ取得)
親がoNotepadで、子が#32770のウィンドウですね。
そこからは、ファイル名欄は32770ウィンドウのAnscestorを取得・・という形になっていきます。値をセットするならSetValue() 保存ボタンも取得してInvoke()、保存フォルダにパスをSetValue()して・・といった感じです。
ダウンロードフォルダに”ハローワールド.txt”で保存する場合は、ファイル名欄に”C:\Users\(あなた)\Downloads\ハローワールド.txt”をSetValueすればOKです。
最初、保存ダイアログの上部にパスを指定したのですが全然うまくいかずでした・・
8. 出来たau3を置いておきます
Githubに今回作成したメモ帳起動~書き込み~名前をつけて保存 までのサンプルコードを置きます。
8. メモ帳 UIAUtomationのおさらい
おさらいをすると、
- UIAutomationオブジェクト、デスクトップオブジェクトを取得(初期化的な)
- アプリはデスクトップの下にぶら下がっている
FindFirst( $TreeScope_Childrenで探す) - アプリオブジェクト取得したら、次は取得したいコントロールを取得
(親はアプリオブジェクト) $TreeScope_Descemdamtsで探す - コントロールのPatternから取得したいプロパティを取得
- それに対してActionする。Invokeならクリック、SetValueなら値セット
- メニューなどもアプリの下にぶら下がっているのでアプリオブジェクトから他コントロール同様取得し、Pattern取得しアクション。
- 保存ダイアログもアプリ下にぶら下がっているので取得し、そのダイアログ下に保存、キャンセルボタンなどがある。
コメント
UIASpy.au3を右クリック→コンパイル(ビルド)するときに
includeで素材が足りないよというエラーが出てきます。
必要な素材がセットになっている
こちらのリンクも補足として
https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/
思いっきりリンク間違えていました・・・
指摘ありがとうございます!