pywinauto - how to right-click in systemtray, select an item then subitem - python

I have an application in the hidden part of the systray in Windows 10. I am trying to connect to the application, right-click on it, and then select something like "About". I understand that once I have the target application, I need to connect to the application, which I do in line 25 of the code, but I cannot get further from there.
This is the code I have so far:
from pywinauto import Application
import time
app = Application(backend="uia").connect(path="explorer.exe")
systemTray = app.window(class_name="Shell_TrayWnd")
systemTray.child_window(title="Notification Chevron").click_input(button="left")
#systemTray.print_control_identifiers()
time.sleep(0.25)
list_box = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
list_box_win = list_box.window(class_name="NotifyIconOverflowWindow")
list_box_win.wait('visible', timeout=30, retry_interval=3)
# List all the icons in the systray
for notification_area in list_box_win.children():
for app_in_tray in notification_area.children():
print(str(app_in_tray))
target_app = list_box_win.child_window(title="TrayStatus Pro Trial 4.6\r\nCaps Lock: Off")
target_app.wait('visible', timeout=30, retry_interval=3)
target_app.click_input(button="right")
target_app.target_app.print_control_identifiers()
target_app.dump_tree()
sysapp = Application().connect(path='TrayStatus.exe')
sysapp.menu_select('About') #This part fails

Application() class represents the application and sometime it fails to identify the window. Having said that, you have not mentioned the backend of the application at the beginning you have used UIA backend so figure out for the line sysapp = Application().connect(path='TrayStatus.exe') as well and add, Also adding timeout=10 parameter to the connect() works many times.
Still if the above option doesn't not work for you then try using Desktop class.
again you can mention backend of your choice and compatibility, there is no such way to identify backend of application.
window2 = Desktop(backend="win32").window(title='title of the rayStatus.exe window')
you will need to import -
from pywinauto import Desktop.
Finally you can print the titile of windows using
list_window = Desktop().windows()
for window in list_window:
window.window_texts() # this should print the all open window names on desktop

Related

How to connect to the running windwows application with pywinauto?

