Python Win32API SendMessage win32con WM_SETTEXT only works once - python

Simplified and working code below, but only works once then not again until the window is restarted. Is there some sort of finish set text missing or some other limitation? Can't find any results on google, Thanks
import win32api
import win32gui
import win32con
handle = windowName #Script is working with actual window name
mainWindowHWND = win32gui.FindWindow(None, handle)
win32api.SendMessage(mainWindowHWND, win32con.WM_SETTEXT, 0, "test")

You need to find the exact control handle in order to send the text. Now, you are changing the window title of that program. So Assume that you are setting a notepad window's title to 'test'. Then it become a window with title 'test'. So you can't get the window handle again with the old text.
You need to enumerate the all the child windows of that specific window and check the type of control you are interested in. Then set the text of that control You can use EnumChildWindows api function for that.
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumchildwindows

Related

Which is the best way to interact with already open native OS dialog boxes like (Save AS) using Python?

Is there any efficient way using any Python module like PyWind32 to interact with already existing Native OS dialog boxes like 'Save As' boxes?
I tried searching on Google but no help.
EDIT:
1: The Save As dialog box is triggered when user clicks on a Save As dialog box on a web application.
2: Any suggestion are welcome to handle any native OS dialog boxes which are already triggered using Python.(Need not be specific to Selenium webdriver, I am looking for a generic suggestion.)
(When I was posting the question I thought that by 'interacting with a dialog box' will implicitly mean that it is an existing one as if I am able to create one then surely I can interact with it as it is under my programs control. After reading the first 2 answers I realized I was not explicitly clear. Thats why the EDIT )
Thanks
While looking for a possible solution for this I came across several solutions on SO and otherwise.
Some of them were using AutoIT, or editing browsers profile to make it store the file directly without a prompt.
I found all this solution too specific like you can overcome the issue for Save As dialog by editing the browser profile but if later you need to handle some other window then you are stuck.
For using AutoIT is overkill, this directly collides for the fact I choose Python to do this task. (I mean Python is itself so powerful, depending on some other tool is strict NO NO for any Pythonist)
So after a long search for a possible generic solution to this problem which not only serves any one who is looking to handle any Native OS dialog boxes like 'Save As', 'File Upload' etc in the process of automating a web application using selenium web driver but also to any one who wants to interact with a specific window using only Python APIs.
This solution makes use of Win32gui, SendKeys modules of Python.
I will explain first a generic method to get hold of any window desired then a small code addition which will also make this usable while automating a web application using Selenium Webdriver.
Generic Solution::
import win32gui
import re
import SendKeys
class WindowFinder:
"""Class to find and make focus on a particular Native OS dialog/Window """
def __init__ (self):
self._handle = None
def find_window(self, class_name, window_name = None):
"""Pass a window class name & window name directly if known to get the window """
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
'''Call back func which checks each open window and matches the name of window using reg ex'''
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
""" This function takes a string as input and calls EnumWindows to enumerate through all open windows """
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
"""Get the focus on the desired open window"""
win32gui.SetForegroundWindow(self._handle)
win = WindowFinder()
win.find_window_wildcard(".*Save As.*")
win.set_foreground()
path = "D:\\File.txt" #Path of the file you want to Save
ent = "{ENTER}" #Enter key stroke.
SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog
SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog
To use this code you need to provide a string which is the name of the window you want to get which in this case is 'Save As'. So similarly you can provide any name and get that window focused.
Once you have the focus of the desired window then you can use SendKeys module to send key strokes to the window which in this case includes sending file path where you want to save the file and ENTER.
Specific to Selenium Webdriver::
The above specified code segment can be used to handle native OS dialog boxes which are triggered through a web application during the automation using Selenium Webdriver with the addition of little bit of code.
The issue you will face which I faced while using this code is that once your automation code clicks on any Web Element which triggers a native OS dialog window, the control will stuck at that point waiting for any action on the native OS dialog window. So basically you are stuck at this point.
The work around is to generate a new thread using Python threading module and use it to click on the Web Element to trigger the native OS dialog box and your parent thread will be moving on normally to find the window using the code I showed above.
#Assume that at this point you are on the page where you need to click on a Web Element to trigger native OS window/dialog box
def _action_on_trigger_element(_element):
_element.click()
trigger_element = driver.find_element_by_id('ID of the Web Element which triggers the window')
th = threading.Thread(target = _action_on_trigger_element, args = [trigger_element]) #Thread is created here to call private func to click on Save button
th.start() #Thread starts execution here
time.sleep(1) #Simple Thread Synchronization handle this case.
#Call WindowFinder Class
win = WindowFinder()
win.find_window_wildcard(".*Save As.*")
win.set_foreground()
path = "D:\\File.txt" #Path of the file you want to Save
ent = "{ENTER}" #Enter key stroke.
SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog
SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog
#At this point the native OS window is interacted with and closed after passing a key stroke ENTER.
# Go forward with what ever your Automation code is doing after this point
NOTE::
When using the above code in automating a web application, check the name of the window you want to find and pass that to find_window_wildcard(). The name of windows are browser dependent. E.g. A window which is triggered when you click on an Element to Upload a file is called 'File Upload' in Firefox and Open in Chrome.
Uses Python2.7
I hope this will help any one who is looking for a similar solution whether to use it in any generic form or in automating a web application.
EDIT:
If you are trying to run your code through command line arguments then try to use the thread to find the window using Win32gui and use the original program thread to click on the element (which is clicked here using the thread). The reason being the urllib library will throw an error while creating a new connection using the thread.)
References::
SO Question
SenKeys
Win32gui
There is a Python module called win32ui. Its found in the Python for Windows extensions package. You want the CreateFileDialog function.
Documentation
Edit:
This is a save dialog example. Check the documentation for the other settings.
import win32ui
if __name__ == "__main__":
select_dlg = win32ui.CreateFileDialog(0, ".txt", "default_name", 0, "TXT Files (*.txt)|*.txt|All Files (*.*)|*.*|")
select_dlg.DoModal()
selected_file = select_dlg.GetPathName()
print selected_file
from time import sleep
from pywinauto import Application, keyboard
app = Application(backend='uia').start('notepad.exe')
app.top_window().set_focus()
main = app.window(title='Untitled - Notepad', control_type='Window')
main.draw_outline(colour='red', thickness=2)
fileMenu = main.child_window(title='File')
fileMenu.draw_outline(colour='red', thickness=2)
fileMenu.click_input()
keyboard.send_keys("{VK_CONTROL}{VK_SHIFT}{S}")
sleep(2)
dlg = main.window(title='Save As')
dlg.draw_outline(colour='red', thickness=2)
savebtn = dlg.child_window(title='Save')
filePath = dlg.child_window(title='File name:', control_type='Edit')
savebtn.draw_outline(colour='red', thickness=2)
filePath.set_text('D:\\aa.txt')
filePath.draw_outline(colour='red', thickness=2)
savebtn.click_input()
I recommend using pywinauto lib.
If you have opened notepad and "Save as" dialog window:
from pywinauto import application
app = application.Application()
app.connect(title='test1.txt - Notepad')
app.SaveAs.Edit1.type_keys("test2.txt")
app.SaveAs.Save.click()

