自動化

UIAutomationとは|Windows UI自動化の仕組みとC#・Python・VBA実装

UIAutomation(Microsoft UI Automation、略してUIA)は、Windowsに標準搭載されたアクセシビリティAPIです。スクリーンリーダーが画面を読み上げるための仕組みですが、同じAPIをテスト自動化や業務システムの操作自動化に転用できます。座標をクリックする「画像認識マクロ」と違い、ボタンやテキストボックスをUI要素そのものとして取得して操作するため、ウィンドウ位置がずれても壊れません。この記事では、UIAの構造(プロバイダー/クライアント、要素ツリー、コントロールパターン)を押さえたうえで、C#・Python・VBA・PowerShellの実装、RPAツールとの使い分け、要素が取得できないときの原因までを扱います。

まとめ

  • UIAはプロバイダーAPI(アプリ側が情報を公開する)とクライアントAPI(自動化する側が読み取り・操作する)の二層構造。自動化スクリプトを書く立場ならクライアントAPIだけ理解すればよい。
  • 操作対象の指定はAutomationIdを最優先にする。Name(表示文字列)に依存すると、UIの文言変更や表示言語の違いでスクリプトが壊れる。
  • 要素の調査はWindows SDKのInspect.exe、または後継のAccessibility Insights for Windowsで行う。要素のAutomationIdとサポートするパターンが分からないまま書き始めると、検索条件もパターン呼び出しも当てずっぽうになる。
  • 言語別の入り口は、C#=FlaUI.UIA3 5.0.0(NuGet)、Python=uiautomation 2.0.29pip install uiautomation)、VBA=参照設定のUIAutomationClientCreateObjectでは呼べず事前バインディング必須)。
  • WindowsアプリのE2E自動化として広く使われたWinAppDriverは2022年以降ほぼ更新が止まっている。新規採用は避け、UIAを直接叩くかFlaUIを使う。
  • Webの操作はPlaywright、業務フロー全体の自動化はOpenRPAなどのRPAが適任。UIAは「デスクトップアプリの要素を型として掴む」用途に絞るのが妥当。

UIAutomationの正体:Windows標準のアクセシビリティAPI

UIAはWindows Vistaで導入され、それ以前のMicrosoft Active Accessibility(MSAA)を置き換える位置づけで設計されました。Microsoft Learnの「UI オートメーションの概要」は、WPFのボタンのContent、Win32ボタンのCaption、HTML画像のALTがいずれもUIAの単一プロパティNameにマップされると説明しています。UIフレームワークの違いをUIAコアが吸収するため、WPF・WinForms・Win32・ストアアプリを同じコードで扱えるのがUIAの本質的な価値です。

4つの構成要素とAPIの二層構造

Microsoftの公式ドキュメントは、UIAを次の4コンポーネントに分けています。

コンポーネント 実体 担当
プロバイダーAPI UIAutomationProvider.dll / UIAutomationTypes.dll アプリ側がUI情報を公開する
クライアントAPI UIAutomationClient.dll / UIAutomationTypes.dll 自動化する側が要素を取得・操作する
UIAコア UiAutomationCore.dll プロバイダーとクライアントの通信を仲介
クライアント側プロバイダー UIAutomationClientsideProviders.dll レガシコントロールをUIA対応に見せる

UIAコアの表記は、.NET FrameworkのドキュメントではUiAutomationCore.dll、Win32側のドキュメントではUIAutomationCore.dllと揺れていますが、同じファイルを指します。

自動化スクリプトを書くだけなら、必要なのはクライアントAPIだけです。プロバイダーAPIは「自作のカスタムコントロールを支援技術やテストツールから見えるようにしたい」開発者が実装する側で、両者を混同したまま調べ始めると、必要のないSystem.Windows.Automation.Providerの解説を延々と読むことになります。

なお、C#のマネージドAPI(System.Windows.Automation)のドキュメントは冒頭に「UI オートメーションの最新情報については Windows Automation API を参照」という注記があり、更新も2017年で止まっています。Microsoftが最新版として案内しているのはCOMベースのUIA 3.0(UIAutomationCore.dll)で、後述のFlaUIやPythonのuiautomationはいずれもこのCOM APIを叩いています。

要素ツリーの3つのビューとコントロールパターン

UIAはデスクトップをルートとする木構造としてUIを公開します。この木には3つのビューがあります。

  • Rawビュー:すべての要素。レイアウト用のパネルまで含むため深く、探索が遅くなる。
  • Controlビュー:ユーザーが操作・認識できるコントロールのみ。通常の自動化はここを使う。
  • Contentビュー:情報として意味のある要素のみ。スクリーンリーダー向け。

