pywinauto: How to select this dialog? Which spying tool to use? What information do I need on it?

J. Does picture J. Does · Feb 13, 2017 · Viewed 8.6k times · Source

How can I write "hello" on the first field of the 7-zip "Add to Archive" dialog?

I managed so far to trigger the 7-zip (windows 64x) "Add to Archive" dialog using this

from pywinauto.application import Application
app = Application().start(r"C:\Program Files\7-Zip\7zFM.exe") #set the app
app.top_window_().Edit.type_keys(r"C:\Users\me\Desktop{ENTER}") 
app.top_window_().SysListView32.Select(r'test.txt') #select files in list
app.top_window_().ToolbarAdd.TypeKeys("{ENTER}") #apply

Then I can't select the Add to Archive dialog.

1: This did not work. I guess because it did not find the dialog. If so, why?

app.window(title_re="Add to Archive", class_name="#32770").print_control_identifiers()

2: This also did not work:

app.window(title_re="Add to Archive", class_name="#32770").Edit.type_keys("hello")

3: I tried to find all available dialogs on my app using print(app.windows())

But it prints this:

[<pywinauto.controls.win32_controls.DialogWrapper object at 0x0000000004033D68>, <pywinauto.controls.common_controls.ToolTipsWrapper object at 0x0000000004089128>, <pywinauto.controls.hwndwrapper.HwndWrapper object at 0x0000000004089208>, <pywinauto.controls.win32_controls.DialogWrapper object at 0x
00000000040893C8>, <pywinauto.controls.win32_controls.DialogWrapper object at 0x0000000004089390>]

I don't see any "Add to Archive" windows, why? What are those things (eg. in32_controls.DialogWrapper)?

Print screen of different spy tools spy++ for the dialog enter image description here

spy++ on the first control (it says Edit, but au enter image description here

inspect.exe for the dialog: enter image description here

Answer

J. Does picture J. Does · Feb 16, 2017

Vasily's already answered the question. I just wanted to gather all the points also mentioned in the comments and in the latest docs). (Answers in italic). Don't hesitate to fill up the holes left in this basic tuto (several question remains), or to correct it .


1/ I can't connect to this dialog

app.window(title_re="Add to Archive", class_name="#32770").print_control_identifiers()

Answer: it did not work because it's another process. So it's a kind of new app (app2). So you need to reconnect to it (some apps can launch a new process for each windows they launch).

For some app you will also need to specify the "backend", by default it's "win32". If the spy tool (cf bellow) can see the "controls" (name, class, etc. of each field, button...) in the "uia" mode, you should use Application(backend='uia')

To reconnect you need to do again app2=Application().connect(path='7zG.exe') then to select the control

It seems that the more you specify stuff to connect the easier it will connect. That's probably why Vasily used the path + the title. I just wanted to show that it also works with only the title ―in this case

2/ yes but ow do I know that it's a new process?

Answer: You can see that in the spying tool (cf 6/ and the printscreen bellow).

3/ I can't select the control (enter text in a field) on that dialog:

app.window(title_re="Add to Archive", class_name="#32770").Edit.type_keys("hello")

Answer: it's normal, you need first to connect to the dialog. First connect to the app2 (cf. above) then do that:

app2.window(title_re="Add to Archive", class_name="#32770").Edit1.type_keys(r"great success!", with_spaces = True)

4/ I tried to find all available dialogs on my app using print(app.windows())But it prints this (and other weird stuff):

[<pywinauto.controls.win32_controls.DialogWrapper object at 0x0000000004033D68>, <pywinauto.controls.common_controls.ToolTipsWrapper object at 0x0000000004089128>, <pywinauto.controls.hwndwrapper.HwndWrapper object at 0x0000000004089208>, <pywinauto.controls.win32_controls.DialogWrapper object at 0x
00000000040893C8>, <pywinauto.controls.win32_controls.DialogWrapper object at 0x0000000004089390>]

I don't see any "Add to Archive" windows, why? What are those things (eg. in32_controls.DialogWrapper)?

answer: "it returns actionable wrappers for every window". Each of these strings is the memory location (address) of the object. I don't know how to use them

You can get some text using print ([w.window_text() for w in app.windows()]) (it print that ['C:\\Users\\Me\\Desktop\\', '', '', 'M', 'Default IME'] No idea what does that means.)

5/ If I get all information needed to access these dialog and control do I really need to print these list of dialog or control?

I don't know. I don't yet fully understand the need to print the dialog list. But what I understand (maybe) is that this list of control offers way to shorten the code. Eg. it gives things like AddToArchive. Instead of writting app2.window(title_re="Add to Archive"). you could write app2.AddToArchive.

6/ Spy++ and inspect.exe doesn't even show the process (plus the second is heavy and buggy)

Answer: the best spying tool seems to be the one from AutoHotkey (bellow a printscreen of AU3_Spy.exe). It shows the name/class/process and even the control name (and other things) in a tiny window without loading the CPU. And unlike the 2 others spying tool, AutoHotkey gives the right control name

Notice also that the control names change from one spying tool to the other. The most accurate seems to be the one from autohotkey (all test worked so far). And it only gives what you need, the other spying tool show a lot of useless stuff exept what you need (such as the process and the real names of the controls)

enter image description here

You will find a bunch of spy tool here Acc explorer complete nicely Ahk (It does the same stuff as spy++, but only better).

(Feel free to use my screenshots)


Extra tips:

Is there a way to shorten the code?

.window(title_re="Add to Archive", class_name="#32770")

is equivalent to .AddtoArchive . So you could also write:

app2.AddtoArchive.type_keys(r"great success!", with_spaces = True)

Idem for other app like ditto:

dittoApp=Application().connect(path='Ditto.exe')
ditto_dialog=ditto.window(best_match='Ditto')

Is equivalent to:

ditto=Application().connect(path='Ditto.exe')
dittoApp.Ditto

Is there a list of action I can play with? You will here many action you could perform (on list, button, editing field...).

You can list all available methods of the object using:

print(dir(dlg_spec.wrapper_object()))

ex:

print(dir(ditto.ditto.SysListView321.wrapper_object()))

You need to import the pywinauto modules before using them! Modules are the class you need to import (ex: pywinauto.application module) To use them dont forget to import the class! Ex to use one of the method listed in the findbestmatch module you need: from pywinauto import findbestmatch

Another example: you need from pywinauto import keyboard to use SendKeys('^a^c')