Command line аналог Spyxx (Spy++)


(Vol) #1

Всем привет,

Посоветуйте тулзу аналогичную к Spyxx (Spy++) которая будет выводить список открытых диалогов + котролов внутри диалога (buttons, radiobuttons, etc) в cmd или файл.


(apetrovskiy) #2

Не совсем тоже самое, что Spyxx, поскольку работает, в основном, поверх MS UI Automation (и не выдаст контролов для приложений некоторых типов, например, написанных на Java)

http://uiautomation.codeplex.com/

Вам потребуется Windows PowerShell 2.0 или выше (вполне вероятно, что оболочка уже установлена, или вам придётся сделать некоторые манипуляции в Windows Features, или загрузить с сайта Microsoft).

Если ваше приложение поддерживается майкрософтовской библитечкой UI Automation, проделайте примерно то, что я проделаю ниже с калькулятором:

Это общий код (как будто бы у вас такой путь есть, вы загрузили то, что я посоветовал и туда положили):

  

  ipmo C:\1\UIAutomation.dll

ipmo C:\1\TMX.dll  

  

это примеры:

вот так сохраняем имена (тайтлы) контролов:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | %{$_.Current.Name >> C:\1\calc_report.txt;}

вот так сохраняем AutomationId (имени ведь может и не быть? Айди, впрочем, тоже):

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | %{$_.Current.AutomationId >> C:\1\calc_report.txt;}

А если и то, и другое? Вот:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | %{"$($_.Current.Name)`t$($_.Current.AutomationId)" >> C:\1\calc_report.txt;}

В результате уже более полезная информация:

Decimal separator           84

Memory add      125

Negate 80

Divide   91

Multiply               92

Subtract               94

Add        93

Memory subtract             126

Square root        110

Percentage         118

Reciprocal           114

Equals   121

Calculator            TitleBar

System Menu Bar            SystemMenuBar

System Item 1

Minimize             Minimize

Maximize            Maximize

Close     Close

Application         MenuBar

 

Может быть, вам надо что-то специфическое, кнопочки вот, к примеру (на калькуляторе смотрится особенно роскошно):

Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -ControlType Button -Name * | %{"$($_.Current.Name)`t$($_.Current.AutomationId)" >> C:\1\calc_report_2.txt;}

 

А вот не хотите ли полную инфу?

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | %{$_.Current >>

 C:\1\calc_report_3.txt;}

 

А, может быть, вам просто надо сравнить то, что было в прошолм билде, с тем, что подвалило в этом? Так можно и сравнить, отчего же нет. Вот так сохраняем контролы в виде хэш-таблиц (вместо –Full можно поиграться с –Include и –Exclude, а то зачем вам ProcessId и NativeWindowHandle?):

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | ConvertTo-UIASearchCriteria -Full  >> C:\1\calc_report_4.txt; "," >> C:\1\calc_report_4.txt;

В файле вы обнаружите что-то вроде:

@{Name="";AutomationId="";ControlType="Pane";Class="CalcFrame";AcceleratorKey="";AccessKey="";BoundingRectangle="86,205,212,264";FrameworkId="Win32";HasKeyboardFocus=$true;HelpText="";IsContentElement=$true;IsControlElement=$true;IsEnabled=$true;IsKeyboardFocusable=$false;IsOffscreen=$false;IsPassword=$false;IsRequiredForForm=$false;ItemStatus="";ItemType="";LocalizedControlType="pane";NativeWindowHandle="2035836";Orientation="None";ProcessId="3468"}

@{Name="";AutomationId="160";ControlType="Image";Class="Static";AcceleratorKey="";AccessKey="";BoundingRectangle="97,215,190,50";FrameworkId="Win32";HasKeyboardFocus=$false;HelpText="";IsContentElement=$true;IsControlElement=$true;IsEnabled=$true;IsKeyboardFocusable=$false;IsOffscreen=$false;IsPassword=$false;IsRequiredForForm=$false;ItemStatus="";ItemType="";LocalizedControlType="image";NativeWindowHandle="1773578";Orientation="None";ProcessId="3468"}