各要素はNameAutomationIdといったプロパティに加えて、コントロールパターンを公開します。パターンは「その要素で何ができるか」を表す振る舞いの単位で、ボタンならInvokePattern(押す)、テキストボックスならValuePattern(値を読み書きする)、リストならSelectionPatternが対応します。公式ドキュメントが明記しているとおり、コントロール種別とパターンは一対一ではありません。コンボボックスは展開・折りたたみのExpandCollapsePatternと選択のSelectionPatternを同時に持ちます。「クリックできない」とつまずく原因の多くは、その要素がサポートしていないパターンを呼んでいることです。

操作対象の特定:InspectとAccessibility Insights

コードを書く前に、対象アプリの要素がどんなAutomationIdNameControlTypeを持ち、どのパターンをサポートするかを調べます。手段は2つです。

  • Inspect.exe:Windows SDKに同梱される調査ツール(既定のインストール先はC:\Program Files (x86)\Windows Kits\10\bin\<version>\x64\inspect.exe)。UIAのプロパティとコントロールパターン、MSAAのプロパティを両方表示できる。Microsoftはこれをレガシツールと位置づけている。
  • Accessibility Insights for Windows:Inspectの後継としてMicrosoftが公開しているツール。要素にホバーするだけでUIAのプロパティ・パターン・イベントを確認できる。新規に始めるならこちらでよい。

ここで見るべきはAutomationIdです。Windowsの電卓であれば「7」ボタンのAutomationIdnum7Button、「=」はequalButtonという固定のIDが振られています。Nameで探すコードは、表示言語が日本語か英語かだけで動かなくなります(電卓のウィンドウ名は日本語環境で「電卓」、英語環境で「Calculator」)。AutomationIdが振られていない要素にぶつかった場合に限り、ControlType+Nameの組み合わせや、親要素からの相対位置で妥協します。

言語別の実装:C#・Python・VBA・PowerShell

以下はいずれも「電卓を操作する」最小の実装です。UIAの手順はどの言語でも同じで、ルート(デスクトップ)→ウィンドウ→目的の要素、と条件で絞り込み、パターンを取得して呼ぶという流れになります。

C#:System.Windows.AutomationとFlaUI

.NETのマネージドAPIをそのまま使う場合は、UIAutomationClientUIAutomationTypesを参照して次のように書きます。

using System.Windows.Automation;

var window = AutomationElement.RootElement.FindFirst(
    TreeScope.Children,
    new PropertyCondition(AutomationElement.NameProperty, "電卓"));

var seven = window.FindFirst(
    TreeScope.Descendants,
    new PropertyCondition(AutomationElement.AutomationIdProperty, "num7Button"));

var invoke = (InvokePattern)seven.GetCurrentPattern(InvokePattern.Pattern);
invoke.Invoke();

ただし、.NET 5以降ではWindowsデスクトップ向けターゲット(net8.0-windowsなど)にしたうえで参照を追加する必要があり、素のマネージドAPIは記述量も多くなります。実務ではFlaUI(NuGetのFlaUI.UIA3、最新は5.0.0)を使うほうが速く、要素検索とパターン呼び出しが1行にまとまります。

using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;

using var automation = new UIA3Automation();
var window = automation.GetDesktop()
    .FindFirstChild(cf => cf.ByName("電卓"))
    .AsWindow();

window.FindFirstDescendant(cf => cf.ByAutomationId("num7Button"))
      .AsButton()
      .Invoke();

ここでApplication.Launch("calc.exe")からGetMainWindow()を呼ぶ書き方をすると、電卓では要素が取れません。現在の電卓はストアアプリで、calc.exeは本体プロセスを起こして自分は終了するランチャーにすぎず、Launchが返すプロセスにウィンドウが存在しないためです。起動プロセスと自動化対象プロセスが一致しないアプリでは、デスクトップから名前で引く(上のコードの形)か、起動後に実プロセスへアタッチします。

Python:pip install uiautomation

Pythonではuiautomationパッケージ(最新2.0.29、2025年8月5日リリース、Apache-2.0)が定番です。内部はcomtypes経由でUIAのCOM APIを呼んでいます。

pip install uiautomation
import subprocess
import uiautomation as auto

subprocess.Popen('calc.exe')
auto.SetGlobalSearchTimeout(5)

calc = auto.WindowControl(searchDepth=1, RegexName='電卓|Calculator')
calc.SetActive()
calc.ButtonControl(AutomationId='num7Button').Click()
calc.ButtonControl(AutomationId='plusButton').Click()
calc.ButtonControl(AutomationId='num3Button').Click()
calc.ButtonControl(AutomationId='equalButton').Click()

print(calc.TextControl(AutomationId='CalculatorResults').Name)