Python: win32gui.SetForegroundWindow

I have just written simple script to launch an applciation and I am trying to use "SendKeys" module to send keystrokes to this application. There is one "Snapshot" button, but I cant get Python to click "Snapshot" button, as the new window is not in focus. So I am planning to use Win32gui module's win32gui.FindWindow and win32gui.SetForegroundWindow functionality. But it gives me error- invalid handle. My app name is "DMCap"
Here is code snippet in Python:
handle = win32gui.FindWindow(0, "DMCap") //paassing 0 as I dont know classname
win32gui.SetForegroundWindow(handle) //put the window in foreground
Can anyone help me? Is this Python code correct? Can I send handle directly like this?
Your code should run just fine as-is, IF there is truly a window titled "DMCap." To get a list of handles and titles, run the code below:
import win32gui
def window_enum_handler(hwnd, resultList):
if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd) != '':
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
def get_app_list(handles=[]):
mlst=[]
win32gui.EnumWindows(window_enum_handler, handles)
for handle in handles:
mlst.append(handle)
return mlst
appwindows = get_app_list()
for i in appwindows:
print i
This will produce a list of tuples containing handle, title pairs.

Interacting with a gtk.container while gtk.main() is executing?

Experimenting with a battery monitor icon at the moment in Python using pygtk and egg.trayicon to create an icon to display a battery icon/tooltip.
I seem to be able to add the icon and the tooltip text, but when it then reaches the gtk.main() stage I need a way to modify these so it can then show the updated values.
I've tried gobject.idle_add() and gobject.timeout_add() without much luck, not sure where to go from this.
Anyone got any ideas?
EDIT: Perhaps not the clearest of questions.
I need to loop, fetching information from acpi while running and apply it to widgets inside the gtk container.
EDIT 2: Ok, it's properly down now. The issue was that I wasn't returning anything inside my callback. I just gave it "return 123" and now it's happily chugging away in my system tray, notifying me of my battery percentage :)
This example works for me:
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
import gobject
import gtk
from egg import trayicon
label = gtk.Label("Over here")
def callback(widget, ev):
label.set_text("You found me")
def timeout():
label.set_text("What are you waiting for?")
tray = trayicon.TrayIcon("TrayIcon")
box = gtk.EventBox()
box.add(label)
tray.add(box)
tray.show_all()
box.connect("button-press-event", callback)
gobject.timeout_add(3000L, timeout)
gtk.main()
Without seeing your code, it's hard to tell what doesn't work.

