I just discovered this old piece of code while digging through ancient e-mails. which I was quite pleased about since I thought it had been lost.
I wrote it to perform the simple function of getting text from an open window in XP, though I assume it would work for other Windows versions.
I had been writing a Java program which required text from the output of a native Windows application. And although this could probably better be achieved in a different language, I thought that integrating Python output into a Java application would be fairly trivial.
I achieved it by simply using Runtime and Process objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | final String pythonDir = "cmd /c pythonFile.py"; final Runtime r = Runtime.getRuntime(); //run python process try { Process p = r.exec(pythonDir); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()), 5000); //while there is text, read. while ((line = br.readLine()) != null) { //parse each line } } catch (Exception e) { } // done |
However, from what I remember it was the Python that proved exceptionally difficult, mainly due to terrible documentation, and from some Googling I can see I’m not the only one to have found this problem. Now at least it does seem to have gotten better, though probably it’s easier to find now that I know what to search for.
Nevertheless, I managed to hack together workable code to find a specific open window based on the Title bar text, and grab text from that window.
Though it is probably not the most elegant or fastest solution, it worked and I was able to read the window text output into my Java application perfectly.
I can’t remember enough to document my code line by line, but I think from the comments it should be quite straightforward…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | import win32con import win32gui import array import ctypes import struct import sys import win32api from ctypes import * results = [] topWindows = [] chatHwnd = 0 windowTitleText = "Window Title" #The text that the wanted window string begins with, so we can find it windowStartText = "Welcome" if __name__ == '__main__': #declare global global chatHwnd #enumerate all open windows, return topWindows win32gui.EnumWindows(_windowEnumerationHandler, topWindows) #check each window to fin the one we need for hwnd, windowText, windowClass in topWindows: if windowText.find(windowTitleText)>-1: #search the child windows # save the window handle chatHwnd = searchChildWindows(hwnd) #set the appropriate window focus (if needed) win32gui.SetFocus(hwnd) win32gui.SetForegroundWindow(hwnd) initBuff = 0 #get text while chatHwnd>0: buf_size = 1 + win32gui.SendMessage(chatHwnd, win32con.WM_GETTEXTLENGTH, 0, 0) buffer = win32gui.PyMakeBuffer(buf_size) # send a win GETTEXT request to the window and read into buffer win32gui.SendMessage(chatHwnd, win32con.WM_GETTEXT, buf_size, buffer) if buf_size-initBuff>1: print buffer[initBuff:buf_size] initBuff = buf_size #after 5 seconds, get any new text time.sleep(5) # needed for Java to read the output correctly sys.stdout.flush() '''Handler to enumerate the window with param hwnd Returns resultsList; the window details as an array, with hwnd, text and class''' def _windowEnumerationHandler(hwnd, resultList): resultList.append((hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd))) '''Recursive function, checks the text of all the children of the window with handle param hwnd until it reaches the text that we require, returns the String of this data''' def searchChildWindows(hwnd): childWindows = [] try: #get child windows win32gui.EnumChildWindows(hwnd, _windowEnumerationHandler, childWindows) except win32gui.error, exception: # This seems to mean that the control does not or cannot have child windows return #get details of each child window for childHwnd, windowText, windowClass in childWindows: #create text buffer buf_size = 1 + win32gui.SendMessage(childHwnd, win32con.WM_GETTEXTLENGTH, 0, 0) buffer = win32gui.PyMakeBuffer(buf_size) #get text from Window using hardware call. (getWindowText() did not return anything) win32gui.SendMessage(childHwnd, win32con.WM_GETTEXT, buf_size, buffer) #check to see if it's the data we want... if buffer[0:buf_size].find(windowStartText)>-1: #return the hwnd #global chatHwnd #chatHwnd = childHwnd return int(childHwnd) #else recurse, checking this window for children #might not be needed... #searchChildWindows(childHwnd) |
And there we are, I hope this is able to save someone else all the time that it cost me.
