openmedialibrary_platform_w.../Lib/site-packages/win32/lib/win32gui_struct.py
2016-04-14 21:54:42 +02:00

729 lines
29 KiB
Python

# This is a work in progress - see Demos/win32gui_menu.py
# win32gui_struct.py - helpers for working with various win32gui structures.
# As win32gui is "light-weight", it does not define objects for all possible
# win32 structures - in general, "buffer" objects are passed around - it is
# the callers responsibility to pack the buffer in the correct format.
#
# This module defines some helpers for the commonly used structures.
#
# In general, each structure has 3 functions:
#
# buffer, extras = PackSTRUCTURE(items, ...)
# item, ... = UnpackSTRUCTURE(buffer)
# buffer, extras = EmtpySTRUCTURE(...)
#
# 'extras' is always items that must be held along with the buffer, as the
# buffer refers to these object's memory.
# For structures that support a 'mask', this mask is hidden from the user - if
# 'None' is passed, the mask flag will not be set, or on return, None will
# be returned for the value if the mask is not set.
#
# NOTE: I considered making these structures look like real classes, and
# support 'attributes' etc - however, ctypes already has a good structure
# mechanism - I think it makes more sense to support ctype structures
# at the win32gui level, then there will be no need for this module at all.
# XXX - the above makes sense in terms of what is built and passed to
# win32gui (ie, the Pack* functions) - but doesn't make as much sense for
# the Unpack* functions, where the aim is user convenience.
import sys
import win32gui
import win32con
import struct
import array
import commctrl
import pywintypes
is64bit = "64 bit" in sys.version
try:
from collections import namedtuple
def _MakeResult(names_str, values):
names = names_str.split()
nt = namedtuple(names[0], names[1:])
return nt(*values)
except ImportError:
# no namedtuple support - just return the values as a normal tuple.
def _MakeResult(names_str, values):
return values
_nmhdr_fmt = "PPi"
if is64bit:
# When the item past the NMHDR gets aligned (eg, when it is a struct)
# we need this many bytes padding.
_nmhdr_align_padding = "xxxx"
else:
_nmhdr_align_padding = ""
# Encode a string suitable for passing in a win32gui related structure
# If win32gui is built with UNICODE defined (ie, py3k), then functions
# like InsertMenuItem are actually calling InsertMenuItemW etc, so all
# strings will need to be unicode.
if win32gui.UNICODE:
def _make_text_buffer(text):
# XXX - at this stage win32gui.UNICODE is only True in py3k,
# and in py3k is makes sense to reject bytes.
if not isinstance(text, str):
raise TypeError('MENUITEMINFO text must be unicode')
data = (text+'\0').encode("unicode-internal")
return array.array("b", data)
else:
def _make_text_buffer(text):
if isinstance(text, str):
text = text.encode("mbcs")
return array.array("b", text+'\0')
# make an 'empty' buffer, ready for filling with cch characters.
def _make_empty_text_buffer(cch):
return _make_text_buffer("\0" * cch)
if sys.version_info < (3,0):
def _make_memory(ob):
return str(buffer(ob))
def _make_bytes(sval):
return sval
else:
def _make_memory(ob):
return bytes(memoryview(ob))
def _make_bytes(sval):
return sval.encode('ascii')
# Generic WM_NOTIFY unpacking
def UnpackWMNOTIFY(lparam):
format = "PPi"
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
return _MakeResult("WMNOTIFY hwndFrom idFrom code", struct.unpack(format, buf))
def UnpackNMITEMACTIVATE(lparam):
format = _nmhdr_fmt + _nmhdr_align_padding
if is64bit:
# the struct module doesn't handle this correctly as some of the items
# are actually structs in structs, which get individually aligned.
format = format + "iiiiiiixxxxP"
else:
format = format + "iiiiiiiP"
buf = win32gui.PyMakeBuffer(struct.calcsize(format), lparam)
return _MakeResult("NMITEMACTIVATE hwndFrom idFrom code iItem iSubItem uNewState uOldState uChanged actionx actiony lParam",
struct.unpack(format, buf))
# MENUITEMINFO struct
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Resources/Menus/MenuReference/MenuStructures/MENUITEMINFO.asp
# We use the struct module to pack and unpack strings as MENUITEMINFO
# structures. We also have special handling for the 'fMask' item in that
# structure to avoid the caller needing to explicitly check validity
# (None is used if the mask excludes/should exclude the value)
_menuiteminfo_fmt = '5i5PiP'
def PackMENUITEMINFO(fType=None, fState=None, wID=None, hSubMenu=None,
hbmpChecked=None, hbmpUnchecked=None, dwItemData=None,
text=None, hbmpItem=None, dwTypeData=None):
# 'extras' are objects the caller must keep a reference to (as their
# memory is used) for the lifetime of the INFO item.
extras = []
# ack - dwItemData and dwTypeData were confused for a while...
assert dwItemData is None or dwTypeData is None, \
"sorry - these were confused - you probably want dwItemData"
# if we are a long way past 209, then we can nuke the above...
if dwTypeData is not None:
import warnings
warnings.warn("PackMENUITEMINFO: please use dwItemData instead of dwTypeData")
if dwItemData is None:
dwItemData = dwTypeData or 0
fMask = 0
if fType is None: fType = 0
else: fMask |= win32con.MIIM_FTYPE
if fState is None: fState = 0
else: fMask |= win32con.MIIM_STATE
if wID is None: wID = 0
else: fMask |= win32con.MIIM_ID
if hSubMenu is None: hSubMenu = 0
else: fMask |= win32con.MIIM_SUBMENU
if hbmpChecked is None:
assert hbmpUnchecked is None, \
"neither or both checkmark bmps must be given"
hbmpChecked = hbmpUnchecked = 0
else:
assert hbmpUnchecked is not None, \
"neither or both checkmark bmps must be given"
fMask |= win32con.MIIM_CHECKMARKS
if dwItemData is None: dwItemData = 0
else: fMask |= win32con.MIIM_DATA
if hbmpItem is None: hbmpItem = 0
else: fMask |= win32con.MIIM_BITMAP
if text is not None:
fMask |= win32con.MIIM_STRING
str_buf = _make_text_buffer(text)
cch = len(text)
# We are taking address of strbuf - it must not die until windows
# has finished with our structure.
lptext = str_buf.buffer_info()[0]
extras.append(str_buf)
else:
lptext = 0
cch = 0
# Create the struct.
# 'P' format does not accept PyHANDLE's !
item = struct.pack(
_menuiteminfo_fmt,
struct.calcsize(_menuiteminfo_fmt), # cbSize
fMask,
fType,
fState,
wID,
int(hSubMenu),
int(hbmpChecked),
int(hbmpUnchecked),
dwItemData,
lptext,
cch,
int(hbmpItem)
)
# Now copy the string to a writable buffer, so that the result
# could be passed to a 'Get' function
return array.array("b", item), extras
def UnpackMENUITEMINFO(s):
(cb,
fMask,
fType,
fState,
wID,
hSubMenu,
hbmpChecked,
hbmpUnchecked,
dwItemData,
lptext,
cch,
hbmpItem) = struct.unpack(_menuiteminfo_fmt, s)
assert cb==len(s)
if fMask & win32con.MIIM_FTYPE==0: fType = None
if fMask & win32con.MIIM_STATE==0: fState = None
if fMask & win32con.MIIM_ID==0: wID = None
if fMask & win32con.MIIM_SUBMENU==0: hSubMenu = None
if fMask & win32con.MIIM_CHECKMARKS==0: hbmpChecked = hbmpUnchecked = None
if fMask & win32con.MIIM_DATA==0: dwItemData = None
if fMask & win32con.MIIM_BITMAP==0: hbmpItem = None
if fMask & win32con.MIIM_STRING:
text = win32gui.PyGetString(lptext, cch)
else:
text = None
return _MakeResult("MENUITEMINFO fType fState wID hSubMenu hbmpChecked "
"hbmpUnchecked dwItemData text hbmpItem",
(fType, fState, wID, hSubMenu, hbmpChecked, hbmpUnchecked, \
dwItemData, text, hbmpItem))
def EmptyMENUITEMINFO(mask = None, text_buf_size=512):
# text_buf_size is number of *characters* - not necessarily no of bytes.
extra = []
if mask is None:
mask = win32con.MIIM_BITMAP | win32con.MIIM_CHECKMARKS | \
win32con.MIIM_DATA | win32con.MIIM_FTYPE | \
win32con.MIIM_ID | win32con.MIIM_STATE | \
win32con.MIIM_STRING | win32con.MIIM_SUBMENU
# Note: No MIIM_TYPE - this screws win2k/98.
if mask & win32con.MIIM_STRING:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
# Now copy the string to a writable buffer, so that the result
# could be passed to a 'Get' function
buf = struct.pack(
_menuiteminfo_fmt,
struct.calcsize(_menuiteminfo_fmt), # cbSize
mask,
0, #fType,
0, #fState,
0, #wID,
0, #hSubMenu,
0, #hbmpChecked,
0, #hbmpUnchecked,
0, #dwItemData,
text_addr,
text_buf_size,
0, #hbmpItem
)
return array.array("b", buf), extra
# MENUINFO struct
_menuinfo_fmt = 'iiiiPiP'
def PackMENUINFO(dwStyle = None, cyMax = None,
hbrBack = None, dwContextHelpID = None, dwMenuData = None,
fMask = 0):
if dwStyle is None: dwStyle = 0
else: fMask |= win32con.MIM_STYLE
if cyMax is None: cyMax = 0
else: fMask |= win32con.MIM_MAXHEIGHT
if hbrBack is None: hbrBack = 0
else: fMask |= win32con.MIM_BACKGROUND
if dwContextHelpID is None: dwContextHelpID = 0
else: fMask |= win32con.MIM_HELPID
if dwMenuData is None: dwMenuData = 0
else: fMask |= win32con.MIM_MENUDATA
# Create the struct.
item = struct.pack(
_menuinfo_fmt,
struct.calcsize(_menuinfo_fmt), # cbSize
fMask,
dwStyle,
cyMax,
hbrBack,
dwContextHelpID,
dwMenuData)
return array.array("b", item)
def UnpackMENUINFO(s):
(cb,
fMask,
dwStyle,
cyMax,
hbrBack,
dwContextHelpID,
dwMenuData) = struct.unpack(_menuinfo_fmt, s)
assert cb==len(s)
if fMask & win32con.MIM_STYLE==0: dwStyle = None
if fMask & win32con.MIM_MAXHEIGHT==0: cyMax = None
if fMask & win32con.MIM_BACKGROUND==0: hbrBack = None
if fMask & win32con.MIM_HELPID==0: dwContextHelpID = None
if fMask & win32con.MIM_MENUDATA==0: dwMenuData = None
return _MakeResult("MENUINFO dwStyle cyMax hbrBack dwContextHelpID dwMenuData",
(dwStyle, cyMax, hbrBack, dwContextHelpID, dwMenuData))
def EmptyMENUINFO(mask = None):
if mask is None:
mask = win32con.MIM_STYLE | win32con.MIM_MAXHEIGHT| \
win32con.MIM_BACKGROUND | win32con.MIM_HELPID | \
win32con.MIM_MENUDATA
buf = struct.pack(
_menuinfo_fmt,
struct.calcsize(_menuinfo_fmt), # cbSize
mask,
0, #dwStyle
0, #cyMax
0, #hbrBack,
0, #dwContextHelpID,
0, #dwMenuData,
)
return array.array("b", buf)
##########################################################################
#
# Tree View structure support - TVITEM, TVINSERTSTRUCT and TVDISPINFO
#
##########################################################################
# XXX - Note that the following implementation of TreeView structures is ripped
# XXX - from the SpamBayes project. It may not quite work correctly yet - I
# XXX - intend checking them later - but having them is better than not at all!
_tvitem_fmt = "iPiiPiiiiP"
# Helpers for the ugly win32 structure packing/unpacking
# XXX - Note that functions using _GetMaskAndVal run 3x faster if they are
# 'inlined' into the function - see PackLVITEM. If the profiler points at
# _GetMaskAndVal(), you should nuke it (patches welcome once they have been
# tested)
def _GetMaskAndVal(val, default, mask, flag):
if val is None:
return mask, default
else:
if flag is not None:
mask |= flag
return mask, val
def PackTVINSERTSTRUCT(parent, insertAfter, tvitem):
tvitem_buf, extra = PackTVITEM(*tvitem)
tvitem_buf = tvitem_buf.tostring()
format = "PP%ds" % len(tvitem_buf)
return struct.pack(format, parent, insertAfter, tvitem_buf), extra
def PackTVITEM(hitem, state, stateMask, text, image, selimage, citems, param):
extra = [] # objects we must keep references to
mask = 0
mask, hitem = _GetMaskAndVal(hitem, 0, mask, commctrl.TVIF_HANDLE)
mask, state = _GetMaskAndVal(state, 0, mask, commctrl.TVIF_STATE)
if not mask & commctrl.TVIF_STATE:
stateMask = 0
mask, text = _GetMaskAndVal(text, None, mask, commctrl.TVIF_TEXT)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.TVIF_IMAGE)
mask, selimage = _GetMaskAndVal(selimage, 0, mask, commctrl.TVIF_SELECTEDIMAGE)
mask, citems = _GetMaskAndVal(citems, 0, mask, commctrl.TVIF_CHILDREN)
mask, param = _GetMaskAndVal(param, 0, mask, commctrl.TVIF_PARAM)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
text_len = len(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
buf = struct.pack(_tvitem_fmt,
mask, hitem,
state, stateMask,
text_addr, text_len, # text
image, selimage,
citems, param)
return array.array("b", buf), extra
# Make a new buffer suitable for querying hitem's attributes.
def EmptyTVITEM(hitem, mask = None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = commctrl.TVIF_HANDLE | commctrl.TVIF_STATE | commctrl.TVIF_TEXT | \
commctrl.TVIF_IMAGE | commctrl.TVIF_SELECTEDIMAGE | \
commctrl.TVIF_CHILDREN | commctrl.TVIF_PARAM
if mask & commctrl.TVIF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(_tvitem_fmt,
mask, hitem,
0, 0,
text_addr, text_buf_size, # text
0, 0,
0, 0)
return array.array("b", buf), extra
def UnpackTVITEM(buffer):
item_mask, item_hItem, item_state, item_stateMask, \
item_textptr, item_cchText, item_image, item_selimage, \
item_cChildren, item_param = struct.unpack(_tvitem_fmt, buffer)
# ensure only items listed by the mask are valid (except we assume the
# handle is always valid - some notifications (eg, TVN_ENDLABELEDIT) set a
# mask that doesn't include the handle, but the docs explicity say it is.)
if not (item_mask & commctrl.TVIF_TEXT): item_textptr = item_cchText = None
if not (item_mask & commctrl.TVIF_CHILDREN): item_cChildren = None
if not (item_mask & commctrl.TVIF_IMAGE): item_image = None
if not (item_mask & commctrl.TVIF_PARAM): item_param = None
if not (item_mask & commctrl.TVIF_SELECTEDIMAGE): item_selimage = None
if not (item_mask & commctrl.TVIF_STATE): item_state = item_stateMask = None
if item_textptr:
text = win32gui.PyGetString(item_textptr)
else:
text = None
return _MakeResult("TVITEM item_hItem item_state item_stateMask "
"text item_image item_selimage item_cChildren item_param",
(item_hItem, item_state, item_stateMask, text,
item_image, item_selimage, item_cChildren, item_param))
# Unpack the lparm from a "TVNOTIFY" message
def UnpackTVNOTIFY(lparam):
item_size = struct.calcsize(_tvitem_fmt)
format = _nmhdr_fmt + _nmhdr_align_padding
if is64bit:
format = format + "ixxxx"
else:
format = format + "i"
format = format + "%ds%ds" % (item_size, item_size)
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, action, buf_old, buf_new \
= struct.unpack(format, buf)
item_old = UnpackTVITEM(buf_old)
item_new = UnpackTVITEM(buf_new)
return _MakeResult("TVNOTIFY hwndFrom id code action item_old item_new",
(hwndFrom, id, code, action, item_old, item_new))
def UnpackTVDISPINFO(lparam):
item_size = struct.calcsize(_tvitem_fmt)
format = "PPi%ds" % (item_size,)
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, buf_item = struct.unpack(format, buf)
item = UnpackTVITEM(buf_item)
return _MakeResult("TVDISPINFO hwndFrom id code item",
(hwndFrom, id, code, item))
#
# List view items
_lvitem_fmt = "iiiiiPiiPi"
def PackLVITEM(item=None, subItem=None, state=None, stateMask=None, text=None, image=None, param=None, indent=None):
extra = [] # objects we must keep references to
mask = 0
# _GetMaskAndVal adds quite a bit of overhead to this function.
if item is None: item = 0 # No mask for item
if subItem is None: subItem = 0 # No mask for sibItem
if state is None:
state = 0
stateMask = 0
else:
mask |= commctrl.LVIF_STATE
if stateMask is None: stateMask = state
if image is None: image = 0
else: mask |= commctrl.LVIF_IMAGE
if param is None: param = 0
else: mask |= commctrl.LVIF_PARAM
if indent is None: indent = 0
else: mask |= commctrl.LVIF_INDENT
if text is None:
text_addr = text_len = 0
else:
mask |= commctrl.LVIF_TEXT
text_buffer = _make_text_buffer(text)
text_len = len(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
buf = struct.pack(_lvitem_fmt,
mask, item, subItem,
state, stateMask,
text_addr, text_len, # text
image, param, indent)
return array.array("b", buf), extra
def UnpackLVITEM(buffer):
item_mask, item_item, item_subItem, \
item_state, item_stateMask, \
item_textptr, item_cchText, item_image, \
item_param, item_indent = struct.unpack(_lvitem_fmt, buffer)
# ensure only items listed by the mask are valid
if not (item_mask & commctrl.LVIF_TEXT): item_textptr = item_cchText = None
if not (item_mask & commctrl.LVIF_IMAGE): item_image = None
if not (item_mask & commctrl.LVIF_PARAM): item_param = None
if not (item_mask & commctrl.LVIF_INDENT): item_indent = None
if not (item_mask & commctrl.LVIF_STATE): item_state = item_stateMask = None
if item_textptr:
text = win32gui.PyGetString(item_textptr)
else:
text = None
return _MakeResult("LVITEM item_item item_subItem item_state "
"item_stateMask text item_image item_param item_indent",
(item_item, item_subItem, item_state, item_stateMask,
text, item_image, item_param, item_indent))
# Unpack an "LVNOTIFY" message
def UnpackLVDISPINFO(lparam):
item_size = struct.calcsize(_lvitem_fmt)
format = _nmhdr_fmt + _nmhdr_align_padding + ("%ds" % (item_size,))
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, buf_item = struct.unpack(format, buf)
item = UnpackLVITEM(buf_item)
return _MakeResult("LVDISPINFO hwndFrom id code item",
(hwndFrom, id, code, item))
def UnpackLVNOTIFY(lparam):
format = _nmhdr_fmt + _nmhdr_align_padding + "7i"
if is64bit:
format = format + "xxxx" # point needs padding.
format = format + "P"
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, item, subitem, newstate, oldstate, \
changed, pt_x, pt_y, lparam = struct.unpack(format, buf)
return _MakeResult("UnpackLVNOTIFY hwndFrom id code item subitem "
"newstate oldstate changed pt lparam",
(hwndFrom, id, code, item, subitem, newstate, oldstate,
changed, (pt_x, pt_y), lparam))
# Make a new buffer suitable for querying an items attributes.
def EmptyLVITEM(item, subitem, mask = None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = commctrl.LVIF_IMAGE | commctrl.LVIF_INDENT | commctrl.LVIF_TEXT | \
commctrl.LVIF_PARAM | commctrl.LVIF_STATE
if mask & commctrl.LVIF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(_lvitem_fmt,
mask, item, subitem,
0, 0,
text_addr, text_buf_size, # text
0, 0, 0)
return array.array("b", buf), extra
# List view column structure
_lvcolumn_fmt = "iiiPiiii"
def PackLVCOLUMN(fmt=None, cx=None, text=None, subItem=None, image=None, order=None):
extra = [] # objects we must keep references to
mask = 0
mask, fmt = _GetMaskAndVal(fmt, 0, mask, commctrl.LVCF_FMT)
mask, cx = _GetMaskAndVal(cx, 0, mask, commctrl.LVCF_WIDTH)
mask, text = _GetMaskAndVal(text, None, mask, commctrl.LVCF_TEXT)
mask, subItem = _GetMaskAndVal(subItem, 0, mask, commctrl.LVCF_SUBITEM)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.LVCF_IMAGE)
mask, order= _GetMaskAndVal(order, 0, mask, commctrl.LVCF_ORDER)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
text_len = len(text)
buf = struct.pack(_lvcolumn_fmt,
mask, fmt, cx,
text_addr, text_len, # text
subItem, image, order)
return array.array("b", buf), extra
def UnpackLVCOLUMN(lparam):
mask, fmt, cx, text_addr, text_size, subItem, image, order = \
struct.unpack(_lvcolumn_fmt, lparam)
# ensure only items listed by the mask are valid
if not (mask & commctrl.LVCF_FMT): fmt = None
if not (mask & commctrl.LVCF_WIDTH): cx = None
if not (mask & commctrl.LVCF_TEXT): text_addr = text_size = None
if not (mask & commctrl.LVCF_SUBITEM): subItem = None
if not (mask & commctrl.LVCF_IMAGE): image = None
if not (mask & commctrl.LVCF_ORDER): order = None
if text_addr:
text = win32gui.PyGetString(text_addr)
else:
text = None
return _MakeResult("LVCOLUMN fmt cx text subItem image order",
(fmt, cx, text, subItem, image, order))
# Make a new buffer suitable for querying an items attributes.
def EmptyLVCOLUMN(mask = None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = commctrl.LVCF_FMT | commctrl.LVCF_WIDTH | commctrl.LVCF_TEXT | \
commctrl.LVCF_SUBITEM | commctrl.LVCF_IMAGE | commctrl.LVCF_ORDER
if mask & commctrl.LVCF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(_lvcolumn_fmt,
mask, 0, 0,
text_addr, text_buf_size, # text
0, 0, 0)
return array.array("b", buf), extra
# List view hit-test.
def PackLVHITTEST(pt):
format = "iiiii"
buf = struct.pack(format,
pt[0], pt[1],
0, 0, 0)
return array.array("b", buf), None
def UnpackLVHITTEST(buf):
format = "iiiii"
x, y, flags, item, subitem = struct.unpack(format, buf)
return _MakeResult("LVHITTEST pt flags item subitem",
((x,y), flags, item, subitem))
def PackHDITEM(cxy = None, text = None, hbm = None, fmt = None,
param = None, image = None, order = None):
extra = [] # objects we must keep references to
mask = 0
mask, cxy = _GetMaskAndVal(cxy, 0, mask, commctrl.HDI_HEIGHT)
mask, text = _GetMaskAndVal(text, None, mask, commctrl.LVCF_TEXT)
mask, hbm = _GetMaskAndVal(hbm, 0, mask, commctrl.HDI_BITMAP)
mask, fmt = _GetMaskAndVal(fmt, 0, mask, commctrl.HDI_FORMAT)
mask, param = _GetMaskAndVal(param, 0, mask, commctrl.HDI_LPARAM)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.HDI_IMAGE)
mask, order = _GetMaskAndVal(order, 0, mask, commctrl.HDI_ORDER)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
text_len = len(text)
format = "iiPPiiPiiii"
buf = struct.pack(format,
mask, cxy, text_addr, hbm, text_len,
fmt, param, image, order, 0, 0)
return array.array("b", buf), extra
# Device notification stuff
# Generic function for packing a DEV_BROADCAST_* structure - generally used
# by the other PackDEV_BROADCAST_* functions in this module.
def PackDEV_BROADCAST(devicetype, rest_fmt, rest_data, extra_data=_make_bytes('')):
# It seems a requirement is 4 byte alignment, even for the 'BYTE data[1]'
# field (eg, that would make DEV_BROADCAST_HANDLE 41 bytes, but we must
# be 44.
extra_data += _make_bytes('\0' * (4-len(extra_data)%4))
format = "iii" + rest_fmt
full_size = struct.calcsize(format) + len(extra_data)
data = (full_size, devicetype, 0) + rest_data
return struct.pack(format, *data) + extra_data
def PackDEV_BROADCAST_HANDLE(handle, hdevnotify=0, guid=_make_bytes("\0"*16), name_offset=0, data=_make_bytes("\0")):
return PackDEV_BROADCAST(win32con.DBT_DEVTYP_HANDLE, "PP16sl",
(int(handle), int(hdevnotify), _make_memory(guid), name_offset),
data)
def PackDEV_BROADCAST_VOLUME(unitmask, flags):
return PackDEV_BROADCAST(win32con.DBT_DEVTYP_VOLUME, "II",
(unitmask, flags))
def PackDEV_BROADCAST_DEVICEINTERFACE(classguid, name=""):
if win32gui.UNICODE:
# This really means "is py3k?" - so not accepting bytes is OK
if not isinstance(name, str):
raise TypeError("Must provide unicode for the name")
name = name.encode('unicode-internal')
else:
# py2k was passed a unicode object - encode as mbcs.
if isinstance(name, str):
name = name.encode('mbcs')
# 16 bytes for the IID followed by \0 term'd string.
rest_fmt = "16s%ds" % len(name)
# _make_memory(iid) hoops necessary to get the raw IID bytes.
rest_data = (_make_memory(pywintypes.IID(classguid)), name)
return PackDEV_BROADCAST(win32con.DBT_DEVTYP_DEVICEINTERFACE, rest_fmt, rest_data)
# An object returned by UnpackDEV_BROADCAST.
class DEV_BROADCAST_INFO:
def __init__(self, devicetype, **kw):
self.devicetype = devicetype
self.__dict__.update(kw)
def __str__(self):
return "DEV_BROADCAST_INFO:" + str(self.__dict__)
# Support for unpacking the 'lparam'
def UnpackDEV_BROADCAST(lparam):
if lparam == 0:
return None
hdr_format = "iii"
hdr_size = struct.calcsize(hdr_format)
hdr_buf = win32gui.PyGetMemory(lparam, hdr_size)
size, devtype, reserved = struct.unpack("iii", hdr_buf)
# Due to x64 alignment issues, we need to use the full format string over
# the entire buffer. ie, on x64:
# calcsize('iiiP') != calcsize('iii')+calcsize('P')
buf = win32gui.PyGetMemory(lparam, size)
extra = x = {}
if devtype == win32con.DBT_DEVTYP_HANDLE:
# 2 handles, a GUID, a LONG and possibly an array following...
fmt = hdr_format + "PP16sl"
_, _, _, x['handle'], x['hdevnotify'], guid_bytes, x['nameoffset'] = \
struct.unpack(fmt, buf[:struct.calcsize(fmt)])
x['eventguid'] = pywintypes.IID(guid_bytes, True)
elif devtype == win32con.DBT_DEVTYP_DEVICEINTERFACE:
fmt = hdr_format + "16s"
_, _, _, guid_bytes = struct.unpack(fmt, buf[:struct.calcsize(fmt)])
x['classguid'] = pywintypes.IID(guid_bytes, True)
x['name'] = win32gui.PyGetString(lparam + struct.calcsize(fmt))
elif devtype == win32con.DBT_DEVTYP_VOLUME:
# int mask and flags
fmt = hdr_format + "II"
_, _, _, x['unitmask'], x['flags'] = struct.unpack(fmt, buf[:struct.calcsize(fmt)])
else:
raise NotImplementedError("unknown device type %d" % (devtype,))
return DEV_BROADCAST_INFO(devtype, **extra)