UIAutomation spettacoli API barra dei menu quando viene chiamato da un app, ma non un altro?

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

  •  25-10-2019
  •  | 
  •  

Domanda

Ho una domanda che sto cercando di scrivere un test dell'interfaccia utente automatizzato per. Il è un nativo C ++ applicazione ATL, che ha un paio di controlli e una barra dei menu. Un'applicazione client di automazione scritto in C # può vedere la barra dei menu, ma per nessun motivo apparente, un programma equivalente scritto in IronRuby non possono.

Il mio C # console applicazione può enumerare i bambini della finestra principale, e vede la MenuBar ... Ecco il codice

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

Tuttavia, quando scrivo il codice equivalente utilizzando IronRuby (v1.1.3), la barra del titolo ei controlli MenuBar non sono elencati!

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

Come si può vedere, gli elementi con una proprietà ClassName di stringa vuota, non sono sempre visibili (e anche notare l'AutomationId sulla barra di stato è diversa) ... ma perché ????

L'unico codice non mostrato qui è la roba spazio dei nomi utilizzando ...

Tutte le idee cosa potrebbe causare questo? Sia il mio C # app e IronRuby hanno un unico filo conduttore che è STA, e nemmeno chiamare CoInitializeSecurity per quanto posso dire.

PS: La solita risposta a queste domande è quello di installare l'aggiornamento Microsoft UI Automation 3.0 per Windows XP, Vista, Server2003, ecc Sono in esecuzione su Windows 7, e per quanto ne so, non ci sono aggiornamenti UIA per Windows 7

PPS: Ecco il codice per il metodo Inspect, che è lo stesso (abbastanza vicino) sia per ruby ??e 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);
}
È stato utile?

Soluzione

Dopo un presentimento, ho attivato i registri di fusione, e ho notato che il mio C # applicazione stava caricando UIAutomationClientSideProviders.dll, ma la mia domanda IronRuby non lo ero. spettacoli riflettore che questa DLL contiene un intero gruppo di fornitori per i componenti di Windows, quindi questo sembrava sospetto.

Il passo successivo è stato quello di caricare esplicitamente che dll da IronRuby, che non ha fatto nulla.

Ho poi alzò gli occhi come clientside fornitori di lavoro - è necessario chiamare ClientSettings.RegisterClientSideProviderAssembly registrare assemblee contenenti fornitori. Quando ho tentato di fare questo, ho ottenuto la seguente eccezione:

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'

Di nuovo alla riflettore a guardare il codice per LoadDefaultProxies. Non voglio copiare / incollare il codice, ma ha fondamentalmente questo:

  1. Usa riflessione di guardare a tutte le assemblee referenziati per l'eseguibile corrente
  2. Utilizzare questi riferimenti per individuare il UIAutomationClient assemblaggio.
  3. carico UIAutomationClientsideProviders da stringa-nome, utilizzando la versione, la cultura e la chiave pubblica gettoni copiato dal UIAutomationClient assemblaggio

Questo spiega perché funziona:

La mia console app ha un esplicito riferimento alla UIAutomationClient, e così ottiene la piena token di chiave pubblica, ecc, e può caricare i ClientSideProviders DLL dal GAC

IronRuby ha non ha riferimenti espliciti come è tutto dinamica, in modo che solo i carichi utilizzando la stringa di nome senza token di chiave pubblica, ecc, e quindi non può utilizzare il GAC.

Una volta ho scoperto questo, ho copiato UIAutomationClientsideProviders.dll nella mia directory bin IronRuby (quindi sarebbe nel percorso di carico), e abbastanza sicuro, ha funzionato.

Non c'è bisogno di qualcosa di esplicitamente carico, IronRuby ha bisogno semplicemente di essere in grado di caricare UIAutomationClientsideProviders.dll senza una chiave informazioni simbolico o versione pubblica, e tutto va bene.


Per evitare di dover copiare le cose intorno, il codice seguente utilizza l'evento AssemblyResolve di restituire il corretto montaggio

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top