API UIAutomation montre barre de menu lorsqu'il est appelé d'une application, mais pas un autre?

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

  •  25-10-2019
  •  | 
  •  

Question

J'ai une application que je suis en train d'écrire un test d'interface automatisée pour. Le est une application C de l'ATL native, qui a deux contrôles, et une barre de menus. Une application client d'automatisation écrit en C # peut voir la barre de menu, mais sans raison apparente, une application équivalente écrite en IronRuby ne peut pas.

Mon C # application console peut énumérer les enfants de la fenêtre principale, et il voit le MenuBar ... Voici le 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">

Cependant, quand j'écris le code équivalent en utilisant IronRuby (v1.1.3), la barre de titre et les contrôles MenuBar ne sont pas répertoriés!

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

Comme vous pouvez le voir, les éléments avec une propriété ClassName de chaîne vide ne sont pas représentés se (et notez le AutomationId sur la barre d'état est différent) ... mais pourquoi ????

Le seul code non représenté ici est la substance de l'espace de noms à l'aide ...

Toutes les idées ce serait la cause? Les deux mon application C # et IronRuby ont un seul fil qui est STA, ni appel CoInitializeSecurity pour autant que je peux dire.

PS: La réponse habituelle à ces questions est d'installer l'interface utilisateur MS automatisation 3.0 mise à jour pour Windows XP, Vista, server2003, etc. Je suis en cours d'exécution sur Windows 7, et pour autant que je sache, il n'y a aucune mise à jour de l'UIA pour les fenêtres 7

PPS: Voici le code pour la méthode Inspecter, qui est le même (assez proche) pour les deux rubis et 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);
}
Était-ce utile?

La solution

Après un pressentiment, j'ENABLED les journaux de fusion, et a remarqué que mon application C # chargeait UIAutomationClientSideProviders.dll, mais ma demande IronRuby était pas. montre de réflecteur que cette DLL contient un tas de fournisseurs pour les composants Windows, donc cela avait l'air suspect.

Mon étape suivante a consisté à charger explicitement que dll de IronRuby, qui n'a rien fait.

Je puis regardé comment fonctionnent les fournisseurs InfoClient - vous devez appeler ClientSettings.RegisterClientSideProviderAssembly pour enregistrer des ensembles contenant des fournisseurs. Quand je tentais de le faire, je suis l'exception suivante:

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'

Retour à réflecteur à regarder le code pour LoadDefaultProxies. Je ne vais pas copier / coller le code, mais il fait essentiellement ceci:

  1. Utiliser la réflexion pour examiner toutes les assemblées pour l'exécutable Référencés courant
  2. Utilisez ces références pour localiser l'ensemble UIAutomationClient.
  3. charge UIAutomationClientsideProviders par chaîne nom, en utilisant la version, la culture et la clé publique jetons copié de l'ensemble UIAutomationClient

Ceci explique pourquoi cela fonctionne:

Mon application de la console a une référence explicite à UIAutomationClient, et obtient donc le jeton de clé publique, etc, et peut charger les ClientSideProviders dll du GAC

IronRuby a n'a pas de références explicites car il est tout dynamique, il charge uniquement à l'aide de la chaîne nom sans jeton de clé publique, etc., et ne peut donc pas utiliser le GAC.

Une fois que j'ai découvert, je copié UIAutomationClientsideProviders.dll dans mon répertoire bin IronRuby (donc il serait dans le chemin de charge), et bien sûr, cela a fonctionné.

Vous n'avez pas besoin de quoi que ce soit de façon explicite la charge, IronRuby doit simplement pouvoir charger UIAutomationClientsideProviders.dll sans une clé publique d'information jeton ou la version, et tout va bien.


Pour éviter d'avoir à copier les choses, le code suivant utilise l'événement AssemblyResolve pour retourner l'assemblage correct

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top