How do I take out the focus or minimize a window with Python?

I need to get focus to a specified window, and the only way I'm seeing on my head, is minimizing all windows on front of it until I get the right one...
How can I do it?
Windows 7, and no specific toolkit....
Every type of window, for example, firefox and console command
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus:
import win32gui
toplist = []
winlist = []
def enum_callback(hwnd, results):
winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
win32gui.EnumWindows(enum_callback, toplist)
firefox = [(hwnd, title) for hwnd, title in winlist if 'firefox' in title.lower()]
# just grab the first window that matches
firefox = firefox[0]
# use the window handle to set focus
win32gui.SetForegroundWindow(firefox[0])
To minimize the window, the following line:
import win32con
win32gui.ShowWindow(firefox[0], win32con.SW_MINIMIZE)
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus
To minimize the window use the following line:
def enumHandler(hwnd, lParam):
if 'firefox' in win32gui.GetWindowText(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
win32gui.EnumWindows(enumHandler, None)
This works for Windows 10, Python3.5 32bit, pywin32‑223.
I reported the above case, but an error occurred.
Traceback (most recent call last):
TypeError: The object is not a PyHANDLE object
I'm assuming from the question, that you want to write a generic to that can work with any window from any application.
You might want to try the Python Win32 GUI Automation library. I haven't used it but sounds like it might be what you are looking for. If that doesn't work, your best option might be forgo python and use a tool like AutoIt that provides built in support for window manipulation.
If neither of those solutions work you will probable have to directly invoke windows api. I do not know if the win32api package wraps the necessary functionality, otherwise you will have write a python module in c/c++.
If this kind of functionality is available in the .net api, you could use IronPython.

Alert boxes in Python?

Is it possible to produce an alert similar to JavaScript's alert("message") in python, with an application running as a daemon.
This will be run in Windows, Most likely XP but 2000 and Vista are also very real possibilities.
Update:
This is intended to run in the background and alert the user when certain conditions are met, I figure that the easiest way to alert the user would be to produce a pop-up, as it needs to be handled immediately, and other options such as just logging, or sending an email are not efficient enough.
what about this:
import win32api
win32api.MessageBox(0, 'hello', 'title')
Additionally:
win32api.MessageBox(0, 'hello', 'title', 0x00001000)
will make the box appear on top of other windows, for urgent messages. See MessageBox function for other options.
For those of us looking for a purely Python option that doesn't interface with Windows and is platform independent, I went for the option listed on the following website:
https://pythonspot.com/tk-message-box/ (archived link: https://archive.ph/JNuvx)
# Python 3.x code
# Imports
import tkinter
from tkinter import messagebox
# This code is to hide the main tkinter window
root = tkinter.Tk()
root.withdraw()
# Message Box
messagebox.showinfo("Title", "Message")
You can choose to show various types of messagebox options for different scenarios:
showinfo()
showwarning()
showerror ()
askquestion()
askokcancel()
askyesno ()
askretrycancel ()
edited code per my comment below
You can use PyAutoGui to make alert boxes
First install pyautogui with pip:
pip install pyautogui
Then type this in python:
import pyautogui as pag
pag.alert(text="Hello World", title="The Hello World Box")
Here are more message boxes, stolen from Javascript:
confirm()
With Ok and Cancel Button
prompt()
With Text Input
password()
With Text Input, but typed characters will be appeared as *
GTK may be a better option, as it is cross-platform. It'll work great on Ubuntu, and should work just fine on Windows when GTK and Python bindings are installed.
from gi.repository import Gtk
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, "This is an INFO MessageDialog")
dialog.format_secondary_text(
"And this is the secondary text that explains things.")
dialog.run()
print "INFO dialog closed"
You can see other examples here. (pdf)
The arguments passed should be the gtk.window parent (or None), DestroyWithParent, Message type, Message-buttons, title.
You can use win32 library in Python, this is classical example of OK or Cancel.
import win32api
import win32com.client
import pythoncom
result = win32api.MessageBox(None,"Do you want to open a file?", "title",1)
if result == 1:
print 'Ok'
elif result == 2:
print 'cancel'
The collection:
win32api.MessageBox(0,"msgbox", "title")
win32api.MessageBox(0,"ok cancel?", "title",1)
win32api.MessageBox(0,"abort retry ignore?", "title",2)
win32api.MessageBox(0,"yes no cancel?", "title",3)
Start an app as a background process that either has a TCP port bound to localhost, or communicates through a file -- your daemon has the file open, and then you echo "foo" > c:\your\file. After, say, 1 second of no activity, you display the message and truncate the file.

Categories