UI Automatisierungsereignisse werden nach einer Weile nicht mehr angezeigt, wenn eine Anwendung überwacht und nach einiger Zeit neu gestartet wird

9

Wir verwenden Microsofts UIAutomation-Framework, um einen Client zu entwickeln, der Ereignisse einer bestimmten Anwendung überwacht und auf unterschiedliche Weise darauf reagiert. Wir haben mit der verwalteten Version des Frameworks begonnen, aber aufgrund von Verzögerungsproblemen wurde die native Version in UIACOMWrapper verschoben. Nach weiteren Problemen mit der Leistung in unserer (massiven) WPF-Anwendung haben wir uns entschieden, sie in eine separate Terminalanwendung zu verschieben (Übertragung der Ereignisse über UDP an unsere WPF-App), die alle Leistungsprobleme zu beheben schien. Das einzige Problem ist, dass die Ereignisse für TabSelection, StructureChanged, WindowOpened und WindowClosed alle paar Minuten für einige Minuten nicht mehr aufgenommen werden. Überraschenderweise werden PropertyChanged-Ereignisse weiterhin empfangen und behandelt, während dies geschieht. Ich werde den relevanten Code unseres Ereignismonitors veröffentlichen, aber das ist wahrscheinlich irrelevant, da wir ein ähnliches Verhalten bei der Verwendung des eigenen AccEvent-Dienstprogramms von Microsoft gesehen haben. Ich kann den Code der überwachten Anwendung nicht veröffentlichen, da er auch proprietär und vertraulich ist. Ich kann sagen, dass es eine WinForms-Anwendung ist, die WPF-Fenster hostet und auch ziemlich massiv ist. Hat jemand diese Art von Verhalten bei der Arbeit mit dem UI Automation Framework gesehen? Danke für deine Zeit.

Hier ist der Überwachungscode (Ich weiß, dass die Ereignisbehandlung in den UI Automation-Threads erfolgt, aber wenn Sie sie in einen dedizierten Thread verschieben, ändert sich nichts):

%Vor%

BEARBEITEN: Ich habe vergessen zu erwähnen, dass ich stark vermute, dass das Problem darin liegt, dass einer der Event-Handler-Threads der UI-Automation irgendwie hängen bleibt. Der Grund dafür ist, dass ich, als das Problem in meinem Monitor auftrat, eine Instanz von AccEvent gestartet habe und alle fehlenden Ereignisse erhalten hatte, die mein Monitor nicht erhalten hatte. Dies bedeutet, dass die Ereignisse ausgelöst, aber nicht an meinen Monitor übergeben werden.

EDIT2: Ich habe vergessen zu erwähnen, dass dies in Windows 8 mit der spezifischen Zielanwendung ausgeführt wird, ich habe dieses Phänomen auf meinem eigenen Windows 7-Rechner mit anderen Anwendungen nicht gesehen. Eine andere interessante Sache ist, dass es periodisch mehr oder weniger zu passieren scheint, aber unabhängig davon, wann ich Events abonniere, d. H. Es kann fast sofort nach dem Abonnieren passieren, aber es dauert einige Minuten, bis es wieder auftritt.

    
o_weisman 02.09.2015, 08:04
quelle

2 Antworten

2

Ich habe dieses Verhalten in meinem Projekt gesehen. Die Lösung bestand darin, die Ereignisse abzubestellen und die Ereignisse mithilfe eines Timers erneut zu abonnieren. Außerdem setze ich eine Aktion nach den Ereignissen in einer neuen Aufgabe (die in einem STA-Thread-Pool ausgeführt wird) aus.

    
DoronG 11.09.2015 04:37
quelle
2

Ich fürchte, ich kenne die Ursache der Verzögerungen, die Sie sehen, nicht, aber hier sind einige Gedanken dazu ...

Alles, was ich unten sage, bezieht sich auf die native UIA API in Windows, nicht auf die verwaltete .NET UIA API. Alle Verbesserungen an UIA in den letzten Jahren wurden an der Windows UIA API vorgenommen. Wenn ich also den C # -Code des UIA-Clients schreibe, rufe ich UIA über einen verwalteten Wrapper an, den ich mit dem SDK-Tool tlbimp.exe erzeuge.

Das heißt, ich erzeuge den Wrapper zuerst mit einem Befehl wie ...

"C: \ Programme (x86) \ Microsoft SDKs \ Windows \ v8.1A \ bin \ NETFX 4.5.1 Extras \ x64 \ tlbimp.exe" c: \ windows \ system32 \ uiautomationcore.dll / out: Interop .UIAutomationCore.dll

