Tom Gur <gu*****@gmail. comwrote:
I was wondering how do I get control over a window (Win32).
to be more specific, I need to find a handle to a window of a certain
program and minimize the window.
Here's a function which returns a list of all windows where the class is
'PuTTY' or the title contains a particular string:
from win32gui import EnumWindows, GetClassName, EnumChildWindow s
from win32ui import CreateWindowFro mHandle, MessageBox
def toplevelWindows ():
res = []
def callback(hwnd, arg):
name = GetClassName(hw nd)
w = CreateWindowFro mHandle(hwnd)
title = w.GetWindowText ()
if "'s password:" in title or name=='PuTTY':
res.append(w)
EnumWindows(cal lback, 0)
return res
You can minimize a window once you have found it by calling ShowWindow
(or SetWindowPlacem ent).
If you don't want to depend on Python's win32 extensions being installed
then you can also do the same thing using ctypes.
In either case be very careful that you are only picking up the windows
you wanted to find as enumerating top level windows will return a lot of hidden windows and if you start messing with these you will probably need to reboot your system.
Here's something adapted from some stuff where I was playing with ctypes
(so you could probably cut out a lot of crud). It's a complete program
which will find a Firefox window with a specified string in the title
and minimize it (without the test for the classname it will also minimize
the command window you run it from).
--------- minimize.py -------------
#
# Minimize a specified window.
#
import sys
import ctypes
from ctypes import *
def _stdcall(dllnam e, restype, funcname, *argtypes):
# a decorator for a generator.
# The decorator loads the specified dll, retrieves the
# function with the specified name, set its restype and argtypes,
# it then invokes the generator which must yield twice: the first
# time it should yield the argument tuple to be passed to the dll
# function (and the yield returns the result of the call).
# It should then yield the result to be returned from the
# function call.
def decorate(func):
api = getattr(WinDLL( dllname), funcname)
api.restype = restype
api.argtypes = argtypes
def decorated(*args , **kw):
iterator = func(*args, **kw)
nargs = iterator.next()
if not isinstance(narg s, tuple):
nargs = (nargs,)
try:
res = api(*nargs)
except Exception, e:
return iterator.throw( e)
return iterator.send(r es)
return decorated
return decorate
from ctypes.wintypes import HWND #, RECT, POINT
LPARAM = c_ulong
class metaENUM(type(c types.c_int)):
def __init__(cls, name, bases, namespace):
'''Convert enumeration names into attributes'''
names = namespace.get(' _names_', {})
if hasattr(names, 'keys'):
for (k,v) in names.items():
setattr(cls, k, cls(v))
names[v]=k
else:
for (i,k) in enumerate(names ):
setattr(cls, k, cls(i))
super(metaENUM, cls).__init__(n ame, bases, namespace)
class ENUM(ctypes.c_i nt):
'''Enumeration base class. Set _names_ attribute to a list
of enumeration names (counting from 0)
or a dictionary of name:value pairs.'''
__metaclass__ = metaENUM
def __str__(self):
return self.__repr__(f mt="%(value)s" )
def __repr__(self, fmt="<%(name)s %(value)s>"):
try:
return self._names_[self.value]
except:
return fmt % dict(name=self. __class__.__nam e__, value=self.valu e)
def __int__(self):
return self.value
class BITMASK(ENUM):
'''Some Microsoft 'enums' are actually bitmasks with several bits or'd together'''
def __repr__(self, fmt="<%(name)s %(value)s>"):
v = self.value
values = []
while v:
bit = v&(~v+1)
try:
values.append(s elf._names_[bit])
except (KeyError, IndexError):
values.append(f mt % dict(name=self. __class__.__nam e__, value=self.valu e))
v &= ~bit
if not values:
return '0'
return '|'.join(values )
def __or__(self, other):
return type(self)(int( self.value)|int (other.value))
class SHOWCMD(ENUM):
_names_ = '''SW_HIDE SW_NORMAL SW_SHOW_MINIMIZ ED SW_SHOW_MAXIMIZ ED
SW_SHOW_NOACTIV ATE SW_SHOW SW_MINIMIZE SW_SHOWMINNOACT IVE
SW_SHOWNA SW_RESTORE SW_SHOWDEFAULT SW_FORCEMINIMIZ E'''.split()
class WindowPlacement Flags(BITMASK):
_names_ = dict(WPF_SETMIN POSITION = 1,
WPF_RESTORETOMA XIMIZED = 2,
WPF_ASYNCWINDOW PLACEMENT = 4)
class Structure(ctype s.Structure):
"""As ctypes Structure but with added repr and comparison testing"""
def __repr__(self):
return "%s(%s)" % (self.__class__ .__name__,
", ".join("%s= %r" % (f, getattr(self, f)) for (f,t) in self._fields_))
def __eq__(self, other):
if self._fields_ != other._fields_:
return False
for (f,t) in self._fields_:
if getattr(self,f) != getattr(other,f ):
return False
return True
class RECT(Structure) :
_fields_ = [("left", c_long),
("top", c_long),
("right", c_long),
("bottom", c_long)]
class POINT(Structure ):
_fields_ = [("x", c_long),
("y", c_long)]
class StructureWithLe ngth(Structure) :
_fields_ = [('length', ctypes.c_ulong)]
def __init__(self):
ctypes.Structur e.__init__(self )
self.length = ctypes.sizeof(s elf)
class WINDOWPLACEMENT (StructureWithL ength):
_fields_ = [
('flags', WindowPlacement Flags),
('showCmd', SHOWCMD),
('ptMinPosition ', POINT),
('ptMaxPosition ', POINT),
('rcNormalPosit ion', RECT),
]
def nonzero(result) :
# If the result is zero, and GetLastError() returns a non-zero
# error code, raise a WindowsError
if result == 0 and GetLastError():
raise WinError()
return result
WNDENUMPROC = ctypes.WINFUNCT YPE(ctypes.c_in t, HWND, LPARAM)
@ _stdcall("user3 2", c_int, "EnumWindow s", WNDENUMPROC, LPARAM)
def EnumWindows(cal lback, lparam=0):
yield nonzero((yield WNDENUMPROC(cal lback), lparam))
@ _stdcall("user3 2", c_int, "GetWindowTextL engthW", HWND)
def GetWindowTextLe ngth(hwnd):
yield nonzero((yield hwnd,))
@ _stdcall("user3 2", c_int, "GetWindowTextW ", HWND, c_wchar_p, c_int)
def GetWindowText(h wnd):
len = GetWindowTextLe ngth(hwnd)+1
buf = create_unicode_ buffer(len)
nonzero((yield hwnd, buf, len))
yield buf.value
@ _stdcall("user3 2", c_int, "GetClassNameW" , HWND, c_wchar_p, c_int)
def GetClassName(hw nd):
len = 256
buf = create_unicode_ buffer(len)
nonzero((yield hwnd, buf, len))
yield buf.value
@ _stdcall("user3 2", c_int, "GetWindowRect" , HWND, POINTER(RECT))
def GetWindowRect(h wnd):
buf = RECT()
nonzero((yield hwnd, buf))
yield buf
@ _stdcall("user3 2", c_int, "GetClientRect" , HWND, POINTER(RECT))
def GetClientRect(h wnd):
buf = RECT()
nonzero((yield hwnd, buf))
yield buf
@ _stdcall("user3 2", c_int, "GetWindowPlace ment", HWND, POINTER(WINDOWP LACEMENT))
def GetWindowPlacem ent(hwnd):
buf = WINDOWPLACEMENT ()
nonzero((yield hwnd, buf))
yield buf
@ _stdcall("user3 2", c_int, "SetWindowPlace ment", HWND, POINTER(WINDOWP LACEMENT))
def SetWindowPlacem ent(hwnd, placement):
yield nonzero((yield hwnd, placement))
@ _stdcall("user3 2", c_int, "IsWindow", HWND)
def IsWindow(hwnd):
yield bool((yield hwnd,))
@ _stdcall("user3 2", c_int, "ShowWindow ", HWND, SHOWCMD)
def ShowWindow(hwnd , showcmd):
yield bool((yield hwnd,showcmd))
def toplevelWindows ():
res = []
def callback(hwnd, arg):
res.append(hwnd )
return True
EnumWindows(cal lback, 0)
return res
def iterWindows(kla ss, match):
for hwnd in toplevelWindows ():
if IsWindow(hwnd):
try:
title = GetWindowText(h wnd)
except WindowsError, e:
continue
if klass==GetClass Name(hwnd) and match in title:
yield hwnd
if __name__=='__ma in__':
for hwnd in iterWindows("Mo zillaUIWindowCl ass", sys.argv[1]):
wp = GetWindowPlacem ent(hwnd)
ShowWindow(hwnd , SHOWCMD.SW_MINI MIZE)
else:
print "Sorry, I couldn't find the window"
-----------------------------------