@{Name="Running History";AutomationId="404";ControlType="Text";Class="Static";AcceleratorKey="";AccessKey="";BoundingRectangle="101,218,182,13";FrameworkId="Win32";HasKeyboardFocus=$false;HelpText="";IsContentElement=$false;IsControlElement=$true;IsEnabled=$true;IsKeyboardFocusable=$false;IsOffscreen=$false;IsPassword=$false;IsRequiredForForm=$false;ItemStatus="";ItemType="";LocalizedControlType="text";NativeWindowHandle="8065048";Orientation="None";ProcessId="3468"}

@{Name="Memory";AutomationId="401";ControlType="Text";Class="Static";AcceleratorKey="";AccessKey="";BoundingRectangle="97,240,14,18";FrameworkId="Win32";HasKeyboardFocus=$false;HelpText="";IsContentElement=$false;IsControlElement=$true;IsEnabled=$true;IsKeyboardFocusable=$false;IsOffscreen=$false;IsPassword=$false;IsRequiredForForm=$false;ItemStatus="";ItemType="";LocalizedControlType="text";NativeWindowHandle="1642578";Orientation="None";ProcessId="3468"}

А вот так можно проверить (проверяем наличие кнопок с именами 1, 2 и 3):

Start-Process calc -PassThru | Get-UIAWindow | Test-UIAControlState -SearchCriteria @{Name="1";ControlType="Button"},@{name="2";controltype="button"},@{name="3";controltype="button"}

В результате вым выдадут или True, или False, что можно обработать достаточно легко. что-то у меня в 10-м ие ни перенос строки не работает, ни смена шрифта, ни смена цвета шрифта...

 


(swapy-ob) #3

Готового консольного ничего не знаю.

 

Пример питон скрипта для вывода списка всех окон:

import pywinauto

handles = pywinauto.findwindows.find_windows(title_re='.*')

app = pywinauto.application.Application()

for w_handle in handles:

  wind = app.window_(handle=w_handle)

  print wind.Texts()

 

Вывод всех контролов:

import pywinauto

app = pywinauto.application.Application()

w_handle = pywinauto.findwindows.find_window(title_re=u'.*Notepad++.*', class_name='Notepad++')

window = pwa_app.window_(handle=w_handle)

window.PrintControlIdentifiers()


(apetrovskiy) #4

если вам нужно сохранять в файл именно подокна, тогда код примет вид: get-uiawindow -n apptitle | get-uiachildwindow ... | и далее мои примеры. Если же вам надо это ловить автоматически, т.е. открылся диалог, а вы пошли за кофе, смотрите в сторону командлеты Register-UIAWindowOpenedEvent. Если же вам надо зарепортить нежданное окошко, которое вне процесса приложения, которое вы тестируете, тут уже надо звать на помощь стандартную командлету Register-WmiEvent, точа её на запуск файла (к примеру, dw20.exe), а потом уже ловить окошко через Get-UIAWindow -pn dw20 | Get-......


(apetrovskiy) #5

Если контролов много, к примеру, грид с десятками и сотнями ячеек, UI Automation может работать неожиданно долго. Конечно, и командлеты будут висеть столько же времени, ничего не выдавая. В таких случаях (это, увы, случается) приходится брать "опорные" контролы (у них обязательно должен быть хэндл), и плясать от них, ниже по иерархии.  Get-UIAWindow -n nameofwin | Get-UIAButton -Name aaa -Win32 | Get-.... .  Что касается питоновской библиотечки, интересно было бы узнать, она поддерживает контролы без хэндлов или нет? Т.е. поверх она сишной версии MS UI Automation или нет? Я смотрел её в 2008-м году, тогда она не поддерживала контролы без хэндлов (в калькуляторе даже кнопки без хэндлов, по крайней мере, на Windows 8), тогда от неё пришлось отказаться.


(swapy-ob) #6

С 2008 мало что поменялось. pywinauto это только стандартные контролы.


(apetrovskiy) #7

Сие грустно слышать, потому что, на самом деле, самая "сильная" часть MS UI Automation изначально написана на C++. На C# её позже перевели (и время от вермени обновляют). И, собственно, питон должен уметь работать и с COM (когда-то я изучал различные скриптовые языки с целью применения в том тестировании, которое тогда было (а это было ADSI, в основном), и пробовал самые разные, включая Perl и Python, надеясь на волшебство. Волшебства нет, лучше всего работали с виндовыми объектами VBA/VBScript/JScript :) ).