Dann schließe ich einen Verweis auf die Interop.UIAutomationCore.dll in meinem C # -Projekt ein, füge "mit Interop.UIAutomationCore;" zu meiner C # Datei, und dann kann ich Dinge tun wie ...

%Vor%

...

%Vor%

In Windows 7 gab es einige wichtige Einschränkungen für UIA-Ereignishandler. Es war einfach, Event-Handler zu schreiben, die diese Einschränkungen nicht berücksichtigten, was zu langen Verzögerungen bei der Interaktion mit UIA führen konnte. Zum Beispiel war es wichtig, einen UIA-Event-Handler nicht innerhalb eines Event-Handlers hinzuzufügen oder zu entfernen. Zu der Zeit habe ich absichtlich keine UIA-Aufrufe von meinem Event-Handler ausgeführt. Stattdessen poste ich mir selbst eine Nachricht oder füge eine Aktion zu einer Warteschlange hinzu, erlaube meinem Event-Handler zurückzukehren und führe kurz danach in einem anderen Thread die Aktion aus, die ich als Reaktion auf das Ereignis ausführen möchte. Das erforderte etwas mehr Arbeit von mir, aber ich wollte keine Verzögerungen riskieren. Alle von mir erstellten Threads würden in einem MTA ausgeführt.

Ein Beispiel für die oben beschriebene Aktion ist in meinem alten Fokus-Tracking-Beispiel bei Ссылка . Die Datei FocusEventHandler.cs erstellt den MTA-Thread und stellt Nachrichten in die Warteschlange, um zu verhindern, dass UIA-Aufrufe innerhalb des Ereignishandlers ausgeführt werden.

Seit Fenster 7 weiß ich, dass die Einschränkungen in UIA in Bezug auf Threading und Verzögerungen gelockert wurden und die Wahrscheinlichkeit, Verzögerungen zu begegnen, reduziert wurde. In letzter Zeit gab es in diesem Bereich einige Verbesserungen zwischen Windows 8.1 und Windows 10. Wenn es also praktisch wäre, Ihren Code unter Windows 10 auszuführen, wäre es interessant zu sehen, ob die Verzögerungen dort immer noch reproduziert werden.

Ich weiß, dass dies zeitaufwendig ist, aber Sie könnten daran interessiert sein, die Interaktion mit UIA in Ihren Event-Handlern zu entfernen und zu sehen, ob die Verzögerungen verschwinden. Wenn dies der Fall ist, wird bestimmt, welche Aktion das Problem auszulösen scheint und ob es einen alternativen Weg gibt, um Ihre Ziele zu erreichen, ohne die UIA-Interaktion in den Event-Handlern durchzuführen.

Sie rufen zum Beispiel in Ihrem Event-Handler ...

auf

this.getAutomationParent (Element) .GetRuntimeId ();

Ich erwarte, dass dies zu zwei Rückrufen in die Provider-App führt, die das Ereignis generiert hat. Der erste Aufruf besteht darin, das übergeordnete Element des Quellelements abzurufen, und der zweite Aufruf ruft die Laufzeit-ID dieses übergeordneten Elements ab. Während also UIA auf die Rückkehr Ihres Event-Handlers wartet, haben Sie zweimal in UIA zurückgerufen. Obwohl ich nicht weiß, dass das ein Problem ist, würde ich es vermeiden.

Manchmal können Sie einen Cross-Proc-Aufruf an den Provider-Prozess vermeiden, indem Sie einige interessante Daten mit dem Event selbst zwischenspeichern. Angenommen, ich weiß, dass ich die RuntimeId eines Elements möchte, das ein WindowOpened-Ereignis ausgelöst hat. Ich kann UIA bitten, diese Daten mit den Ereignissen, die ich erhalte, zwischenzuspeichern, wenn ich mich für die Ereignisse anmelde.

%Vor%

...

%Vor%

...

%Vor%

Wenn ich es für praktikabel halte, cache ich immer Daten, wenn ich mit Ereignissen oder durch UIA auf Elemente zugreife (indem ich Aufrufe wie FindFirstBuildCache () verwende), da ich so viele Cross-Proc-Aufrufe wie möglich vermeiden möchte.

Also mein Rat wäre:

  1. Verwenden Sie die native Windows UIA API mit einem verwalteten Wrapper, der von tlbimp.exe generiert wird.
  2. Speichern Sie so viele Daten wie möglich mit den Ereignissen, um zu vermeiden, dass Sie später unnötig in den Provider-Prozess zurückrufen müssen.
  3. Vermeiden Sie Anrufe von einem UIA-Ereignishandler in den UIA.

Danke,

Typ

    
Guy Barker - Microsoft 25.09.2015 16:03
quelle