UIAutomationについて

.NET Framework 3.0から追加になっていたらしい、UI オートメーションが面白い。何が出来るか、については、Microsoft SDKについてくる、UISpyを触るとわかりやすいと思います。UISpyは、UIAutomationで出来る事を、ストレートにGUIでラップした感じのものなので。使うと、FirefoxのDOM InspectorでWindowsのデスクトップが触れる、みたいな印象だと思います。他プログラムのウィンドウやコントロールを取得して、操作出来る。操作するには、コントロールからGetCurrentPatternで、操作用のパターンを取得する必要があり、ちゃんと対応するにはそれ用のインターフェースを実装している必要があるみたい(よくわかっていません……)ですが、ネイティブアプリが対象でも、結構いろいろ出来ます。WPFの一部ですが、いわゆるWPFアプリしか操作できないわけではありません。
起動中のアクセサリ - > 電卓の"1"ボタンを押すプログラム。VB.NET。先に電卓を起動させておく必要があります。

Imports System.Windows.Automation

Public Module CalcPush
  Public Sub Main()
    ' 電卓取得
    Dim calc = ( _
       From al As AutomationElement In AutomationElement.RootElement.FindAll(TreeScope.Children, Condition.TrueCondition) _
      Where al.Current.Name = "電卓" _
    ).Single

    ' 「1」のボタンを取得
    Dim b1 = ( _
      From al As AutomationElement In calc.FindAll(TreeScope.Children, Condition.TrueCondition) _
     Where al.Current.Name = "1" _
    ).Single

    ' 押す
    b1.GetCurrentPattern(InvokePattern.Pattern).Invoke()
  End Sub
End Module

これと同じ事が出来るPowerShellスクリプトも作成したのですが、上手く動きません……。


[void][System.Reflection.Assembly]::LoadFile("C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationClient.dll")
[void][System.Reflection.Assembly]::LoadFile("C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationTypes.dll")

# 子要素を全て取り出すフィルター
filter fa(){ $_.FindAll("Children", [System.Windows.Automation.Condition]::TrueCondition) }

# 電卓の1ボタン
$b1 = [System.Windows.Automation.AutomationElement]::RootElement | fa | ? { $_.Current.Name -eq "電卓"} | fa | ? { $_.Current.Name -eq "1"}

# ボタンをInvokePatternにする
$ip = $b1.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)

# 実行
$ip.Invoke()

電卓のボタン取得までは、変数の中身を見ても上手くいっているようなのですが、GetCurrentPatternするところで、"サポートされていないパターンです。"という例外が出ます。VB.NETで書いたほうでは、InvokePatternで取得できているのがよくわかりません。ちなみに、InvokePattern以外の全パターンで試したけどだめだった、というか、PowerShellでは、一度もGetCurrentPatternが成功していないので、なにか大きな勘違いをしていそうなのですが……。
AutomationElement.RootElement ← がUIのルートとなっていて、この下に、各アプリのウィンドウや、"Program Manager"がいるんですが、階層構造なので、これもPowerShellのPSProviderにしてしまえば、PowerShellから自在に他ウィンドウのコントロールまで操れるようになって最高だと思うのですが、どうでしょうか……。