ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/ns_dev/Python/NinoCode/Active_prgs/winGuiAuto.py
Revision: 8
Committed: Sat May 5 04:21:19 2012 UTC (13 years, 10 months ago) by ninoborges
Content type: text/x-python
File size: 30593 byte(s)
Log Message:
Initial Import

File Contents

# User Rev Content
1 ninoborges 8 # Module : winGuiAuto.py
2     # Synopsis : Windows GUI automation utilities
3     # Programmer : Simon Brunning - simon@brunningonline.net
4     # Date : 25 June 2003
5     # Version : 1.0 pre-alpha 2
6     # Copyright : Released to the public domain. Provided as-is, with no warranty.
7     # Notes : Requires Python 2.3, win32all and ctypes
8     '''Windows GUI automation utilities.
9    
10     Until I get around to writing some docs and examples, the tests at the foot of
11     this module should serve to get you started.
12     '''
13    
14     import array
15     import ctypes
16     import os
17     import struct
18     import sys
19     import win32api
20     import win32con
21     import win32gui
22    
23     def findTopWindow(wantedText=None, wantedClass=None, selectionFunction=None):
24     '''Find the hwnd of a top level window.
25     You can identify windows using captions, classes, a custom selection
26     function, or any combination of these. (Multiple selection criteria are
27     ANDed. If this isn't what's wanted, use a selection function.)
28    
29     Arguments:
30     wantedText Text which the required window's captions must contain.
31     wantedClass Class to which the required window must belong.
32     selectionFunction Window selection function. Reference to a function
33     should be passed here. The function should take hwnd as
34     an argument, and should return True when passed the
35     hwnd of a desired window.
36    
37     Raises:
38     WinGuiAutoError When no window found.
39    
40     Usage example: optDialog = findTopWindow(wantedText="Options")
41     '''
42     topWindows = findTopWindows(wantedText, wantedClass, selectionFunction)
43     if topWindows:
44     return topWindows[0]
45     else:
46     raise WinGuiAutoError("No top level window found for wantedText=" +
47     repr(wantedText) +
48     ", wantedClass=" +
49     repr(wantedClass) +
50     ", selectionFunction=" +
51     repr(selectionFunction))
52    
53     def findTopWindows(wantedText=None, wantedClass=None, selectionFunction=None):
54     '''Find the hwnd of top level windows.
55     You can identify windows using captions, classes, a custom selection
56     function, or any combination of these. (Multiple selection criteria are
57     ANDed. If this isn't what's wanted, use a selection function.)
58    
59     Arguments:
60     wantedText Text which required windows' captions must contain.
61     wantedClass Class to which required windows must belong.
62     selectionFunction Window selection function. Reference to a function
63     should be passed here. The function should take hwnd as
64     an argument, and should return True when passed the
65     hwnd of a desired window.
66    
67     Returns: A list containing the window handles of all top level
68     windows matching the supplied selection criteria.
69    
70     Usage example: optDialogs = findTopWindows(wantedText="Options")
71     '''
72     results = []
73     topWindows = []
74     win32gui.EnumWindows(_windowEnumerationHandler, topWindows)
75     for hwnd, windowText, windowClass in topWindows:
76     if wantedText and not _normaliseText(wantedText) in _normaliseText(windowText):
77     continue
78     if wantedClass and not windowClass == wantedClass:
79     continue
80     if selectionFunction and not selectionFunction(hwnd):
81     continue
82     results.append(hwnd)
83     return results
84    
85     def dumpWindow(hwnd):
86     '''Dump all controls from a window into a nested list
87     Useful during development, allowing to you discover the structure of the
88     contents of a window, showing the text and class of all contained controls.
89    
90     Arguments: The window handle of the top level window to dump.
91    
92     Returns A nested list of controls. Each entry consists of the
93     control's hwnd, its text, its class, and its sub-controls,
94     if any.
95    
96     Usage example: replaceDialog = findTopWindow(wantedText='Replace')
97     pprint.pprint(dumpWindow(replaceDialog))
98     '''
99     windows = []
100     try:
101     win32gui.EnumChildWindows(hwnd, _windowEnumerationHandler, windows)
102     except win32gui.error:
103     # No child windows
104     return
105     windows = [list(window) for window in windows]
106     for window in windows:
107     childHwnd, windowText, windowClass = window
108     window_content = dumpWindow(childHwnd)
109     if window_content:
110     window.append(window_content)
111     return windows
112    
113     def findControl(topHwnd,
114     wantedText=None,
115     wantedClass=None,
116     selectionFunction=None):
117     '''Find a control.
118     You can identify a control using caption, classe, a custom selection
119     function, or any combination of these. (Multiple selection criteria are
120     ANDed. If this isn't what's wanted, use a selection function.)
121    
122     Arguments:
123     topHwnd The window handle of the top level window in which the
124     required controls reside.
125     wantedText Text which the required control's captions must contain.
126     wantedClass Class to which the required control must belong.
127     selectionFunction Control selection function. Reference to a function
128     should be passed here. The function should take hwnd as
129     an argument, and should return True when passed the
130     hwnd of the desired control.
131    
132     Returns: The window handle of the first control matching the
133     supplied selection criteria.
134    
135     Raises:
136     WinGuiAutoError When no control found.
137    
138     Usage example: optDialog = findTopWindow(wantedText="Options")
139     okButton = findControl(optDialog,
140     wantedClass="Button",
141     wantedText="OK")
142     '''
143     controls = findControls(topHwnd,
144     wantedText=wantedText,
145     wantedClass=wantedClass,
146     selectionFunction=selectionFunction)
147     if controls:
148     return controls[0]
149     else:
150     raise WinGuiAutoError("No control found for topHwnd=" +
151     repr(topHwnd) +
152     ", wantedText=" +
153     repr(wantedText) +
154     ", wantedClass=" +
155     repr(wantedClass) +
156     ", selectionFunction=" +
157     repr(selectionFunction))
158    
159     def findControls(topHwnd,
160     wantedText=None,
161     wantedClass=None,
162     selectionFunction=None):
163     '''Find controls.
164     You can identify controls using captions, classes, a custom selection
165     function, or any combination of these. (Multiple selection criteria are
166     ANDed. If this isn't what's wanted, use a selection function.)
167    
168     Arguments:
169     topHwnd The window handle of the top level window in which the
170     required controls reside.
171     wantedText Text which the required controls' captions must contain.
172     wantedClass Class to which the required controls must belong.
173     selectionFunction Control selection function. Reference to a function
174     should be passed here. The function should take hwnd as
175     an argument, and should return True when passed the
176     hwnd of a desired control.
177    
178     Returns: The window handles of the controls matching the
179     supplied selection criteria.
180    
181     Usage example: optDialog = findTopWindow(wantedText="Options")
182     def findButtons(hwnd, windowText, windowClass):
183     return windowClass == "Button"
184     buttons = findControl(optDialog, wantedText="Button")
185     '''
186     def searchChildWindows(currentHwnd):
187     results = []
188     childWindows = []
189     try:
190     win32gui.EnumChildWindows(currentHwnd,
191     _windowEnumerationHandler,
192     childWindows)
193     except win32gui.error:
194     # This seems to mean that the control *cannot* have child windows,
195     # i.e. not a container.
196     return
197     for childHwnd, windowText, windowClass in childWindows:
198     descendentMatchingHwnds = searchChildWindows(childHwnd)
199     if descendentMatchingHwnds:
200     results += descendentMatchingHwnds
201    
202     if wantedText and \
203     not _normaliseText(wantedText) in _normaliseText(windowText):
204     continue
205     if wantedClass and \
206     not windowClass == wantedClass:
207     continue
208     if selectionFunction and \
209     not selectionFunction(childHwnd):
210     continue
211     results.append(childHwnd)
212     return results
213    
214     return searchChildWindows(topHwnd)
215    
216     def getTopMenu(hWnd):
217     '''Get a window's main, top level menu.
218    
219     Arguments:
220     hWnd The window handle of the top level window for which the top
221     level menu is required.
222    
223     Returns: The menu handle of the window's main, top level menu.
224    
225     Usage example: hMenu = getTopMenu(hWnd)'''
226     return ctypes.windll.user32.GetMenu(ctypes.c_long(hWnd))
227    
228     def activateMenuItem(hWnd, menuItemPath):
229     '''Activate a menu item
230    
231     Arguments:
232     hWnd The window handle of the top level window whose menu you
233     wish to activate.
234     menuItemPath The path to the required menu item. This should be a
235     sequence specifying the path through the menu to the
236     required item. Each item in this path can be specified
237     either as an index, or as a menu name.
238    
239     Raises:
240     WinGuiAutoError When the requested menu option isn't found.
241    
242     Usage example: activateMenuItem(notepadWindow, ('file', 'open'))
243    
244     Which is exactly equivalent to...
245    
246     activateMenuItem(notepadWindow, (0, 1))'''
247     # By Axel Kowald (kowald@molgen.mpg.de)
248     # Modified by S Brunning to accept strings in addition to indicies.
249    
250     # Top level menu
251     hMenu = getTopMenu(hWnd)
252    
253     # Get top level menu's item count. Is there a better way to do this?
254     for hMenuItemCount in xrange(256):
255     try:
256     getMenuInfo(hMenu, hMenuItemCount)
257     except WinGuiAutoError:
258     break
259     hMenuItemCount -= 1
260    
261     # Walk down submenus
262     for submenu in menuItemPath[:-1]:
263     try: # submenu is an index
264     0 + submenu
265     submenuInfo = getMenuInfo(hMenu, submenu)
266     hMenu, hMenuItemCount = submenuInfo.submenu, submenuInfo.itemCount
267     except TypeError: # Hopefully, submenu is a menu name
268     try:
269     dump, hMenu, hMenuItemCount = _findNamedSubmenu(hMenu,
270     hMenuItemCount,
271     submenu)
272     except WinGuiAutoError:
273     raise WinGuiAutoError("Menu path " +
274     repr(menuItemPath) +
275     " cannot be found.")
276    
277     # Get required menu item's ID. (the one at the end).
278     menuItem = menuItemPath[-1]
279     try: # menuItem is an index
280     0 + menuItem
281     menuItemID = ctypes.windll.user32.GetMenuItemID(hMenu,
282     menuItem)
283     except TypeError: # Hopefully, menuItem is a menu name
284     try:
285     subMenuIndex, dump, dump = _findNamedSubmenu(hMenu,
286     hMenuItemCount,
287     menuItem)
288     except WinGuiAutoError:
289     raise WinGuiAutoError("Menu path " +
290     repr(menuItemPath) +
291     " cannot be found.")
292     # TODO - catch WinGuiAutoError. and pass on with better info.
293     menuItemID = ctypes.windll.user32.GetMenuItemID(hMenu, subMenuIndex)
294    
295     # Activate
296     win32gui.PostMessage(hWnd, win32con.WM_COMMAND, menuItemID, 0)
297    
298     def getMenuInfo(hMenu, uIDItem):
299     '''Get various info about a menu item.
300    
301     Arguments:
302     hMenu The menu in which the item is to be found.
303     uIDItem The item's index
304    
305     Returns: Menu item information object. This object is basically
306     a 'bunch'
307     (see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52308).
308     It will have useful attributes: name, itemCount,
309     submenu, isChecked, isDisabled, isGreyed, and
310     isSeperator
311    
312     Raises:
313     WinGuiAutoError When the requested menu option isn't found.
314    
315     Usage example: submenuInfo = getMenuInfo(hMenu, submenu)
316     hMenu, hMenuItemCount = submenuInfo.submenu, submenuInfo.itemCount'''
317     # An object to hold the menu info
318     class MenuInfo(Bunch):
319     pass
320     menuInfo = MenuInfo()
321    
322     # Menu state
323     menuState = ctypes.windll.user32.GetMenuState(hMenu,
324     uIDItem,
325     win32con.MF_BYPOSITION)
326     if menuState == -1:
327     raise WinGuiAutoError("No such menu item, hMenu=" +
328     str(hMenu) +
329     " uIDItem=" +
330     str(uIDItem))
331     menuInfo.isChecked = bool(menuState & win32con.MF_CHECKED)
332     menuInfo.isDisabled = bool(menuState & win32con.MF_DISABLED)
333     menuInfo.isGreyed = bool(menuState & win32con.MF_GRAYED)
334     menuInfo.isSeperator = bool(menuState & win32con.MF_SEPARATOR)
335     # ... there are more, but these are the ones I'm interested in
336    
337     # Menu name
338     menuName = ctypes.c_buffer("\000" * 32)
339     ctypes.windll.user32.GetMenuStringA(ctypes.c_int(hMenu),
340     ctypes.c_int(uIDItem),
341     menuName, ctypes.c_int(len(menuName)),
342     win32con.MF_BYPOSITION)
343     menuInfo.name = menuName.value
344    
345     # Sub menu info
346     menuInfo.itemCount = menuState >> 8
347     if bool(menuState & win32con.MF_POPUP):
348     menuInfo.submenu = ctypes.windll.user32.GetSubMenu(hMenu, uIDItem)
349     else:
350     menuInfo.submenu = None
351    
352     return menuInfo
353    
354     def clickButton(hwnd):
355     '''Simulates a single mouse click on a button
356    
357     Arguments:
358     hwnd Window handle of the required button.
359    
360     Usage example: okButton = findControl(fontDialog,
361     wantedClass="Button",
362     wantedText="OK")
363     clickButton(okButton)
364     '''
365     _sendNotifyMessage(hwnd, win32con.BN_CLICKED)
366    
367     def clickStatic(hwnd):
368     '''Simulates a single mouse click on a static
369    
370     Arguments:
371     hwnd Window handle of the required static.
372    
373     Usage example: TODO
374     '''
375     _sendNotifyMessage(hwnd, win32con.STN_CLICKED)
376    
377     def doubleClickStatic(hwnd):
378     '''Simulates a double mouse click on a static
379    
380     Arguments:
381     hwnd Window handle of the required static.
382    
383     Usage example: TODO
384     '''
385     _sendNotifyMessage(hwnd, win32con.STN_DBLCLK)
386    
387     def getComboboxItems(hwnd):
388     '''Returns the items in a combo box control.
389    
390     Arguments:
391     hwnd Window handle for the combo box.
392    
393     Returns: Combo box items.
394    
395     Usage example: fontCombo = findControl(fontDialog, wantedClass="ComboBox")
396     fontComboItems = getComboboxItems(fontCombo)
397     '''
398    
399     return _getMultipleWindowValues(hwnd,
400     getCountMessage=win32con.CB_GETCOUNT,
401     getValueMessage=win32con.CB_GETLBTEXT)
402    
403     def selectComboboxItem(hwnd, item):
404     '''Selects a specified item in a Combo box control.
405    
406     Arguments:
407     hwnd Window handle of the required combo box.
408     item The reqired item. Either an index, of the text of the
409     required item.
410    
411     Usage example: fontComboItems = getComboboxItems(fontCombo)
412     selectComboboxItem(fontCombo,
413     random.choice(fontComboItems))
414     '''
415     try: # item is an index Use this to select
416     0 + item
417     win32gui.SendMessage(hwnd, win32con.CB_SETCURSEL, item, 0)
418     _sendNotifyMessage(hwnd, win32con.CBN_SELCHANGE)
419     except TypeError: # Item is a string - find the index, and use that
420     items = getComboboxItems(hwnd)
421     itemIndex = items.index(item)
422     selectComboboxItem(hwnd, itemIndex)
423    
424     def getListboxItems(hwnd):
425     '''Returns the items in a list box control.
426    
427     Arguments:
428     hwnd Window handle for the list box.
429    
430     Returns: List box items.
431    
432     Usage example: TODO
433     '''
434    
435     return _getMultipleWindowValues(hwnd,
436     getCountMessage=win32con.LB_GETCOUNT,
437     getValueMessage=win32con.LB_GETTEXT)
438    
439     def selectListboxItem(hwnd, item):
440     '''Selects a specified item in a list box control.
441    
442     Arguments:
443     hwnd Window handle of the required list box.
444     item The reqired item. Either an index, of the text of the
445     required item.
446    
447     Usage example: TODO
448     '''
449     try: # item is an index Use this to select
450     0 + item
451     win32gui.SendMessage(hwnd, win32con.LB_SETCURSEL, item, 0)
452     _sendNotifyMessage(hwnd, win32con.LBN_SELCHANGE)
453     except TypeError: # Item is a string - find the index, and use that
454     items = getListboxItems(hwnd)
455     itemIndex = items.index(item)
456     selectListboxItem(hwnd, itemIndex)
457    
458     def getEditText(hwnd):
459     '''Returns the text in an edit control.
460    
461     Arguments:
462     hwnd Window handle for the edit control.
463    
464     Returns Edit control text lines.
465    
466     Usage example: pprint.pprint(getEditText(editArea))
467     '''
468     return _getMultipleWindowValues(hwnd,
469     getCountMessage=win32con.EM_GETLINECOUNT,
470     getValueMessage=win32con.EM_GETLINE)
471    
472     def setEditText(hwnd, text, append=False):
473     '''Set an edit control's text.
474    
475     Arguments:
476     hwnd The edit control's hwnd.
477     text The text to send to the control. This can be a single
478     string, or a sequence of strings. If the latter, each will
479     be become a a seperate line in the control.
480     append Should the new text be appended to the existing text?
481     Defaults to False, meaning that any existing text will be
482     replaced. If True, the new text will be appended to the end
483     of the existing text.
484     Note that the first line of the new text will be directly
485     appended to the end of the last line of the existing text.
486     If appending lines of text, you may wish to pass in an
487     empty string as the 1st element of the 'text' argument.
488    
489     Usage example: print "Enter various bits of text."
490     setEditText(editArea, "Hello, again!")
491     time.sleep(.5)
492     setEditText(editArea, "You still there?")
493     time.sleep(.5)
494     setEditText(editArea, ["Here come", "two lines!"])
495     time.sleep(.5)
496    
497     print "Add some..."
498     setEditText(editArea, ["", "And a 3rd one!"], append=True)
499     time.sleep(.5)'''
500    
501     # Ensure that text is a list
502     try:
503     text + ''
504     text = [text]
505     except TypeError:
506     pass
507    
508     # Set the current selection range, depending on append flag
509     if append:
510     win32gui.SendMessage(hwnd,
511     win32con.EM_SETSEL,
512     -1,
513     0)
514     else:
515     win32gui.SendMessage(hwnd,
516     win32con.EM_SETSEL,
517     0,
518     -1)
519    
520     # Send the text
521     win32gui.SendMessage(hwnd,
522     win32con.EM_REPLACESEL,
523     True,
524     os.linesep.join(text))
525    
526     def _getMultipleWindowValues(hwnd, getCountMessage, getValueMessage):
527     '''A common pattern in the Win32 API is that in order to retrieve a
528     series of values, you use one message to get a count of available
529     items, and another to retrieve them. This internal utility function
530     performs the common processing for this pattern.
531    
532     Arguments:
533     hwnd Window handle for the window for which items should be
534     retrieved.
535     getCountMessage Item count message.
536     getValueMessage Value retrieval message.
537    
538     Returns: Retrieved items.'''
539     result = []
540    
541     VALUE_LENGTH = 256
542     bufferlength_int = struct.pack('i', VALUE_LENGTH) # This is a C style int.
543    
544     valuecount = win32gui.SendMessage(hwnd, getCountMessage, 0, 0)
545     for itemIndex in range(valuecount):
546     valuebuffer = array.array('c',
547     bufferlength_int +
548     " " * (VALUE_LENGTH - len(bufferlength_int)))
549     valueLength = win32gui.SendMessage(hwnd,
550     getValueMessage,
551     itemIndex,
552     valuebuffer)
553     result.append(valuebuffer.tostring()[:valueLength])
554     return result
555    
556     def _windowEnumerationHandler(hwnd, resultList):
557     '''Pass to win32gui.EnumWindows() to generate list of window handle,
558     window text, window class tuples.'''
559     resultList.append((hwnd,
560     win32gui.GetWindowText(hwnd),
561     win32gui.GetClassName(hwnd)))
562    
563     def _buildWinLong(high, low):
564     '''Build a windows long parameter from high and low words.
565     See http://support.microsoft.com/support/kb/articles/q189/1/70.asp
566     '''
567     # return ((high << 16) | low)
568     return int(struct.unpack('>L',
569     struct.pack('>2H',
570     high,
571     low)) [0])
572    
573     def _sendNotifyMessage(hwnd, nofifyMessage):
574     '''Send a notify message to a control.'''
575     win32gui.SendMessage(win32gui.GetParent(hwnd),
576     win32con.WM_COMMAND,
577     _buildWinLong(nofifyMessage,
578     win32api.GetWindowLong(hwnd,
579     win32con.GWL_ID)),
580     hwnd)
581    
582     def _normaliseText(controlText):
583     '''Remove '&' characters, and lower case.
584     Useful for matching control text.'''
585     return controlText.lower().replace('&', '')
586    
587     def _findNamedSubmenu(hMenu, hMenuItemCount, submenuName):
588     '''Find the index number of a menu's submenu with a specific name.'''
589     for submenuIndex in range(hMenuItemCount):
590     submenuInfo = getMenuInfo(hMenu, submenuIndex)
591     if _normaliseText(submenuInfo.name).startswith(_normaliseText(submenuName)):
592     return submenuIndex, submenuInfo.submenu, submenuInfo.itemCount
593     raise WinGuiAutoError("No submenu found for hMenu=" +
594     repr(hMenu) +
595     ", hMenuItemCount=" +
596     repr(hMenuItemCount) +
597     ", submenuName=" +
598     repr(submenuName))
599    
600    
601     class Bunch(object):
602     '''See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52308'''
603    
604     def __init__(self, **kwds):
605     self.__dict__.update(kwds)
606    
607     def __str__(self):
608     state = ["%s=%r" % (attribute, value)
609     for (attribute, value)
610     in self.__dict__.items()]
611     return '\n'.join(state)
612    
613     class WinGuiAutoError(Exception):
614     pass
615    
616     if __name__ == '__main__':
617     # Test - drives notepad.
618     # I't like to use unittest here, but I've no idea how to automate these
619     # tests.
620    
621     # NT/2K/XP notepads have a different menu stuctures.
622     win_version = {4: "NT", 5: "2K", 6: "XP"}[os.sys.getwindowsversion()[0]]
623     print "win_version=", win_version
624    
625     import pprint
626     import random
627     import time
628    
629     print "Open and locate Notepad"
630     os.startfile('notepad')
631     time.sleep(.5)
632     notepadWindow = findTopWindow(wantedClass='Notepad')
633    
634     print "Open and locate the 'replace' dialogue"
635     if win_version in ["NT"]:
636     activateMenuItem(notepadWindow, ['search', 'replace'])
637     elif win_version in ["2K", "XP"]:
638     activateMenuItem(notepadWindow, ['edit', 'replace'])
639     time.sleep(.5)
640     replaceDialog = findTopWindow(wantedText='Replace')
641    
642     print "Locate the 'find' edit box"
643     findValue = findControl(replaceDialog, wantedClass="Edit")
644    
645     print "Enter some text - and wait long enough for it to be seen"
646     setEditText(findValue, "Hello, mate!")
647     time.sleep(.5)
648    
649     print "Locate the 'cancel' button, and click it."
650     cancelButton = findControl(replaceDialog,
651     wantedClass="Button",
652     wantedText="Cancel")
653     clickButton(cancelButton)
654    
655     print "Open and locate the 'font' dialogue"
656     if win_version in ["NT"]:
657     activateMenuItem(notepadWindow, ['edit', 'set font'])
658     elif win_version in ["2K", "XP"]:
659     activateMenuItem(notepadWindow, ['format', 'font'])
660     time.sleep(.5)
661     fontDialog = findTopWindow(wantedText='Font')
662    
663     print "Let's see if dumping works. Dump the 'font' dialogue contents:"
664     pprint.pprint(dumpWindow(fontDialog))
665    
666     print "Change the font"
667     fontCombos = findControls(fontDialog, wantedClass="ComboBox")
668     print "Find the font selection combo"
669     for fontCombo in fontCombos:
670     fontComboItems = getComboboxItems(fontCombo)
671     if 'Arial' in fontComboItems:
672     break
673    
674     print "Select at random"
675     selectComboboxItem(fontCombo, random.choice(fontComboItems))
676     time.sleep(.5)
677    
678     okButton = findControl(fontDialog, wantedClass="Button", wantedText="OK")
679     clickButton(okButton)
680    
681     print "Locate notpads edit area, and enter various bits of text."
682     editArea = findControl(notepadWindow,wantedClass="Edit")
683     setEditText(editArea, "Hello, again!")
684     time.sleep(.5)
685     setEditText(editArea, "You still there?")
686     time.sleep(.5)
687     setEditText(editArea, ["Here come", "two lines!"])
688     time.sleep(.5)
689    
690     print "Add some..."
691     setEditText(editArea, ["", "And a 3rd one!"], append=True)
692     time.sleep(.5)
693    
694     print "See what's there now:"
695     pprint.pprint(getEditText(editArea))
696    
697     print "Exit notepad"
698     activateMenuItem(notepadWindow, ('file', 'exit'))
699     time.sleep(.5)
700    
701     print "Don't save."
702     saveDialog = findTopWindow(wantedText='Notepad')
703     time.sleep(.5)
704     noButton = findControl(saveDialog,wantedClass="Button", wantedText="no")
705     clickButton(noButton)
706    
707     print "OK, now we'll have a go with WordPad."
708     os.startfile('wordpad')
709     time.sleep(1)
710     wordpadWindow = findTopWindow(wantedText='WordPad')
711    
712     print "Open and locate the 'new document' dialog."
713     activateMenuItem(wordpadWindow, [0, 0])
714     time.sleep(.5)
715     newDialog = findTopWindow(wantedText='New')
716    
717     print "Check you get an exception for non-existent control"
718     try:
719     findControl(newDialog, wantedClass="Banana")
720     raise Exception("Test failed")
721     except WinGuiAutoError, winGuiAutoError:
722     print "Yup, got: ", str(winGuiAutoError)
723    
724     print "Locate the 'document type' list box"
725     docType = findControl(newDialog, wantedClass="ListBox")
726     typeListBox = getListboxItems(docType)
727     print "getListboxItems(docType)=", typeListBox
728    
729     print "Select a type at random"
730     selectListboxItem(docType, random.randint(0, len(typeListBox)-1))
731     time.sleep(.5)
732     clickButton(findControl(newDialog, wantedClass="Button", wantedText="OK"))
733    
734     print "Check you get an exception for non-existent menu path"
735     try:
736     activateMenuItem(wordpadWindow, ('not', 'there'))
737     raise Exception("Test failed")
738     except WinGuiAutoError, winGuiAutoError:
739     print "Yup, got: ", str(winGuiAutoError)
740    
741     print "Check you get an exception for non-existent menu item"
742     try:
743     activateMenuItem(wordpadWindow, ('file', 'missing'))
744     raise Exception("Test failed")
745     except WinGuiAutoError, winGuiAutoError:
746     print "Yup, got: ", str(winGuiAutoError)
747    
748     print "Exit wordpad"
749     activateMenuItem(wordpadWindow, ('file', 'exit'))
750    
751     print "Check you get an exception for non-existent top window"
752     try:
753     findTopWindow(wantedText="Banana")
754     raise Exception("Test failed")
755     except WinGuiAutoError, winGuiAutoError:
756     print "Yup, got: ", str(winGuiAutoError)
757    
758     print "Err, that's it."