SetGlobalSearchTimeoutは要素が現れるまでの待ち時間で、既定は10秒です。各コントロールは操作時にこのタイムアウトの範囲で再検索を試みるため、ウィンドウの描画が遅いアプリでも即座に落ちることはありませんが、タイムアウトを短く設定したまま重いダイアログを掴もうとすると要素未検出で例外になります。最終行のCalculatorResultsが返すNameは数値だけでなく「表示は 10」(英語環境では「Display is 10」)という読み上げ用の文字列なので、値として使うならパースが要ります。要素ツリーを確認したいときはauto.EnumAndLogControlでダンプでき、Inspectを開かずに構造を把握できます。なお、このパッケージ名(uiautomation)とMicrosoftのAPI名が同じため検索結果に両方が混ざりますが、pip install uiautomationで入るのはあくまでPythonラッパーです。

VBA:参照設定でUIAutomationClientを追加する

ExcelなどのVBAからもUIAは使えます。ここが最もつまずきやすいポイントで、CreateObject("UIAutomationClient")は動きません。UIAのクライアントはProgIDを持つ通常のCOMオブジェクトとして登録されていないためです。VBEの[ツール]→[参照設定]でUIAutomationClientにチェックを入れる事前バインディングを行ってください(実体はC:\Windows\System32\UIAutomationCore.dllのタイプライブラリ)。CLSIDモニカ(GetObject("new:{ff48dba4-60ef-4201-aa87-54103eef594e}"))で遅延バインドする裏技もありますが、その場合UIA_NamePropertyIdのような型ライブラリ由来の定数が使えず、数値をハードコードする羽目になります。参照設定を使うのが実質的な前提と考えてよいでしょう。

Sub ClickSeven()
    Dim uia As New CUIAutomation
    Dim root As IUIAutomationElement
    Dim cond As IUIAutomationCondition
    Dim win As IUIAutomationElement
    Dim btn As IUIAutomationElement
    Dim inv As IUIAutomationInvokePattern

    Set root = uia.GetRootElement()
    Set cond = uia.CreatePropertyCondition(UIA_NamePropertyId, "電卓")
    Set win = root.FindFirst(TreeScope_Children, cond)

    Set cond = uia.CreatePropertyCondition(UIA_AutomationIdPropertyId, "num7Button")
    Set btn = win.FindFirst(TreeScope_Descendants, cond)

    Set inv = btn.GetCurrentPattern(UIA_InvokePatternId)
    inv.Invoke
End Sub

「Excelの操作をVBAで、他アプリの画面操作をUIAで」という組み合わせは、レガシー業務システムのデータ転記でよく採られます。ただしWeb版OfficeやOffice ScriptsにはVBA相当の外部アプリ操作機能はありません。Excel側の自動化手段を検討しているなら、Office ScriptsとVBAの違いも併せて確認してください。

PowerShell:追加インストールなしで試す

手元で挙動を確認するだけなら、PowerShellが最短です。.NETのアセンブリをロードするだけで動きます(Windows PowerShell 5.1で動作。PowerShell 7系ではWindowsデスクトップ ランタイムを含むビルドが必要です)。

Add-Type -AssemblyName UIAutomationClient, UIAutomationTypes

$root = [Windows.Automation.AutomationElement]::RootElement
$cond = New-Object Windows.Automation.PropertyCondition(
    [Windows.Automation.AutomationElement]::NameProperty, "電卓")
$win  = $root.FindFirst("Children", $cond)

$cond = New-Object Windows.Automation.PropertyCondition(
    [Windows.Automation.AutomationElement]::AutomationIdProperty, "num7Button")
$btn = $win.FindFirst("Descendants", $cond)
$btn.GetCurrentPattern([Windows.Automation.InvokePattern]::Pattern).Invoke()

UIAを選ぶべき場面と、選ぶべきでない場面

UIAは万能ではありません。次の切り分けを最初に決めておくと、作ってから作り直す事故を防げます。

対象 適した手段 UIAの位置づけ
WPF / WinForms / Win32アプリ UIA(FlaUI・uiautomation) 本命
ブラウザ上のWebアプリ Playwright・Selenium 使わない
複数システムをまたぐ業務フロー RPA(OpenRPA等) RPAの内部エンジンとして働く
UIを持たない処理 API・CLI・DB直結 使わない

特に、Webアプリの操作にUIAを使ってはいけません。ChromiumベースのブラウザはDOMの要素をUIAツリーにも公開するため一見操作できますが、UIAにはネットワークやJavaScript実行の完了を待つ仕組みも、フレームを切り替える手段も、DOMセレクタもありません。Playwrightのようなブラウザ専用ツールに比べて安定性で勝ち目がありません。逆に、複数アプリを横断する定型業務ならOpenRPAのようなRPAツールのほうが手数は少なく済みます。ここでRPAツールの実装方式の違いを知っておくと選定を誤りません。OpenRPAのWindows操作はUIAベースで要素を掴みますが、TagUIはSikuliXによる画像認識とOCRでデスクトップを操作します。画像認識型は解像度・テーマ・フォントの変化で壊れます。要素として確実に掴みたいなら、UIAベースの手段を選ぶことが前提条件になります。UIAを直接書く価値があるのは、「RPAツールでは掴めない独自コントロールがある」「CIに組み込むテストコードとしてバージョン管理したい」といった、ツールの抽象化が邪魔になる領域です。

