WinActorでUIAutomationを使えるようにしてみた。

### １．背景

WinActorには自動化機能としてOfficeソフトとの連携、各種ブラウザソフトとの連携、JPathを使ったJavaソフトウェアの操作、WIN32ライブラリを使ったソフトウェアの操作が容易されています。

Office以外のexe形式のインストール型ソフトウェアの場合は、操作する方法がWIN32APIか画像識別に頼るしかない状況で、単純なクリック操作ならなんとかなるんだけども、表示内容の読み取りとかが乏しい印象がありました。

いろいろUI自動化について調べて、UIAutomationライブラリを使えればもっと細かいアプリ制御ができそうってところまでわかったので、拙いながらもWinActorに組み込むところまでやってみた実験の結果です。

### ２．UIAutomationの実行モジュールを作る

Visual Studioを使ってコマンドラインアプリケーションを作ってみる。

```vb.net:UIA_cmd.exe
Imports System.Windows.Automation

Module Module1

    Sub Main(args As String())
        Dim argVal As String

        If args.Length < 3 Then
            Console.WriteLine("コマンドラインオプションが不足しています。")
            Exit Sub
        ElseIf args.Length = 4 Then
            argVal = args(3)
        End If

        ' コマンドライン引数を取得
        Dim func As String = args(0)
        Dim hwnd As String = args(1)
        Dim AutoID As String = args(2)

        Try
            ' AutomationElementを取得する。
            Dim elm As AutomationElement = AutomationElement.FromHandle(hwnd)
            Dim targetElm As AutomationElement = elm.FindFirst(TreeScope.Descendants, New PropertyCondition(AutomationElement.AutomationIdProperty, AutoID, PropertyConditionFlags.IgnoreCase))

            If IsNothing(targetElm) Then
                Console.WriteLine("操作対象を取得できませんでした。")
                Exit Sub
            End If

            ' 第一引数によって処理を変える。
            Select Case StrConv(func, VbStrConv.Lowercase)
                Case "click"
                    Dim ptnInvk As InvokePattern = targetElm.GetCurrentPattern(InvokePattern.Pattern)
                    ptnInvk.Invoke()
                Case "focus"
                    targetElm.SetFocus()
                Case "setvalue"
                    Dim ptnVal As ValuePattern = targetElm.GetCurrentPattern(ValuePattern.Pattern)
                    ptnVal.SetValue(argVal)
                Case "getvalue"
                    Dim ptnVal As ValuePattern = targetElm.GetCurrentPattern(ValuePattern.Pattern)
                    Console.WriteLine(ptnVal.Current.Value)
                Case "gettext"
                    Console.WriteLine(targetElm.GetCurrentPropertyValue(AutomationElement.NameProperty).ToString())
                Case Else
                    Console.WriteLine("[" & func & "]に相当する処理はありませんでした。")
            End Select
        Catch ex As Exception
            Console.WriteLine("UIAutomation処理に失敗しました。")
        End Try
    End Sub

End Module
```

### ３．作ったUIA_cmd.exe実行環境に配置

２のコードをコンパイルしたファイルをUIA_cmd.exeという名前にしてWinActor.exeと同じフォルダに配置する。

### ４．スクリプト実行ノードから呼び出す。
スクリプト実行ノードのスクリプトタブに以下のスクリプトを張り付け。

``` vb.net:UIAutomationを呼びだす
hwnd = GetUMSWindowHandle(@ウィンドウ識別名@)
AutoID = !AutomationID!
func = !操作の内容|Click,Focus,SetValue,GetValue,GetText!
sval = !設定値!
uia = "UIA_cmd.exe "

If IsNull(hwnd) Then
  Err.Raise 1, "", "ウィンドウハンドルを取得できませんでした。"
Else
  Set objExecCmd = CreateObject("WScript.Shell").Exec(uia & func & " """ & hwnd & """ """ & AutoID & """ " & sval)
  Do While objExecCmd.Status = 0
    WScript.Sleep(500)
  Loop
  SetUMSVariable $取得結果$ , objExecCmd.StdOut.ReadAll
End If
```

### ５．Inspectツールで取得したAutomationID使って動作を試して完了


<img width="366" alt="uia_wa_script.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360097/98b7a1fb-8308-4057-24f6-fa31c43542aa.png">

以下、奮闘の履歴です。
[ウィンドウハンドルについて](https://yizm.work/winactor/window_hwnd/)
[アプリケーションのUIを分析する（Inspectツール）](https://yizm.work/winactor/uiautomation_inspect_tool/)
[UIAutomationでUI操作してみる](https://yizm.work/winactor/uiautomation_create_exe/)
[UIAutomationをWinActorに組み込む](https://yizm.work/winactor/uiautomation_script_winactor/)