Windows 標準 UI の自動化のヒント

windows-ui-automation
はじめに

今回は、Windows アプリケーションの UI 自動化について、基本的過ぎて今さら聞けない(かもしれない)ポイントをいくつか解説します。

Internet Explorer の通知バー

ウェブブラウザーでウェブサイトを開き、データファイルをダウンロードするという自動化シナリオは多いと思います。Windows に標準で付いてくる Internet Explorer は Edge の登場で引退勧告を受けているといった印象はありますが、UiPath の Edge のサポートはまだ試験段階ということもあり、まだまだ現役で使われている現状はあるかと思います。

ところで、Internet Explorer でウェブサイトからファイルのダウンロードリンクをクリックすると、クライアントエリアの下端に通知バーと呼ばれる長方形のウィンドウ (Frame Notification Bar クラス) が表示されます。 

windows-ui-automation1

このウィンドウ上に「保存」ボタンがあり、プルダウンメニューを開くためボタンがそのすぐ右に隣接しています (下の画面の赤丸部分)。ダウンロードしたファイルを「名前を付けて保存」するために、そのプルダウンメニューを開く必要がありますが、このボタン、ダウンロードを開始した直後にクリックアクティビティで SINGLE_CLICK してもプルダウンメニューが開かないことがよくあります。 

windows-ui-automation2

この問題を解く鍵は通知バーのウィンドウの可視性にあります。

通知バーは、Internet Explorer の起動直後には存在していません。表示する必要が生じた時点で生成されます。ただ一度表示されると、そのあとはウィンドウが閉じたように見えても実際には非表示状態でウィンドウはもとの場所に存在し続けます。ウィンドウスタイルの WS_VISIBLE フラグがリセットされた状態です。

ロボットは非表示状態の通知バーのウィンドウをセレクトできるのです。つまり考えられる真相としては次のとおりです。

ダウンロードを開始した直後にクリックアクティビティが非表示状態の通知バーに対して SINGLE_CLICK してしまうためにプルダウンメニューが開かないのです。そのあと、通知バーが表示状態になるため、クリックしたのにプルダウンメニューが開かない、とワークフロー開発者は誤解してしまうのです。

この問題を解決するには、要素を探す (Find Element) アクティビティで「保存しますか?」というラベルが表示されるのを待つのが良いでしょう。そのあと、クリックアクティビティで SINGLE_CLICK すれば良いわけです。

「保存しますか?」というラベルは、name 属性に「通知バーのテキスト」という固定の文字列が入りますので、これをセレクターに含めるのが良いでしょう。text 属性はセレクターには含めません。ダウンロードする対象によって設定される文字列が異なってくるからです。

クリックアクティビティの実行前の待機時間プロパティを設定して待つという方法もありますが、その待機時間で通知バーが準備完了になるかどうかは分からないのでラベルが表示されるのを待つほうが安全です。

名前をつけて保存

アプリケーションで取り扱っているデータをファイルにセーブする場合、ファイルメニューから「名前を付けて保存」を選択することでしょう。そしてポップアップするダイアログボックスのファイル名フィールドにファイル名を入力することになります。前節の例でも次のような標準的なダイアログボックスが表示されます。

windows-ui-automation3

 このファイル名を入力するフィールドはコンボボックスコントロールです。単なるエディットコントロールではないのです。ここに文字を入力 (Type Into) アクティビティでテキストを入力すると、入力した文字列に一致する実在のファイルのリストがドロップダウンリストに表示されます。この挙動は UI スレッドに負担をかけるため、コンピューターのスペックが低い場合にテキスト入力に対する応答を阻害する原因となる場合があります。UI スレッドが入力された文字を取りこぼすわけです。この入力をテキストを設定 (Set Text) アクティビティによって行うことで UI スレッドへの負担を抑えることができます。テキストを設定 (Set Text) アクティビティによるファイル名の入力は一度にすべての文字列が設定されるため、入力途中の検索結果がドロップダウンリストに表示されることはありません。

セレクターについては、cls 属性が ComboBox となる wnd 要素の次の ctrl 要素で cls 属性が Edit であるコントロールを指定することにより、確実にこのコンボボックスを構成するテキスト入力フィールドに対する操作とすることができます。

なお、入力するファイル名はフルパス名にしましょう。フォルダーのツリーからフォルダーを選ぶ必要はありませんし、ファイルの種類を選ぶ必要もありません。

ウィンドウクラス名は #32770

これ分かりますか?

ダイアログテンプレート(ダイアログを構成するラベルやボタンの情報を記述したテキスト情報)から生成されるダイアログボックスのウィンドウクラス名です。

前節の名前を付けて保存ダイアログも含め、Win32 API を利用して生成されるダイアログボックスはどれも一律このウィンドウクラス名で作成されます。そのため、特定のダイアログボックスをセレクトする場合、ウィンドウクラス名だけではうまくいきません。そこで、ダイアログボックスまたはその中のコントロールを対象とするセレクターには、トップレベルの wnd 要素に cls 属性として ’#32770’ を指定するほか、app 属性、title 属性を指定することになるわけです。app 属性にはアプリケーションの実行可能ファイルのフルパス名を指定し、title 属性にはダイアログボックスのウィンドウフレームに表示されるタイトル文字列を指定することになります。

ここで、タイトル文字列がワークフロー開発時と実運用時とで異なる場合、title 属性の値はワイルドカードを使って差異を吸収すると良いと思います。この注意ポイントは、ダイアログボックスのセレクターにのみ限る話ではありません。通常のウィンドウのセレクターに対する話にも適用されます。とはいえ、ダイアログボックスは頻繁に登場するウィンドウであり、#32770 が唯一無二のウィンドウクラス名ではないということを知った上でセレクターを調整することは良いことです。

なお、ウィンドウクラス名が一律固定となる例はまだあります。メニューバーからポップアップするメニューのウィンドウがそれです。ウィンドウクラス名は #32768 です。

メニューウィンドウに表示されるメニューアイテムをセレクトする場合、ウィンドウタイトルはないのでトップレベルの wnd 要素に title 属性は付きません。それでもメニューウィンドウの場合はシステムモーダル(その時点でシステムで唯一ユーザーの入力を受け付けている)ウィンドウなのでウィンドウクラス名のみでセレクトされるはずです。その点がダイアログボックスの場合と異なります。あとは第 2 要素や第 3 要素の ctrl 要素で name 属性にメニューアイテムのラベル文字列を指定すればよいのです。

おわりに

今回は、Windows アプリケーションの UI 自動化について、Internet Explorer でファイルをダウンロードする例を取り上げていくつかのポイントを説明しました。

可視性やクラス名といったウィンドウの特性や属性を考慮すると、いわゆる自動化における不安定さ=意図しない動きの理由が分かったりするのではないでしょうか。

Avatar Placeholder Big
Hideaki Narita

Senior Product Management Specialist, UiPath