uiautomation APIは、あるアプリから呼び出されたときにメニューバーを表示しますが、別のアプリではありませんか?
-
25-10-2019 - |
質問
自動UIテストを作成しようとしているアプリケーションがあります。 ISネイティブC ++ ATLアプリケーションでは、いくつかのコントロールがあり、メノバがあります。 C#に記載されているオートメーションクライアントアプリケーションはメニューバーを見ることができますが、明白な理由はありませんが、Ironrubyで書かれた同等のアプリケーションはできません。
私のC#コンソールアプリは、メインウィンドウの子供を列挙することができ、メノバーが表示されます...これがコードです
var desktop = AutomationElement.RootElement;
var walker = TreeWalker.RawViewWalker;
var mainWindow = desktop.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "TheWindowName"));
var child = walker.GetFirstChild(mainWindow);
do
{
Console.WriteLine(child.Inspect());
child = walker.GetNextSibling(child);
}
while (child != null);
---- Output ----
<Static Name="view:" AutomationId="4337">
<Static Name="[ALL]" AutomationId="4341">
<Button Name="View" AutomationId="4322">
<AtlAxWinLic100 Name="" AutomationId="1101">
<ATL:msctls_statusbar32 Name="" AutomationId="StatusBar">
< Name="TheWindowName" AutomationId="TitleBar">
< Name="Application" AutomationId="MenuBar">
ただし、Ironruby(v1.1.3)を使用して同等のコードを書くと、タイトルバーとメノバーコントロールはリストされていません!
desktop = AutomationElement.RootElement;
walker = TreeWalker.RawViewWalker;
mainWindow = desktop.FindFirst(TreeScope.Children, PropertyCondition.new(AutomationElement.NameProperty, "TheWindowName".to_clr_string));
child = walker.GetFirstChild(mainWindow);
until child.nil? do
Console.WriteLine(Inspect(child));
child = walker.GetNextSibling(child);
end
---- Output ----
<Static Name="view:" AutomationId="4337">
<Static Name="[ALL]" AutomationId="4341">
<Button Name="View" AutomationId="4322">
<AtlAxWinLic100 Name="" AutomationId="1101">
<ATL:msctls_statusbar32 Name="" AutomationId="6872212">
ご覧のとおり、空の文字列のクラス名プロパティを備えたアイテムは表示されていません(また、StatusBarのAutomationIDが異なることにも注意してください)...しかし、なぜ????
ここに示されていない唯一のコードは、使用している名前空間のものです...
これを引き起こすものは何ですか?私のC#アプリとIronRubyの両方には、STAである単一のスレッドがあり、私が知る限りCoinitializeSecurityを呼び出すことはありません。
PS:これらの質問に対する通常の回答は、Windows XP、Vista、Server2003などのMS UI Automation 3.0アップデートをインストールすることです。Windows7で実行されています。Windows7のUIAアップデートはありません。
PPS:RubyとC#の両方で同じ(十分に近い)検査方法のコードがあります。
public static string Inspect(this AutomationElement element)
{
var className = element.GetCurrentPropertyValue(AutomationElement.ClassNameProperty);
var name = element.GetCurrentPropertyValue(AutomationElement.NameProperty);
var id = element.GetCurrentPropertyValue(AutomationElement.AutomationIdProperty);
return String.Format("<{0} Name=\"{1}\" AutomationId=\"{2}\">", className, name, id);
}
解決
予感の後、Fusionログを有効にし、C#アプリケーションが読み込まれていることに気付きました UIAutomationClientSideProviders.dll
, 、しかし、私のIronrubyアプリケーションはそうではありませんでした。 Reflectorは、このDLLにはWindowsコンポーネント用のプロバイダー全体が含まれていることを示しているため、これは疑わしいように見えました。
私の次のステップは、Ironrubyからそのdllを明示的にロードすることでしたが、それは何もしませんでした。
それから私はクライアントサイドプロバイダーの仕組みを調べました - あなたは電話する必要があります ClientSettings.RegisterClientSideProviderAssembly
プロバイダーを含むアセンブリを登録する。これをやろうとしたとき、次の例外が得られました。
UIAutomationClient:0:in `RegisterProxyAssembly': 'UIAutomationClientsideProviders' assembly not found.
(System::Windows::Automation::ProxyAssemblyNotLoadedException)
from UIAutomationClient:0:in `LoadDefaultProxies'
from UIAutomationClient:0:in `RegisterWindowHandlers'
from UIAutomationClient:0:in `RegisterClientSideProviders'
リフレクターに戻ってコードを確認してください LoadDefaultProxies
. 。コードをコピー/貼り付けませんが、基本的にこれを行います。
- リフレクションを使用して、現在の実行可能ファイルの参照されているすべてのアセンブリを調べます
- これらの参照を使用して、
UIAutomationClient
組み立て。 - ロード
UIAutomationClientsideProviders
string-nameで、バージョン、文化、公開キーのトークンを使用してコピーしましたUIAutomationClient
組み立て
これは、それが機能する理由を説明しています:
私のコンソールアプリには、明示的な参照があります UIAutomationClient
, 、そのため、完全な公開キートークンなどを取得し、GACからclientsidediproviders dllをロードできます
Ironrubyにはすべて動的であるため、明示的な参照はありません。そのため、公開キートークンなどの文字列名を使用してのみロードするため、GACを使用できません。
これを発見したら、コピーしました UIAutomationClientsideProviders.dll
Ironruby binディレクトリに(したがって、ロードパスにあります)、確かに機能しました。
明示的に何もロードする必要はありません、Ironrubyは単にロードできる必要があります UIAutomationClientsideProviders.dll
公開キーのトークンやバージョン情報がなければ、すべてが順調です。
物事をコピーする必要がないようにするために、次のコードは AssemblyResolve
正しいアセンブリを返すイベント
require 'UIAutomationClientSideProviders, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL'
System::AppDomain.current_domain.assembly_resolve do |sender, args|
args.name == "UIAutomationClientsideProviders" ?
UIAutomationClientsideProviders::UIAutomationClientSideProviders.to_clr_type.assembly :
nil
end