Z
zapazap
Dear Snake Charming Gurus,
(Was: http://mail.python.org/pipermail/python-list/2004-January/204454.html)
First, a thank you to Tim Golden, Thomas Heller, and Mark Hammond
for your earlier help with this problem. I am uncertain about what
etiquette calls for, but more on that later.
My Objective:
I am trying to control the _VMWare Desktop_ application
pythonically on WinXP Professional OS, with hopes of doing
the same later on Linux. (If it can be done easily on Linux
I might quit the WinXP work now, but I have never done any
automation like this on Linux before.)
My Progress:
I have been trying to extend Simon Brunning's _winGuiAuto_
module to deal with tabs listviews. This was the subject
of my previous thread. I am facing a more fundamental
problem. I am unable even to exercise the application's
main menu, which is something I thought winGuiAuto in its
present form should have been able to do.
My Test:
I have a unittest that successfully opens and closes both
_Notepad_ and _Freecell_, but fails to close _VMware_.
My Suspicion:
I suspect that there is a different "path" (so to speak) to
the menu control in the VMWare application than exists in
the other two applications.
Question #1 (My Etiquette):
Having said "Much Thanks!!" at the end of my first post, should
I have written back in thanks, privately or publicly? I greatly
appreciated the help (and helpful it was), but have long thought
"thanks in advance" covered the "friction" of followup thanks.
But I recently read ESR's "How To Ask Questions The Smart Way"
and am not so sure.
Question #2:
Is my suspicion correct? Might I have to go through several
nested controls before I get to the menu control of some apps?
If so, I think may need to search for some interactive browser
and/or debugger for windows app to reverse engineer the app's
structure. But I fear how much windows arcana I will need to
learn if I am to do this :-( -- advice of any sort would sure
be encouraging.
Question #3:
Perhaps life would be much easier for me if I do it in Linux?
(Since most of my work will eventually be done inside the VMs,
the host OS does not matter so greatly to me.)
Let me say that my goal is for a user to be able to see ONLY the
virtual machine, but be able to have snapshots taken and restored,
devices reassigned, etc, from within the VM without seeing the
host. I will just have the VM talk to the Host via sockets, that
is no problem to hack on. My only difficulty is having a process
on the host actually drive the VMWare application in a way that
does not require the VM to leave full-screen mode. Perhaps this
description might help someone in their helping me?
My failing unittest follows. It was run under Python 2.3.2.
Thank you again!
- Bryan Hann (zapazap AT yahoo DOT com)
---------------snip-------------------------------------------------
# Warning: close all instances of NOTEPAD, FREECELL
# and VMWARE before running this test
import os
import sys
import time
import unittest
import ctypes
import win32con
import win32gui
##########################################
# begin user configurable values
##########################################
# path to vmware folder
VMWARE_HOME = 'D:\\Progra~1\\VMware\\VMware~1'
# number of seconds to wait for the OS to respond to a change request.
DELAY = 2.0
# command prefix
CMD = 'start cmd /c '
##########################################
# end user configurable values
##########################################
class Test_CloseViaMenu(unittest.TestCase):
def test_freecell(self):
# I document this method; the others are similar.
# text to be found in the title of a freecell application
appname = 'FreeCell'
command = CMD + appname
# ensure no currently running instance of the application
assert not get_hwnds(appname)
# launch the application
os.system(command)
# give it time
time.sleep(DELAY)
# get the (unique) hwnd for the application's main window
[hwnd] = get_hwnds(appname)
# find the id for the Game|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0)=='&Game'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,9)=='E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 9)
# try to close the application
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
# give it time
time.sleep(DELAY)
# it should be gone now
assert not get_hwnds(appname)
def test_notepad(self):
appname = 'Notepad'
command = CMD + appname
assert not get_hwnds(appname)
os.system(command)
time.sleep(DELAY)
[hwnd] = get_hwnds(appname)
# find the id for the File|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0) == '&File'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,8) == 'E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 8)
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
time.sleep(DELAY)
assert not get_hwnds(appname)
def test_vm(self):
appname ='VMware'
command = CMD + appname
assert not get_hwnds(appname)
os.system(command)
time.sleep(DELAY)
[hwnd] = get_hwnds(appname)
# find the id for the File|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0)=='&File'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,12)=='E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 8)
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
time.sleep(DELAY)
assert not get_hwnds(self.appname)
def menu_name(hMenu,nn):
"""
Given an hMeny and index nn, return the name of
the nn-th item in the menu.
"""
dummy = ctypes.c_buffer("\000" * 32)
ctypes.windll.user32.GetMenuStringA(
ctypes.c_int(hMenu),
ctypes.c_int(nn),
dummy,
ctypes.c_int(len(dummy)),
win32con.MF_BYPOSITION
)
return dummy.value
def get_hwnds(text):
"""
Return list of all top level hwnds with specified
text in the title.
"""
fn = win32gui.GetWindowText
list = []
win32gui.EnumWindows( (lambda hwnd,acc: acc.append(hwnd)), list)
return [ hwnd for hwnd in list if text in fn(hwnd) ]
if __name__=='__main__':
fn = sys.getwindowsversion
win_ver = {4: "NT", 5: "2K", 6: "XP"}[fn()[0]]
assert win_ver in ["2K","XP"]
if not win_ver == "2K":
print >> sys.stderr, 'warning: tested only on windows 2K'
os.environ['PATH'] = os.environ['PATH'] + ';' + VMWARE_HOME
unittest.main()
##########################################
# The following is the output I got
##########################################
"""
...F
======================================================================
FAIL: test_vm (__main__.Test_CloseViaMenu)
(Was: http://mail.python.org/pipermail/python-list/2004-January/204454.html)
First, a thank you to Tim Golden, Thomas Heller, and Mark Hammond
for your earlier help with this problem. I am uncertain about what
etiquette calls for, but more on that later.
My Objective:
I am trying to control the _VMWare Desktop_ application
pythonically on WinXP Professional OS, with hopes of doing
the same later on Linux. (If it can be done easily on Linux
I might quit the WinXP work now, but I have never done any
automation like this on Linux before.)
My Progress:
I have been trying to extend Simon Brunning's _winGuiAuto_
module to deal with tabs listviews. This was the subject
of my previous thread. I am facing a more fundamental
problem. I am unable even to exercise the application's
main menu, which is something I thought winGuiAuto in its
present form should have been able to do.
My Test:
I have a unittest that successfully opens and closes both
_Notepad_ and _Freecell_, but fails to close _VMware_.
My Suspicion:
I suspect that there is a different "path" (so to speak) to
the menu control in the VMWare application than exists in
the other two applications.
Question #1 (My Etiquette):
Having said "Much Thanks!!" at the end of my first post, should
I have written back in thanks, privately or publicly? I greatly
appreciated the help (and helpful it was), but have long thought
"thanks in advance" covered the "friction" of followup thanks.
But I recently read ESR's "How To Ask Questions The Smart Way"
and am not so sure.
Question #2:
Is my suspicion correct? Might I have to go through several
nested controls before I get to the menu control of some apps?
If so, I think may need to search for some interactive browser
and/or debugger for windows app to reverse engineer the app's
structure. But I fear how much windows arcana I will need to
learn if I am to do this :-( -- advice of any sort would sure
be encouraging.
Question #3:
Perhaps life would be much easier for me if I do it in Linux?
(Since most of my work will eventually be done inside the VMs,
the host OS does not matter so greatly to me.)
Let me say that my goal is for a user to be able to see ONLY the
virtual machine, but be able to have snapshots taken and restored,
devices reassigned, etc, from within the VM without seeing the
host. I will just have the VM talk to the Host via sockets, that
is no problem to hack on. My only difficulty is having a process
on the host actually drive the VMWare application in a way that
does not require the VM to leave full-screen mode. Perhaps this
description might help someone in their helping me?
My failing unittest follows. It was run under Python 2.3.2.
Thank you again!
- Bryan Hann (zapazap AT yahoo DOT com)
---------------snip-------------------------------------------------
# Warning: close all instances of NOTEPAD, FREECELL
# and VMWARE before running this test
import os
import sys
import time
import unittest
import ctypes
import win32con
import win32gui
##########################################
# begin user configurable values
##########################################
# path to vmware folder
VMWARE_HOME = 'D:\\Progra~1\\VMware\\VMware~1'
# number of seconds to wait for the OS to respond to a change request.
DELAY = 2.0
# command prefix
CMD = 'start cmd /c '
##########################################
# end user configurable values
##########################################
class Test_CloseViaMenu(unittest.TestCase):
def test_freecell(self):
# I document this method; the others are similar.
# text to be found in the title of a freecell application
appname = 'FreeCell'
command = CMD + appname
# ensure no currently running instance of the application
assert not get_hwnds(appname)
# launch the application
os.system(command)
# give it time
time.sleep(DELAY)
# get the (unique) hwnd for the application's main window
[hwnd] = get_hwnds(appname)
# find the id for the Game|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0)=='&Game'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,9)=='E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 9)
# try to close the application
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
# give it time
time.sleep(DELAY)
# it should be gone now
assert not get_hwnds(appname)
def test_notepad(self):
appname = 'Notepad'
command = CMD + appname
assert not get_hwnds(appname)
os.system(command)
time.sleep(DELAY)
[hwnd] = get_hwnds(appname)
# find the id for the File|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0) == '&File'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,8) == 'E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 8)
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
time.sleep(DELAY)
assert not get_hwnds(appname)
def test_vm(self):
appname ='VMware'
command = CMD + appname
assert not get_hwnds(appname)
os.system(command)
time.sleep(DELAY)
[hwnd] = get_hwnds(appname)
# find the id for the File|Exit menu entry
hmenu = ctypes.windll.user32.GetMenu(hwnd)
assert hmenu, 'Application %s has no menu!' % appname
assert menu_name(hmenu,0)=='&File'
hmenu = ctypes.windll.user32.GetSubMenu(hmenu, 0)
assert menu_name(hmenu,12)=='E&xit'
ExitID = ctypes.windll.user32.GetMenuItemID(hmenu, 8)
win32gui.PostMessage(hwnd, win32con.WM_COMMAND, ExitID, 0)
time.sleep(DELAY)
assert not get_hwnds(self.appname)
def menu_name(hMenu,nn):
"""
Given an hMeny and index nn, return the name of
the nn-th item in the menu.
"""
dummy = ctypes.c_buffer("\000" * 32)
ctypes.windll.user32.GetMenuStringA(
ctypes.c_int(hMenu),
ctypes.c_int(nn),
dummy,
ctypes.c_int(len(dummy)),
win32con.MF_BYPOSITION
)
return dummy.value
def get_hwnds(text):
"""
Return list of all top level hwnds with specified
text in the title.
"""
fn = win32gui.GetWindowText
list = []
win32gui.EnumWindows( (lambda hwnd,acc: acc.append(hwnd)), list)
return [ hwnd for hwnd in list if text in fn(hwnd) ]
if __name__=='__main__':
fn = sys.getwindowsversion
win_ver = {4: "NT", 5: "2K", 6: "XP"}[fn()[0]]
assert win_ver in ["2K","XP"]
if not win_ver == "2K":
print >> sys.stderr, 'warning: tested only on windows 2K'
os.environ['PATH'] = os.environ['PATH'] + ';' + VMWARE_HOME
unittest.main()
##########################################
# The following is the output I got
##########################################
"""
...F
======================================================================
FAIL: test_vm (__main__.Test_CloseViaMenu)