|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999 |
- # 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 array
- import struct
- import sys
-
- import commctrl
- import pywintypes
- import win32con
- import win32gui
-
- 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("utf-16le")
- 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.tobytes()
- 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, 0, 0, 0, 0 # text
- )
- 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, subItem, image, order # text
- )
- 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, 0, 0, 0 # text
- )
- 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("utf-16le")
- 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)
|