trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

C#でUIAutomationを使う

目的

UIAutomation使って自動でボタンポチポチ押すくらいできるようになる

対象

ちょっとUIAutomation使ってみたいなーくらいの人

ざっくりとした手順

  1. 操作したいオブジェクトを調査する
  2. 操作したいオブジェクトのAutomationElementを取得する
  3. 取得したオブジェクトを操作する

詳細

UIAutomation Treeについて

Desktopを根とした木構造になっている。

Desktop-アプリ-アプリが持つボタン、メニュー、etc.-…

これをたどって操作したいオブジェクトのAutomationElementを取得する。

操作したいオブジェクトを調査する

調査で取得する情報

オブジェクトの検索に使う情報を取得する。ひとまず Name,ControlType,AutomationId,ClassName を調べればよい。対象は操作したいオブジェクトとそれの親 or 祖先であるアプリ。

調査方法

以下のツールを使う。

UIAutomationSpy,Inspect,Accessibility Insights
など。

操作したいオブジェクトのAutomationElementを取得する1

まず検索の起点となるAutomationElementを取得する。 取得したAutomationElementから条件と方向を指定して検索する。

操作したいオブジェクトを持つアプリのAutomationElementを取得して検索の起点とするとよい。

アプリのAutomationElementを取得する方法

方法はいくつかあるがアプリはDesktopの子要素であることが多いので、DesktopAutomationElementから子要素を対象としてアプリを検索すると楽。

Desktopの子要素でnameと一致するNameプロパティを持つものを取得。

var cnd = new PropertyCondition(AutomationElement.NameProperty, name);
var apliElement = AutomationElement.RootElement.FindFirst(TreeScope.Children, cnd);

AutomationElement.RootElementDesktopAutomationElement

検索の詳細については次項。

検索方法

起点となるAutomationElementから検索条件と検索対象範囲を指定して検索する。

検索条件を作成する2

検索対象とするプロパティと一致条件を指定して検索条件を作成する。

検索対象をNameプロパティ、nameと一致することを条件とする場合。

var cnd = new PropertyCondition(AutomationElement.NameProperty, name);

AutomationElement.NamePropertyを変更すればControlType,AutomationId,ClassNameを対象にできる。 それぞれAutomationElement.ControlTypeProperty,AutomationElement.AutomationIdProperty,AutomationElement.ClassNamePropertyControlTypeを対象にする場合、一致条件にControlTypeクラスを指定する。他はstring

検索する

検索の起点から検索条件と検索対象範囲(自分、子要素、孫要素)を指定して検索する。

起点であるapliElementから条件cndで子要素を検索する場合。

var targetElement = apliElement.FindFirst(TreeScope.Children, cnd);

FindFirstの場合条件に合った最初のAutomationElementを返す。 FindAllを使うと条件に合ったすべてのAutomationElementを返す。

TreeScope.Childrenを変更することで検索対象を変更できる。

オブジェクトを操作する

取得したAutomationElementから適切なPattern Objectを得てそれを操作する。

適切なPattern Objectを取得する

操作に適切なAutomationPatternを指定してPattern Objectを取得する。

ボタンを押すのであればInvokePattern.Pattern

var btn = targetElement.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;

GetCurrentPatternの返り値はobjectなので変換を忘れずに。

取得したPattern Objectを操作する

取得したPattern Objectのメソッドを実行する。 ボタンを押す場合はInvoke

btn.Invoke();

参考資料

AutomationElementを取得する方法

Obtaining UI Automation Elements - Win32 apps | Microsoft Docs

ControlTypeについて

ControlType Class (System.Windows.Automation) | Microsoft Docs

検索範囲(TreeScope)について3

TreeScope Enum (System.Windows.Automation) | Microsoft Docs

ControlTypePatternの対応表

Control Pattern Mapping for UI Automation Clients | Microsoft Docs

それぞれのPatter詳細へのリンク

UI Automation Control Patterns Overview | Microsoft Docs

その他

menuItemとか右クリックメニューとかを操作したい場合

目標とするオブジェクトが描画されてないと検索できないっぽい4
MenuItemを操作するには一旦Menuを取得して展開してから検索・取得・操作する。 右クリックメニューを操作するには右クリックイベントを発生させたりショートカットキーを使って表示させてから検索・取得・操作する。

ショートカットキーを使って右クリックメニューを表示させる例。右クリックメニューを持つオブジェクトにフォーカスしてからショートカットキーを送る。送った後ちょっと待ち時間を入れた方がよい。

automationElement.SetFocus();
SendKeys.SendWait("+{F10}");

  1. 例にあげているもの以外については参考資料を確認

  2. 有効なものとか複数条件とかいろいろできる

  3. Ancestors,Parentは Not supported であることに注意

  4. 最小化したら検索できなくなったりするのもある。何やねんこいつら。