AutoItでUIAutomation Interfaceを使う その2(推奨)

autoitでUIAutomationを使う AutoIT

先日、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ツールと一緒に解説しています。

Using UI Automation Code in AutoIt
This example is about using Microsoft UI Automation APIs in AutoIt. Ie. it's about using interfaces, objects, methods, properties and constants as they are defi...

UIA Spyを作成した時のコメントに刺激され、UIA Spyを使ってUIAutomation利用のコードの書き方を詳しく書いています。

UIASpy - UI Automation Spy Tool
The GUI looks like shown in the picture: It contains a main menu, a treeview in left pane that lists UI Automation elements, a listview in right pane that displ...

2. UIA Spy.exeを作成し開く

下記から、UIASpy.7zをダウンロードする
(5/4 ぽよん氏コメントの指摘で間違った情報を書いていたのを修正しました。ありがとうございます!)

UIASpy - UI Automation Spy Tool
The GUI looks like shown in the picture: It contains a main menu, a treeview in left pane that lists UI Automation elements, a listview in right pane that displ...
autoit uiautomation uiaspyをダウンロード

展開すると下記のようなファイル・フォルダ構成になっているので、まずは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を押してみると、取得するクラスが変わるのがわかると思います。

uiautomation uiaspy

右パネルの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を日本語訳し、実際に手順を真似てみる

Using UI Automation Code in AutoIt
This example is about using Microsoft UI Automation APIs in AutoIt. Ie. it's about using interfaces, objects, methods, properties and constants as they are defi...

このスレッドの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」でコードが出てきます。

UIASpy notepadのところで右クリックする

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

uiaspy 生成したコードをコピー

変数名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です。

UIASpy エディタコントロールを取得

ここで、先ほどのようにコードを取得しても良いですが、テキストエディターコントロールはツリーで見るとメモ帳の下にぶら下がっています。
「メモ帳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」を選択しサンプルコードを出しコピペします。

UIASpy エディタコントロールを制御

出来たコードをまた置換しましょう。
$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)

autoit uiautomationを使ってメモ帳に「ハローワールド」

ただこれだけだと、UIAutomation使わないで普通にnotepadをSetFocus()しSend()したほうが早いし楽ですね。
ではメニューを操作しましょうか。

6. UIAutomationでメニューを操作する

ここからが本番といったところです。メニューを制御していきます。

6.1 メニュー「ファイル」をクリック(Invoke)

メモ帳のメニュー「ファイル」にカーソルを合わせF1を押します。下記3つに対してcreate sample codeしておきましょう。

$oParent -> $oNotepad
$pMenuItem2 -> $pMenuFile
$oMenuItem2 -> $oMenuFile
$pInvokePattern1 -> $pInvokeFile
$oInvokePattern1 -> $oInvokeFile


最後に$oInvokeFile.Invoke()でメニューの「ファイル」をクリックします。
実行してみましょう。メニュー「ファイル」が開かれました。

6.2 メニュー「名前をつけて保存(A)…」を選択

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

UIASpy メモ帳のメニューを取得

入れ替えてInvoke()すると、保存ダイアログが出てきます。

7. 保存ダイアログの操作

最後に保存ダイアログです。ダイアログはウィンドウなので、タイトルバーの空欄でF2(ウィンドウ取得)
親がoNotepadで、子が#32770のウィンドウですね。

そこからは、ファイル名欄は32770ウィンドウのAnscestorを取得・・という形になっていきます。値をセットするならSetValue() 保存ボタンも取得してInvoke()、保存フォルダにパスをSetValue()して・・といった感じです。

ダウンロードフォルダに”ハローワールド.txt”で保存する場合は、ファイル名欄に”C:\Users\(あなた)\Downloads\ハローワールド.txt”をSetValueすればOKです。
最初、保存ダイアログの上部にパスを指定したのですが全然うまくいかずでした・・

8. 出来たau3を置いておきます

Githubに今回作成したメモ帳起動~書き込み~名前をつけて保存 までのサンプルコードを置きます。

https://github.com/cfautog/autoit/blob/master/uia/uia_notepad2.au3

8. メモ帳 UIAUtomationのおさらい

おさらいをすると、

  • UIAutomationオブジェクト、デスクトップオブジェクトを取得(初期化的な)
  • アプリはデスクトップの下にぶら下がっている
    FindFirst( $TreeScope_Childrenで探す)
  • アプリオブジェクト取得したら、次は取得したいコントロールを取得
    (親はアプリオブジェクト) $TreeScope_Descemdamtsで探す
  • コントロールのPatternから取得したいプロパティを取得
  • それに対してActionする。Invokeならクリック、SetValueなら値セット
  • メニューなどもアプリの下にぶら下がっているのでアプリオブジェクトから他コントロール同様取得し、Pattern取得しアクション。
  • 保存ダイアログもアプリ下にぶら下がっているので取得し、そのダイアログ下に保存、キャンセルボタンなどがある。

9. 参考リンク

UIASpy - UI Automation Spy Tool
The GUI looks like shown in the picture: It contains a main menu, a treeview in left pane that lists UI Automation elements, a listview in right pane that displ...
Using UI Automation Code in AutoIt

コメント

  1. ぽよん より:

    UIASpy.au3を右クリック→コンパイル(ビルド)するときに
    includeで素材が足りないよというエラーが出てきます。

    必要な素材がセットになっている
    こちらのリンクも補足として

    https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/

    • cfautog管理者 より:

      思いっきりリンク間違えていました・・・
      指摘ありがとうございます!

タイトルとURLをコピーしました