I'm having a problem connecting to a running window application that was opened in the browser via citrix links. I have a snippet of the window name here.
How can I find out if pywinauto can see the running window of the application?
Which code do I need for this?
My code doesn't work:
import pywinauto
from pywinauto.application import Application
app = Application(backend='uia').connect(title = 'Applikationsmenü - Produktivsystem der
LogSys-Applikation für XY')
Use process Id, see sample code
from pywinauto import application
from pywinauto.application import Application
# add your exe name here; you can get via Task Manager
yourExeName = ""
# get PID of your running process
pid = application.process_from_module(module = yourExeName)
# use Pid to connect
app = Application(backend='uia').connect(process = pid)

Pywinauto automation fails when there is no user session

I am working on program automation (program named SEO indexer). I wrote the automation using python's library name pywinauto.
Everything works just great when I am running the automation over RDP connection to the server. But when I am trying to leave the program and disconnect from RDP the "Save AS" windows window is not starting and the program crashes ...
someone knows how can I fix it?
the code that is responsible to save the file is -
def run(self, process_id, link):
controls = self._app[u'TForm1']
text_box = controls.Edit
text_box.set_text(link)
button = controls.ToolBar1
windows = Desktop(backend="uia")
button.click()
self.wait_for_finish(process_id)
result_box = controls.TVirtualStringTree
result_box.RightClick()
sleep(1)
windows_list = windows.windows()
context_menu = windows.window(best_match = "Context")
save_all_button = context_menu.children()[2]
save_all_button.select()
save_as = windows.window(best_match = "save_as")
properties_section = save_as.children()[0]
file_name = "C:\\Windows\\Temp\\indexer_" + str(randint(0, 10000))
file_name_label = properties_section.children()[4].children()[0]
file_name_label.set_text(file_name)
save_button = save_as.children()[2]
save_button.click()
sleep(2)
yes_no_dialog = windows.window(best_match = "GSA SEO Indexer v2.34")
yes_no_dialog.children()[0].click()
return file_name
it crashed on -
save_as = windows.window(best_match = "save_as")
there is a way to force it opening the save as dialog even if there are no screen ?
UPDATE:
I Just notices that the problem is not that the Save as panel is not created, the problem is that when I am without screen and trying to select from the context menu (which is created) - just the text is selected, without clicking on it
The Remote Execution Guide is what you need. This is common problem for any GUI automation tool. So the question is not exactly pywinauto related, but I wrote this guide a year ago to address it for many users.

A trouble with automation of Windows RDP through console

A brief description of my problem:
1.
My Jenkins job is required to establish an RDP connection to another machine to perform some activities.
2.
Until recently, the default password was maintained between sessions. But now some settings have changed, and the password needs to be reentered by hand each time I creating a new RDP session.
I prepared a short python script interacting with the Windows gui via the win32gui package.
I built a stand alone executable file from this script using the pyinstaller.
And finally I added a call to this executable file directly to the job.
Somethig like that:
while attempts:
security_window_title = "Windows Security"
try:
hwnd_credentials = win32gui.FindWindow(0, security_window_title)
window_controls = []
win32gui.EnumChildWindows(hwnd_credentials, collect_window_control, None)
focus_on_window(hwnd_credentials)
sleep(0.5)
prev_user_login = window_controls[2]["hwnd"]
x = int(window_controls[1]["x"] + 80)
y = int(window_controls[1]["y"] + 20)
click(x, y)
type_message(password)
ok_button = window_controls[6]["hwnd"]
push_button(ok_button)
except win32gui.error:
sleep(1)
attempts -= 1
if not attempts:
raise RuntimeError("Can't interact with window: {}.".format(security_window_title))
else:
break
while attempts:
sleep(timeout)
attempts -= 1
if check_connection_started():
break
if check_certificate_errors():
for control in window_controls[::-1]:
if control["text"] == "&Yes":
push_button(control["hwnd"])
if not attempts:
raise RuntimeError("Connection not established.")
3.
This would not be a problem when script running from the job working with the fully functional Windows ui. I can find a window in which my script is supposed to specify a password using the win32gui python package. I can generate all the appropriate keyboard events to enter a password.
Using RDP via console provides me a very strange set of windows-like objects which I can not interact with using the win32gui python package the same way as with ordinary windows. For example, I do locate a window with non zero hwnd and with text property equal to "Remote Desktop Connection". But I can't focus on such a window using the basic method win32gui.SetForegroundWindow(hwnd). This leads to an unnamed win32gui exception.
Is there any possibility to transfer the password to the desired control of the desired window-like structure, so that the job does not interrupt its execution?
Thank you so much for any help.
I can focus on both "Remote Desktop Connection" and "Windows Security" with win32gui.SetForegroundWindow(hwnd).
Sample code:
import win32api
import win32gui
import win32con
import time
from pynput.keyboard import Key, Controller
def main():
Remote = "Remote Desktop Connection"
Security = "Windows Security"
try:
hwnd_Remote = win32gui.FindWindow(0, Remote)
print(hwnd_Remote)
win32gui.ShowWindow(hwnd_Remote,win32con.SW_SHOWNORMAL)
win32gui.SetForegroundWindow(hwnd_Remote)
keyboard = Controller()
keyboard.type('ipaddress')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
time.sleep(3)
hwnd_Security = win32gui.FindWindow(0, Security)
print(hwnd_Security)
win32gui.ShowWindow(hwnd_Security,win32con.SW_SHOWNORMAL)
win32gui.SetForegroundWindow(hwnd_Security)
keyboard.type('password')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
except win32gui.error:
raise RuntimeError("Can't interact with window: {}.".format(Remote))
if __name__ == "__main__":
main()
Make sure that the foreground process did not disable calls to the SetForegroundWindow function. Add the LockSetForegroundWindow(LSFW_UNLOCK) or AllowSetForegroundWindow(ASFW_ANY) to enable the call of SetForegroundWindow.

How to automate with python software sessions with assigned unique dynamic parameter?

I've tried to automate UCL Enchance tasks, but after selection of file from list each consecutive session has unique dynamic parameter for any task. I programmed using SWAPY32bit.exe tool for pywinauto. How to automate software with unique parameters for any task?
UCL Enhance Home Page - UCL Phonetics and Linguistics
www.phon.ucl.ac.uk/resource/sfs/enhance.php
from pywinauto.application import Application
from pywinauto.timings import Timings
import time
app = Application().Start(cmd_line=u'"C:\\Program Files\\SFS\\Enhance\\enhance.exe"')
afxbd = app[u'Untitled - UCLEnhance']
afxbd.Wait('ready')
time.sleep(3)
menu_item = afxbd.MenuItem(u'&File->&1 File.wav')
menu_item.Select()
time.sleep(3)
app = Application().Start(cmd_line=u'"C:\\Program Files\\SFS\\Enhance\\enhance.exe"')
afxbd = app[u'File.wav - UCLEnhance']
menu_item = afxbd.MenuItem(u'&File->&Save Original &As...\tCtrl+S')
menu_item.Select()
The following code should work for you (tested on pywinauto 0.6.0):
from pywinauto.application import Application
import time
app = Application().Start(cmd_line=u'"C:\\Program Files\\SFS\\Enhance\\enhance.exe"')
main_window = app[u'Untitled - UCLEnhance']
main_window.wait('ready')
# further actions can be done in a loop for every input file
main_window.menu_select('&File->Open...')
app.OpenDialog.Edit.set_text(ur'C:\Program Files\SFS\Enhance\six.wav')
app.OpenDialog.Open.click_input()
app.OpenDialog.wait_not('visible')
main_window = app.window(title_re='.* - UCLEnhance')
main_window.wait('ready')
# time.sleep(...) might be necessary here
main_window.Toolbar.press_button(11) # 'Enhance' button
# WM_CHECK is handled incorrectly so use WM_CLICK to check the option
app.Enhancement.SpeechLevelRadioButton.check_by_click()
app.Enhancement.OK.click()
app.Enhancement.OK.wait_not('visible')
Hope it helps.
P.S. SWAPY is useful for simple scenarios, but more complicated cases require reading documentation and some experience in desktop GUI automation (this is really not easy sometimes). Feel free to ask more questions.
P.P.S. Very similar and more readable code using backend='uia' (MS UI Automation technology):
from pywinauto.application import Application
app = Application(backend='uia').start(cmd_line=u'"C:\\Program Files\\SFS\\Enhance\\enhance.exe"')
main_window = app[u'Untitled - UCLEnhance']
main_window.wait('ready')
main_window.menu_select('&File->Open...')
main_window.OpenDialog.Edit.type_keys(ur'C:\Program Files\SFS\Enhance\six.wav{ENTER}', with_spaces=True)
main_window.OpenDialog.wait_not('visible')
main_window = app.window(title_re='.* - UCLEnhance')
main_window.wait('ready')
main_window.Toolbar.Enhance.click()
main_window.Enhancement.SpeechLevelRadioButton.invoke()
main_window.Enhancement.OK.click()
main_window.Enhancement.OK.wait_not('visible')

xmms2 track change detection for pynotify?

I have written this little script to show current track playing on xmms2 on a notification widget using xmms client and pynotify, so when i run it i can see the widget popup with current artist and title using xmmsclient methods.
Can anybody give some hints about how to detect track change to notify automatically without having to run the script manually?
You connect the client library to a main loop, and register as a listener via the broadcast_ playback_current_id method. If you want the currently playing id when the script starts as well you can call the playback_current_id method.
Here is a small adaptation of tutorial6 in the xmms2-tutorial.git which uses the GLib Mainloop to drive the connection:
import xmmsclient
import xmmsclient.glib
import os
import sys
import gobject
def cb(result):
if not result.is_error():
print "Current: %(artist)s - %(title)s" % result.value()
ml = gobject.MainLoop(None, False)
xc = xmmsclient.XMMS("stackoverflow")
xc.connect()
conn = xmmsclient.glib.GLibConnector(xc)
xc.broadcast_playback_current_id(lambda r: xc.medialib_get_info(r.value(), cb))
ml.run()

Categories