0001# GUI Application automation and testing library
0002# Copyright (C) 2006 Mark Mc Mahon
0003#
0004# This library is free software; you can redistribute it and/or
0005# modify it under the terms of the GNU Lesser General Public License
0006# as published by the Free Software Foundation; either version 2.1
0007# of the License, or (at your option) any later version.
0008#
0009# This library is distributed in the hope that it will be useful,
0010# but WITHOUT ANY WARRANTY; without even the implied warranty of
0011# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0012# See the GNU Lesser General Public License for more details.
0013#
0014# You should have received a copy of the GNU Lesser General Public
0015# License along with this library; if not, write to the
0016# Free Software Foundation, Inc.,
0017# 59 Temple Place,
0018# Suite 330,
0019# Boston, MA 02111-1307 USA
0020
0021"""Functions to retrieve properties from a window handle
0022
0023These are implemented in a procedural way so as to to be
0024useful to other modules with the least conceptual overhead
0025"""
0026
0027__revision__ = "$Revision: 497 $"
0028
0029import ctypes
0030
0031import win32functions
0032import win32defines
0033import win32structures
0034
0035import findwindows # for children
0036
0037
0038#=========================================================================
0039def text(handle):
0040 "Return the text of the window"
0041 length = win32functions.GetWindowTextLength(handle,)
0042
0043 textval = ''
0044 if length:
0045 length += 1
0046
0047 buffer_ = (ctypes.c_wchar * length)()
0048
0049 ret = win32functions.GetWindowText(
0050 handle, ctypes.byref(buffer_), length)
0051
0052 if ret:
0053 textval = buffer_.value
0054
0055 return textval
0056
0057#=========================================================================
0058def classname(handle):
0059 "Return the class name of the window"
0060 class_name = (ctypes.c_wchar * 257)()
0061 win32functions.GetClassName (handle, ctypes.byref(class_name), 256)
0062 return class_name.value
0063
0064
0065#=========================================================================
0066def parent(handle):
0067 "Return the handle of the parent of the window"
0068 return win32functions.GetParent(handle)
0069
0070#=========================================================================
0071def style(handle):
0072 "Return the style of the window"
0073 return win32functions.GetWindowLong (handle, win32defines.GWL_STYLE)
0074
0075#=========================================================================
0076def exstyle(handle):
0077 "Return the extended style of the window"
0078 return win32functions.GetWindowLong (handle, win32defines.GWL_EXSTYLE)
0079
0080#=========================================================================
0081def controlid(handle):
0082 "Return the ID of the control"
0083 return win32functions.GetWindowLong (handle, win32defines.GWL_ID)
0084
0085#=========================================================================
0086def userdata(handle):
0087 "Return the value of any userdata associated with the window"
0088 return win32functions.GetWindowLong (handle, win32defines.GWL_USERDATA)
0089
0090#=========================================================================
0091def contexthelpid(handle):
0092 "Return the context help id of the window"
0093 return win32functions.GetWindowContextHelpId (handle)
0094
0095#=========================================================================
0096def iswindow(handle):
0097 "Return True if the handle is a window"
0098 return bool(win32functions.IsWindow(handle))
0099
0100#=========================================================================
0101def isvisible(handle):
0102 "Return True if the window is visible"
0103 return bool(win32functions.IsWindowVisible(handle))
0104
0105#=========================================================================
0106def isunicode(handle):
0107 "Teturn True if the window is a unicode window"
0108 return bool(win32functions.IsWindowUnicode(handle))
0109
0110#=========================================================================
0111def isenabled(handle):
0112 "Return True if the window is enabled"
0113 return bool(win32functions.IsWindowEnabled(handle))
0114
0115#=========================================================================
0116def clientrect(handle):
0117 "Return the client rectangle of the control"
0118 client_rect = win32structures.RECT()
0119 win32functions.GetClientRect(handle, ctypes.byref(client_rect))
0120 return client_rect
0121
0122#=========================================================================
0123def rectangle(handle):
0124 "Return the rectangle of the window"
0125 rect = win32structures.RECT()
0126 win32functions.GetWindowRect(handle, ctypes.byref(rect))
0127 return rect
0128
0129#=========================================================================
0130def font(handle):
0131 "Return the font as a LOGFONTW of the window"
0132
0133 # get the font handle
0134 font_handle = win32functions.SendMessage(
0135 handle, win32defines.WM_GETFONT, 0, 0)
0136
0137 # if the fondUsed is 0 then the control is using the
0138 # system font
0139 if not font_handle:
0140 font_handle = win32functions.GetStockObject(win32defines.SYSTEM_FONT)
0141
0142 # Get the Logfont structure of the font of the control
0143 fontval = win32structures.LOGFONTW()
0144 ret = win32functions.GetObject(
0145 font_handle, ctypes.sizeof(fontval), ctypes.byref(fontval))
0146
0147 # The function could not get the font - this is probably
0148 # because the control does not have associated Font/Text
0149 # So we should make sure the elements of the font are zeroed.
0150 if not ret:
0151 fontval = win32structures.LOGFONTW()
0152
0153 # if it is a main window
0154 if is_toplevel_window(handle):
0155
0156 if "MS Shell Dlg" in fontval.lfFaceName or fontval.lfFaceName == "System":
0158 # these are not usually the fonts actaully used in for
0159 # title bars so we need to get the default title bar font
0160
0161 # get the title font based on the system metrics rather
0162 # than the font of the control itself
0163 ncms = win32structures.NONCLIENTMETRICSW()
0164 ncms.cbSize = ctypes.sizeof(ncms)
0165 win32functions.SystemParametersInfo(
0166 win32defines.SPI_GETNONCLIENTMETRICS,
0167 ctypes.sizeof(ncms),
0168 ctypes.byref(ncms),
0169 0)
0170
0171 # with either of the following 2 flags set the font of the
0172 # dialog isthe small one (but there is normally no difference!
0173 if has_style(handle, win32defines.WS_EX_TOOLWINDOW) or has_style(handle, win32defines.WS_EX_PALETTEWINDOW):
0175
0176 fontval = ncms.lfSmCaptionFont
0177 else:
0178 fontval = ncms.lfCaptionFont
0179
0180 return fontval
0181
0182#=========================================================================
0183def processid(handle):
0184 "Retrun the ID of process that controls this window"
0185 process_id = ctypes.c_int()
0186 win32functions.GetWindowThreadProcessId(handle, ctypes.byref(process_id))
0187
0188 return process_id.value
0189
0190#=========================================================================
0191def children(handle):
0192 "Return a list of handles to the children of this window"
0193 return findwindows.enum_child_windows(handle)
0194
0195
0196#=========================================================================
0197def has_style(handle, tocheck):
0198 "Return True if the control has style tocheck"
0199 hwnd_style = style(handle)
0200 return tocheck & hwnd_style == tocheck
0201
0202#=========================================================================
0203def has_exstyle(handle, tocheck):
0204 "Return True if the control has extended style tocheck"
0205 hwnd_exstyle = exstyle(handle)
0206 return tocheck & hwnd_exstyle == tocheck
0207
0208
0209#=========================================================================
0210def is_toplevel_window(handle):
0211 "Return whether the window is a top level window or not"
0212
0213 # only request the style once - this is an optimization over calling
0214 # (handle, style) for each style I wan to check!
0215 style_ = style(handle)
0216
0217 if (style_ & win32defines.WS_OVERLAPPED == win32defines.WS_OVERLAPPED or style_ & win32defines.WS_CAPTION == win32defines.WS_CAPTION) and not (style_ & win32defines.WS_CHILD == win32defines.WS_CHILD):
0220 return True
0221 else:
0222 return False
0223
0224
0225#=========================================================================
0226#def get_button_friendlyclassname(handle):
0227# "Return the friendly class name of a button control"
0228#
0229# # get the least significant bit
0230# style_lsb = style(handle) & 0xF
0231#
0232# # default to "Button"
0233# f_classname = "Button"
0234#
0235# if style_lsb == win32defines.BS_3STATE or \
0236# style_lsb == win32defines.BS_AUTO3STATE or \
0237# style_lsb == win32defines.BS_AUTOCHECKBOX or \
0238# style_lsb == win32defines.BS_CHECKBOX:
0239# f_classname = "CheckBox"
0240#
0241# elif style_lsb == win32defines.BS_RADIOBUTTON or \
0242# style_lsb == win32defines.BS_AUTORADIOBUTTON:
0243# f_classname = "RadioButton"
0244#
0245# elif style_lsb == win32defines.BS_GROUPBOX:
0246# f_classname = "GroupBox"
0247#
0248# if style(handle) & win32defines.BS_PUSHLIKE:
0249# f_classname = "Button"
0250#
0251# return f_classname
0252
0253
0254#def friendlyclassname(handle):
0255# """Return the friendly class name of the window
0256#
0257# The friendly class name might be subjective, but it
0258# tries to be what a normal user would call a window
0259# rather then the windows class name for the window.
0260# """
0261#
0262# import warnings
0263# warnings.warn("handleprops.friendlyclassname() is deprecated. Please use"
0264# "FriendlyClassMethod() of HwndWrapper",
0265# DeprecationWarning)
0266#
0267# # if it's a dialog then return that
0268# if is_toplevel_window(handle) and classname(handle) == "#32770":
0269# return "Dialog"
0270#
0271# # otherwise ask the wrapper class for the friendly class name
0272# class_name = classname(handle)
0273#
0274# from controls import wraphandle
0275# info = wraphandle._find_wrapper(class_name)
0276#
0277# if info:
0278# return info.friendlyclassname
0279#
0280# else:
0281# return class_name
0282
0283
0284
0285#
0286#
0287# # Check if the class name is in the known classes
0288# for cls_name, f_cls_name in _class_names.items():
0289#
0290# # OK we found it
0291# if re.match(cls_name, classname(handle)):
0292# # If it is a string then just return it
0293# if isinstance(f_cls_name, basestring):
0294# return f_cls_name
0295# # otherwise it is a function so call it
0296# else:
0297# return f_cls_name(handle)
0298#
0299# # unknown class - just return it's classname
0300# return classname(handle)
0301
0302
0303
0304
0305
0306#=========================================================================
0307def dumpwindow(handle):
0308 "Dump a window to a set of properties"
0309 props = {}
0310
0311 for func in (
0312 text,
0313 classname,
0314 rectangle,
0315 clientrect,
0316 style,
0317 exstyle,
0318 contexthelpid,
0319 controlid,
0320 userdata,
0321 font,
0322 parent,
0323 processid,
0324 isenabled,
0325 isunicode,
0326 isvisible,
0327 children,
0328 ):
0329
0330 props[func.__name__] = func(handle)
0331
0332 return props