К примеру, проект http://uiacomwrapper.codeplex.com/ написан тем же дядечкой, что и дотнетовский UI Automation (штатный). Это обёртка поверх COM, который работает с MSAA. Т.е. автор питоновской библиотечки, похоже, просто задвинул дальнейшую разработку - ну можно же на питоне дёргать COM, разве нет??

А фразу "стандартные контролы" в наши дни следует читать как "Win32", "common controls" или "те, что из MFC". Сейчас даже Winforms контролы зачастую идут без хэндлов, к примеру, меню, или DataGrid.


(swapy-ob) #8

Python, конечно же, может работать с COM. Пробемы, помню, были с COM без диспатчера, но кажеться они тоже решаемы.

Автор pywinauto действительно давно подзабил на свое детище, но готов с радостью принимать изменения. Но похоже что таких изменений не сильно много :(

И как я понял из беседы с ним, нет никого кто бы занимался адаптацией под MSAA.

Спасибо за ссылки - очень интересно, почитаю. Может всетаки получиться скрестить python с MSAA


(swapy-ob) #9

>Я смотрел её в 2008-м году, тогда она не поддерживала контролы без хэндлов (в калькуляторе даже кнопки без хэндлов, по крайней мере, на Windows 8), тогда от неё пришлось отказаться.

Только что проверил на последнем релизе Windows 8 - в калькуляторе есть хендлы и pywinauto видит кнопочки и может на них нажимать. Правда текст кнопочек не виден, точно также как и в Win7.


(apetrovskiy) #10

да, признаюсь, с отсутствием хэндлов я хватил :) Хэндлы есть:

PS C:\Users\shuran> (Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1).Current


ControlType          : System.Windows.Automation.ControlType
LocalizedControlType : button
Name                 : 1
AcceleratorKey       :
AccessKey            :
HasKeyboardFocus     : False
IsKeyboardFocusable  : True
IsEnabled            : True
BoundingRectangle    : 1622,804,34,27
HelpText             :
IsControlElement     : True
IsContentElement     : True
LabeledBy            :
AutomationId         : 131
ItemType             :
IsPassword           : False
ClassName            : Button
NativeWindowHandle   : 133664
ProcessId            : 7248
IsOffscreen          : False
Orientation          : None
FrameworkId          : Win32
IsRequiredForForm    : False
ItemStatus           :

Просто у меня не срабатывала конструкция Get-UIAButton -Name 1 -Win32 (параметр -Win32 форсирует командлету использовать FindWindowEx вместо MS UI Automation, и чаще всего фейлится на контролах без хэндла), отчего я так опрометчиво и подумал.

Судя по всему, цифра не является тайтлом контрола (т.е. кнопки), Spy++ показывает, что Caption пустой (на заметку автору топика, кстати). Как пишет автор managed MS UI Automation, "The managed client API for UI Automation had a number of workarounds, some of them unstable, to try to cope with WinForms and Win32 common controls". Т.е., они знают где брать, и подсовывают цифру как имя контрола. А spy++ честно ничего не видит.

 


(Vol) #11

Всем спасибо за ваши ответы, я все их пересмотрел и выбрал "свой" метод - WinApi C++.

Работает очень быстро, задает мало вопросов, делает принт контролов окна в CMD + print into unicode txt file (для саппорта специальных сиволов, т.к планирую использовать на JPN). Если будут нужны исходники - обращайтесь. 

Как использовать - читайте readme.txt. :)

Ссылка на програмку - https://docs.google.com/open?id=0B4AuDIy0AOpBZ2htTjZGdmZXVUk


(apetrovskiy) #12

Вам просто повезло, что ваше приложение довольно простое (или задача простая). Если взять, к примеру spyxx из десятой студии и натравить, к примеру, на services.msc, то что мы увидим? Спай не увидит пунктов меню, кнопок тулбара, строк, тем более ячеек, грида, даже табы и то не особо. Конечно, MS UI Automation будет немного медленнее: ведь работы-то у неё в десятки раз больше. Один лишь грид содержит несколько столбцов помноженных на несколько десятков строк.


(Vol) #13

Да, кстати, такую проблему я уже видел...

Есть некоторые кнопочки которых даже Spy не видит. Особенно такое стал наблюдать на Windows 8 OS. А также в Office 2010 ("Save as" dialog).

Пока что это не критично... но нужно согласиться что это будет проблема в будущем.