もう一点、選定で押さえておきたいのがWinAppDriverです。Appium経由でWindowsアプリをE2Eテストする定番として紹介されてきましたが、Microsoftによるサーバー本体の更新は2022年以降ほぼ止まっており、Appium公式ドキュメント自体が代替ドライバーへの移行を案内している状況です。既存資産の保守はともかく、これから新規に組むならWinAppDriverを土台に選ぶ理由はありません。C#ならFlaUI、Pythonならuiautomationやpywinauto(backend="uia"指定でUIAを使う)へ寄せるほうが、将来の手詰まりが少なくなります。

動かないときに疑う4つの原因

FindFirstがnullを返す原因:探索スコープとツリー非公開の切り分け

まずInspectやAccessibility Insightsでその要素がUIAツリーに存在するかを確認します。DirectXやOpenGLで画面を自前描画するアプリ(ゲームエンジン製のUI、独自描画の業務パッケージ)はプロバイダーを実装しておらず、ウィンドウ1個としてしか見えないことがあります。この場合はUIAでは手が出ず、画像認識やキーボード操作の送出に切り替えるしかありません。ツリーに存在するのに取れない場合は、探索スコープがTreeScope.Childrenのままで、実際は孫以下にあるケースがほとんどです。

UIPIによる制限:昇格プロセスのUIは操作できない

WindowsのUIPI(ユーザーインターフェイス特権の分離)により、権限の低いプロセスから管理者として昇格したプロセスのUIへは操作を送れません。対象アプリを管理者として実行しているなら、自動化スクリプト側も管理者として実行してください。UIAccess付きの署名済みアプリとして配置する正攻法もありますが、社内ツールでそこまでやる必要はまずありません。

探索速度の劣化:プロセス境界をまたぐコスト

UIAの要素アクセスはプロセス境界をまたぐため、プロパティを1つ読むたびに通信が発生します。TreeScope.Descendantsでデスクトップから全走査すると数秒単位で待たされます。対策は、ウィンドウを掴んでからその配下だけを探索することと、複数プロパティをまとめて取得するCacheRequest(マネージドAPIのCacheRequest、COM APIのIUIAutomationCacheRequest。FlaUIにも同等のキャッシュ機構がある)を使うことです。ループの中で毎回ルートから引き直しているコードは、たいていここが原因で遅くなっています。

Name依存による破損:AutomationId付与という根本対策

Nameやツリーの相対位置に依存した検索は、アプリの更新で簡単に壊れます。持続可能にする条件は単純で、自社開発アプリならAutomationIdを開発側に振ってもらうことです。WPFならAutomationProperties.AutomationIdをXAMLに書くだけで、テストコード側の要素特定は安定します。UIAはアクセシビリティAPIなので、この対応はスクリーンリーダー対応の改善も同時に達成します。他社製アプリが相手でこれができない場合は、UIの更新でテストが落ちる前提でメンテナンス工数を見込んでおく必要があります。

よくある質問

UI Automationとは何ですか?

Windowsに標準搭載されたアクセシビリティAPIで、デスクトップ上のUI要素をプログラムから取得・操作できます。スクリーンリーダーなどの支援技術のために設計された仕組みですが、同じクライアントAPIをテスト自動化や業務システムの操作自動化に使えます。

UI AutomationとVBAの関係は?

VBAからUIAのCOMインターフェイスを呼び出せば、Excelマクロから他アプリの画面を操作できます。VBEの[ツール]→[参照設定]でUIAutomationClientを追加する事前バインディングが必要で、CreateObjectによる遅延バインディングは使えません。

WindowsのUIAとは何ですか?

UIAはUI Automationの略称です。Windows Vistaで導入され、それ以前のMSAA(Microsoft Active Accessibility)を置き換える設計になっています。現在Microsoftが最新として案内しているのはCOMベースのUIA 3.0で、UIAutomationCore.dllが実体です。

pip install uiautomationで入るのはMicrosoftの製品ですか?

いいえ。PyPIのuiautomationはMicrosoftのUIA COM APIをPythonから呼ぶためのサードパーティ製ラッパー(Apache-2.0、最新2.0.29)です。名前が同じため混同されますが、API本体はWindows側にあります。

UI AutomationでWebページは操作できますか?

要素自体はUIAツリーに現れますが、実用には向きません。UIAには通信やJavaScript実行の完了を待つ機構、iframeを切り替える手段、DOMセレクタがないためです。Web操作はPlaywrightやSeleniumを使ってください。

関連記事

資料請求

RELATED POSTS 関連記事