First the Background:
A while back I wrote an insane program to automate Omnipage 14 (an OCR program) mostly via GUI automation. The urge to do this was caused by Omnipage not handling more than 300 files on its own before dying, and the lack of a better solution in the market place.
So Omnipage was very tempermental and quit often for all kinds of unexplained reasons. So my solution was to feed Omnipage 3 files at once and when it finished OCR’ing the 3 files kill all of its processes. Then give it 3 new files and relaunch it and so on.
Once I had completed the programming I set it off on it’s own to work on a network drive full of ~30,000 files needing to be OCR’d.
1 month goes by …
I come back to check on it and here is what I see on the screen!
Apparently killing the processes didn’t allow some Omnipage process to clear its system tray icon. So as the headline promised here is at least one way that killing a process is harmful (and humorous). I’m sure there are plenty of more serious reasons though. (Yes, moving the mouse over these icons caused them to dissapear, so I spent a challenging 30 minutes randomly moving my mouse around the system tray and exterminating these things … )
A Better Option Than Killing
After that experience, here is the method I switched to. After Omnipage finishes its 3 files, I kindly request that it close itself using Python’s Win32 extensions. Here is the code (mostly copied from their win32 examples):
import sys
import win32process, win32api, win32pdhutil, win32con, win32security
import win32event, msvcrt, win32gui
def get_all_windows():
"""Returns dict with window desc and hwnd"""
def _MyCallback( hwnd, extra ):
"""Helper function"""
hwnds, classes = extra
hwnds.append(hwnd)
classn = win32gui.GetClassName(hwnd)
if not classn in classes:
classes[classn] = []
classes[classn].append( hwnd )
windows = []
classes = {}
win32gui.EnumWindows(_MyCallback, (windows, classes))
return classes
def request_windows_to_close(list_window_descs_to_close):
"""Send me a list of stuff to close such as:stuff_to_close=['OP15_OmniPage_Agent_Class']
run get_all_windows() to see what's available"""
classes=get_all_windows()
for windesc_to_close in list_window_descs_to_close:
if windesc_to_close in classes:
for hwnd in classes[windesc_to_close]:
win32gui.PostMessage( hwnd, win32con.WM_CLOSE, 0, 0 )
print 'requested closure with', windesc_to_close
else:
print 'Did not find a window desc. as',windesc_to_close
Life is good now I think
Points of discussion:
- Did I miss an OCR product that I can just give it a directory with up to 60K files and have it OCR them into PDF’s?
- Is there a programmatic way to ask Windows to refresh the system tray (Don’t say moving the mouse programmatically over the system, that’s cheating.)
- I considered using the Omnipage SDK instead of GUI automation but it looked too expensive and hard to learn. Has anyone had experience with that method?
Tags: Python, win32, python win32, Python for Windows, Omnipage, GUI Automation, Automation, WTF, Windows 2000, System tray, icon, WM_CLOSE, win32gui, OCR, Autoit
Posted by Greg Pinero (Primary Searcher) in GUI Automation, win32, Python, Automation
RSS 2.0