Die UIAUTOMATION -API zeigt Menüleiste an, wenn sie aus einer App aufgerufen werden, aber nicht eine andere?

StackOverflow https://stackoverflow.com/questions/5813666

  •  25-10-2019
  •  | 
  •  

Frage

Ich habe eine Anwendung, für die ich versuche, einen automatisierten UI -Test zu schreiben. Das ist eine native C ++ ATL -Anwendung, die ein paar Kontrollpersonen hat, und eine Menüung. Eine in C# geschriebene Automatisierungs -Client -Anwendung kann die Menüleiste sehen, aber ohne ersichtlichen Grund kann eine in IronRuby geschriebene äquivalente Anwendung nicht.

Meine C# -Konsole -App kann Kinder des Hauptfensters aufzählen, und sie sieht die Menüung ... hier ist der Code

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">

Wenn ich jedoch den äquivalenten Code mit IronRuby (v1.1.3) schreibe, sind die Titelleiste und die Menubar -Steuerelemente nicht aufgeführt!

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">

Wie Sie sehen können, werden Elemente mit einer Klassenname -Eigenschaft der leeren Zeichenfolge nicht angezeigt (und beachten Sie auch die Automatisierung der Statusbar) ... aber warum ????

Der einzige Code, der hier nicht gezeigt wird, ist das Verwenden von Namespace -Zeug ...

Irgendwelche Ideen, was würde das verursachen? Sowohl meine C# App als auch IronRuby haben einen einzelnen Faden, der STA ist, und weder call coinitializecurity soweit ich das beurteilen kann.

PS: Die übliche Antwort auf diese Fragen ist die Installation des MS UI Automation 3.0 -Updates für Windows XP, Vista, Server2003 usw. Ich laufe unter Windows 7 und soweit ich weiß, gibt es keine UIA -Updates für Windows 7

PPS: Hier ist der Code für die Inspektmethode, die (nah genug) sowohl für Ruby als auch für C# ist

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);
}
War es hilfreich?

Lösung

Nach einer Ahnung fand ich Fusionsprotokolle aktiviert und bemerkte, dass meine C# -Anwendung geladen wurde UIAutomationClientSideProviders.dll, aber meine eiserne Anwendung war es nicht. Reflektor zeigt, dass diese DLL eine ganze Reihe von Anbietern für Windows -Komponenten enthält, so dass dies misstrauisch aussah.

Mein nächster Schritt war es, diese DLL von IronRuby explizit zu laden, was nichts tat.

Ich habe dann nachgeschlagen, wie Kundenanbieter arbeiten - Sie müssen anrufen ClientSettings.RegisterClientSideProviderAssembly Versammlungen, die Anbieter enthalten. Als ich dazu versuchte, bekam ich die folgende Ausnahme:

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'

Zurück zum Reflektor, um den Code für zu betrachten LoadDefaultProxies. Ich werde den Code nicht kopieren/einfügen, aber er tut dies im Grunde:

  1. Verwenden Sie die Reflexion, um alle referenzierten Baugruppen für die aktuelle ausführbare Datei zu betrachten
  2. Verwenden Sie diese Referenzen, um die zu lokalisieren UIAutomationClient Montage.
  3. Belastung UIAutomationClientsideProviders nach String-Name, mithilfe der Version, Kultur und öffentlichen Schlüssel-Token aus dem kopiert UIAutomationClient Montage

Dies erklärt, warum es funktioniert:

Meine Konsolen -App hat einen expliziten Verweis auf UIAutomationClient, und bekommt so das vollständige öffentliche Schlüsselmarke usw. und kann die ClientsideProviders DLL aus dem GAC laden

IronRuby hat keine expliziten Referenzen, da alles dynamisch ist. Daher wird nur der Zeichenfolgenname ohne öffentliche Schlüsselmotor usw. geladen und kann den GAC nicht verwenden.

Nachdem ich das entdeckt hatte, kopierte ich UIAutomationClientsideProviders.dll In mein IronRuby Bin -Verzeichnis (so wäre es im Lastpfad) und sicher genug.

Sie müssen nichts explizit laden, IronRuby muss lediglich laden können UIAutomationClientsideProviders.dll Ohne ein öffentliches Schlüssel Token oder Versionsinformationen, und alles ist gut.


Um zu vermeiden, dass Sie Dinge kopieren müssen, verwendet der folgende Code den AssemblyResolve Ereignis, um die richtige Baugruppe zurückzugeben

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top