Im new in python and pywinauto, I need start a presentation in Chrome using pywinauto and Chrome_widgetWin_1, after I ran a program - Chrome started but just show a new tab, presentation didn't appear.
First part of program calls pdf a html presentations and add a path to Chrome,
second part is calling some Chrome widget for start a presentation but apparently it doesn't work.
I have no idea what can be the problem because I don't work with there up to now and on internet there is nothing helpful.
Can anyone has any experiences with that? I appreciate any kind of help, tnx :)
pdf = "\\CIT_presentation.pdf"
htmlpres = "file:///...template_cit2.html#1"
adobe = "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
chrome = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
import xml.etree.ElementTree as ET
from suds.client import Client
class Presentation:
def start(self):
from pywinauto import application
app = application.Application()
app.start_(chrome)
pwa_app = pywinauto.application.Application()
while True:
try:
w_handle = pywinauto.findwindows.find_windows(class_name='Chrome_WidgetWin_1')[0]
window = pwa_app.window_(handle=w_handle)
window.TypeKeys(htmlpres, with_spaces = True)
window.TypeKeys("~")
break
except:
pass
Probably you mixed 2 Application objects: app and pwa_app. app relates to started chrome.exe process, pwa_app is not connected to any process, it's just a "copy-paste" from SWAPY tool.
Just remove line pwa_app = pywinauto.application.Application() and replace all pwa_app objects with app ones.
[edit1] Just in case... You need 32-bit Python 2.7.
Trying to understand the question.. First let's make that code able to actually run, by :
import pywinauto
import time
import sys
htmlpres = "zcuba.dk/2014"
chrome = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
class Presentation:
def __init__(self):
pass
def start(self):
app = pywinauto.application.Application()
app.start_(chrome)
pwa_app = pywinauto.application.Application()
while True:
try:
w_handle = pywinauto.findwindows.find_windows(class_name='Chrome_WidgetWin_1')[0]
window = pwa_app.window_(handle=w_handle)
window.TypeKeys(htmlpres, with_spaces = True)
window.TypeKeys("~")
window.TypeKeys("{F11}")
break;
except:
e = sys.exc_info()[0]
print e
time.sleep(1)
p = Presentation()
p.start()
now it works here, I cannot find any errors... sorry
next debug version of the code, it looks less like your original version, and has a lot of output to help you pinpoint your problem!
import pywinauto
import time
import sys
htmlpres = "zcuba.dk/2014"
chrome = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
class Presentation:
def __init__(self):
pass
def start(self):
print "starting the pywinauto application object, by default construction"
pwa_app = pywinauto.application.Application()
print "start chrome, via pywinauto, without parameters, for later interaction"
pwa_app.start_(chrome)
print "now I'll attempt to communicate with the chrome instance"
while True:
try:
print "find the first windows application, that has an open window, with the class name 'Chrome_WidgetWin_1' (typically a chrome tab/window instance)"
w_handle = pywinauto.findwindows.find_windows(class_name='Chrome_WidgetWin_1')[0]
print "assigned a handle to the applications window:"
print "handle is: " + str(w_handle)
print "use the handle to create a window automation object"
window = pwa_app.window_(handle=w_handle)
print "window object created:"
print window
print "Now, attempt to simulate keyboard, and write the address in the chrome window (wherever focus is - we assume it is in the address bar - but some extensions can change this behaviour)"
window.TypeKeys(htmlpres, with_spaces = True)
print "pressing enter to start the search for the address entered"
window.TypeKeys("{ENTER}")
print "pressing F11 to go for fullscreen - it is a presentation ;)"
window.TypeKeys("{F11}")
print "yay, we are done :)"
break;
except:
print "Oh, no, an Exception, (something went wrong):"
e = sys.exc_info()[0]
print e
time.sleep(1)
print "will now retry_________________________________________"
print "build presentation object"
p = Presentation()
print "start presentation"
p.start()
Vasily --- yes, now it print a some errors
<type 'exceptions.TypeError'>
File "C:/.../Program.py", line 23, in start
window = app.window_(handle=w_handle)
File "C:\Python27\lib\site-packages\pywinauto\application.py", line 400, in window_
**kwargs)
File "C:\Python27\lib\site-packages\pywinauto\application.py", line 290, in _wait_for_function_success
return func(*args, ** kwargs)
File "C:\Python27\lib\site-packages\pywinauto\findwindows.py", line 60, in find_window
windows = find_windows(**kwargs)
TypeError: find_windows() got an unexpected keyword argument 'handle'
Related
Source code
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
app = Application(backend='uia').start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
win = app['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.wait('ready')
win.menu_select("Setup->Refresh Serial and Ethernet")
win.top_window().print_control_identifiers(filename="file.txt")
# win.top_window().OKButton.click_input() ---------This is what I hope to do
else
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Problem Statement
I had to run this application with elevation rights. The above is my code. The problem is I can't identify the window (view in output image) that pops up after selection from menu. I need to close the window. Please excuse the line
win.top_window().print_control_identifiers(filename="file.txt")
It was meant write the identifiers into a text file because the structure of this code does not display the outputs for me to view. However, since nothing is appended, I guess pywinauto couldn't identify the dialog.
For a clearer understanding, please view the image (input) of when it selects the menu.
Input
Now, it pops up with this dialog (output)
Output
I've also used spy to identify the caption and it gives:
(Handle: 004E07D4,
Caption: Information,
Class: #32770(Dialog),
Style: 94C801C5)
Other things I've tried:
Besides using win.topwindow() to identify the dialog, I've used
win[Information].OKButton.click_input()
win[Information].OK.click_input()
win[Information].OK.close()
win[Information].OK.kill(soft=false)
win.Information.OKButton.click_input()
win.Information.OK.click_input()
win.Information.OK.close()
win.Information.OK.kill(soft=false)
app[Information] ...... curious if I could discover the new window from original application
I've also send keys like enter, space, esc & alt-f4 to close the dialog with libraries like keyboard, pynput & ctypes. It still doesn't work.
Link to download the same application: http://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-1NHAMZX
Any help would be greatly appreciated !
I finally found a thread that demonstrated the way multi thread works to solve this issue. I tried it myself and it works. It's a little different as a few parts of the code have depreciated. Here is the link to the solution:
How to stop a warning dialog from halting execution of a Python program that's controlling it?
Here are the edits I made to solve the problem:
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
def __init__(self, window_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
def run(self):
while True:
try:
handles = windows.find_windows(title=self.window_name)
except windows.WindowNotFoundError:
pass
else:
for hwnd in handles:
app = Application()
app.connect(handle=hwnd)
popup = app[self.window_name]
popup.close()
if self.quit_event.is_set():
break
time.sleep(1)
quit_event = threading.Event()
mythread = ClearPopupThread('Information', quit_event)
mythread.start()
application = Application(backend="uia").start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
time.sleep(2)
win = application['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.menu_select("Setup->Refresh Serial and Ethernet")
quit_event.set()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
The best thing is this solution works for every other dialog that halts the main script from working & I could use them to do different actions like clicking buttons, inserting values, by adding more multi threads.
I'm writing a Python application with PyQt 5.10.It seems I have some sort of bug/memory leak, since when I call close() on my MainWindow the process keeps running. After a bit of research and debugging I was able to circumscribe the supposedly faulty code.This is my main:
if __name__ == '__main__':
app = QApplication(sys.argv)
matteo = God()
matteo.runApp()
sys.exit(app.exec())
Here you will find the runApp function from God class:
def runApp(self):
self.painter = Painter()
self.dbManager = DBManager()
self.userInput = UserInput()
self.excelFile = ExcelFile()
self.painter.connectToClasses(self, ["god","db","ui"])
self.excelFile.connectToClasses(self, ["god",])
self.painter.drawMainWindow()
self.loadConf()
self.openDB(True)
if self.dbManager.error==None:
self.painter.drawSearchWidget()
else:
print("Closed.")
The process keeps running when the app is not able to find the configuration file, and so it creates a new one from scratch and it asks the user to select the database which he wants to connect to. This prompts an error message - if the selected file is corrupted or it's not the right format - and I think there might lie my problem.That's the code:
def checkError(self, classType):
if classType=="db":
error = self.dbManager.error
elif classType=="excel":
error = self.excelFile.error
if error!=None:
self.painter.drawError(classType)
self.userInput.error = self.painter.error.clickedButton()
self.userInput.error = self.painter.error.buttonRole(self.userInput.error)
if (self.userInput.error==1):
self.painter.mainWindow.close()
return 0
return 1
def drawError(self, classType):
if (classType=="db"):
title = "Database"
error = self.dbManager.error
otherButton = "Browse"
elif (classType=="excel"):
title = "Excel file"
error = self.excelFile.error
try:
self.setErrorText(False, error)
if error[0]:
if self.error.icon()!=3:
self.error.setIcon(3)
buttons = self.error.buttons()
for button in buttons:
if button.text()!="Quit":
button.hide()
button.deleteLater()
except AttributeError:
self.error = QMessageBox()
self.setErrorText(True, error)
if (error[0]):
self.error.setIcon(3)
else:
self.error.setIcon(2)
self.error.addButton(otherButton, self.error.AcceptRole)
self.error.addButton("Quit", self.error.RejectRole)
self.error.setWindowTitle(title)
self.error.exec()
If the user clicks the quit button on the error window, the function closes main window and return 0. The other functions return and the application prints closed on the console. But the process keeps going.
I kind of resolved this issue calling sys.exit() instead of printing closed.
It's a brute force solution to say the least, but I needed to deliver the application fast and I had no time to debug it.I guess this sad story will end here.
We have an app that is built with openframeworks. When started, it first opens a console window that does some work (and stays open) and then starts two more child processes that each open a window in fullscreen, one on each monitor. According to the guy that is building the app, it is impossible to give those two windows titles.
My job is to build a script that:
Checks if the app has crashed and reopens it
Verifies that the windows are in the foreground and one of them is in focus and fixes them if they aren't
I want to reuse an old python script of mine that did exactly this and altered it to fit the bill.
from time import sleep
import subprocess
import psutil
import re
import win32gui
import win32con
client_path = "C:\\path_to_app.exe"
window_name = ""
class WindowMgr:
"""Encapsulates some calls to the winapi for window management"""
def __init__(self, ):
"""Constructor"""
self._handle = None
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
'''Pass to win32gui.EnumWindows() to check all the opened windows'''
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
"""put the window in the foreground"""
win32gui.SetForegroundWindow(self._handle)
def maximize(self):
win32gui.ShowWindow(self._handle, win32con.SW_MAXIMIZE)
def is_minimized(self):
return win32gui.IsIconic(self._handle)
def client_crashed():
for pid in psutil.pids():
if psutil.Process(pid).name() == "app.exe":
return False
return True
if __name__ == "__main__":
w = WindowMgr()
w.find_window_wildcard(window_name)
print("Checking")
while True:
if client_crashed() is True:
print("Reopening app.exe")
subprocess.Popen([client_path])
else:
print("Not crashed")
if w.is_minimized:
print("Maximizing")
w.set_foreground()
w.maximize()
else:
print("Not minimized")
print("Sleeping for 10")
sleep(10)
Now the checking for crashing and restarting works just fine. But since the windows have no title, the best I've come up with so far is to check for windows with no name, which apparently opens random programms like the Windows 10 movie programm (or at least brings them to the foreground which is weird because they should not be running).
Is there a better way to bring a window into focus without knowing its name? One thought of mine was to get the parent process and then access the children from there and bring them into focus somehow, but I've not been able to figure out how.
If there are better ways to achieve what I want than using python, I would also be glad for any pointers in that direction.
If you have unique window class name you can try GetClassName() https://msdn.microsoft.com/en-us/library/windows/desktop/ms633582(v=vs.85).aspx
Or get the window process GetWindowThreadProcessId() and check whether it's an instance of your app. See How to get the process name in C++
One thought of mine was to get the parent process and then
access the children from there and bring them into focus somehow, but
I've not been able to figure out how."
I've been through the very similar issue, I wanted to find a child proccess with random title name, I only had the name of the executable. Here is what I've done.
import win32gui
def windowFocusPassingPID(pid):
def callback(hwnd, list_to_append):
list_to_append.append((hwnd, win32gui.GetWindowText(hwnd)))
window_list = []
win32gui.EnumWindows(callback, window_list)
for i in window_list:
print(i) # if you want to check each item
if pid == i[0]:
print(i) # printing the found item (id, window_title)
win32gui.ShowWindow(i[0], 5)
win32gui.SetForegroundWindow(i[0])
break
# Here we will call the function, providing a valid PID
windowFocusPassingPID(INSERT_PID_HERE_IT_MUST_BE_AN_INTEGER)
So, this is a function that will call win32gui.EnumWindows, which handles all top-level windows. Those windows will be appended to the window_list, letting us know all the ID's and window names...
In the loop, we will iterate over the list and match the PID you want to bring to focus...
You can comment both print(i) if you want.
Here is the documentation:
http://timgolden.me.uk/pywin32-docs/win32gui__EnumWindows_meth.html
I see there's win32process.GetWindowThreadProcess() that gets a window handler and returns it's process id. Is there a way to do the opposite: get the window handler of a running process by it's process id? Something like win32gui.GetWindowHandler(processId) ?
Specifically What I'm trying to do:
I have a python script that runs an external program, lets say notepad.exe.
Notepad is fired when runProgram() method is called. I want to prevent this method from running Notepad more than once. I accomplish this in the following way, using win32process:
import win32process as process
import sys
PORTABLE_APPLICATION_LOCATION = "C:\\Windows\\system32\\notepad.exe"
processHandler = -1
def runProgram():
global processHandler
#don't run a process more than once
if (isLiveProcess(processHandler)):
#Bring focus back to running window!
return;
try:
startObj = process.STARTUPINFO()
myProcessTuple = process.CreateProcess(PORTABLE_APPLICATION_LOCATION,None,None,None,8,8,None,None,startObj)
processHandler = myProcessTuple[2]
except:
print(sys.exc_info[0])
def isLiveProcess(processHandler): #Process handler is dwProcessId
processList = process.EnumProcesses()
for aProcess in processList:
if (aProcess == processHandler):
return True
return False
runProgram()
This works as expected, but if the process is found to be already alive, I'd like to bring it's window back to front with win32gui
I dont think that Windows API provides a method for this , but you could iterate over all open windows , and find the one that belongs to you .
I have modified your program so it looks like this :
import win32process
import win32process as process
import win32gui
import sys
PORTABLE_APPLICATION_LOCATION = "C:\\Windows\\system32\\notepad.exe"
processHandler = -1
def callback(hwnd, procid):
if procid in win32process.GetWindowThreadProcessId(hwnd):
win32gui.SetForegroundWindow(hwnd)
def show_window_by_process(procid):
win32gui.EnumWindows(callback, procid)
def runProgram():
global processHandler
#don't run a process more than once
if (isLiveProcess(processHandler)):
#Bring focus back to running window!
show_window_by_process(processHandler)
return;
try:
startObj = process.STARTUPINFO()
myProcessTuple = process.CreateProcess(PORTABLE_APPLICATION_LOCATION,None,None,None,8,8,None,None,startObj)
processHandler = myProcessTuple[2]
except:
print(sys.exc_info[0])
def isLiveProcess(processHandler): #Process handler is dwProcessId
processList = process.EnumProcesses()
for aProcess in processList:
if (aProcess == processHandler):
return True
return False
runProgram()
Is there a way that I can run a script from another while getting output as readily as I get by executing it by itself.
For example:
I use the os.popen3 command to execute abc.py, but I am unable to get output from abc.py as readily as I would with doing python abc.py; it seems that I need to wait for os.popen3 command to finish:
fin, fout, ferr=os.popen3("abc.py")
out = fout.read()
err = ferr.read()
fo.write(out)
fe.write(err)
print out
print err
[EDIT]:fo and fe here are file handles to the output and error logs, respectively.
Also, what widget do I use to populate the output in, in pygtk?
import subprocess
pro = subprocess.Popen('abc.py')
Is a much better way of fiddling with another scripts ins, outs, and errors.
The subprocess module is the option, but the tricky part is to follow the output un parallel with your main loop of gtk, to accomplish that goal you must have to consider the platform that you are dealing, if you are in linux you can easily run another thread and use gtk.gdk.threads_init to use threads in pygtk, but if you are planing to run your application on windows, then you should use generators and gobject.idle_add.
About the widget, use gtk.TextBuffer associated with a gtk.TextView
Here is an example with threads
import gtk
import subprocess
import threading
gtk.gdk.threads_init()
class FollowProcess(threading.Thread):
def __init__(self, cmd, text_buffer):
self.tb = text_buffer
self.child = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
super(FollowProcess, self).__init__()
def run(self):
while not self.child.poll():
out = self.child.stdout.read(1)
if out != '':
gtk.gdk.threads_enter()
self.tb.insert_at_cursor(out)
gtk.gdk.threads_leave()
def destroy(w, cmd):
cmd.child.terminate()
gtk.main_quit()
i = 0
def click_count(btn):
global i
message.set_text('Calling button %d' %i)
i += 1
other_command = 'python extranger.py'
w = gtk.Window()
w.resize(400, 400)
message = gtk.Label('Nothing')
tb = gtk.TextBuffer()
tv = gtk.TextView(tb)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(tv)
box = gtk.VBox()
button = gtk.Button('Active button')
cmd = FollowProcess('python extranger.py', tb)
button.connect('clicked', click_count )
w.connect('destroy', destroy, cmd)
box.pack_start(button, False)
box.pack_start(message, False)
box.pack_start(scroll)
w.add(box)
w.show_all()
cmd.start()
gtk.main()
And in extranger.py
import time
import sys
i = 0
while True:
print 'some output %d' % i
sys.stdout.flush() # you need this to see the output
time.sleep(.5)
i += 1
Note how the button stills responsive even with the update in parallel.
You mentioned PyGtk but you can give a try to PyQt and particularly QProcess class wich has some nice signals like :
readyReadStandardError
readyReadStandardOutput
Look for a similar tool with PyGtk.