From 22bfc50756e78caa971fe1b43ff4558c9c6b6c16 Mon Sep 17 00:00:00 2001 From: junkmd <45822440+junkmd@users.noreply.github.com> Date: Fri, 30 Dec 2022 15:24:41 +0900 Subject: [PATCH] add auto-formatter GHA triggered by PR (#427) * add `# fmt: ...` for avoiding redundant format * add GHA setting * apply automatic formatter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .github/workflows/autofmt.yml | 27 + comtypes/GUID.py | 17 +- comtypes/__init__.py | 339 ++++++---- comtypes/_comobject.py | 230 ++++--- comtypes/_memberspec.py | 85 ++- comtypes/_meta.py | 19 +- comtypes/_npsupport.py | 79 ++- comtypes/_safearray.py | 38 +- comtypes/automation.py | 295 ++++++--- comtypes/client/__init__.py | 96 ++- comtypes/client/_code_cache.py | 19 +- comtypes/client/_constants.py | 1 + comtypes/client/_events.py | 51 +- comtypes/client/_generate.py | 20 +- comtypes/client/dynamic.py | 32 +- comtypes/client/lazybind.py | 80 +-- comtypes/connectionpoints.py | 124 ++-- comtypes/errorinfo.py | 83 ++- comtypes/git.py | 40 +- comtypes/hints.pyi | 13 +- comtypes/hresult.py | 65 +- comtypes/logutil.py | 25 +- comtypes/messageloop.py | 5 +- comtypes/patcher.py | 5 +- comtypes/persist.py | 226 ++++--- comtypes/safearray.py | 110 ++-- comtypes/server/__init__.py | 29 +- comtypes/server/automation.py | 22 +- comtypes/server/connectionpoints.py | 53 +- comtypes/server/inprocserver.py | 13 +- comtypes/server/localserver.py | 25 +- comtypes/server/register.py | 144 +++-- comtypes/server/w_getopt.py | 30 +- comtypes/shelllink.py | 270 +++++--- comtypes/test/TestComServer.py | 22 +- comtypes/test/TestDispServer.py | 15 +- comtypes/test/__init__.py | 58 +- comtypes/test/find_memleak.py | 43 +- comtypes/test/runtests.py | 2 + comtypes/test/setup.py | 2 +- comtypes/test/test_BSTR.py | 26 +- comtypes/test/test_DISPPARAMS.py | 3 + comtypes/test/test_GUID.py | 27 +- comtypes/test/test_QueryService.py | 11 +- comtypes/test/test_agilent.py | 12 +- comtypes/test/test_avmc.py | 8 +- comtypes/test/test_basic.py | 20 +- comtypes/test/test_casesensitivity.py | 8 +- comtypes/test/test_client.py | 62 +- comtypes/test/test_collections.py | 19 +- comtypes/test/test_comserver.py | 59 +- comtypes/test/test_createwrappers.py | 57 +- comtypes/test/test_dict.py | 4 +- comtypes/test/test_dispinterface.py | 44 +- comtypes/test/test_dyndispatch.py | 3 +- comtypes/test/test_excel.py | 62 +- comtypes/test/test_findgendir.py | 25 +- comtypes/test/test_getactiveobj.py | 17 +- comtypes/test/test_ie.py | 49 +- comtypes/test/test_msscript.py | 11 +- comtypes/test/test_npsupport.py | 43 +- comtypes/test/test_outparam.py | 30 +- comtypes/test/test_propputref.py | 6 +- comtypes/test/test_safearray.py | 59 +- comtypes/test/test_sapi.py | 2 + comtypes/test/test_server.py | 127 ++-- comtypes/test/test_showevents.py | 5 +- comtypes/test/test_subinterface.py | 3 + comtypes/test/test_typeinfo.py | 10 +- comtypes/test/test_urlhistory.py | 10 +- comtypes/test/test_variant.py | 134 ++-- comtypes/test/test_win32com_interop.py | 15 +- comtypes/test/test_wmi.py | 6 +- comtypes/test/test_word.py | 9 +- comtypes/tools/codegenerator.py | 299 ++++++--- comtypes/tools/tlbparser.py | 454 +++++++------ comtypes/tools/typedesc.py | 20 +- comtypes/tools/typedesc_base.py | 50 +- comtypes/typeinfo.py | 861 ++++++++++++++++--------- comtypes/util.py | 77 ++- comtypes/viewobject.py | 263 +++++--- 81 files changed, 3800 insertions(+), 2062 deletions(-) create mode 100644 .github/workflows/autofmt.yml diff --git a/.github/workflows/autofmt.yml b/.github/workflows/autofmt.yml new file mode 100644 index 00000000..e1b59e12 --- /dev/null +++ b/.github/workflows/autofmt.yml @@ -0,0 +1,27 @@ +on: + pull_request: + branches: [drop_py2] # TODO: add `master` + +jobs: + formatter: + name: auto-formatter + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.7 + - name: Install black + run: pip install black==22.12.0 + - name: Format + run: python -m black comtypes/. + - name: Auto-commit + uses: stefanzweifel/git-auto-commit-action@v4 + with: + branch: ${{ github.head_ref }} + commit_message: apply automatic formatter + commit_user_name: github-actions[bot] + commit_user_email: 41898282+github-actions[bot]@users.noreply.github.com + commit_author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/comtypes/GUID.py b/comtypes/GUID.py index adabe905..44b81c3c 100644 --- a/comtypes/GUID.py +++ b/comtypes/GUID.py @@ -2,12 +2,16 @@ import sys if sys.version_info >= (2, 6): + def binary(obj): return bytes(obj) + else: + def binary(obj): return buffer(obj) + if sys.version_info >= (3, 0): text_type = str base_text_type = str @@ -31,11 +35,9 @@ def binary(obj): # Note: Comparing GUID instances by comparing their buffers # is slightly faster than using ole32.IsEqualGUID. + class GUID(Structure): - _fields_ = [("Data1", DWORD), - ("Data2", WORD), - ("Data3", WORD), - ("Data4", BYTE * 8)] + _fields_ = [("Data1", DWORD), ("Data2", WORD), ("Data3", WORD), ("Data4", BYTE * 8)] def __init__(self, name=None): if name is not None: @@ -50,6 +52,7 @@ def __unicode__(self): result = p.value _CoTaskMemFree(p) return result + __str__ = __unicode__ def __cmp__(self, other): @@ -61,8 +64,7 @@ def __bool__(self): return self != GUID_null def __eq__(self, other): - return isinstance(other, GUID) and \ - binary(self) == binary(other) + return isinstance(other, GUID) and binary(self) == binary(other) def __hash__(self): # We make GUID instances hashable, although they are mutable. @@ -73,8 +75,7 @@ def copy(self): @classmethod def from_progid(cls, progid): - """Get guid from progid, ... - """ + """Get guid from progid, ...""" if hasattr(progid, "_reg_clsid_"): progid = progid._reg_clsid_ if isinstance(progid, cls): diff --git a/comtypes/__init__.py b/comtypes/__init__.py index fed0f071..721b571d 100644 --- a/comtypes/__init__.py +++ b/comtypes/__init__.py @@ -4,14 +4,18 @@ import atexit from ctypes import * from ctypes import _SimpleCData + try: from _ctypes import COMError except ImportError as e: - msg = "\n".join(( - "COM technology not available (maybe it's the wrong platform).", - "Note that COM is only supported on Windows.", - "For more details, please check: " - "https://learn.microsoft.com/en-us/windows/win32/com")) + msg = "\n".join( + ( + "COM technology not available (maybe it's the wrong platform).", + "Note that COM is only supported on Windows.", + "For more details, please check: " + "https://learn.microsoft.com/en-us/windows/win32/com", + ) + ) raise ImportError(msg) from e import logging import os @@ -20,6 +24,7 @@ ################################################################ +# fmt: off def add_metaclass(metaclass): """Class decorator from six.py for creating a class with a metaclass. @@ -56,6 +61,7 @@ def wrapper(cls): orig_vars['__qualname__'] = cls.__qualname__ return metaclass(cls.__name__, cls.__bases__, orig_vars) return wrapper +# fmt: on ################################################################ @@ -78,17 +84,22 @@ def wrapper(cls): # if TYPE_CHECKING: from ctypes import _CData # only in `typeshed`, private in runtime + # _CData = _SimpleCData.__mro__[:-1][-1] # defining in runtime from ctypes import _Pointer from typing import Any, ClassVar, overload, TypeVar + # XXX: symbols for backward compatibility. # instead of `builtins`. see PEP585. from typing import Dict, List, Tuple, Type + # instead of `collections.abc`. see PEP585. from typing import Callable, Iterable, Iterator + # instead of `A | B` and `None | A`. see PEP604. from typing import Union as _UnionT # avoiding confusion with `ctypes.Union` from typing import Optional + # utilities or workarounds for annotations. from comtypes import hints as hints @@ -98,8 +109,12 @@ def wrapper(cls): from comtypes import patcher from comtypes._npsupport import interop as npsupport from comtypes._memberspec import ( - ComMemberGenerator, _ComMemberSpec, DispMemberGenerator, _DispMemberSpec, - _encode_idl, _resolve_argspec, + ComMemberGenerator, + _ComMemberSpec, + DispMemberGenerator, + _DispMemberSpec, + _encode_idl, + _resolve_argspec, ) ################################################################ @@ -109,11 +124,14 @@ def wrapper(cls): text_type = unicode _all_slice = slice(None, None, None) + class NullHandler(logging.Handler): """A Handler that does nothing.""" + def emit(self, record): pass + logger = logging.getLogger(__name__) # Add a NULL handler to the comtypes logger. This prevents getting a @@ -125,6 +143,7 @@ def emit(self, record): def _check_version(actual, tlib_cached_mtime=None): from comtypes.tools.codegenerator import version as required + if actual != required: raise ImportError("Wrong version") if not hasattr(sys, "frozen"): @@ -137,6 +156,7 @@ def _check_version(actual, tlib_cached_mtime=None): if not tlib_cached_mtime or abs(tlib_curr_mtime - tlib_cached_mtime) >= 1: raise ImportError("Typelib different than module") + if sys.version_info >= (3, 0): pythonapi.PyInstanceMethod_New.argtypes = [py_object] pythonapi.PyInstanceMethod_New.restype = py_object @@ -147,10 +167,13 @@ def instancemethod(func, inst, cls): if inst is None: return mth return mth.__get__(inst) + else: + def instancemethod(func, inst, cls): return types.MethodType(func, inst, cls) + class ReturnHRESULT(Exception): """ReturnHRESULT(hresult, text) @@ -158,6 +181,7 @@ class ReturnHRESULT(Exception): without logging an error. """ + # class IDLWarning(UserWarning): # "Warn about questionable type information" @@ -198,7 +222,7 @@ class ReturnHRESULT(Exception): CLSCTX_ENABLE_AAA = 65536 CLSCTX_FROM_DEFAULT_CONTEXT = 131072 -tagCLSCTX = c_int # enum +tagCLSCTX = c_int # enum CLSCTX = tagCLSCTX # Constants for security setups @@ -210,26 +234,28 @@ class ReturnHRESULT(Exception): EOAC_NONE = 0 - ################################################################ # Initialization and shutdown _ole32 = oledll.ole32 -_ole32_nohresult = windll.ole32 # use this for functions that don't return a HRESULT +_ole32_nohresult = windll.ole32 # use this for functions that don't return a HRESULT -COINIT_MULTITHREADED = 0x0 +COINIT_MULTITHREADED = 0x0 COINIT_APARTMENTTHREADED = 0x2 -COINIT_DISABLE_OLE1DDE = 0x4 +COINIT_DISABLE_OLE1DDE = 0x4 COINIT_SPEED_OVER_MEMORY = 0x8 + def CoInitialize(): return CoInitializeEx(COINIT_APARTMENTTHREADED) + def CoInitializeEx(flags=None): if flags is None: flags = getattr(sys, "coinit_flags", COINIT_APARTMENTTHREADED) logger.debug("CoInitializeEx(None, %s)", flags) _ole32.CoInitializeEx(None, flags) + # COM is initialized automatically for the thread that imports this # module for the first time. sys.coinit_flags is passed as parameter # to CoInitializeEx, if defined, otherwise COINIT_APARTMENTTHREADED @@ -247,9 +273,11 @@ def CoUninitialize(): _ole32_nohresult.CoUninitialize() -def _shutdown(func=_ole32_nohresult.CoUninitialize, - _debug=logger.debug, - _exc_clear=getattr(sys, "exc_clear", lambda: None)): +def _shutdown( + func=_ole32_nohresult.CoUninitialize, + _debug=logger.debug, + _exc_clear=getattr(sys, "exc_clear", lambda: None), +): # Make sure no COM pointers stay in exception frames. _exc_clear() # Sometimes, CoUninitialize, running at Python shutdown, @@ -259,14 +287,17 @@ def _shutdown(func=_ole32_nohresult.CoUninitialize, if __debug__: func() else: - try: func() - except WindowsError: pass + try: + func() + except WindowsError: + pass # Set the flag which means that calling obj.Release() is no longer # needed. if _cominterface_meta is not None: _cominterface_meta._com_shutting_down = True _debug("CoUninitialize() done.") + atexit.register(_shutdown) ################################################################ @@ -278,11 +309,13 @@ def _shutdown(func=_ole32_nohresult.CoUninitialize, # allows to find coclasses by guid strings (clsid) com_coclass_registry = {} + def _is_object(obj): """This function determines if the argument is a COM object. It is used in several places to determine whether propputref or propput setters have to be used.""" from comtypes.automation import VARIANT + # A COM pointer is an 'Object' if isinstance(obj, POINTER(IUnknown)): return True @@ -292,13 +325,16 @@ def _is_object(obj): # It may be a dynamic dispatch object. return hasattr(obj, "_comobj") + ################################################################ # The metaclasses... + class _cominterface_meta(type): """Metaclass for COM interfaces. Automatically creates high level methods from COMMETHOD lists. """ + if TYPE_CHECKING: _case_insensitive_ = hints.AnnoField() # type: bool _iid_ = hints.AnnoField() # type: GUID @@ -334,12 +370,14 @@ def __new__(cls, name, bases, namespace): _ptr_bases = (new_cls, POINTER(bases[0])) # The interface 'new_cls' is used as a mixin. - p = type(_compointer_base)("POINTER(%s)" % new_cls.__name__, - _ptr_bases, - {"__com_interface__": new_cls, - "_needs_com_addref_": None}) + p = type(_compointer_base)( + "POINTER(%s)" % new_cls.__name__, + _ptr_bases, + {"__com_interface__": new_cls, "_needs_com_addref_": None}, + ) from ctypes import _pointer_type_cache + _pointer_type_cache[new_cls] = p if new_cls._case_insensitive_: @@ -353,7 +391,7 @@ def __getattr__(self, name): fixed_name = self.__map_case__[name.lower()] except KeyError: raise AttributeError(name) - if fixed_name != name: # prevent unbounded recursion + if fixed_name != name: # prevent unbounded recursion return getattr(self, fixed_name) raise AttributeError(name) @@ -365,9 +403,9 @@ def __getattr__(self, name): # How much faster would this be if implemented in C? def __setattr__(self, name, value): """Implement case insensitive access to methods and properties""" - object.__setattr__(self, - self.__map_case__.get(name.lower(), name), - value) + object.__setattr__( + self, self.__map_case__.get(name.lower(), name), value + ) @patcher.Patch(POINTER(p)) class ReferenceFix(object): @@ -394,6 +432,7 @@ def __setitem__(self, index, value): super(POINTER(p), self).__setitem__(index, value) return from _ctypes import CopyComPointer + CopyComPointer(value, self) return new_cls @@ -425,6 +464,7 @@ def has_name(name): # XXX These special methods should be generated by the code generator. if has_name("Count"): + @patcher.Patch(self) class _(object): def __len__(self): @@ -432,6 +472,7 @@ def __len__(self): return self.Count if has_name("Item"): + @patcher.Patch(self) class _(object): # 'Item' is the 'default' value. Make it available by @@ -486,6 +527,7 @@ def __setitem__(self, index, value): raise TypeError(msg % type(self)) if has_name("_NewEnum"): + @patcher.Patch(self) class _(object): def __iter__(self): @@ -508,6 +550,7 @@ def __iter__(self): # _NewEnum returns an IUnknown pointer, QueryInterface() it to # IEnumVARIANT from comtypes.automation import IEnumVARIANT + return enum.QueryInterface(IEnumVARIANT) def _make_case_insensitive(self): @@ -598,15 +641,19 @@ def _make_methods(self, methods): if self._case_insensitive_: self.__map_case__[name.lower()] = name + ################################################################ + class _compointer_meta(type(c_void_p), _cominterface_meta): "metaclass for COM interface pointer classes" # no functionality, but needed to avoid a metaclass conflict + @add_metaclass(_compointer_meta) class _compointer_base(c_void_p): "base class for COM interface pointer classes" + def __del__(self, _debug=logger.debug): "Release the COM refcount we own." if self: @@ -632,13 +679,17 @@ def __cmp__(self, other): return 1 # get the value property of the c_void_p baseclass, this is the pointer value - return cmp(super(_compointer_base, self).value, super(_compointer_base, other).value) + return cmp( + super(_compointer_base, self).value, super(_compointer_base, other).value + ) def __eq__(self, other): if not isinstance(other, _compointer_base): return False # get the value property of the c_void_p baseclass, this is the pointer value - return super(_compointer_base, self).value == super(_compointer_base, other).value + return ( + super(_compointer_base, self).value == super(_compointer_base, other).value + ) def __hash__(self): """Return the hash value of the pointer.""" @@ -648,6 +699,7 @@ def __hash__(self): # redefine the .value property; return the object itself. def __get_value(self): return self + value = property(__get_value, doc="""Return self.""") def __repr__(self): @@ -691,12 +743,15 @@ def from_param(cls, value): raise TypeError("Interface %s not supported" % cls._iid_) return value.QueryInterface(cls.__com_interface__) + ################################################################ + class BSTR(_SimpleCData): "The windows BSTR data type" _type_ = "X" _needsfree = False + def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self.value) @@ -707,8 +762,7 @@ def __ctypes_from_outparam__(self): def __del__(self, _free=windll.oleaut32.SysFreeString): # Free the string if self owns the memory # or if instructed by __ctypes_from_outparam__. - if self._b_base_ is None \ - or self._needsfree: + if self._b_base_ is None or self._needsfree: _free(self) @classmethod @@ -721,35 +775,45 @@ def from_param(cls, value): # on destruction. return cls(value) + ################################################################ # IDL stuff + class helpstring(text_type): "Specifies the helpstring for a COM method or property." + class defaultvalue(object): "Specifies the default value for parameters marked optional." + def __init__(self, value): self.value = value + class dispid(int): "Specifies the DISPID of a method or property." + # XXX STDMETHOD, COMMETHOD, DISPMETHOD, and DISPPROPERTY should return # instances with more methods or properties, and should not behave as an unpackable. + def STDMETHOD(restype, name, argtypes=()): "Specifies a COM method slot without idlflags" return _ComMemberSpec(restype, name, argtypes, None, (), None) + def DISPMETHOD(idlflags, restype, name, *argspec): "Specifies a method of a dispinterface" return _DispMemberSpec("DISPMETHOD", name, tuple(idlflags), restype, argspec) + def DISPPROPERTY(idlflags, proptype, name): "Specifies a property of a dispinterface" return _DispMemberSpec("DISPPROPERTY", name, tuple(idlflags), proptype, ()) + # tuple(idlflags) is for the method itself: (dispid, 'readonly') # sample generated code: @@ -758,6 +822,7 @@ def DISPPROPERTY(idlflags, proptype, name): # [6], None, 'Render', ([], c_int, 'hdc'), ([], c_int, 'x'), ([], c_int, 'y') # ) + def COMMETHOD(idlflags, restype, methodname, *argspec): """Specifies a COM method slot with idlflags. @@ -796,12 +861,15 @@ class _IUnknown_Base(c_void_p): In runtime, this symbol in the namespace is just alias for `builtins.object`. """ + __com_QueryInterface = hints.AnnoField() # type: Callable[[Any, Any], int] __com_AddRef = hints.AnnoField() # type: Callable[[], int] __com_Release = hints.AnnoField() # type: Callable[[], int] + else: _IUnknown_Base = object + @add_metaclass(_cominterface_meta) class IUnknown(_IUnknown_Base): """The most basic COM interface. @@ -815,14 +883,14 @@ class IUnknown(_IUnknown_Base): The _methods_ list must in VTable order. Methods are specified with STDMETHOD or COMMETHOD calls. """ + _case_insensitive_ = False # type: ClassVar[bool] _iid_ = GUID("{00000000-0000-0000-C000-000000000046}") # type: ClassVar[GUID] _methods_ = [ - STDMETHOD(HRESULT, "QueryInterface", - [POINTER(GUID), POINTER(c_void_p)]), + STDMETHOD(HRESULT, "QueryInterface", [POINTER(GUID), POINTER(c_void_p)]), STDMETHOD(c_ulong, "AddRef"), - STDMETHOD(c_ulong, "Release") + STDMETHOD(c_ulong, "Release"), ] # type: ClassVar[List[_ComMemberSpec]] # NOTE: Why not `QueryInterface(T) -> _Pointer[T]`? @@ -837,9 +905,9 @@ def QueryInterface(self, interface, iid=None): if iid is None: iid = interface._iid_ self.__com_QueryInterface(byref(iid), byref(p)) - clsid = self.__dict__.get('__clsid') + clsid = self.__dict__.get("__clsid") if clsid is not None: - p.__dict__['__clsid'] = clsid + p.__dict__["__clsid"] = clsid return p # type: ignore # these are only so that they get a docstring. @@ -859,12 +927,11 @@ def Release(self): # IPersist is a trivial interface, which allows to ask an object about # its clsid. class IPersist(IUnknown): - _iid_ = GUID('{0000010C-0000-0000-C000-000000000046}') + _iid_ = GUID("{0000010C-0000-0000-C000-000000000046}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'GetClassID', - ( ['out'], POINTER(GUID), 'pClassID' )), - ] + COMMETHOD([], HRESULT, "GetClassID", (["out"], POINTER(GUID), "pClassID")), + ] if TYPE_CHECKING: # Returns the CLSID that uniquely represents an object class that # defines the code that can manipulate the object's data. @@ -872,7 +939,7 @@ class IPersist(IUnknown): class IServiceProvider(IUnknown): - _iid_ = GUID('{6D5140C1-7436-11CE-8034-00AA006009FA}') + _iid_ = GUID("{6D5140C1-7436-11CE-8034-00AA006009FA}") if TYPE_CHECKING: _QueryService = hints.AnnoField() # type: Callable[[Any, Any, Any], int] # Overridden QueryService to make it nicer to use (passing it an @@ -884,24 +951,32 @@ def QueryService(self, serviceIID, interface): return p # type: ignore _methods_ = [ - COMMETHOD([], HRESULT, 'QueryService', - ( ['in'], POINTER(GUID), 'guidService' ), - ( ['in'], POINTER(GUID), 'riid' ), - ( ['in'], POINTER(c_void_p), 'ppvObject' )) - ] + COMMETHOD( + [], + HRESULT, + "QueryService", + (["in"], POINTER(GUID), "guidService"), + (["in"], POINTER(GUID), "riid"), + (["in"], POINTER(c_void_p), "ppvObject"), + ) + ] + ################################################################ if TYPE_CHECKING: + @overload def CoGetObject(displayname, interface): # `interface` can't be missing # type: (str, None) -> IUnknown pass + @overload def CoGetObject(displayname, interface): # it should be called this way # type: (str, Type[_T_IUnknown]) -> _T_IUnknown pass + def CoGetObject(displayname, interface): # type: (str, Optional[Type[IUnknown]]) -> IUnknown """Convert a displayname to a moniker, then bind and return the object @@ -910,10 +985,9 @@ def CoGetObject(displayname, interface): interface = IUnknown punk = POINTER(interface)() # Do we need a way to specify the BIND_OPTS parameter? - _ole32.CoGetObject(text_type(displayname), - None, - byref(interface._iid_), - byref(punk)) + _ole32.CoGetObject( + text_type(displayname), None, byref(interface._iid_), byref(punk) + ) return punk # type: ignore @@ -924,11 +998,13 @@ def CoGetObject(displayname, interface): def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): # type: (GUID, None, Optional[int], Optional[pUnkOuter]) -> IUnknown pass + @overload def CoCreateInstance(clsid, interface, clsctx=None, punkouter=None): # type: (GUID, Type[_T_IUnknown], Optional[int], Optional[pUnkOuter]) -> _T_IUnknown pass + def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): # type: (GUID, Optional[Type[IUnknown]], Optional[int], Optional[pUnkOuter]) -> IUnknown """The basic windows api to create a COM class object and return a @@ -945,41 +1021,44 @@ def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): if TYPE_CHECKING: + @overload def CoGetClassObject(clsid, clsctx=None, pServerInfo=None, interface=None): # type: (GUID, Optional[int], Optional[COSERVERINFO], None) -> hints.IClassFactory pass + @overload def CoGetClassObject(clsid, clsctx=None, pServerInfo=None, interface=None): # type: (GUID, Optional[int], Optional[COSERVERINFO], Type[_T_IUnknown]) -> _T_IUnknown pass + def CoGetClassObject(clsid, clsctx=None, pServerInfo=None, interface=None): # type: (GUID, Optional[int], Optional[COSERVERINFO], Optional[Type[IUnknown]]) -> IUnknown if clsctx is None: clsctx = CLSCTX_SERVER if interface is None: import comtypes.server + interface = comtypes.server.IClassFactory p = POINTER(interface)() - _CoGetClassObject(clsid, - clsctx, - pServerInfo, - interface._iid_, - byref(p)) + _CoGetClassObject(clsid, clsctx, pServerInfo, interface._iid_, byref(p)) return p # type: ignore if TYPE_CHECKING: + @overload def GetActiveObject(clsid, interface=None): # type: (GUID, None) -> IUnknown pass + @overload def GetActiveObject(clsid, interface): # type: (GUID, Type[_T_IUnknown]) -> _T_IUnknown pass + def GetActiveObject(clsid, interface=None): # type: (GUID, Optional[Type[IUnknown]]) -> IUnknown """Retrieves a pointer to a running object""" @@ -991,125 +1070,155 @@ def GetActiveObject(clsid, interface=None): class MULTI_QI(Structure): - _fields_ = [("pIID", POINTER(GUID)), - ("pItf", POINTER(c_void_p)), - ("hr", HRESULT)] + _fields_ = [("pIID", POINTER(GUID)), ("pItf", POINTER(c_void_p)), ("hr", HRESULT)] if TYPE_CHECKING: pIID = hints.AnnoField() # type: GUID pItf = hints.AnnoField() # type: _Pointer[c_void_p] hr = hints.AnnoField() # type: HRESULT + class _COAUTHIDENTITY(Structure): _fields_ = [ - ('User', POINTER(c_ushort)), - ('UserLength', c_ulong), - ('Domain', POINTER(c_ushort)), - ('DomainLength', c_ulong), - ('Password', POINTER(c_ushort)), - ('PasswordLength', c_ulong), - ('Flags', c_ulong), + ("User", POINTER(c_ushort)), + ("UserLength", c_ulong), + ("Domain", POINTER(c_ushort)), + ("DomainLength", c_ulong), + ("Password", POINTER(c_ushort)), + ("PasswordLength", c_ulong), + ("Flags", c_ulong), ] + + COAUTHIDENTITY = _COAUTHIDENTITY + class _COAUTHINFO(Structure): _fields_ = [ - ('dwAuthnSvc', c_ulong), - ('dwAuthzSvc', c_ulong), - ('pwszServerPrincName', c_wchar_p), - ('dwAuthnLevel', c_ulong), - ('dwImpersonationLevel', c_ulong), - ('pAuthIdentityData', POINTER(_COAUTHIDENTITY)), - ('dwCapabilities', c_ulong), + ("dwAuthnSvc", c_ulong), + ("dwAuthzSvc", c_ulong), + ("pwszServerPrincName", c_wchar_p), + ("dwAuthnLevel", c_ulong), + ("dwImpersonationLevel", c_ulong), + ("pAuthIdentityData", POINTER(_COAUTHIDENTITY)), + ("dwCapabilities", c_ulong), ] + + COAUTHINFO = _COAUTHINFO + class _COSERVERINFO(Structure): _fields_ = [ - ('dwReserved1', c_ulong), - ('pwszName', c_wchar_p), - ('pAuthInfo', POINTER(_COAUTHINFO)), - ('dwReserved2', c_ulong), + ("dwReserved1", c_ulong), + ("pwszName", c_wchar_p), + ("pAuthInfo", POINTER(_COAUTHINFO)), + ("dwReserved2", c_ulong), ] if TYPE_CHECKING: dwReserved1 = hints.AnnoField() # type: int pwszName = hints.AnnoField() # type: Optional[str] pAuthInfo = hints.AnnoField() # type: _COAUTHINFO dwReserved2 = hints.AnnoField() # type: int + + COSERVERINFO = _COSERVERINFO _CoGetClassObject = _ole32.CoGetClassObject -_CoGetClassObject.argtypes = [POINTER(GUID), DWORD, POINTER(COSERVERINFO), - POINTER(GUID), POINTER(c_void_p)] +_CoGetClassObject.argtypes = [ + POINTER(GUID), + DWORD, + POINTER(COSERVERINFO), + POINTER(GUID), + POINTER(c_void_p), +] + class tagBIND_OPTS(Structure): _fields_ = [ - ('cbStruct', c_ulong), - ('grfFlags', c_ulong), - ('grfMode', c_ulong), - ('dwTickCountDeadline', c_ulong) + ("cbStruct", c_ulong), + ("grfFlags", c_ulong), + ("grfMode", c_ulong), + ("dwTickCountDeadline", c_ulong), ] + + # XXX Add __init__ which sets cbStruct? BIND_OPTS = tagBIND_OPTS + class tagBIND_OPTS2(Structure): _fields_ = [ - ('cbStruct', c_ulong), - ('grfFlags', c_ulong), - ('grfMode', c_ulong), - ('dwTickCountDeadline', c_ulong), - ('dwTrackFlags', c_ulong), - ('dwClassContext', c_ulong), - ('locale', c_ulong), - ('pServerInfo', POINTER(_COSERVERINFO)), + ("cbStruct", c_ulong), + ("grfFlags", c_ulong), + ("grfMode", c_ulong), + ("dwTickCountDeadline", c_ulong), + ("dwTrackFlags", c_ulong), + ("dwClassContext", c_ulong), + ("locale", c_ulong), + ("pServerInfo", POINTER(_COSERVERINFO)), ] + + # XXX Add __init__ which sets cbStruct? BINDOPTS2 = tagBIND_OPTS2 -#Structures for security setups +# Structures for security setups ######################################### class _SEC_WINNT_AUTH_IDENTITY(Structure): _fields_ = [ - ('User', POINTER(c_ushort)), - ('UserLength', c_ulong), - ('Domain', POINTER(c_ushort)), - ('DomainLength', c_ulong), - ('Password', POINTER(c_ushort)), - ('PasswordLength', c_ulong), - ('Flags', c_ulong), + ("User", POINTER(c_ushort)), + ("UserLength", c_ulong), + ("Domain", POINTER(c_ushort)), + ("DomainLength", c_ulong), + ("Password", POINTER(c_ushort)), + ("PasswordLength", c_ulong), + ("Flags", c_ulong), ] + + SEC_WINNT_AUTH_IDENTITY = _SEC_WINNT_AUTH_IDENTITY + class _SOLE_AUTHENTICATION_INFO(Structure): _fields_ = [ - ('dwAuthnSvc', c_ulong), - ('dwAuthzSvc', c_ulong), - ('pAuthInfo', POINTER(_SEC_WINNT_AUTH_IDENTITY)), + ("dwAuthnSvc", c_ulong), + ("dwAuthzSvc", c_ulong), + ("pAuthInfo", POINTER(_SEC_WINNT_AUTH_IDENTITY)), ] + + SOLE_AUTHENTICATION_INFO = _SOLE_AUTHENTICATION_INFO + class _SOLE_AUTHENTICATION_LIST(Structure): _fields_ = [ - ('cAuthInfo', c_ulong), - ('pAuthInfo', POINTER(_SOLE_AUTHENTICATION_INFO)), + ("cAuthInfo", c_ulong), + ("pAuthInfo", POINTER(_SOLE_AUTHENTICATION_INFO)), ] + + SOLE_AUTHENTICATION_LIST = _SOLE_AUTHENTICATION_LIST if TYPE_CHECKING: + @overload def CoCreateInstanceEx( - clsid, interface=None, clsctx=None, machine=None, pServerInfo=None): + clsid, interface=None, clsctx=None, machine=None, pServerInfo=None + ): # type: (GUID, None, Optional[int], Optional[str], Optional[COSERVERINFO]) -> IUnknown pass + @overload def CoCreateInstanceEx( - clsid, interface=None, clsctx=None, machine=None, pServerInfo=None): + clsid, interface=None, clsctx=None, machine=None, pServerInfo=None + ): # type: (GUID, Type[_T_IUnknown], Optional[int], Optional[str], Optional[COSERVERINFO]) -> _T_IUnknown pass -def CoCreateInstanceEx(clsid, interface=None, - clsctx=None, - machine=None, - pServerInfo=None): + +def CoCreateInstanceEx( + clsid, interface=None, clsctx=None, machine=None, pServerInfo=None +): # type: (GUID, Optional[Type[IUnknown]], Optional[int], Optional[str], Optional[COSERVERINFO]) -> IUnknown """The basic windows api to create a COM class object and return a pointer to an interface, possibly on another machine. @@ -1118,7 +1227,7 @@ def CoCreateInstanceEx(clsid, interface=None, """ if clsctx is None: - clsctx=CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER + clsctx = CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER if pServerInfo is not None: if machine is not None: @@ -1133,12 +1242,9 @@ def CoCreateInstanceEx(clsid, interface=None, interface = IUnknown multiqi = MULTI_QI() multiqi.pIID = pointer(interface._iid_) # type: ignore - _ole32.CoCreateInstanceEx(byref(clsid), - None, - clsctx, - pServerInfo, - 1, - byref(multiqi)) + _ole32.CoCreateInstanceEx( + byref(clsid), None, clsctx, pServerInfo, 1, byref(multiqi) + ) return cast(multiqi.pItf, POINTER(interface)) # type: ignore @@ -1151,12 +1257,16 @@ def CoCreateInstanceEx(clsid, interface=None, from comtypes._meta import _coclass_meta + @add_metaclass(_coclass_meta) class CoClass(COMObject): pass + + ################################################################ +# fmt: off __known_symbols__ = [ "BIND_OPTS", "tagBIND_OPTS", "BINDOPTS2", "tagBIND_OPTS2", "BSTR", "_check_version", "CLSCTX", "tagCLSCTX", "CLSCTX_ALL", @@ -1183,3 +1293,4 @@ class CoClass(COMObject): "SOLE_AUTHENTICATION_INFO", "_SOLE_AUTHENTICATION_LIST", "SOLE_AUTHENTICATION_LIST", "STDMETHOD", "wireHWND", ] +# fmt: on diff --git a/comtypes/_comobject.py b/comtypes/_comobject.py index a128dfa5..d042267c 100644 --- a/comtypes/_comobject.py +++ b/comtypes/_comobject.py @@ -1,6 +1,14 @@ from ctypes import ( - FormatError, POINTER, Structure, WINFUNCTYPE, byref, c_long, c_void_p, - oledll, pointer, windll + FormatError, + POINTER, + Structure, + WINFUNCTYPE, + byref, + c_long, + c_void_p, + oledll, + pointer, + windll, ) from _ctypes import CopyComPointer import logging @@ -11,8 +19,15 @@ from comtypes.errorinfo import ISupportErrorInfo, ReportException, ReportError from comtypes import IPersist from comtypes.hresult import ( - DISP_E_BADINDEX, DISP_E_MEMBERNOTFOUND, E_FAIL, E_NOINTERFACE, - E_INVALIDARG, E_NOTIMPL, RPC_E_CHANGED_MODE, S_FALSE, S_OK + DISP_E_BADINDEX, + DISP_E_MEMBERNOTFOUND, + E_FAIL, + E_NOINTERFACE, + E_INVALIDARG, + E_NOTIMPL, + RPC_E_CHANGED_MODE, + S_FALSE, + S_OK, ) from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2 @@ -23,7 +38,7 @@ _error = logger.error if sys.version_info >= (3, 0): - int_types = (int, ) + int_types = (int,) else: int_types = (int, long) @@ -63,15 +78,18 @@ def winerror(exc): # violation raised by ctypes has only text, for example. In this # cases we return a generic error code. return E_FAIL - raise TypeError("Expected comtypes.COMERROR or WindowsError instance, got %s" % type(exc).__name__) + raise TypeError( + "Expected comtypes.COMERROR or WindowsError instance, got %s" + % type(exc).__name__ + ) def _do_implement(interface_name, method_name): def _not_implemented(*args): """Return E_NOTIMPL because the method is not implemented.""" - _debug("unimplemented method %s_%s called", interface_name, - method_name) + _debug("unimplemented method %s_%s called", interface_name, method_name) return E_NOTIMPL + return _not_implemented @@ -83,34 +101,41 @@ def call_with_this(*args, **kw): result = mth(*args, **kw) except ReturnHRESULT as err: (hresult, text) = err.args - return ReportError(text, iid=interface._iid_, clsid=clsid, - hresult=hresult) + return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult) except (COMError, WindowsError) as details: - _error("Exception in %s.%s implementation:", interface.__name__, - mthname, exc_info=True) + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True, + ) return HRESULT_FROM_WIN32(winerror(details)) except E_NotImplemented: - _warning("Unimplemented method %s.%s called", interface.__name__, - mthname) + _warning("Unimplemented method %s.%s called", interface.__name__, mthname) return E_NOTIMPL except: - _error("Exception in %s.%s implementation:", interface.__name__, - mthname, exc_info=True) + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True, + ) return ReportException(E_FAIL, interface._iid_, clsid=clsid) if result is None: return S_OK return result + if paramflags is None: has_outargs = False else: - has_outargs = bool([x[0] for x in paramflags - if x[0] & 2]) + has_outargs = bool([x[0] for x in paramflags if x[0] & 2]) call_with_this.has_outargs = has_outargs return call_with_this ################################################################ + def hack(inst, mth, paramflags, interface, mthname): if paramflags is None: return catch_errors(inst, mth, paramflags, interface, mthname) @@ -126,9 +151,9 @@ def hack(inst, mth, paramflags, interface, mthname): args_out_idx = [] args_in_idx = [] for i, a in enumerate(dirflags): - if a&2: + if a & 2: args_out_idx.append(i) - if a&1 or a==0: + if a & 1 or a == 0: args_in_idx.append(i) args_out = len(args_out_idx) @@ -146,7 +171,7 @@ def call_without_this(this, *args): # if not a: # return E_POINTER - #make argument list for handler by index array built above + # make argument list for handler by index array built above inargs = [] for a in args_in_idx: inargs.append(args[a]) @@ -162,12 +187,15 @@ def call_without_this(this, *args): args[args_out_idx[i]][0] = value except ReturnHRESULT as err: (hresult, text) = err.args - return ReportError(text, iid=interface._iid_, clsid=clsid, - hresult=hresult) + return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult) except COMError as err: (hr, text, details) = err.args - _error("Exception in %s.%s implementation:", interface.__name__, - mthname, exc_info=True) + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True, + ) try: descr, source, helpfile, helpcontext, progid = details except (ValueError, TypeError): @@ -175,22 +203,29 @@ def call_without_this(this, *args): else: msg = "%s: %s" % (source, descr) hr = HRESULT_FROM_WIN32(hr) - return ReportError(msg, iid=interface._iid_, clsid=clsid, - hresult=hr) + return ReportError(msg, iid=interface._iid_, clsid=clsid, hresult=hr) except WindowsError as details: - _error("Exception in %s.%s implementation:", interface.__name__, - mthname, exc_info=True) + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True, + ) hr = HRESULT_FROM_WIN32(winerror(details)) return ReportException(hr, interface._iid_, clsid=clsid) except E_NotImplemented: - _warning("Unimplemented method %s.%s called", interface.__name__, - mthname) + _warning("Unimplemented method %s.%s called", interface.__name__, mthname) return E_NOTIMPL except: - _error("Exception in %s.%s implementation:", interface.__name__, - mthname, exc_info=True) + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True, + ) return ReportException(E_FAIL, interface._iid_, clsid=clsid) return S_OK + if args_out: call_without_this.has_outargs = True return call_without_this @@ -241,8 +276,7 @@ def find_impl(self, interface, mthname, paramflags, idlflags): return self.getter(propname) if "propput" in idlflags and len(paramflags) == 1: return self.setter(propname) - _debug("%r: %s.%s not implemented", self.inst, interface.__name__, - mthname) + _debug("%r: %s.%s not implemented", self.inst, interface.__name__, mthname) return None def setter(self, propname): @@ -254,6 +288,7 @@ def set(self, value): setattr(self, propname, value) except AttributeError: raise E_NotImplemented() + return instancemethod(set, self.inst, type(self.inst)) def getter(self, propname): @@ -262,6 +297,7 @@ def get(self): return getattr(self, propname) except AttributeError: raise E_NotImplemented() + return instancemethod(get, self.inst, type(self.inst)) @@ -269,12 +305,15 @@ def _create_vtbl_type(fields, itf): try: return _vtbl_types[fields] except KeyError: + class Vtbl(Structure): _fields_ = fields + Vtbl.__name__ = "Vtbl_%s" % itf.__name__ _vtbl_types[fields] = Vtbl return Vtbl + # Ugh. Another type cache to avoid leaking types. _vtbl_types = {} @@ -285,6 +324,7 @@ class Vtbl(Structure): _InterlockedDecrement = windll.kernel32.InterlockedDecrement except AttributeError: import threading + _lock = threading.Lock() _acquire = _lock.acquire _release = _lock.release @@ -303,6 +343,7 @@ def _InterlockedDecrement(ob): ob.value = refcnt _release() return refcnt + else: _InterlockedIncrement.argtypes = [POINTER(c_long)] _InterlockedDecrement.argtypes = [POINTER(c_long)] @@ -336,6 +377,7 @@ def run(self, classobjects): def run_sta(self): from comtypes import messageloop + messageloop.run() def run_mta(self): @@ -359,7 +401,6 @@ def Unlock(self): class InprocServer(object): - def __init__(self): self.locks = c_long(0) @@ -415,12 +456,15 @@ def __prepare_comobject(self): interfaces += (ISupportErrorInfo,) if hasattr(self, "_reg_typelib_"): from comtypes.typeinfo import LoadRegTypeLib + self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_) if hasattr(self, "_reg_clsid_"): if IProvideClassInfo not in interfaces: interfaces += (IProvideClassInfo,) - if hasattr(self, "_outgoing_interfaces_") and \ - IProvideClassInfo2 not in interfaces: + if ( + hasattr(self, "_outgoing_interfaces_") + and IProvideClassInfo2 not in interfaces + ): interfaces += (IProvideClassInfo2,) if hasattr(self, "_reg_clsid_"): if IPersist not in interfaces: @@ -475,45 +519,45 @@ def __make_interface_pointer(self, itf): ################# if what == "DISPMETHOD": - if 'propget' in idlflags: + if "propget" in idlflags: invkind = 2 # DISPATCH_PROPERTYGET mthname = "_get_" + mthname - elif 'propput' in idlflags: + elif "propput" in idlflags: invkind = 4 # DISPATCH_PROPERTYPUT mthname = "_set_" + mthname - elif 'propputref' in idlflags: + elif "propputref" in idlflags: invkind = 8 # DISPATCH_PROPERTYPUTREF mthname = "_setref_" + mthname else: invkind = 1 # DISPATCH_METHOD if restype: - argspec = argspec + ((['out'], restype, ""),) - self.__make_dispentry(finder, interface, mthname, - idlflags, argspec, invkind) + argspec = argspec + ((["out"], restype, ""),) + self.__make_dispentry( + finder, interface, mthname, idlflags, argspec, invkind + ) elif what == "DISPPROPERTY": # DISPPROPERTY have implicit "out" if restype: - argspec += ((['out'], restype, ""),) - self.__make_dispentry(finder, interface, - "_get_" + mthname, - idlflags, argspec, - 2 # DISPATCH_PROPERTYGET - ) - if not 'readonly' in idlflags: - self.__make_dispentry(finder, interface, - "_set_" + mthname, - idlflags, argspec, - 4) # DISPATCH_PROPERTYPUT + argspec += ((["out"], restype, ""),) + self.__make_dispentry( + finder, + interface, + "_get_" + mthname, + idlflags, + argspec, + 2, # DISPATCH_PROPERTYGET + ) + if not "readonly" in idlflags: + self.__make_dispentry( + finder, interface, "_set_" + mthname, idlflags, argspec, 4 + ) # DISPATCH_PROPERTYPUT # Add DISPATCH_PROPERTYPUTREF also? - def __make_dispentry(self, - finder, interface, mthname, - idlflags, argspec, invkind): + def __make_dispentry(self, finder, interface, mthname, idlflags, argspec, invkind): # We build a _dispmap_ entry now that maps invkind and # dispid to implementations that the finder finds; # IDispatch_Invoke will later call it. - paramflags = [((_encode_idl(x[0]), x[1]) + tuple(x[3:])) - for x in argspec] + paramflags = [((_encode_idl(x[0]), x[1]) + tuple(x[3:])) for x in argspec] # XXX can the dispid be at a different index? Check codegenerator. dispid = idlflags[0] impl = finder.get_impl(interface, mthname, paramflags, idlflags) @@ -553,8 +597,7 @@ def __run_localserver__(classobjects): @staticmethod def __keep__(obj): COMObject._instances_[obj] = None - _debug("%d active COM objects: Added %r", len(COMObject._instances_), - obj) + _debug("%d active COM objects: Added %r", len(COMObject._instances_), obj) if COMObject.__server__: COMObject.__server__.Lock() @@ -565,19 +608,19 @@ def __unkeep__(obj): except AttributeError: _debug("? active COM objects: Removed %r", obj) else: - _debug("%d active COM objects: Removed %r", - len(COMObject._instances_), obj) + _debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj) _debug("Remaining: %s", list(COMObject._instances_.keys())) if COMObject.__server__: COMObject.__server__.Unlock() + # ################################################################ ######################################################### # IUnknown methods implementations - def IUnknown_AddRef(self, this, - __InterlockedIncrement=_InterlockedIncrement, - _debug=_debug): + def IUnknown_AddRef( + self, this, __InterlockedIncrement=_InterlockedIncrement, _debug=_debug + ): result = __InterlockedIncrement(self._refcnt) if result == 1: self.__keep__(self) @@ -589,9 +632,9 @@ def _final_release_(self): to free allocated resources or so.""" pass - def IUnknown_Release(self, this, - __InterlockedDecrement=_InterlockedDecrement, - _debug=_debug): + def IUnknown_Release( + self, this, __InterlockedDecrement=_InterlockedDecrement, _debug=_debug + ): # If this is called at COM shutdown, _InterlockedDecrement() # must still be available, although module level variables may # have been deleted already - so we supply it as default @@ -625,8 +668,9 @@ def QueryInterface(self, interface): # interface pointers from COMObject instances. ptr = self._com_pointers_.get(interface._iid_, None) if ptr is None: - raise COMError(E_NOINTERFACE, FormatError(E_NOINTERFACE), - (None, None, 0, None, None)) + raise COMError( + E_NOINTERFACE, FormatError(E_NOINTERFACE), (None, None, 0, None, None) + ) # CopyComPointer(src, dst) calls AddRef! result = POINTER(interface)() CopyComPointer(ptr, byref(result)) @@ -683,8 +727,7 @@ def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo): except AttributeError: return E_NOTIMPL - def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, - rgDispId): + def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId): # This call uses windll instead of oledll so that a failed # call to DispGetIDsOfNames will return a HRESULT instead of # raising an error. @@ -692,11 +735,20 @@ def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, tinfo = self.__typeinfo except AttributeError: return E_NOTIMPL - return windll.oleaut32.DispGetIDsOfNames(tinfo, - rgszNames, cNames, rgDispId) - - def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, - pDispParams, pVarResult, pExcepInfo, puArgErr): + return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId) + + def IDispatch_Invoke( + self, + this, + dispIdMember, + riid, + lcid, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr, + ): try: self._dispimpl_ except AttributeError: @@ -715,8 +767,14 @@ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, interface = self._com_interfaces_[0] ptr = self._com_pointers_[interface._iid_] return windll.oleaut32.DispInvoke( - ptr, tinfo, dispIdMember, wFlags, pDispParams, pVarResult, - pExcepInfo, puArgErr + ptr, + tinfo, + dispIdMember, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr, ) try: @@ -744,8 +802,9 @@ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, # How are the parameters unpacked for propertyput # operations with additional parameters? Can propput # have additional args? - args = [params.rgvarg[i].value - for i in reversed(list(range(params.cNamedArgs)))] + args = [ + params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs))) + ] # MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or # DISPATCH_PROPERTYPUTREF is specified. return mth(this, *args) @@ -758,8 +817,9 @@ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, # 2to3 has problems to translate 'range(...)[::-1]' # correctly, so use 'list(range)[::-1]' instead (will be # fixed in Python 3.1, probably): - named_indexes = [params.rgdispidNamedArgs[i] - for i in range(params.cNamedArgs)] + named_indexes = [ + params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs) + ] # the positions of unnamed arguments num_unnamed = params.cArgs - params.cNamedArgs unnamed_indexes = list(reversed(list(range(num_unnamed)))) diff --git a/comtypes/_memberspec.py b/comtypes/_memberspec.py index 6cbfd520..7548a493 100644 --- a/comtypes/_memberspec.py +++ b/comtypes/_memberspec.py @@ -6,8 +6,17 @@ if TYPE_CHECKING: from comtypes import _CData from typing import ( - Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union as _UnionT + Any, + Callable, + Dict, + Iterator, + List, + Optional, + Tuple, + Type, + Union as _UnionT, ) + PositionalParamFlagType = Tuple[int, Optional[str]] OptionalParamFlagType = Tuple[int, Optional[str], Any] ParamFlagType = _UnionT[PositionalParamFlagType, OptionalParamFlagType] @@ -22,7 +31,7 @@ "lcid": 4, "retval": 8, "optional": 16, - } +} def _encode_idl(names): @@ -72,7 +81,9 @@ def _resolve_argspec(items): class _MemberSpec(object): """Specifier of a slot of method or property.""" + __slots__ = ("name", "idlflags", "restype") + def __init__(self, name, idlflags, restype): self.name = name # type: str self.idlflags = idlflags # type: Tuple[_UnionT[str, int], ...] @@ -86,6 +97,7 @@ def is_prop(self): class _ComMemberSpec(_MemberSpec): """Specifier for a slot of COM method or property.""" + __slots__ = ("argtypes", "paramflags", "doc") def __init__(self, restype, name, argtypes, paramflags, idlflags, doc): @@ -98,12 +110,20 @@ def __iter__(self): # for backward compatibility: # A function that returns this object used to return a `tuple`. # So it is implemented as unpackable as well. - for item in (self.restype, self.name, self.argtypes, self.paramflags, self.idlflags, self.doc): + for item in ( + self.restype, + self.name, + self.argtypes, + self.paramflags, + self.idlflags, + self.doc, + ): yield item class _DispMemberSpec(_MemberSpec): """Specifier for a slot of dispinterface method or property.""" + __slots__ = ("what", "argspec") def __init__(self, what, name, idlflags, restype, argspec): @@ -141,6 +161,7 @@ def _fix_inout_args(func, argtypes, paramflags): # version is used where the bug is fixed. SIMPLETYPE = type(ctypes.c_int) BYREFTYPE = type(ctypes.byref(ctypes.c_int())) + def call_with_inout(self, *args, **kw): args = list(args) # Indexed by order in the output @@ -205,12 +226,15 @@ def call_with_inout(self, *args, **kw): for outnum, o in outargs.items(): rescode[outnum] = o.__ctypes_from_outparam__() return rescode + return call_with_inout class PropertyMapping(object): def __init__(self): - self._data = {} # type: Dict[Tuple[str, Optional[str], int], List[Optional[Callable[..., Any]]]] + self._data = ( + {} + ) # type: Dict[Tuple[str, Optional[str], int], List[Optional[Callable[..., Any]]]] def add_propget(self, name, doc, nargs, func): # type: (str, Optional[str], int, Callable[..., Any]) -> None @@ -232,10 +256,12 @@ def __iter__(self): # and calls 'propputref' if it is an Object (in the VB # sense), or call 'propput' otherwise. put, putref = propput, propputref + def put_or_putref(self, *args): if comtypes._is_object(args[-1]): return putref(self, *args) return put(self, *args) + fset = put_or_putref elif propputref is not None: fset = propputref @@ -303,21 +329,21 @@ def to_propget_keys(self, m): nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) # XXX or should we do this? # nargs = len([f for f in paramflags if (f[0] & 1) or (f[0] == 0)]) - return m.name[len("_get_"):], m.doc, nargs + return m.name[len("_get_") :], m.doc, nargs def to_propput_keys(self, m): # type: (_ComMemberSpec) -> Tuple[str, Optional[str], int] assert m.name.startswith("_set_") assert m.paramflags is not None nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1 - return m.name[len("_set_"):], m.doc, nargs + return m.name[len("_set_") :], m.doc, nargs def to_propputref_keys(self, m): # type: (_ComMemberSpec) -> Tuple[str, Optional[str], int] assert m.name.startswith("_setref_") assert m.paramflags is not None nargs = len([f for f in m.paramflags if f[0] & 7 in (0, 1)]) - 1 - return m.name[len("_setref_"):], m.doc, nargs + return m.name[len("_setref_") :], m.doc, nargs class DispPropertyGenerator(PropertyGenerator): @@ -341,7 +367,9 @@ def __init__(self, cls_name, vtbl_offset, iid): self._iid = iid self._props = ComPropertyGenerator(cls_name) # sequence of (name: str, func: Callable, raw_func: Callable, is_prop: bool) - self._mths = [] # type: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]] + self._mths = ( + [] + ) # type: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]] self._member_index = 0 def add(self, m): @@ -368,7 +396,7 @@ def _fix_args(self, m, func): # type: (_ComMemberSpec, Callable[..., Any]) -> Callable[..., Any] """This is a workaround. See `_fix_inout_args` docstring and comments.""" if m.paramflags: - dirflags = [(p[0]&3) for p in m.paramflags] + dirflags = [(p[0] & 3) for p in m.paramflags] if 3 in dirflags: return _fix_inout_args(func, m.argtypes, m.paramflags) return func @@ -385,12 +413,14 @@ def __init__(self, cls_name): # type: (str) -> None self._props = DispPropertyGenerator(cls_name) # sequence of (name: str, func_or_prop: Callable | property, is_prop: bool) - self._items = [] # type: List[Tuple[str, _UnionT[Callable[..., Any], property], bool]] + self._items = ( + [] + ) # type: List[Tuple[str, _UnionT[Callable[..., Any], property], bool]] def add(self, m): # type: (_DispMemberSpec) -> None if m.what == "DISPPROPERTY": # DISPPROPERTY - assert not m.argspec # XXX does not yet work for properties with parameters + assert not m.argspec # XXX does not yet work for properties with parameters is_prop = True accessor = self._make_disp_property(m) self._items.append((m.name, accessor, is_prop)) @@ -407,15 +437,19 @@ def _make_disp_property(self, m): # type: (_DispMemberSpec) -> property # XXX doc string missing in property memid = m.memid + def fget(obj): - return obj.Invoke(memid, _invkind=2) # DISPATCH_PROPERTYGET + return obj.Invoke(memid, _invkind=2) # DISPATCH_PROPERTYGET + if "readonly" in m.idlflags: return property(fget) + def fset(obj, value): # Detect whether to use DISPATCH_PROPERTYPUT or # DISPATCH_PROPERTYPUTREF invkind = 8 if comtypes._is_object(value) else 4 return obj.Invoke(memid, value, _invkind=invkind) + return property(fget, fset) # Should the funcs/mths we create have restype and/or argtypes attributes? @@ -423,29 +457,45 @@ def _make_disp_method(self, m): # type: (_DispMemberSpec) -> Callable[..., Any] memid = m.memid if "propget" in m.idlflags: + def getfunc(obj, *args, **kw): - return obj.Invoke(memid, _invkind=2, *args, **kw) # DISPATCH_PROPERTYGET + return obj.Invoke( + memid, _invkind=2, *args, **kw + ) # DISPATCH_PROPERTYGET + return getfunc elif "propput" in m.idlflags: + def putfunc(obj, *args, **kw): - return obj.Invoke(memid, _invkind=4, *args, **kw) # DISPATCH_PROPERTYPUT + return obj.Invoke( + memid, _invkind=4, *args, **kw + ) # DISPATCH_PROPERTYPUT + return putfunc elif "propputref" in m.idlflags: + def putreffunc(obj, *args, **kw): - return obj.Invoke(memid, _invkind=8, *args, **kw) # DISPATCH_PROPERTYPUTREF + return obj.Invoke( + memid, _invkind=8, *args, **kw + ) # DISPATCH_PROPERTYPUTREF + return putreffunc # a first attempt to make use of the restype. Still, support for # named arguments and default argument values should be added. if hasattr(m.restype, "__com_interface__"): interface = m.restype.__com_interface__ # type: ignore + def comitffunc(obj, *args, **kw): result = obj.Invoke(memid, _invkind=1, *args, **kw) if result is None: return return result.QueryInterface(interface) + return comitffunc + def func(obj, *args, **kw): - return obj.Invoke(memid, _invkind=1, *args, **kw) # DISPATCH_METHOD + return obj.Invoke(memid, _invkind=1, *args, **kw) # DISPATCH_METHOD + return func def items(self): @@ -459,6 +509,7 @@ def properties(self): # helper classes for COM propget / propput # Should they be implemented in C for speed? + class bound_named_property(object): def __init__(self, name, fget, fset, instance): self.name = name @@ -495,7 +546,7 @@ def __repr__(self): return "" % (self.name, id(self)) def __iter__(self): - """ Explicitly disallow iteration. """ + """Explicitly disallow iteration.""" msg = "%r is not iterable" % self.name raise TypeError(msg) diff --git a/comtypes/_meta.py b/comtypes/_meta.py index 2d26b15d..4476c424 100644 --- a/comtypes/_meta.py +++ b/comtypes/_meta.py @@ -5,6 +5,7 @@ ################################################################ # metaclass for CoClass (in comtypes/__init__.py) + def _wrap_coclass(self): # We are an IUnknown pointer, represented as a c_void_p instance, # but we really want this interface: @@ -14,11 +15,13 @@ def _wrap_coclass(self): result.__dict__["__clsid"] = str(self._reg_clsid_) return result + def _coclass_from_param(cls, obj): if isinstance(obj, (cls._com_interfaces_[0], cls)): return obj raise TypeError(obj) + # # The mro() of a POINTER(App) type, where class App is a subclass of CoClass: # @@ -30,6 +33,7 @@ def _coclass_from_param(cls, obj): # _CData # object + class _coclass_meta(type): # metaclass for CoClass # @@ -46,16 +50,21 @@ def __new__(cls, name, bases, namespace): if "_reg_clsid_" in namespace: clsid = namespace["_reg_clsid_"] comtypes.com_coclass_registry[str(clsid)] = klass - PTR = _coclass_pointer_meta("POINTER(%s)" % klass.__name__, - (klass, c_void_p), - {"__ctypes_from_outparam__": _wrap_coclass, - "from_param": classmethod(_coclass_from_param), - }) + PTR = _coclass_pointer_meta( + "POINTER(%s)" % klass.__name__, + (klass, c_void_p), + { + "__ctypes_from_outparam__": _wrap_coclass, + "from_param": classmethod(_coclass_from_param), + }, + ) from ctypes import _pointer_type_cache + _pointer_type_cache[klass] = PTR return klass + # will not work if we change the order of the two base classes! class _coclass_pointer_meta(type(c_void_p), _coclass_meta): pass diff --git a/comtypes/_npsupport.py b/comtypes/_npsupport.py index 0f013cd5..2c5351d1 100644 --- a/comtypes/_npsupport.py +++ b/comtypes/_npsupport.py @@ -5,9 +5,10 @@ class Interop: - """ Class encapsulating all the functionality necessary to allow interop of + """Class encapsulating all the functionality necessary to allow interop of comtypes with numpy. Needs to be enabled with the "enable()" method. """ + def __init__(self): self.enabled = False self.VARIANT_dtype = None @@ -16,7 +17,7 @@ def __init__(self): self.com_null_date64 = None def _make_variant_dtype(self): - """ Create a dtype for VARIANT. This requires support for Unions, which + """Create a dtype for VARIANT. This requires support for Unions, which is available in numpy version 1.7 or greater. This does not support the decimal type. @@ -26,34 +27,65 @@ def _make_variant_dtype(self): if not self.enabled: return None # pointer typecode - ptr_typecode = '=1.2.0 numpy interop must be explicitly enabled with " @@ -124,13 +157,13 @@ def numpy(self): ) def enable(self): - """ Enables numpy/comtypes interop. - """ + """Enables numpy/comtypes interop.""" # don't do this twice if self.enabled: return # first we have to be able to import numpy import numpy + # if that succeeded we can be enabled self.enabled = True self.VARIANT_dtype = self._make_variant_dtype() diff --git a/comtypes/_safearray.py b/comtypes/_safearray.py index eaef799a..76518bc0 100644 --- a/comtypes/_safearray.py +++ b/comtypes/_safearray.py @@ -22,22 +22,28 @@ _oleaut32 = WinDLL("oleaut32") + class tagSAFEARRAYBOUND(Structure): _fields_ = [ - ('cElements', DWORD), - ('lLbound', LONG), -] + ("cElements", DWORD), + ("lLbound", LONG), + ] + + SAFEARRAYBOUND = tagSAFEARRAYBOUND + class tagSAFEARRAY(Structure): _fields_ = [ - ('cDims', USHORT), - ('fFeatures', USHORT), - ('cbElements', DWORD), - ('cLocks', DWORD), - ('pvData', PVOID), - ('rgsabound', SAFEARRAYBOUND * 1), - ] + ("cDims", USHORT), + ("fFeatures", USHORT), + ("cbElements", DWORD), + ("cLocks", DWORD), + ("pvData", PVOID), + ("rgsabound", SAFEARRAYBOUND * 1), + ] + + SAFEARRAY = tagSAFEARRAY SafeArrayAccessData = _oleaut32.SafeArrayAccessData @@ -64,11 +70,14 @@ class tagSAFEARRAY(Structure): _SafeArrayGetVartype = _oleaut32.SafeArrayGetVartype _SafeArrayGetVartype.restype = HRESULT _SafeArrayGetVartype.argtypes = [POINTER(SAFEARRAY), POINTER(VARTYPE)] + + def SafeArrayGetVartype(pa): result = VARTYPE() _SafeArrayGetVartype(pa, result) return result.value + SafeArrayGetElement = _oleaut32.SafeArrayGetElement SafeArrayGetElement.restype = HRESULT SafeArrayGetElement.argtypes = [POINTER(SAFEARRAY), POINTER(LONG), c_void_p] @@ -92,14 +101,19 @@ def SafeArrayGetVartype(pa): _SafeArrayGetLBound = _oleaut32.SafeArrayGetLBound _SafeArrayGetLBound.restype = HRESULT _SafeArrayGetLBound.argtypes = [POINTER(SAFEARRAY), UINT, POINTER(LONG)] + + def SafeArrayGetLBound(pa, dim): result = LONG() _SafeArrayGetLBound(pa, dim, result) return result.value + _SafeArrayGetUBound = _oleaut32.SafeArrayGetUBound _SafeArrayGetUBound.restype = HRESULT _SafeArrayGetUBound.argtypes = [POINTER(SAFEARRAY), UINT, POINTER(LONG)] + + def SafeArrayGetUBound(pa, dim): result = LONG() _SafeArrayGetUBound(pa, dim, result) @@ -119,10 +133,14 @@ def SafeArrayGetUBound(pa, dim): _SafeArrayGetIID = _oleaut32.SafeArrayGetIID _SafeArrayGetIID.restype = HRESULT _SafeArrayGetIID.argtypes = [POINTER(SAFEARRAY), POINTER(GUID)] + + def SafeArrayGetIID(pa): result = GUID() _SafeArrayGetIID(pa, result) return result + + SafeArrayDestroyDescriptor = _oleaut32.SafeArrayDestroyDescriptor SafeArrayDestroyDescriptor.restype = HRESULT SafeArrayDestroyDescriptor.argtypes = [POINTER(SAFEARRAY)] diff --git a/comtypes/automation.py b/comtypes/automation.py index ee1e8898..ed56eb29 100644 --- a/comtypes/automation.py +++ b/comtypes/automation.py @@ -8,29 +8,45 @@ from ctypes import _Pointer from _ctypes import CopyComPointer from comtypes import ( - BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD, TYPE_CHECKING, + BSTR, + COMError, + COMMETHOD, + GUID, + IID, + IUnknown, + STDMETHOD, + TYPE_CHECKING, ) from comtypes.hresult import * import comtypes.patcher import comtypes + try: from comtypes import _safearray except (ImportError, AttributeError): + class _safearray(object): tagSAFEARRAY = None + from ctypes.wintypes import DWORD, LONG, UINT, VARIANT_BOOL, WCHAR, WORD if TYPE_CHECKING: from typing import ( - Any, Callable, ClassVar, List, Optional, Tuple, Union as _UnionT, + Any, + Callable, + ClassVar, + List, + Optional, + Tuple, + Union as _UnionT, ) from comtypes import hints if sys.version_info >= (3, 0): - int_types = (int, ) - str_types = (str, ) + int_types = (int,) + str_types = (str,) base_text_type = str else: int_types = (int, long) @@ -67,7 +83,7 @@ class _safearray(object): ################################################################ # VARIANT, in all it's glory. -VARENUM = c_int # enum +VARENUM = c_int # enum VT_EMPTY = 0 VT_NULL = 1 VT_I2 = 2 @@ -124,19 +140,23 @@ class _safearray(object): class tagCY(Structure): _fields_ = [("int64", c_longlong)] + + CY = tagCY CURRENCY = CY class tagDEC(Structure): - _fields_ = [("wReserved", c_ushort), - ("scale", c_ubyte), - ("sign", c_ubyte), - ("Hi32", c_ulong), - ("Lo64", c_ulonglong)] + _fields_ = [ + ("wReserved", c_ushort), + ("scale", c_ubyte), + ("sign", c_ubyte), + ("Hi32", c_ulong), + ("Lo64", c_ulonglong), + ] def as_decimal(self): - """ Convert a tagDEC struct to Decimal. + """Convert a tagDEC struct to Decimal. See http://msdn.microsoft.com/en-us/library/cc234586.aspx for the tagDEC specification. @@ -144,7 +164,7 @@ def as_decimal(self): """ digits = (self.Hi32 << 64) + self.Lo64 decimal_str = "{0}{1}e-{2}".format( - '-' if self.sign else '', + "-" if self.sign else "", digits, self.scale, ) @@ -170,8 +190,8 @@ class __tagVARIANT(Structure): # this is the ctypes version - functional as well. class U_VARIANT2(Union): class _tagBRECORD(Structure): - _fields_ = [("pvRecord", c_void_p), - ("pRecInfo", POINTER(IUnknown))] + _fields_ = [("pvRecord", c_void_p), ("pRecInfo", POINTER(IUnknown))] + _fields_ = [ ("VT_BOOL", VARIANT_BOOL), ("VT_I1", c_byte), @@ -190,20 +210,22 @@ class _tagBRECORD(Structure): ("c_wchar_p", c_wchar_p), ("c_void_p", c_void_p), ("pparray", POINTER(POINTER(_safearray.tagSAFEARRAY))), - ("bstrVal", BSTR), ("_tagBRECORD", _tagBRECORD), - ] + ] _anonymous_ = ["_tagBRECORD"] - _fields_ = [("vt", VARTYPE), - ("wReserved1", c_ushort), - ("wReserved2", c_ushort), - ("wReserved3", c_ushort), - ("_", U_VARIANT2) + + _fields_ = [ + ("vt", VARTYPE), + ("wReserved1", c_ushort), + ("wReserved2", c_ushort), + ("wReserved3", c_ushort), + ("_", U_VARIANT2), ] - _fields_ = [("__VARIANT_NAME_2", __tagVARIANT), - ("decVal", DECIMAL)] + + _fields_ = [("__VARIANT_NAME_2", __tagVARIANT), ("decVal", DECIMAL)] _anonymous_ = ["__VARIANT_NAME_2"] + _fields_ = [("__VARIANT_NAME_1", U_VARIANT1)] _anonymous_ = ["__VARIANT_NAME_1"] @@ -249,8 +271,11 @@ def _set_value(self, value): _VariantClear(self) if value is None: self.vt = VT_NULL - elif (hasattr(value, '__len__') and len(value) == 0 - and not isinstance(value, base_text_type)): + elif ( + hasattr(value, "__len__") + and len(value) == 0 + and not isinstance(value, base_text_type) + ): self.vt = VT_NULL # since bool is a subclass of int, this check must come before # the check for int @@ -302,12 +327,14 @@ def _set_value(self, value): elif isinstance(value, datetime.datetime): delta = value - _com_null_date # a day has 24 * 60 * 60 = 86400 seconds - com_days = delta.days + (delta.seconds + delta.microseconds * 1e-6) / 86400. + com_days = ( + delta.days + (delta.seconds + delta.microseconds * 1e-6) / 86400.0 + ) self.vt = VT_DATE self._.VT_R8 = com_days elif comtypes.npsupport.isdatetime64(value): com_days = value - comtypes.npsupport.com_null_date64 - com_days /= comtypes.npsupport.numpy.timedelta64(1, 'D') + com_days /= comtypes.npsupport.numpy.timedelta64(1, "D") self.vt = VT_DATE self._.VT_R8 = com_days elif decimal is not None and isinstance(value, decimal.Decimal): @@ -343,6 +370,7 @@ def _set_value(self, value): elif isinstance(value, Structure) and hasattr(value, "_recordinfo_"): guids = value._recordinfo_ from comtypes.typeinfo import GetRecordInfoFromGuids + ri = GetRecordInfoFromGuids(*guids) self.vt = VT_RECORD # Assigning a COM pointer to a structure field does NOT @@ -440,7 +468,7 @@ def _get_value(self, dynamic=False): # We should/could return a NULL COM pointer. # But the code generation must be able to construct one # from the __repr__ of it. - return None # XXX? + return None # XXX? ptr = cast(val, POINTER(IUnknown)) # cast doesn't call AddRef (it should, imo!) ptr.AddRef() @@ -451,7 +479,7 @@ def _get_value(self, dynamic=False): val = self._.c_void_p if not val: # See above. - return None # XXX? + return None # XXX? ptr = cast(val, POINTER(IDispatch)) # cast doesn't call AddRef (it should, imo!) ptr.AddRef() @@ -459,6 +487,7 @@ def _get_value(self, dynamic=False): return ptr.__ctypes_from_outparam__() else: from comtypes.client.dynamic import Dispatch + return Dispatch(ptr) # see also c:/sf/pywin32/com/win32com/src/oleargs.cpp elif self.vt & VT_BYREF: @@ -493,7 +522,7 @@ def _get_value(self, dynamic=False): def __getitem__(self, index): if index != 0: raise IndexError(index) - if self.vt == VT_BYREF|VT_VARIANT: + if self.vt == VT_BYREF | VT_VARIANT: v = VARIANT() # apparently VariantCopyInd doesn't work always with # VT_BYREF|VT_VARIANT, so do it manually. @@ -504,7 +533,6 @@ def __getitem__(self, index): _VariantCopyInd(v, self) return v.value - # these are missing: # getter[VT_ERROR] # getter[VT_ARRAY] @@ -539,10 +567,8 @@ def __ctypes_from_outparam__(self): return result def ChangeType(self, typecode): - _VariantChangeType(self, - self, - 0, - typecode) + _VariantChangeType(self, self, 0, typecode) + VARIANT = tagVARIANT VARIANTARG = VARIANT @@ -576,6 +602,7 @@ def ChangeType(self, typecode): _carg_obj = type(byref(c_int())) from ctypes import Array as _CArrayType + @comtypes.patcher.Patch(POINTER(VARIANT)) class _(object): # Override the default .from_param classmethod of POINTER(VARIANT). @@ -605,22 +632,27 @@ def __setitem__(self, index, value): # variant[0] = value self[index].value = value + ################################################################ # interfaces, structures, ... class IEnumVARIANT(IUnknown): - _iid_ = GUID('{00020404-0000-0000-C000-000000000046}') - _idlflags_ = ['hidden'] + _iid_ = GUID("{00020404-0000-0000-C000-000000000046}") + _idlflags_ = ["hidden"] _dynamic = False + def __iter__(self): return self if sys.version_info >= (3, 0): + def __next__(self): item, fetched = self.Next(1) if fetched: return item raise StopIteration + else: + def next(self): item, fetched = self.Next(1) if fetched: @@ -647,21 +679,26 @@ def Next(self, celt): return v._get_value(dynamic=self._dynamic), fetched.value array = (VARIANT * celt)() self.__com_Next(celt, array, fetched) - result = [v._get_value(dynamic=self._dynamic) for v in array[:fetched.value]] + result = [v._get_value(dynamic=self._dynamic) for v in array[: fetched.value]] for v in array: v.value = None return result + IEnumVARIANT._methods_ = [ - COMMETHOD([], HRESULT, 'Next', - ( ['in'], c_ulong, 'celt' ), - ( ['out'], POINTER(VARIANT), 'rgvar' ), - ( ['out'], POINTER(c_ulong), 'pceltFetched' )), - COMMETHOD([], HRESULT, 'Skip', - ( ['in'], c_ulong, 'celt' )), - COMMETHOD([], HRESULT, 'Reset'), - COMMETHOD([], HRESULT, 'Clone', - ( ['out'], POINTER(POINTER(IEnumVARIANT)), 'ppenum' )), + COMMETHOD( + [], + HRESULT, + "Next", + (["in"], c_ulong, "celt"), + (["out"], POINTER(VARIANT), "rgvar"), + (["out"], POINTER(c_ulong), "pceltFetched"), + ), + COMMETHOD([], HRESULT, "Skip", (["in"], c_ulong, "celt")), + COMMETHOD([], HRESULT, "Reset"), + COMMETHOD( + [], HRESULT, "Clone", (["out"], POINTER(POINTER(IEnumVARIANT)), "ppenum") + ), ] @@ -683,23 +720,34 @@ class tagEXCEPINFO(Structure): scode = hints.AnnoField() # type: int def __repr__(self): - return "" % \ - ((self.wCode, self.bstrSource, self.bstrDescription, self.bstrHelpFile, self.dwHelpContext, - self.pfnDeferredFillIn, self.scode),) + return "" % ( + ( + self.wCode, + self.bstrSource, + self.bstrDescription, + self.bstrHelpFile, + self.dwHelpContext, + self.pfnDeferredFillIn, + self.scode, + ), + ) + + tagEXCEPINFO._fields_ = [ - ('wCode', WORD), - ('wReserved', WORD), - ('bstrSource', BSTR), - ('bstrDescription', BSTR), - ('bstrHelpFile', BSTR), - ('dwHelpContext', DWORD), - ('pvReserved', c_void_p), + ("wCode", WORD), + ("wReserved", WORD), + ("bstrSource", BSTR), + ("bstrDescription", BSTR), + ("bstrHelpFile", BSTR), + ("dwHelpContext", DWORD), + ("pvReserved", c_void_p), # ('pfnDeferredFillIn', WINFUNCTYPE(HRESULT, POINTER(tagEXCEPINFO))), - ('pfnDeferredFillIn', c_void_p), - ('scode', SCODE), + ("pfnDeferredFillIn", c_void_p), + ("scode", SCODE), ] EXCEPINFO = tagEXCEPINFO + class tagDISPPARAMS(Structure): if TYPE_CHECKING: rgvarg = hints.AnnoField() # type: Array[VARIANT] @@ -708,15 +756,18 @@ class tagDISPPARAMS(Structure): cNamedArgs = hints.AnnoField() # type: int _fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 696 - ('rgvarg', POINTER(VARIANTARG)), - ('rgdispidNamedArgs', POINTER(DISPID)), - ('cArgs', UINT), - ('cNamedArgs', UINT), + ("rgvarg", POINTER(VARIANTARG)), + ("rgdispidNamedArgs", POINTER(DISPID)), + ("cArgs", UINT), + ("cNamedArgs", UINT), ] + def __del__(self): if self._b_needsfree_: for i in range(self.cArgs): self.rgvarg[i].value = None + + DISPPARAMS = tagDISPPARAMS DISPID_VALUE = 0 @@ -731,48 +782,73 @@ def __del__(self): if TYPE_CHECKING: RawGetIDsOfNamesFunc = Callable[ - [_byref_type, Array[c_wchar_p], int, int, Array[DISPID]], int, + [_byref_type, Array[c_wchar_p], int, int, Array[DISPID]], + int, ] RawInvokeFunc = Callable[ [ - int, _byref_type, int, int, # dispIdMember, riid, lcid, wFlags + int, + _byref_type, + int, + int, # dispIdMember, riid, lcid, wFlags _UnionT[_byref_type, DISPPARAMS], # *pDispParams _UnionT[_byref_type, VARIANT], # pVarResult _UnionT[_byref_type, EXCEPINFO, None], # pExcepInfo _UnionT[_byref_type, c_uint], # puArgErr ], - int + int, ] + class IDispatch(IUnknown): if TYPE_CHECKING: - _disp_methods_ = hints.AnnoField() # type: ClassVar[List[comtypes._DispMemberSpec]] + _disp_methods_ = ( + hints.AnnoField() + ) # type: ClassVar[List[comtypes._DispMemberSpec]] _GetTypeInfo = hints.AnnoField() # type: Callable[[int, int], IUnknown] __com_GetIDsOfNames = hints.AnnoField() # type: RawGetIDsOfNamesFunc __com_Invoke = hints.AnnoField() # type: RawInvokeFunc _iid_ = GUID("{00020400-0000-0000-C000-000000000046}") _methods_ = [ - COMMETHOD([], HRESULT, 'GetTypeInfoCount', - (['out'], POINTER(UINT) ) ), - COMMETHOD([], HRESULT, 'GetTypeInfo', - (['in'], UINT, 'index'), - (['in'], LCID, 'lcid', 0), - # Normally, we would declare this parameter in this way: - # (['out'], POINTER(POINTER(ITypeInfo)) ) ), - # but we cannot import comtypes.typeinfo at the top level (recursive imports!). - (['out'], POINTER(POINTER(IUnknown)) ) ), - STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(IID), POINTER(c_wchar_p), - UINT, LCID, POINTER(DISPID)]), - STDMETHOD(HRESULT, 'Invoke', [DISPID, POINTER(IID), LCID, WORD, - POINTER(DISPPARAMS), POINTER(VARIANT), - POINTER(EXCEPINFO), POINTER(UINT)]), + COMMETHOD([], HRESULT, "GetTypeInfoCount", (["out"], POINTER(UINT))), + COMMETHOD( + [], + HRESULT, + "GetTypeInfo", + (["in"], UINT, "index"), + (["in"], LCID, "lcid", 0), + # Normally, we would declare this parameter in this way: + # (['out'], POINTER(POINTER(ITypeInfo)) ) ), + # but we cannot import comtypes.typeinfo at the top level (recursive imports!). + (["out"], POINTER(POINTER(IUnknown))), + ), + STDMETHOD( + HRESULT, + "GetIDsOfNames", + [POINTER(IID), POINTER(c_wchar_p), UINT, LCID, POINTER(DISPID)], + ), + STDMETHOD( + HRESULT, + "Invoke", + [ + DISPID, + POINTER(IID), + LCID, + WORD, + POINTER(DISPPARAMS), + POINTER(VARIANT), + POINTER(EXCEPINFO), + POINTER(UINT), + ], + ), ] def GetTypeInfo(self, index, lcid=0): # type: (int, int) -> hints.ITypeInfo """Return type information. Index 0 specifies typeinfo for IDispatch""" import comtypes.typeinfo + result = self._GetTypeInfo(index, lcid) return result.QueryInterface(comtypes.typeinfo.ITypeInfo) @@ -804,8 +880,7 @@ def _invoke(self, memid, invkind, lcid, *args): dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT)) dp.rgvarg = array - self.__com_Invoke(memid, riid_null, lcid, invkind, - dp, var, None, argerr) + self.__com_Invoke(memid, riid_null, lcid, invkind, dp, var, None, argerr) return var._get_value(dynamic=True) def Invoke(self, dispid, *args, **kw): @@ -819,7 +894,7 @@ def Invoke(self, dispid, *args, **kw): # objects referred to by rgvarg[ ] or placed in *pVarResult. # # For comtypes this is handled in DISPPARAMS.__del__ and VARIANT.__del__. - _invkind = kw.pop("_invkind", 1) # DISPATCH_METHOD + _invkind = kw.pop("_invkind", 1) # DISPATCH_METHOD _lcid = kw.pop("_lcid", 0) if kw: raise ValueError("named parameters not yet implemented") @@ -828,7 +903,7 @@ def Invoke(self, dispid, *args, **kw): excepinfo = EXCEPINFO() argerr = c_uint() - if _invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): # propput + if _invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): # propput array = (VARIANT * len(args))() for i, a in enumerate(args[::-1]): @@ -851,14 +926,26 @@ def Invoke(self, dispid, *args, **kw): dp.rgvarg = array try: - self.__com_Invoke(dispid, riid_null, _lcid, _invkind, byref(dp), - byref(result), byref(excepinfo), byref(argerr)) + self.__com_Invoke( + dispid, + riid_null, + _lcid, + _invkind, + byref(dp), + byref(result), + byref(excepinfo), + byref(argerr), + ) except COMError as err: (hresult, text, details) = err.args if hresult == DISP_E_EXCEPTION: - details = (excepinfo.bstrDescription, excepinfo.bstrSource, - excepinfo.bstrHelpFile, excepinfo.dwHelpContext, - excepinfo.scode) + details = ( + excepinfo.bstrDescription, + excepinfo.bstrSource, + excepinfo.bstrHelpFile, + excepinfo.dwHelpContext, + excepinfo.scode, + ) raise COMError(hresult, text, details) elif hresult == DISP_E_PARAMNOTFOUND: # MSDN says: You get the error DISP_E_PARAMNOTFOUND @@ -873,9 +960,11 @@ def Invoke(self, dispid, *args, **kw): # coerced. # # Hm, should we raise TypeError, or COMError? - raise COMError(hresult, text, - ("TypeError: Parameter %s" % (argerr.value + 1), - args)) + raise COMError( + hresult, + text, + ("TypeError: Parameter %s" % (argerr.value + 1), args), + ) raise return result._get_value(dynamic=True) @@ -899,29 +988,22 @@ def Invoke(self, dispid, *args, **kw): "L": VT_UI4, "H": VT_UI2, "B": VT_UI1, - } +} _ctype_to_vartype = { c_byte: VT_I1, c_ubyte: VT_UI1, - c_short: VT_I2, c_ushort: VT_UI2, - c_long: VT_I4, c_ulong: VT_UI4, - c_float: VT_R4, c_double: VT_R8, - c_longlong: VT_I8, c_ulonglong: VT_UI8, - VARIANT_BOOL: VT_BOOL, - BSTR: VT_BSTR, VARIANT: VT_VARIANT, - # SAFEARRAY(VARIANT *) # # It is unlear to me if this is allowed or not. Apparently there @@ -936,15 +1018,13 @@ def Invoke(self, dispid, *args, **kw): # We have this code here to make sure that comtypes can import # such a typelib, although calling ths method will fail because # such an array cannot be created. - POINTER(VARIANT): VT_BYREF|VT_VARIANT, - + POINTER(VARIANT): VT_BYREF | VT_VARIANT, # This is needed to import Esri ArcObjects (esriSystem.olb). - POINTER(BSTR): VT_BYREF|VT_BSTR, - + POINTER(BSTR): VT_BYREF | VT_BSTR, # These are not yet implemented: # POINTER(IUnknown): VT_UNKNOWN, # POINTER(IDispatch): VT_DISPATCH, - } +} _vartype_to_ctype = {} for c, v in _ctype_to_vartype.items(): @@ -954,13 +1034,13 @@ def Invoke(self, dispid, *args, **kw): _ctype_to_vartype[c_char] = VT_UI1 - try: from comtypes.safearray import _midlSAFEARRAY except (ImportError, AttributeError): pass +# fmt: off __known_symbols__ = [ "CURRENCY", "CY", "tagCY", "DECIMAL", "tagDEC", "DISPATCH_METHOD", "DISPATCH_PROPERTYGET", "DISPATCH_PROPERTYPUT", "DISPATCH_PROPERTYPUTREF", @@ -984,3 +1064,4 @@ def Invoke(self, dispid, *args, **kw): "VT_UNKNOWN", "VT_USERDEFINED", "VT_VARIANT", "VT_VECTOR", "VT_VERSIONED_STREAM", "VT_VOID", ] +# fmt: on diff --git a/comtypes/client/__init__.py b/comtypes/client/__init__.py index 849eb7f0..5e3f6c7a 100644 --- a/comtypes/client/__init__.py +++ b/comtypes/client/__init__.py @@ -15,9 +15,7 @@ import comtypes from comtypes.hresult import * -from comtypes import ( - automation, CoClass, GUID, IUnknown, TYPE_CHECKING, typeinfo -) +from comtypes import automation, CoClass, GUID, IUnknown, TYPE_CHECKING, typeinfo import comtypes.client.dynamic from comtypes.client._constants import Constants from comtypes.client._events import GetEvents, ShowEvents, PumpEvents @@ -33,6 +31,7 @@ if TYPE_CHECKING: from typing import Any, Optional, overload, Type, TypeVar, Union as _UnionT from comtypes import hints + _T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown) logger = logging.getLogger(__name__) @@ -58,8 +57,8 @@ def GetBestInterface(punk): Generate a wrapper module for the typelib, and QI for the interface found. """ - if not punk: # NULL COM pointer - return punk # or should we return None? + if not punk: # NULL COM pointer + return punk # or should we return None? # find the typelib and the interface name logger.debug("GetBestInterface(%s)", punk) try: @@ -69,10 +68,12 @@ def GetBestInterface(punk): except comtypes.COMError: # Some COM objects support IProvideClassInfo2, but not IProvideClassInfo. # These objects are broken, but we support them anyway. - logger.debug("Does NOT implement IProvideClassInfo, trying IProvideClassInfo2") + logger.debug( + "Does NOT implement IProvideClassInfo, trying IProvideClassInfo2" + ) pci = punk.QueryInterface(typeinfo.IProvideClassInfo2) logger.debug("Does implement IProvideClassInfo2") - tinfo = pci.GetClassInfo() # TypeInfo for the CoClass + tinfo = pci.GetClassInfo() # TypeInfo for the CoClass # find the interface marked as default ta = tinfo.GetTypeAttr() for index in range(ta.cImplTypes): @@ -108,8 +109,8 @@ def GetBestInterface(punk): logger.debug("Does not implement default interface, returning dynamic object") return comtypes.client.dynamic.Dispatch(punk) - itf_name = tinfo.GetDocumentation(-1)[0] # interface name - tlib = tinfo.GetContainingTypeLib()[0] # typelib + itf_name = tinfo.GetDocumentation(-1)[0] # interface name + tlib = tinfo.GetContainingTypeLib()[0] # typelib # import the wrapper, generating it on demand mod = GetModule(tlib) @@ -131,6 +132,8 @@ def GetBestInterface(punk): result = punk.QueryInterface(interface) logger.debug("Final result is %s", result) return result + + # backwards compatibility: wrap = GetBestInterface @@ -142,14 +145,18 @@ def GetBestInterface(punk): # Object creation # if comtypes.TYPE_CHECKING: + @overload def GetActiveObject(progid): # type: (_UnionT[str, CoClass, GUID]) -> Any pass + @overload def GetActiveObject(progid, interface): # type: (_UnionT[str, CoClass, GUID], Type[_T_IUnknown]) -> _T_IUnknown pass + + def GetActiveObject(progid, interface=None, dynamic=False): # type: (_UnionT[str, CoClass, GUID], Optional[Any], bool) -> Any """Return a pointer to a running COM object that has been @@ -176,25 +183,26 @@ def GetActiveObject(progid, interface=None, dynamic=False): def _manage(obj, clsid, interface): # type: (Any, Optional[GUID], Optional[Type[IUnknown]]) -> Any - obj.__dict__['__clsid'] = str(clsid) + obj.__dict__["__clsid"] = str(clsid) if interface is None: obj = GetBestInterface(obj) return obj if TYPE_CHECKING: + @overload def GetClassObject(progid, clsctx=None, pServerInfo=None): # type: (_UnionT[str, CoClass, GUID], Optional[int], Optional[comtypes.COSERVERINFO]) -> hints.IClassFactory pass + @overload def GetClassObject(progid, clsctx=None, pServerInfo=None, interface=None): # type: (_UnionT[str, CoClass, GUID], Optional[int], Optional[comtypes.COSERVERINFO], Optional[Type[_T_IUnknown]]) -> _T_IUnknown pass -def GetClassObject(progid, - clsctx=None, - pServerInfo=None, - interface=None): + + +def GetClassObject(progid, clsctx=None, pServerInfo=None, interface=None): # type: (_UnionT[str, CoClass, GUID], Optional[int], Optional[comtypes.COSERVERINFO], Optional[Type[IUnknown]]) -> IUnknown """Create and return the class factory for a COM object. @@ -207,20 +215,32 @@ def GetClassObject(progid, if TYPE_CHECKING: + @overload def CreateObject(progid): # type: (_UnionT[str, CoClass, GUID]) -> Any pass + @overload - def CreateObject(progid, clsctx=None, machine=None, interface=None, dynamic=False, pServerInfo=None): + def CreateObject( + progid, + clsctx=None, + machine=None, + interface=None, + dynamic=False, + pServerInfo=None, + ): # type: (_UnionT[str, CoClass, GUID], Optional[int], Optional[str], Optional[Type[_T_IUnknown]], bool, Optional[comtypes.COSERVERINFO]) -> _T_IUnknown pass -def CreateObject(progid, # which object to create - clsctx=None, # how to create the object - machine=None, # where to create the object - interface=None, # the interface we want - dynamic=False, # use dynamic dispatch - pServerInfo=None, # server info struct for remoting + + +def CreateObject( + progid, # which object to create + clsctx=None, # how to create the object + machine=None, # where to create the object + interface=None, # the interface we want + dynamic=False, # use dynamic dispatch + pServerInfo=None, # server info struct for remoting ): # type: (_UnionT[str, CoClass, GUID], Optional[int], Optional[str], Optional[Type[IUnknown]], bool, Optional[comtypes.COSERVERINFO]) -> Any """Create a COM object from 'progid', and try to QueryInterface() @@ -248,32 +268,48 @@ def CreateObject(progid, # which object to create elif interface is None: interface = getattr(progid, "_com_interfaces_", [None])[0] if machine is None and pServerInfo is None: - logger.debug("CoCreateInstance(%s, clsctx=%s, interface=%s)", - clsid, clsctx, interface) + logger.debug( + "CoCreateInstance(%s, clsctx=%s, interface=%s)", clsid, clsctx, interface + ) obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface) else: - logger.debug("CoCreateInstanceEx(%s, clsctx=%s, interface=%s, machine=%s,\ + logger.debug( + "CoCreateInstanceEx(%s, clsctx=%s, interface=%s, machine=%s,\ pServerInfo=%s)", - clsid, clsctx, interface, machine, pServerInfo) + clsid, + clsctx, + interface, + machine, + pServerInfo, + ) if machine is not None and pServerInfo is not None: msg = "You can notset both the machine name and server info." raise ValueError(msg) - obj = comtypes.CoCreateInstanceEx(clsid, clsctx=clsctx, - interface=interface, machine=machine, pServerInfo=pServerInfo) + obj = comtypes.CoCreateInstanceEx( + clsid, + clsctx=clsctx, + interface=interface, + machine=machine, + pServerInfo=pServerInfo, + ) if dynamic: return comtypes.client.dynamic.Dispatch(obj) return _manage(obj, clsid, interface=interface) if TYPE_CHECKING: + @overload def CoGetObject(displayname, interface): # type: (str, Type[_T_IUnknown]) -> _T_IUnknown pass + @overload def CoGetObject(displayname, interface=None, dynamic=False): # type: (str, None, bool) -> Any pass + + def CoGetObject(displayname, interface=None, dynamic=False): # type: (str, Optional[Type[comtypes.IUnknown]], bool) -> Any """Create an object by calling CoGetObject(displayname). @@ -287,12 +323,12 @@ def CoGetObject(displayname, interface=None, dynamic=False): punk = comtypes.CoGetObject(displayname, interface) if dynamic: return comtypes.client.dynamic.Dispatch(punk) - return _manage(punk, - clsid=None, - interface=interface) + return _manage(punk, clsid=None, interface=interface) +# fmt: off __all__ = [ "CreateObject", "GetActiveObject", "CoGetObject", "GetEvents", "ShowEvents", "PumpEvents", "GetModule", "GetClassObject", ] +# fmt: on diff --git a/comtypes/client/_code_cache.py b/comtypes/client/_code_cache.py index 7202bf29..bf05efb9 100644 --- a/comtypes/client/_code_cache.py +++ b/comtypes/client/_code_cache.py @@ -6,6 +6,7 @@ """ import ctypes, logging, os, sys, tempfile, types from ctypes import wintypes + logger = logging.getLogger(__name__) @@ -40,6 +41,7 @@ def _find_gen_dir(): """ _create_comtypes_gen_package() from comtypes import gen + gen_path = _ensure_list(gen.__path__) if not _is_writeable(gen_path): # check type of executable image to determine a subdirectory @@ -58,7 +60,7 @@ def _find_gen_dir(): subdir = r"comtypes_cache\%s-%s" % (base, version_str) basedir = tempfile.gettempdir() - else: # ftype in ('windows_exe', 'console_exe') + else: # ftype in ('windows_exe', 'console_exe') # exe created by py2exe base = os.path.splitext(os.path.basename(sys.executable))[0] subdir = r"comtypes_cache\%s-%s" % (base, version_str) @@ -73,25 +75,33 @@ def _find_gen_dir(): logger.info("Using writeable comtypes cache directory: '%s'", result) return result + ################################################################ SHGetSpecialFolderPath = ctypes.OleDLL("shell32.dll").SHGetSpecialFolderPathW GetModuleFileName = ctypes.WinDLL("kernel32.dll").GetModuleFileNameW -SHGetSpecialFolderPath.argtypes = [ctypes.c_ulong, ctypes.c_wchar_p, - ctypes.c_int, ctypes.c_int] +SHGetSpecialFolderPath.argtypes = [ + ctypes.c_ulong, + ctypes.c_wchar_p, + ctypes.c_int, + ctypes.c_int, +] GetModuleFileName.restype = ctypes.c_ulong GetModuleFileName.argtypes = [wintypes.HMODULE, ctypes.c_wchar_p, ctypes.c_ulong] CSIDL_APPDATA = 26 MAX_PATH = 260 + def _create_comtypes_gen_package(): """Import (creating it if needed) the comtypes.gen package.""" try: import comtypes.gen + logger.info("Imported existing %s", comtypes.gen) except ImportError: import comtypes + logger.info("Could not import comtypes.gen, trying to create it.") try: comtypes_path = os.path.abspath(os.path.join(comtypes.__path__[0], "gen")) @@ -111,6 +121,7 @@ def _create_comtypes_gen_package(): comtypes.gen.__path__ = [] logger.info("Created a memory-only package.") + def _is_writeable(path): """Check if the first part, if any, on path is a directory in which we can create files.""" @@ -119,6 +130,7 @@ def _is_writeable(path): # TODO: should we add os.X_OK flag as well? It seems unnecessary on Windows. return os.access(path[0], os.W_OK) + def _get_module_filename(hmodule): """Call the Windows GetModuleFileName function which determines the path from a module handle.""" @@ -127,6 +139,7 @@ def _get_module_filename(hmodule): return path.value raise ctypes.WinError() + def _get_appdata_dir(): """Return the 'file system directory that serves as a common repository for application-specific data' - CSIDL_APPDATA""" diff --git a/comtypes/client/_constants.py b/comtypes/client/_constants.py index 554b9c45..f20222d6 100644 --- a/comtypes/client/_constants.py +++ b/comtypes/client/_constants.py @@ -74,6 +74,7 @@ class Constants(object): >>> 'FileAttribute' in c.alias # as is `key in dict` True """ + __slots__ = ("alias", "consts", "enums", "tcomp") def __init__(self, obj): diff --git a/comtypes/client/_events.py b/comtypes/client/_events.py index d7d71dd1..98a55295 100644 --- a/comtypes/client/_events.py +++ b/comtypes/client/_events.py @@ -8,8 +8,10 @@ import comtypes.connectionpoints from comtypes.client._generate import GetModule import logging + logger = logging.getLogger(__name__) + class _AdviseConnection(object): def __init__(self, source, interface, receiver): self.cp = None @@ -40,6 +42,7 @@ def __del__(self): # Are we sure we want to ignore errors here? pass + def FindOutgoingInterface(source): """XXX Describe the strategy that is used...""" # If the COM object implements IProvideClassInfo2, it is easy to @@ -64,7 +67,7 @@ def FindOutgoingInterface(source): # If we can find the CLSID of the COM object, we can look for a # registered outgoing interface (__clsid has been set by # comtypes.client): - clsid = source.__dict__.get('__clsid') + clsid = source.__dict__.get("__clsid") try: interface = comtypes.com_coclass_registry[clsid]._outgoing_interfaces_[0] except KeyError: @@ -79,6 +82,7 @@ def FindOutgoingInterface(source): raise TypeError("cannot determine source interface") + def find_single_connection_interface(source): # Enumerate the connection interfaces. If we find a single one, # return it, if there are more, we give up since we cannot @@ -101,33 +105,42 @@ def find_single_connection_interface(source): return None + def report_errors(func): # This decorator preserves parts of the decorated function # signature, so that the comtypes special-casing for the 'this' # parameter still works. - if func.__code__.co_varnames[:2] == ('self', 'this'): + if func.__code__.co_varnames[:2] == ("self", "this"): + def error_printer(self, this, *args, **kw): try: return func(self, this, *args, **kw) except: traceback.print_exc() raise + else: + def error_printer(*args, **kw): try: return func(*args, **kw) except: traceback.print_exc() raise + return error_printer + from comtypes._comobject import _MethodFinder + + class _SinkMethodFinder(_MethodFinder): """Special MethodFinder, for finding and decorating event handler methods. Looks for methods on two objects. Also decorates the event handlers with 'report_errors' which will print exceptions in event handlers. """ + def __init__(self, inst, sink): super(_SinkMethodFinder, self).__init__(inst) self.sink = sink @@ -143,9 +156,7 @@ def find_method(self, fq_name, mthname): # decorate it with an error printer... method = report_errors(im_func) # and make a new bound method from it again. - return comtypes.instancemethod(method, - im_self, - type(im_self)) + return comtypes.instancemethod(method, im_self, type(im_self)) except AttributeError as details: raise RuntimeError(details) @@ -158,8 +169,8 @@ def _find_method(self, fq_name, mthname): except AttributeError: return getattr(self.sink, mthname) -def CreateEventReceiver(interface, handler): +def CreateEventReceiver(interface, handler): class Sink(comtypes.COMObject): _com_interfaces_ = [interface] @@ -172,8 +183,9 @@ def _get_method_finder_(self, itf): # Since our Sink object doesn't have typeinfo, it needs a # _dispimpl_ dictionary to dispatch events received via Invoke. - if issubclass(interface, comtypes.automation.IDispatch) \ - and not hasattr(sink, "_dispimpl_"): + if issubclass(interface, comtypes.automation.IDispatch) and not hasattr( + sink, "_dispimpl_" + ): finder = sink._get_method_finder_(interface) dispimpl = sink._dispimpl_ = {} for m in interface._methods_: @@ -188,6 +200,7 @@ def _get_method_finder_(self, itf): return sink + def GetEvents(source, sink, interface=None): """Receive COM events from 'source'. Events will call methods on the 'sink' object. 'interface' is the source interface to use. @@ -202,6 +215,7 @@ def GetEvents(source, sink, interface=None): rcv = CreateEventReceiver(interface, sink) return _AdviseConnection(source, interface, rcv) + class EventDumper(object): """Universal sink for COM events.""" @@ -210,12 +224,15 @@ def __getattr__(self, name): if name.startswith("__") and name.endswith("__"): raise AttributeError(name) print("# event found:", name) + def handler(self, this, *args, **kw): # XXX handler is called with 'this'. Should we really print "None" instead? args = (None,) + args print("Event %s(%s)" % (name, ", ".join([repr(a) for a in args]))) + return comtypes.instancemethod(handler, self, EventDumper) + def ShowEvents(source, interface=None): """Receive COM events from 'source'. A special event sink will be used that first prints the names of events that are found in the @@ -224,11 +241,13 @@ def ShowEvents(source, interface=None): """ return comtypes.client.GetEvents(source, sink=EventDumper(), interface=interface) + # This type is used inside 'PumpEvents', but if we create the type # afresh each time 'PumpEvents' is called we end up creating cyclic # garbage for each call. So we define it here instead. _handles_type = ctypes.c_void_p * 1 + def PumpEvents(timeout): """This following code waits for 'timeout' seconds in the way required for COM, internally doing the correct things depending @@ -262,22 +281,26 @@ def PumpEvents(timeout): # @ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint) def HandlerRoutine(dwCtrlType): - if dwCtrlType == 0: # CTRL+C + if dwCtrlType == 0: # CTRL+C ctypes.windll.kernel32.SetEvent(hevt) return 1 return 0 + HandlerRoutine = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint)(HandlerRoutine) ctypes.windll.kernel32.SetConsoleCtrlHandler(HandlerRoutine, 1) try: try: - res = ctypes.oledll.ole32.CoWaitForMultipleHandles(0, - int(timeout * 1000), - len(handles), handles, - ctypes.byref(ctypes.c_ulong())) + res = ctypes.oledll.ole32.CoWaitForMultipleHandles( + 0, + int(timeout * 1000), + len(handles), + handles, + ctypes.byref(ctypes.c_ulong()), + ) except WindowsError as details: - if details.winerror != RPC_S_CALLPENDING: # timeout expired + if details.winerror != RPC_S_CALLPENDING: # timeout expired raise else: raise KeyboardInterrupt diff --git a/comtypes/client/_generate.py b/comtypes/client/_generate.py index c37e8642..c81759bf 100644 --- a/comtypes/client/_generate.py +++ b/comtypes/client/_generate.py @@ -5,6 +5,7 @@ import os import sys import types + if sys.version_info >= (3, 0): base_text_type = str import winreg @@ -29,6 +30,7 @@ def _my_import(fullname): # type: (str) -> types.ModuleType """helper function to import dotted modules""" import comtypes.gen as g + if comtypes.client.gen_dir and comtypes.client.gen_dir not in g.__path__: g.__path__.append(comtypes.client.gen_dir) # type: ignore return importlib.import_module(fullname) @@ -113,7 +115,9 @@ def GetModule(tlib): # the directory of the calling module (if not from command line) frame = sys._getframe(1) _file_ = frame.f_globals.get("__file__", None) # type: str - pathname, is_abs = _resolve_filename(tlib_string, _file_ and os.path.dirname(_file_)) + pathname, is_abs = _resolve_filename( + tlib_string, _file_ and os.path.dirname(_file_) + ) logger.debug("GetModule(%s), resolved: %s", pathname, is_abs) tlib = _load_tlib(pathname) # don't register if not is_abs: @@ -123,7 +127,7 @@ def GetModule(tlib): logger.info("GetModule(%s): could not resolve to a filename", tlib) pathname = tlib_string # if above path torture resulted in an absolute path, then the file exists (at this point)! - assert not(os.path.isabs(pathname)) or os.path.exists(pathname) + assert not (os.path.isabs(pathname)) or os.path.exists(pathname) else: pathname = None tlib = _load_tlib(tlib) @@ -152,9 +156,13 @@ def _load_tlib(obj): elif isinstance(obj, GUID): clsid = str(obj) # lookup associated typelib in registry - with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\TypeLib" % clsid) as key: + with winreg.OpenKey( + winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\TypeLib" % clsid + ) as key: libid = winreg.EnumValue(key, 0)[1] - with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Version" % clsid) as key: + with winreg.OpenKey( + winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Version" % clsid + ) as key: ver = winreg.EnumValue(key, 0)[1].split(".") return typeinfo.LoadRegTypeLib(GUID(libid), int(ver[0]), int(ver[1]), 0) # obj is a sequence containing libid @@ -191,6 +199,7 @@ def _create_module_in_memory(modulename, code): """create module in memory system, and import it""" # `modulename` is 'comtypes.gen.xxx' import comtypes.gen as g + mod = types.ModuleType(modulename) abs_gen_path = os.path.abspath(g.__path__[0]) # type: ignore mod.__file__ = os.path.join(abs_gen_path, "") @@ -255,7 +264,7 @@ def _get_known_symbols(): "comtypes.automation", "comtypes", "ctypes.wintypes", - "ctypes" + "ctypes", ): mod = importlib.import_module(mod_name) if hasattr(mod, "__known_symbols__"): @@ -266,6 +275,7 @@ def _get_known_symbols(): known_symbols[name] = mod.__name__ return known_symbols + ################################################################ diff --git a/comtypes/client/dynamic.py b/comtypes/client/dynamic.py index be9d7710..bf8009c0 100644 --- a/comtypes/client/dynamic.py +++ b/comtypes/client/dynamic.py @@ -19,6 +19,7 @@ hres.E_INVALIDARG, ] + def Dispatch(obj): # Wrap an object in a Dispatch instance, exposing methods and properties # via fully dynamic dispatch @@ -32,6 +33,7 @@ def Dispatch(obj): return comtypes.client.lazybind.Dispatch(obj, tinfo) return obj + class MethodCaller: # Wrong name: does not only call methods but also handle # property accesses. @@ -43,26 +45,36 @@ def __call__(self, *args): return self._obj._comobj.Invoke(self._id, *args) def __getitem__(self, *args): - return self._obj._comobj.Invoke(self._id, *args, - **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYGET)) + return self._obj._comobj.Invoke( + self._id, *args, **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYGET) + ) def __setitem__(self, *args): if _is_object(args[-1]): - self._obj._comobj.Invoke(self._id, *args, - **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYPUTREF)) + self._obj._comobj.Invoke( + self._id, + *args, + **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYPUTREF) + ) else: - self._obj._comobj.Invoke(self._id, *args, - **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYPUT)) + self._obj._comobj.Invoke( + self._id, + *args, + **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYPUT) + ) + class _Dispatch(object): # Expose methods and properties via fully dynamic dispatch def __init__(self, comobj): self.__dict__["_comobj"] = comobj - self.__dict__["_ids"] = {} # Tiny optimization: trying not to use GetIDsOfNames more than once + self.__dict__[ + "_ids" + ] = {} # Tiny optimization: trying not to use GetIDsOfNames more than once self.__dict__["_methods"] = set() def __enum(self): - e = self._comobj.Invoke(-4) # DISPID_NEWENUM + e = self._comobj.Invoke(-4) # DISPID_NEWENUM return e.QueryInterface(comtypes.automation.IEnumVARIANT) def __cmp__(self, other): @@ -150,17 +162,21 @@ def __iter__(self): # self._comobj.Invoke(-3, index, value, # _invkind=comtypes.automation.DISPATCH_PROPERTYPUT|comtypes.automation.DISPATCH_PROPERTYPUTREF) + class _Collection(object): def __init__(self, enum): self.enum = enum if sys.version_info >= (3, 0): + def __next__(self): item, fetched = self.enum.Next(1) if fetched: return item raise StopIteration + else: + def next(self): item, fetched = self.enum.Next(1) if fetched: diff --git a/comtypes/client/lazybind.py b/comtypes/client/lazybind.py index 4b4a23c6..c26f0cd1 100644 --- a/comtypes/client/lazybind.py +++ b/comtypes/client/lazybind.py @@ -17,9 +17,11 @@ class FuncDesc(object): """Stores important FUNCDESC properties by copying them from a real FUNCDESC instance. """ + def __init__(self, **kw): self.__dict__.update(kw) + # What is missing? # # Should NamedProperty support __call__()? @@ -38,26 +40,15 @@ def __getitem__(self, arg): if self.get is None: raise TypeError("unsubscriptable object") if isinstance(arg, tuple): - return self.disp._comobj._invoke(self.get.memid, - self.get.invkind, - 0, - *arg) + return self.disp._comobj._invoke(self.get.memid, self.get.invkind, 0, *arg) elif arg == _all_slice: - return self.disp._comobj._invoke(self.get.memid, - self.get.invkind, - 0) - return self.disp._comobj._invoke(self.get.memid, - self.get.invkind, - 0, - *[arg]) + return self.disp._comobj._invoke(self.get.memid, self.get.invkind, 0) + return self.disp._comobj._invoke(self.get.memid, self.get.invkind, 0, *[arg]) def __call__(self, *args): if self.get is None: raise TypeError("object is not callable") - return self.disp._comobj._invoke(self.get.memid, - self.get.invkind, - 0, - *args) + return self.disp._comobj._invoke(self.get.memid, self.get.invkind, 0, *args) def __setitem__(self, name, value): # See discussion in Dispatch.__setattr__ below. @@ -68,24 +59,14 @@ def __setitem__(self, name, value): else: descr = self.put or self.putref if isinstance(name, tuple): - self.disp._comobj._invoke(descr.memid, - descr.invkind, - 0, - *(name + (value,))) + self.disp._comobj._invoke(descr.memid, descr.invkind, 0, *(name + (value,))) elif name == _all_slice: - self.disp._comobj._invoke(descr.memid, - descr.invkind, - 0, - value) + self.disp._comobj._invoke(descr.memid, descr.invkind, 0, value) else: - self.disp._comobj._invoke(descr.memid, - descr.invkind, - 0, - name, - value) + self.disp._comobj._invoke(descr.memid, descr.invkind, 0, name, value) def __iter__(self): - """ Explicitly disallow iteration. """ + """Explicitly disallow iteration.""" msg = "%r is not iterable" % self.disp raise TypeError(msg) @@ -102,10 +83,12 @@ def __iter__(self): # 2. Custom objects method support named arguments, Dispatch # objects do not (could be added, would probably be expensive) + class Dispatch(object): """Dynamic dispatch for an object the exposes type information. Binding at runtime is done via ITypeComp::Bind calls. """ + def __init__(self, comobj, tinfo): self.__dict__["_comobj"] = comobj self.__dict__["_tinfo"] = tinfo @@ -130,10 +113,12 @@ def __bind(self, name, invkind): # Using a separate instance to store interesting # attributes of descr avoids that the typecomp instance is # kept alive... - info = FuncDesc(memid=descr.memid, - invkind=descr.invkind, - cParams=descr.cParams, - funckind=descr.funckind) + info = FuncDesc( + memid=descr.memid, + invkind=descr.invkind, + cParams=descr.cParams, + funckind=descr.funckind, + ) self._tdesc[(name, invkind)] = info return info @@ -147,8 +132,7 @@ def __cmp__(self, other): return cmp(self._comobj, other._comobj) def __eq__(self, other): - return isinstance(other, Dispatch) and \ - self._comobj == other._comobj + return isinstance(other, Dispatch) and self._comobj == other._comobj def __hash__(self): return hash(self._comobj) @@ -180,6 +164,7 @@ def __getattr__(self, name): # DISPATCH_METHOD def caller(*args): return self._comobj._invoke(descr.memid, descr.invkind, 0, *args) + try: caller.__name__ = name except TypeError: @@ -220,10 +205,9 @@ def __setattr__(self, name, value): raise AttributeError(name) def __call__(self, *args): - return self._comobj._invoke(DISPID_VALUE, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0, - *args) + return self._comobj._invoke( + DISPID_VALUE, DISPATCH_METHOD | DISPATCH_PROPERTYGET, 0, *args + ) def __getitem__(self, arg): if isinstance(arg, tuple): @@ -234,10 +218,9 @@ def __getitem__(self, arg): args = (arg,) try: - return self._comobj._invoke(DISPID_VALUE, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0, - *args) + return self._comobj._invoke( + DISPID_VALUE, DISPATCH_METHOD | DISPATCH_PROPERTYGET, 0, *args + ) except comtypes.COMError: return iter(self)[arg] @@ -253,15 +236,12 @@ def __setitem__(self, name, value): args = (value,) else: args = (name, value) - return self._comobj._invoke(DISPID_VALUE, - invkind, - 0, - *args) + return self._comobj._invoke(DISPID_VALUE, invkind, 0, *args) def __iter__(self): - punk = self._comobj._invoke(DISPID_NEWENUM, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0) + punk = self._comobj._invoke( + DISPID_NEWENUM, DISPATCH_METHOD | DISPATCH_PROPERTYGET, 0 + ) enum = punk.QueryInterface(IEnumVARIANT) enum._dynamic = True return enum diff --git a/comtypes/connectionpoints.py b/comtypes/connectionpoints.py index 160c1913..955347da 100644 --- a/comtypes/connectionpoints.py +++ b/comtypes/connectionpoints.py @@ -1,109 +1,153 @@ import sys from ctypes import * from comtypes import IUnknown, COMMETHOD, GUID, HRESULT, dispid + _GUID = GUID + class tagCONNECTDATA(Structure): _fields_ = [ - ('pUnk', POINTER(IUnknown)), - ('dwCookie', c_ulong), + ("pUnk", POINTER(IUnknown)), + ("dwCookie", c_ulong), ] + + CONNECTDATA = tagCONNECTDATA ################################################################ + class IConnectionPointContainer(IUnknown): - _iid_ = GUID('{B196B284-BAB4-101A-B69C-00AA00341D07}') + _iid_ = GUID("{B196B284-BAB4-101A-B69C-00AA00341D07}") _idlflags_ = [] + class IConnectionPoint(IUnknown): - _iid_ = GUID('{B196B286-BAB4-101A-B69C-00AA00341D07}') + _iid_ = GUID("{B196B286-BAB4-101A-B69C-00AA00341D07}") _idlflags_ = [] + class IEnumConnections(IUnknown): - _iid_ = GUID('{B196B287-BAB4-101A-B69C-00AA00341D07}') + _iid_ = GUID("{B196B287-BAB4-101A-B69C-00AA00341D07}") _idlflags_ = [] def __iter__(self): return self if sys.version_info >= (3, 0): + def __next__(self): cp, fetched = self.Next(1) if fetched == 0: raise StopIteration return cp + else: + def next(self): cp, fetched = self.Next(1) if fetched == 0: raise StopIteration return cp + class IEnumConnectionPoints(IUnknown): - _iid_ = GUID('{B196B285-BAB4-101A-B69C-00AA00341D07}') + _iid_ = GUID("{B196B285-BAB4-101A-B69C-00AA00341D07}") _idlflags_ = [] def __iter__(self): return self if sys.version_info >= (3, 0): + def __next__(self): cp, fetched = self.Next(1) if fetched == 0: raise StopIteration return cp + else: + def next(self): cp, fetched = self.Next(1) if fetched == 0: raise StopIteration return cp + ################################################################ IConnectionPointContainer._methods_ = [ - COMMETHOD([], HRESULT, 'EnumConnectionPoints', - ( ['out'], POINTER(POINTER(IEnumConnectionPoints)), 'ppEnum' )), - COMMETHOD([], HRESULT, 'FindConnectionPoint', - ( ['in'], POINTER(_GUID), 'riid' ), - ( ['out'], POINTER(POINTER(IConnectionPoint)), 'ppCP' )), + COMMETHOD( + [], + HRESULT, + "EnumConnectionPoints", + (["out"], POINTER(POINTER(IEnumConnectionPoints)), "ppEnum"), + ), + COMMETHOD( + [], + HRESULT, + "FindConnectionPoint", + (["in"], POINTER(_GUID), "riid"), + (["out"], POINTER(POINTER(IConnectionPoint)), "ppCP"), + ), ] IConnectionPoint._methods_ = [ - COMMETHOD([], HRESULT, 'GetConnectionInterface', - ( ['out'], POINTER(_GUID), 'pIID' )), - COMMETHOD([], HRESULT, 'GetConnectionPointContainer', - ( ['out'], POINTER(POINTER(IConnectionPointContainer)), 'ppCPC' )), - COMMETHOD([], HRESULT, 'Advise', - ( ['in'], POINTER(IUnknown), 'pUnkSink' ), - ( ['out'], POINTER(c_ulong), 'pdwCookie' )), - COMMETHOD([], HRESULT, 'Unadvise', - ( ['in'], c_ulong, 'dwCookie' )), - COMMETHOD([], HRESULT, 'EnumConnections', - ( ['out'], POINTER(POINTER(IEnumConnections)), 'ppEnum' )), + COMMETHOD([], HRESULT, "GetConnectionInterface", (["out"], POINTER(_GUID), "pIID")), + COMMETHOD( + [], + HRESULT, + "GetConnectionPointContainer", + (["out"], POINTER(POINTER(IConnectionPointContainer)), "ppCPC"), + ), + COMMETHOD( + [], + HRESULT, + "Advise", + (["in"], POINTER(IUnknown), "pUnkSink"), + (["out"], POINTER(c_ulong), "pdwCookie"), + ), + COMMETHOD([], HRESULT, "Unadvise", (["in"], c_ulong, "dwCookie")), + COMMETHOD( + [], + HRESULT, + "EnumConnections", + (["out"], POINTER(POINTER(IEnumConnections)), "ppEnum"), + ), ] IEnumConnections._methods_ = [ - COMMETHOD([], HRESULT, 'Next', - ( ['in'], c_ulong, 'cConnections' ), - ( ['out'], POINTER(tagCONNECTDATA), 'rgcd' ), - ( ['out'], POINTER(c_ulong), 'pcFetched' )), - COMMETHOD([], HRESULT, 'Skip', - ( ['in'], c_ulong, 'cConnections' )), - COMMETHOD([], HRESULT, 'Reset'), - COMMETHOD([], HRESULT, 'Clone', - ( ['out'], POINTER(POINTER(IEnumConnections)), 'ppEnum' )), + COMMETHOD( + [], + HRESULT, + "Next", + (["in"], c_ulong, "cConnections"), + (["out"], POINTER(tagCONNECTDATA), "rgcd"), + (["out"], POINTER(c_ulong), "pcFetched"), + ), + COMMETHOD([], HRESULT, "Skip", (["in"], c_ulong, "cConnections")), + COMMETHOD([], HRESULT, "Reset"), + COMMETHOD( + [], HRESULT, "Clone", (["out"], POINTER(POINTER(IEnumConnections)), "ppEnum") + ), ] IEnumConnectionPoints._methods_ = [ - COMMETHOD([], HRESULT, 'Next', - ( ['in'], c_ulong, 'cConnections' ), - ( ['out'], POINTER(POINTER(IConnectionPoint)), 'ppCP' ), - ( ['out'], POINTER(c_ulong), 'pcFetched' )), - COMMETHOD([], HRESULT, 'Skip', - ( ['in'], c_ulong, 'cConnections' )), - COMMETHOD([], HRESULT, 'Reset'), - COMMETHOD([], HRESULT, 'Clone', - ( ['out'], POINTER(POINTER(IEnumConnectionPoints)), 'ppEnum' )), + COMMETHOD( + [], + HRESULT, + "Next", + (["in"], c_ulong, "cConnections"), + (["out"], POINTER(POINTER(IConnectionPoint)), "ppCP"), + (["out"], POINTER(c_ulong), "pcFetched"), + ), + COMMETHOD([], HRESULT, "Skip", (["in"], c_ulong, "cConnections")), + COMMETHOD([], HRESULT, "Reset"), + COMMETHOD( + [], + HRESULT, + "Clone", + (["out"], POINTER(POINTER(IEnumConnectionPoints)), "ppEnum"), + ), ] diff --git a/comtypes/errorinfo.py b/comtypes/errorinfo.py index 3573be33..181596b8 100644 --- a/comtypes/errorinfo.py +++ b/comtypes/errorinfo.py @@ -11,51 +11,54 @@ else: base_text_type = basestring + class ICreateErrorInfo(IUnknown): _iid_ = GUID("{22F03340-547D-101B-8E65-08002B2BD119}") _methods_ = [ - COMMETHOD([], HRESULT, 'SetGUID', - (['in'], POINTER(GUID), "rguid")), - COMMETHOD([], HRESULT, 'SetSource', - (['in'], LPCOLESTR, "szSource")), - COMMETHOD([], HRESULT, 'SetDescription', - (['in'], LPCOLESTR, "szDescription")), - COMMETHOD([], HRESULT, 'SetHelpFile', - (['in'], LPCOLESTR, "szHelpFile")), - COMMETHOD([], HRESULT, 'SetHelpContext', - (['in'], DWORD, "dwHelpContext")) - ] + COMMETHOD([], HRESULT, "SetGUID", (["in"], POINTER(GUID), "rguid")), + COMMETHOD([], HRESULT, "SetSource", (["in"], LPCOLESTR, "szSource")), + COMMETHOD([], HRESULT, "SetDescription", (["in"], LPCOLESTR, "szDescription")), + COMMETHOD([], HRESULT, "SetHelpFile", (["in"], LPCOLESTR, "szHelpFile")), + COMMETHOD([], HRESULT, "SetHelpContext", (["in"], DWORD, "dwHelpContext")), + ] + class IErrorInfo(IUnknown): _iid_ = GUID("{1CF2B120-547D-101B-8E65-08002B2BD119}") _methods_ = [ - COMMETHOD([], HRESULT, 'GetGUID', - (['out'], POINTER(GUID), "pGUID")), - COMMETHOD([], HRESULT, 'GetSource', - (['out'], POINTER(BSTR), "pBstrSource")), - COMMETHOD([], HRESULT, 'GetDescription', - (['out'], POINTER(BSTR), "pBstrDescription")), - COMMETHOD([], HRESULT, 'GetHelpFile', - (['out'], POINTER(BSTR), "pBstrHelpFile")), - COMMETHOD([], HRESULT, 'GetHelpContext', - (['out'], POINTER(DWORD), "pdwHelpContext")), - ] + COMMETHOD([], HRESULT, "GetGUID", (["out"], POINTER(GUID), "pGUID")), + COMMETHOD([], HRESULT, "GetSource", (["out"], POINTER(BSTR), "pBstrSource")), + COMMETHOD( + [], HRESULT, "GetDescription", (["out"], POINTER(BSTR), "pBstrDescription") + ), + COMMETHOD( + [], HRESULT, "GetHelpFile", (["out"], POINTER(BSTR), "pBstrHelpFile") + ), + COMMETHOD( + [], HRESULT, "GetHelpContext", (["out"], POINTER(DWORD), "pdwHelpContext") + ), + ] + class ISupportErrorInfo(IUnknown): _iid_ = GUID("{DF0B3D60-548F-101B-8E65-08002B2BD119}") _methods_ = [ - COMMETHOD([], HRESULT, 'InterfaceSupportsErrorInfo', - (['in'], POINTER(GUID), 'riid')) - ] + COMMETHOD( + [], HRESULT, "InterfaceSupportsErrorInfo", (["in"], POINTER(GUID), "riid") + ) + ] + ################################################################ _oleaut32 = oledll.oleaut32 + def CreateErrorInfo(): cei = POINTER(ICreateErrorInfo)() _oleaut32.CreateErrorInfo(byref(cei)) return cei + def GetErrorInfo(): """Get the error information for the current thread.""" errinfo = POINTER(IErrorInfo)() @@ -63,12 +66,15 @@ def GetErrorInfo(): return errinfo return None + def SetErrorInfo(errinfo): """Set error information for the current thread.""" return _oleaut32.SetErrorInfo(0, errinfo) -def ReportError(text, iid, - clsid=None, helpfile=None, helpcontext=0, hresult=DISP_E_EXCEPTION): + +def ReportError( + text, iid, clsid=None, helpfile=None, helpcontext=0, hresult=DISP_E_EXCEPTION +): """Report a COM error. Returns the passed in hresult value.""" ei = CreateErrorInfo() ei.SetDescription(text) @@ -85,12 +91,16 @@ def ReportError(text, iid, except WindowsError: pass else: - ei.SetSource(progid) # progid for the class or application that created the error + ei.SetSource( + progid + ) # progid for the class or application that created the error _oleaut32.SetErrorInfo(0, ei) return hresult -def ReportException(hresult, iid, clsid=None, helpfile=None, helpcontext=None, - stacklevel=None): + +def ReportException( + hresult, iid, clsid=None, helpfile=None, helpcontext=None, stacklevel=None +): """Report a COM exception. Returns the passed in hresult value.""" typ, value, tb = sys.exc_info() if stacklevel is not None: @@ -101,12 +111,19 @@ def ReportException(hresult, iid, clsid=None, helpfile=None, helpcontext=None, text = "%s: %s (%s, line %d)" % (typ, value, name, line) else: text = "%s: %s" % (typ, value) - return ReportError(text, iid, - clsid=clsid, helpfile=helpfile, helpcontext=helpcontext, - hresult=hresult) + return ReportError( + text, + iid, + clsid=clsid, + helpfile=helpfile, + helpcontext=helpcontext, + hresult=hresult, + ) +# fmt: off __all__ = [ "ICreateErrorInfo", "IErrorInfo", "ISupportErrorInfo", "ReportError", "ReportException", "SetErrorInfo", "GetErrorInfo", "CreateErrorInfo", ] +# fmt: on diff --git a/comtypes/git.py b/comtypes/git.py index 703e49c1..ff7d63e9 100644 --- a/comtypes/git.py +++ b/comtypes/git.py @@ -4,20 +4,34 @@ between different threading appartments. """ from ctypes import * -from comtypes import IUnknown, STDMETHOD, COMMETHOD, \ - GUID, HRESULT, CoCreateInstance, CLSCTX_INPROC_SERVER +from comtypes import ( + IUnknown, + STDMETHOD, + COMMETHOD, + GUID, + HRESULT, + CoCreateInstance, + CLSCTX_INPROC_SERVER, +) DWORD = c_ulong + class IGlobalInterfaceTable(IUnknown): _iid_ = GUID("{00000146-0000-0000-C000-000000000046}") _methods_ = [ - STDMETHOD(HRESULT, "RegisterInterfaceInGlobal", - [POINTER(IUnknown), POINTER(GUID), POINTER(DWORD)]), + STDMETHOD( + HRESULT, + "RegisterInterfaceInGlobal", + [POINTER(IUnknown), POINTER(GUID), POINTER(DWORD)], + ), STDMETHOD(HRESULT, "RevokeInterfaceFromGlobal", [DWORD]), - STDMETHOD(HRESULT, "GetInterfaceFromGlobal", - [DWORD, POINTER(GUID), POINTER(POINTER(IUnknown))]), - ] + STDMETHOD( + HRESULT, + "GetInterfaceFromGlobal", + [DWORD, POINTER(GUID), POINTER(POINTER(IUnknown))], + ), + ] def RegisterInterfaceInGlobal(self, obj, interface=IUnknown): cookie = DWORD() @@ -38,24 +52,28 @@ def RevokeInterfaceFromGlobal(self, cookie): # with the debugger. Apparently it is in uuid.lib. CLSID_StdGlobalInterfaceTable = GUID("{00000323-0000-0000-C000-000000000046}") -git = CoCreateInstance(CLSID_StdGlobalInterfaceTable, - interface=IGlobalInterfaceTable, - clsctx=CLSCTX_INPROC_SERVER) +git = CoCreateInstance( + CLSID_StdGlobalInterfaceTable, + interface=IGlobalInterfaceTable, + clsctx=CLSCTX_INPROC_SERVER, +) RevokeInterfaceFromGlobal = git.RevokeInterfaceFromGlobal RegisterInterfaceInGlobal = git.RegisterInterfaceInGlobal GetInterfaceFromGlobal = git.GetInterfaceFromGlobal +# fmt: off __all__ = [ "RegisterInterfaceInGlobal", "RevokeInterfaceFromGlobal", "GetInterfaceFromGlobal", ] +# fmt: on if __name__ == "__main__": from comtypes.typeinfo import CreateTypeLib, ICreateTypeLib - tlib = CreateTypeLib("foo.bar") # we don not save it later + tlib = CreateTypeLib("foo.bar") # we don not save it later assert (tlib.AddRef(), tlib.Release()) == (2, 1) cookie = RegisterInterfaceInGlobal(tlib) diff --git a/comtypes/hints.pyi b/comtypes/hints.pyi index 40f3cfed..79af8b3e 100644 --- a/comtypes/hints.pyi +++ b/comtypes/hints.pyi @@ -1,6 +1,14 @@ from typing import ( - Any, Callable, Generic, NoReturn, Optional, overload, SupportsIndex, - Type, TypeVar, Union as _UnionT, + Any, + Callable, + Generic, + NoReturn, + Optional, + overload, + SupportsIndex, + Type, + TypeVar, + Union as _UnionT, ) # symbols those what might occur recursive imports in runtime. @@ -8,7 +16,6 @@ from comtypes.automation import IDispatch as IDispatch, VARIANT as VARIANT from comtypes.server import IClassFactory as IClassFactory from comtypes.typeinfo import ITypeInfo as ITypeInfo - def AnnoField() -> Any: """**THIS IS `TYPE_CHECKING` ONLY SYMBOL. diff --git a/comtypes/hresult.py b/comtypes/hresult.py index 85f75ceb..cb527910 100644 --- a/comtypes/hresult.py +++ b/comtypes/hresult.py @@ -6,69 +6,74 @@ S_OK = 0 S_FALSE = 1 -E_UNEXPECTED = -2147418113 #0x8000FFFFL +E_UNEXPECTED = -2147418113 # 0x8000FFFFL -E_NOTIMPL = -2147467263 #0x80004001L -E_NOINTERFACE = -2147467262 #0x80004002L -E_POINTER = -2147467261 #0x80004003L -E_FAIL = -2147467259 #0x80004005L -E_INVALIDARG = -2147024809 #0x80070057L -E_OUTOFMEMORY = -2147024882 # 0x8007000EL +E_NOTIMPL = -2147467263 # 0x80004001L +E_NOINTERFACE = -2147467262 # 0x80004002L +E_POINTER = -2147467261 # 0x80004003L +E_FAIL = -2147467259 # 0x80004005L +E_INVALIDARG = -2147024809 # 0x80070057L +E_OUTOFMEMORY = -2147024882 # 0x8007000EL -CLASS_E_NOAGGREGATION = -2147221232 #0x80040110L -CLASS_E_CLASSNOTAVAILABLE = -2147221231 #0x80040111L +CLASS_E_NOAGGREGATION = -2147221232 # 0x80040110L +CLASS_E_CLASSNOTAVAILABLE = -2147221231 # 0x80040111L -CO_E_CLASSSTRING = -2147221005 #0x800401F3L +CO_E_CLASSSTRING = -2147221005 # 0x800401F3L # connection point error codes CONNECT_E_CANNOTCONNECT = -2147220990 CONNECT_E_ADVISELIMIT = -2147220991 CONNECT_E_NOCONNECTION = -2147220992 -TYPE_E_ELEMENTNOTFOUND = -2147352077 #0x8002802BL +TYPE_E_ELEMENTNOTFOUND = -2147352077 # 0x8002802BL -TYPE_E_REGISTRYACCESS = -2147319780 #0x8002801CL -TYPE_E_CANTLOADLIBRARY = -2147312566 #0x80029C4AL +TYPE_E_REGISTRYACCESS = -2147319780 # 0x8002801CL +TYPE_E_CANTLOADLIBRARY = -2147312566 # 0x80029C4AL # all the DISP_E_ values from windows.h DISP_E_BUFFERTOOSMALL = -2147352557 DISP_E_DIVBYZERO = -2147352558 DISP_E_NOTACOLLECTION = -2147352559 DISP_E_BADCALLEE = -2147352560 -DISP_E_PARAMNOTOPTIONAL = -2147352561 #0x8002000F -DISP_E_BADPARAMCOUNT = -2147352562 #0x8002000E -DISP_E_ARRAYISLOCKED = -2147352563 #0x8002000D -DISP_E_UNKNOWNLCID = -2147352564 #0x8002000C -DISP_E_BADINDEX = -2147352565 #0x8002000B -DISP_E_OVERFLOW = -2147352566 #0x8002000A -DISP_E_EXCEPTION = -2147352567 #0x80020009 -DISP_E_BADVARTYPE = -2147352568 #0x80020008 -DISP_E_NONAMEDARGS = -2147352569 #0x80020007 -DISP_E_UNKNOWNNAME = -2147352570 #0x80020006 -DISP_E_TYPEMISMATCH = -2147352571 #0800020005 -DISP_E_PARAMNOTFOUND = -2147352572 #0x80020004 -DISP_E_MEMBERNOTFOUND = -2147352573 #0x80020003 -DISP_E_UNKNOWNINTERFACE = -2147352575 #0x80020001 - -RPC_E_CHANGED_MODE = -2147417850 # 0x80010106 -RPC_E_SERVERFAULT = -2147417851 # 0x80010105 +DISP_E_PARAMNOTOPTIONAL = -2147352561 # 0x8002000F +DISP_E_BADPARAMCOUNT = -2147352562 # 0x8002000E +DISP_E_ARRAYISLOCKED = -2147352563 # 0x8002000D +DISP_E_UNKNOWNLCID = -2147352564 # 0x8002000C +DISP_E_BADINDEX = -2147352565 # 0x8002000B +DISP_E_OVERFLOW = -2147352566 # 0x8002000A +DISP_E_EXCEPTION = -2147352567 # 0x80020009 +DISP_E_BADVARTYPE = -2147352568 # 0x80020008 +DISP_E_NONAMEDARGS = -2147352569 # 0x80020007 +DISP_E_UNKNOWNNAME = -2147352570 # 0x80020006 +DISP_E_TYPEMISMATCH = -2147352571 # 0800020005 +DISP_E_PARAMNOTFOUND = -2147352572 # 0x80020004 +DISP_E_MEMBERNOTFOUND = -2147352573 # 0x80020003 +DISP_E_UNKNOWNINTERFACE = -2147352575 # 0x80020001 + +RPC_E_CHANGED_MODE = -2147417850 # 0x80010106 +RPC_E_SERVERFAULT = -2147417851 # 0x80010105 # 'macros' and constants to create your own HRESULT values: + def MAKE_HRESULT(sev, fac, code): # A hresult is SIGNED in comtypes from ctypes import c_long + return c_long((sev << 31 | fac << 16 | code)).value + SEVERITY_ERROR = 1 SEVERITY_SUCCESS = 0 FACILITY_ITF = 4 FACILITY_WIN32 = 7 + def HRESULT_FROM_WIN32(x): # make signed from ctypes import c_long + x = c_long(x).value if x < 0: return x diff --git a/comtypes/logutil.py b/comtypes/logutil.py index 6d46e13e..7769b001 100644 --- a/comtypes/logutil.py +++ b/comtypes/logutil.py @@ -1,28 +1,37 @@ # logutil.py import logging, ctypes + class NTDebugHandler(logging.Handler): - def emit(self, record, - writeA=ctypes.windll.kernel32.OutputDebugStringA, - writeW=ctypes.windll.kernel32.OutputDebugStringW): + def emit( + self, + record, + writeA=ctypes.windll.kernel32.OutputDebugStringA, + writeW=ctypes.windll.kernel32.OutputDebugStringW, + ): text = self.format(record) if isinstance(text, str): writeA(text + "\n") else: - writeW(text + u"\n") + writeW(text + "\n") + + logging.NTDebugHandler = NTDebugHandler + def setup_logging(*pathnames): import configparser parser = configparser.ConfigParser() - parser.optionxform = str # use case sensitive option names! + parser.optionxform = str # use case sensitive option names! parser.read(pathnames) - DEFAULTS = {"handler": "StreamHandler()", - "format": "%(levelname)s:%(name)s:%(message)s", - "level": "WARNING"} + DEFAULTS = { + "handler": "StreamHandler()", + "format": "%(levelname)s:%(name)s:%(message)s", + "level": "WARNING", + } def get(section, option): try: diff --git a/comtypes/messageloop.py b/comtypes/messageloop.py index 9defb66a..e08a16b4 100644 --- a/comtypes/messageloop.py +++ b/comtypes/messageloop.py @@ -1,6 +1,7 @@ import ctypes from ctypes import WinDLL, byref, WinError from ctypes.wintypes import MSG + _user32 = WinDLL("user32") GetMessage = _user32.GetMessageA @@ -15,7 +16,6 @@ class _MessageLoop(object): - def __init__(self): self._filters = [] @@ -33,7 +33,7 @@ def run(self): if ret == -1: raise WinError() elif ret == 0: - return # got WM_QUIT + return # got WM_QUIT if not self.filter_message(lpmsg): TranslateMessage(lpmsg) DispatchMessage(lpmsg) @@ -41,6 +41,7 @@ def run(self): def filter_message(self, lpmsg): return any(list(filter(lpmsg)) for filter in self._filters) + _messageloop = _MessageLoop() run = _messageloop.run diff --git a/comtypes/patcher.py b/comtypes/patcher.py index 67b02d90..5e5bf488 100644 --- a/comtypes/patcher.py +++ b/comtypes/patcher.py @@ -1,4 +1,3 @@ - class Patch(object): """ Implements a class decorator suitable for patching an existing class with @@ -55,11 +54,12 @@ def __call__(self, patches): for name, value in vars(patches).items(): if name in vars(ReferenceEmptyClass): continue - no_replace = getattr(value, '__no_replace', False) + no_replace = getattr(value, "__no_replace", False) if no_replace and hasattr(self.target, name): continue setattr(self.target, name, value) + def no_replace(f): """ Method decorator to indicate that a method definition shall @@ -68,6 +68,7 @@ def no_replace(f): f.__no_replace = True return f + class ReferenceEmptyClass(object): """ This empty class will serve as a reference for attributes present on diff --git a/comtypes/persist.py b/comtypes/persist.py index e1c8e028..ca6f0d55 100644 --- a/comtypes/persist.py +++ b/comtypes/persist.py @@ -18,47 +18,69 @@ # XXX Replace by canonical solution!!! WSTRING = c_wchar_p + class IErrorLog(IUnknown): - _iid_ = GUID('{3127CA40-446E-11CE-8135-00AA004BB851}') + _iid_ = GUID("{3127CA40-446E-11CE-8135-00AA004BB851}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'AddError', - ( ['in'], WSTRING, 'pszPropName' ), - ( ['in'], POINTER(tagEXCEPINFO), 'pExcepInfo' )), - ] + COMMETHOD( + [], + HRESULT, + "AddError", + (["in"], WSTRING, "pszPropName"), + (["in"], POINTER(tagEXCEPINFO), "pExcepInfo"), + ), + ] + class IPropertyBag(IUnknown): - _iid_ = GUID('{55272A00-42CB-11CE-8135-00AA004BB851}') + _iid_ = GUID("{55272A00-42CB-11CE-8135-00AA004BB851}") _idlflags_ = [] _methods_ = [ # XXX Note: According to MSDN, pVar and pErrorLog are ['in', 'out'] parameters. # # XXX ctypes does NOT yet accept POINTER(IErrorLog) as 'out' parameter: # TypeError: 'out' parameter 3 must be a pointer type, not POINTER(IErrorLog) - COMMETHOD([], HRESULT, 'Read', - ( ['in'], WSTRING, 'pszPropName' ), - ( ['in', 'out'], POINTER(VARIANT), 'pVar' ), - ( ['in'], POINTER(IErrorLog), 'pErrorLog' ), - # ( ['in', 'out'], POINTER(IErrorLog), 'pErrorLog' ), - ), - COMMETHOD([], HRESULT, 'Write', - ( ['in'], WSTRING, 'pszPropName' ), - ( ['in'], POINTER(VARIANT), 'pVar' )), - ] + COMMETHOD( + [], + HRESULT, + "Read", + (["in"], WSTRING, "pszPropName"), + (["in", "out"], POINTER(VARIANT), "pVar"), + (["in"], POINTER(IErrorLog), "pErrorLog"), + # ( ['in', 'out'], POINTER(IErrorLog), 'pErrorLog' ), + ), + COMMETHOD( + [], + HRESULT, + "Write", + (["in"], WSTRING, "pszPropName"), + (["in"], POINTER(VARIANT), "pVar"), + ), + ] + class IPersistPropertyBag(IPersist): - _iid_ = GUID('{37D84F60-42CB-11CE-8135-00AA004BB851}') + _iid_ = GUID("{37D84F60-42CB-11CE-8135-00AA004BB851}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'InitNew'), - COMMETHOD([], HRESULT, 'Load', - ( ['in'], POINTER(IPropertyBag), 'pPropBag' ), - ( ['in'], POINTER(IErrorLog), 'pErrorLog' )), - COMMETHOD([], HRESULT, 'Save', - ( ['in'], POINTER(IPropertyBag), 'pPropBag' ), - ( ['in'], c_int, 'fClearDirty' ), - ( ['in'], c_int, 'fSaveAllProperties' )), - ] + COMMETHOD([], HRESULT, "InitNew"), + COMMETHOD( + [], + HRESULT, + "Load", + (["in"], POINTER(IPropertyBag), "pPropBag"), + (["in"], POINTER(IErrorLog), "pErrorLog"), + ), + COMMETHOD( + [], + HRESULT, + "Save", + (["in"], POINTER(IPropertyBag), "pPropBag"), + (["in"], c_int, "fClearDirty"), + (["in"], c_int, "fSaveAllProperties"), + ), + ] CLIPFORMAT = WORD @@ -71,58 +93,86 @@ class IPersistPropertyBag(IPersist): PROPBAG2_TYPE_STORAGE = 5 PROPBAG2_TYPE_MONIKER = 6 + class tagPROPBAG2(Structure): _fields_ = [ - ('dwType', c_ulong), - ('vt', c_ushort), - ('cfType', CLIPFORMAT), - ('dwHint', c_ulong), - ('pstrName', WSTRING), - ('clsid', GUID), - ] + ("dwType", c_ulong), + ("vt", c_ushort), + ("cfType", CLIPFORMAT), + ("dwHint", c_ulong), + ("pstrName", WSTRING), + ("clsid", GUID), + ] + class IPropertyBag2(IUnknown): - _iid_ = GUID('{22F55882-280B-11D0-A8A9-00A0C90C2004}') + _iid_ = GUID("{22F55882-280B-11D0-A8A9-00A0C90C2004}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'Read', - ( ['in'], c_ulong, 'cProperties' ), - ( ['in'], POINTER(tagPROPBAG2), 'pPropBag' ), - ( ['in'], POINTER(IErrorLog), 'pErrLog' ), - ( ['out'], POINTER(VARIANT), 'pvarValue' ), - ( ['out'], POINTER(HRESULT), 'phrError' )), - COMMETHOD([], HRESULT, 'Write', - ( ['in'], c_ulong, 'cProperties' ), - ( ['in'], POINTER(tagPROPBAG2), 'pPropBag' ), - ( ['in'], POINTER(VARIANT), 'pvarValue' )), - COMMETHOD([], HRESULT, 'CountProperties', - ( ['out'], POINTER(c_ulong), 'pcProperties' )), - COMMETHOD([], HRESULT, 'GetPropertyInfo', - ( ['in'], c_ulong, 'iProperty' ), - ( ['in'], c_ulong, 'cProperties' ), - ( ['out'], POINTER(tagPROPBAG2), 'pPropBag' ), - ( ['out'], POINTER(c_ulong), 'pcProperties' )), - COMMETHOD([], HRESULT, 'LoadObject', - ( ['in'], WSTRING, 'pstrName' ), - ( ['in'], c_ulong, 'dwHint' ), - ( ['in'], POINTER(IUnknown), 'punkObject' ), - ( ['in'], POINTER(IErrorLog), 'pErrLog' )), - ] + COMMETHOD( + [], + HRESULT, + "Read", + (["in"], c_ulong, "cProperties"), + (["in"], POINTER(tagPROPBAG2), "pPropBag"), + (["in"], POINTER(IErrorLog), "pErrLog"), + (["out"], POINTER(VARIANT), "pvarValue"), + (["out"], POINTER(HRESULT), "phrError"), + ), + COMMETHOD( + [], + HRESULT, + "Write", + (["in"], c_ulong, "cProperties"), + (["in"], POINTER(tagPROPBAG2), "pPropBag"), + (["in"], POINTER(VARIANT), "pvarValue"), + ), + COMMETHOD( + [], HRESULT, "CountProperties", (["out"], POINTER(c_ulong), "pcProperties") + ), + COMMETHOD( + [], + HRESULT, + "GetPropertyInfo", + (["in"], c_ulong, "iProperty"), + (["in"], c_ulong, "cProperties"), + (["out"], POINTER(tagPROPBAG2), "pPropBag"), + (["out"], POINTER(c_ulong), "pcProperties"), + ), + COMMETHOD( + [], + HRESULT, + "LoadObject", + (["in"], WSTRING, "pstrName"), + (["in"], c_ulong, "dwHint"), + (["in"], POINTER(IUnknown), "punkObject"), + (["in"], POINTER(IErrorLog), "pErrLog"), + ), + ] + class IPersistPropertyBag2(IPersist): - _iid_ = GUID('{22F55881-280B-11D0-A8A9-00A0C90C2004}') + _iid_ = GUID("{22F55881-280B-11D0-A8A9-00A0C90C2004}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'InitNew'), - COMMETHOD([], HRESULT, 'Load', - ( ['in'], POINTER(IPropertyBag2), 'pPropBag' ), - ( ['in'], POINTER(IErrorLog), 'pErrLog' )), - COMMETHOD([], HRESULT, 'Save', - ( ['in'], POINTER(IPropertyBag2), 'pPropBag' ), - ( ['in'], c_int, 'fClearDirty' ), - ( ['in'], c_int, 'fSaveAllProperties' )), - COMMETHOD([], HRESULT, 'IsDirty'), - ] + COMMETHOD([], HRESULT, "InitNew"), + COMMETHOD( + [], + HRESULT, + "Load", + (["in"], POINTER(IPropertyBag2), "pPropBag"), + (["in"], POINTER(IErrorLog), "pErrLog"), + ), + COMMETHOD( + [], + HRESULT, + "Save", + (["in"], POINTER(IPropertyBag2), "pPropBag"), + (["in"], c_int, "fClearDirty"), + (["in"], c_int, "fSaveAllProperties"), + ), + COMMETHOD([], HRESULT, "IsDirty"), + ] # STGM constants @@ -160,26 +210,37 @@ class IPersistPropertyBag2(IPersist): LPOLESTR = LPCOLESTR = c_wchar_p + class IPersistFile(IPersist): - _iid_ = GUID('{0000010B-0000-0000-C000-000000000046}') + _iid_ = GUID("{0000010B-0000-0000-C000-000000000046}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'IsDirty'), - COMMETHOD([], HRESULT, 'Load', - ( ['in'], LPCOLESTR, 'pszFileName' ), - ( ['in'], DWORD, 'dwMode' )), - COMMETHOD([], HRESULT, 'Save', - ( ['in'], LPCOLESTR, 'pszFileName' ), - ( ['in'], BOOL, 'fRemember' )), - COMMETHOD([], HRESULT, 'SaveCompleted', - ( ['in'], LPCOLESTR, 'pszFileName' )), - COMMETHOD([], HRESULT, 'GetCurFile', - ( ['out'], POINTER(LPOLESTR), 'ppszFileName' )) - ] + COMMETHOD([], HRESULT, "IsDirty"), + COMMETHOD( + [], + HRESULT, + "Load", + (["in"], LPCOLESTR, "pszFileName"), + (["in"], DWORD, "dwMode"), + ), + COMMETHOD( + [], + HRESULT, + "Save", + (["in"], LPCOLESTR, "pszFileName"), + (["in"], BOOL, "fRemember"), + ), + COMMETHOD([], HRESULT, "SaveCompleted", (["in"], LPCOLESTR, "pszFileName")), + COMMETHOD( + [], HRESULT, "GetCurFile", (["out"], POINTER(LPOLESTR), "ppszFileName") + ), + ] from comtypes import COMObject from comtypes.hresult import * + + class DictPropertyBag(COMObject): """An object implementing the IProperty interface on a dictionary. @@ -187,6 +248,7 @@ class DictPropertyBag(COMObject): retrieve from the .values instance variable after the client has called Load(). """ + _com_interfaces_ = [IPropertyBag] def __init__(self, **kw): @@ -213,6 +275,7 @@ def Write(self, this, name, var): return S_OK +# fmt: off __known_symbols__ = [ "CLIPFORMAT", "DictPropertyBag", "IErrorLog", "IPersistFile", "IPersistPropertyBag", "IPersistPropertyBag2", "IPropertyBag", @@ -225,3 +288,4 @@ def Write(self, this, name, var): "STGM_SHARE_DENY_NONE", "STGM_SHARE_DENY_READ", "STGM_SHARE_DENY_WRITE", "STGM_SHARE_EXCLUSIVE", "STGM_SIMPLE", "STGM_TRANSACTED", "STGM_WRITE", ] +# fmt: on diff --git a/comtypes/safearray.py b/comtypes/safearray.py index 9aae20cf..3e6582d5 100644 --- a/comtypes/safearray.py +++ b/comtypes/safearray.py @@ -1,8 +1,7 @@ import threading import array import comtypes -from ctypes import (POINTER, Structure, byref, cast, c_long, memmove, pointer, - sizeof) +from ctypes import POINTER, Structure, byref, cast, c_long, memmove, pointer, sizeof from comtypes import _safearray, IUnknown, com_interface_registry from comtypes.patcher import Patch @@ -10,7 +9,7 @@ class _SafeArrayAsNdArrayContextManager(object): - '''Context manager allowing safe arrays to be extracted as ndarrays. + """Context manager allowing safe arrays to be extracted as ndarrays. This is thread-safe. @@ -23,7 +22,8 @@ class _SafeArrayAsNdArrayContextManager(object): >>> type(my_arr) numpy.ndarray - ''' + """ + thread_local = threading.local() def __enter__(self): @@ -37,12 +37,10 @@ def __exit__(self, exc_type, exc_value, traceback): self.thread_local.count -= 1 def __bool__(self): - '''True if context manager is currently entered on given thread. + """True if context manager is currently entered on given thread.""" + return bool(getattr(self.thread_local, "count", 0)) - ''' - return bool(getattr(self.thread_local, 'count', 0)) - - __nonzero__ = __bool__ # for Py2.7 compatibility + __nonzero__ = __bool__ # for Py2.7 compatibility # Global _SafeArrayAsNdArrayContextManager @@ -67,13 +65,18 @@ def _midlSAFEARRAY(itemtype): def _make_safearray_type(itemtype): # Create and return a subclass of tagSAFEARRAY - from comtypes.automation import _ctype_to_vartype, VT_RECORD, \ - VT_UNKNOWN, IDispatch, VT_DISPATCH + from comtypes.automation import ( + _ctype_to_vartype, + VT_RECORD, + VT_UNKNOWN, + IDispatch, + VT_DISPATCH, + ) meta = type(_safearray.tagSAFEARRAY) - sa_type = meta.__new__(meta, - "SAFEARRAY_%s" % itemtype.__name__, - (_safearray.tagSAFEARRAY,), {}) + sa_type = meta.__new__( + meta, "SAFEARRAY_%s" % itemtype.__name__, (_safearray.tagSAFEARRAY,), {} + ) try: vartype = _ctype_to_vartype[itemtype] @@ -86,6 +89,7 @@ def _make_safearray_type(itemtype): extra = None else: from comtypes.typeinfo import GetRecordInfoFromGuids + extra = GetRecordInfoFromGuids(*guids) vartype = VT_RECORD elif issubclass(itemtype, POINTER(IDispatch)): @@ -125,13 +129,12 @@ def create(cls, value, extra=None): # XXX How to specify the lbound (3. parameter to CreateVectorEx)? # XXX How to write tests for lbound != 0? - pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_, - 0, - len(value), - extra) + pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_, 0, len(value), extra) if not pa: if cls._vartype_ == VT_RECORD and extra is None: - raise TypeError("Cannot create SAFEARRAY type VT_RECORD without IRecordInfo.") + raise TypeError( + "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo." + ) # Hm, there may be other reasons why the creation fails... raise MemoryError() # We now have a POINTER(tagSAFEARRAY) instance which we must cast @@ -155,6 +158,7 @@ def create(cls, value, extra=None): @classmethod def create_from_ndarray(cls, value, extra, lBound=0): from comtypes.automation import VARIANT + # If processing VARIANT, makes sure the array type is correct. if cls._itemtype_ is VARIANT: if value.dtype != comtypes.npsupport.VARIANT_dtype: @@ -181,13 +185,14 @@ def create_from_ndarray(cls, value, extra, lBound=0): nitems *= d rgsa[i].cElements = d rgsa[i].lBound = lBound - pa = _safearray.SafeArrayCreateEx(cls._vartype_, - value.ndim, # cDims - rgsa, # rgsaBound - extra) # pvExtra + pa = _safearray.SafeArrayCreateEx( + cls._vartype_, value.ndim, rgsa, extra # cDims # rgsaBound + ) # pvExtra if not pa: if cls._vartype_ == VT_RECORD and extra is None: - raise TypeError("Cannot create SAFEARRAY type VT_RECORD without IRecordInfo.") + raise TypeError( + "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo." + ) # Hm, there may be other reasons why the creation fails... raise MemoryError() # We now have a POINTER(tagSAFEARRAY) instance which we must cast @@ -257,15 +262,19 @@ def unpack(self): # this must be reshaped and transposed because it is # flat, and in VB order if safearray_as_ndarray: - return comtypes.npsupport.numpy.asarray(result).reshape((cols, rows)).T + return ( + comtypes.npsupport.numpy.asarray(result).reshape((cols, rows)).T + ) result = [tuple(result[r::rows]) for r in range(rows)] return tuple(result) else: - lowerbounds = [_safearray.SafeArrayGetLBound(self, d) - for d in range(1, dim+1)] + lowerbounds = [ + _safearray.SafeArrayGetLBound(self, d) for d in range(1, dim + 1) + ] indexes = (c_long * dim)(*lowerbounds) - upperbounds = [_safearray.SafeArrayGetUBound(self, d) - for d in range(1, dim+1)] + upperbounds = [ + _safearray.SafeArrayGetUBound(self, d) for d in range(1, dim + 1) + ] row = self._get_row(0, indexes, lowerbounds, upperbounds) if safearray_as_ndarray: return comtypes.npsupport.numpy.asarray(row) @@ -275,6 +284,7 @@ def _get_elements_raw(self, num_elements): """Returns a flat list or ndarray containing ALL elements in the safearray.""" from comtypes.automation import VARIANT + # XXX Not sure this is true: # For VT_UNKNOWN and VT_DISPATCH, we should retrieve the # interface iid by SafeArrayGetIID(). @@ -311,16 +321,19 @@ def _get_elements_raw(self, num_elements): # we can get the most speed-up. # XXX Only try to convert types known to # numpy.ctypeslib. - if (safearray_as_ndarray and self._itemtype_ in - list(comtypes.npsupport.typecodes.keys())): - arr = comtypes.npsupport.numpy.ctypeslib.as_array(ptr, - (num_elements,)) + if safearray_as_ndarray and self._itemtype_ in list( + comtypes.npsupport.typecodes.keys() + ): + arr = comtypes.npsupport.numpy.ctypeslib.as_array( + ptr, (num_elements,) + ) return arr.copy() return ptr[:num_elements] def keep_safearray(v): v.__keepref = self return v + return [keep_safearray(x) for x in ptr[:num_elements]] finally: _safearray.SafeArrayUnaccessData(self) @@ -333,23 +346,24 @@ def _get_row(self, dim, indices, lowerbounds, upperbounds): result = [] obj = self._itemtype_() pobj = byref(obj) - if dim+1 == len(indices): + if dim + 1 == len(indices): # It should be faster to lock the array and get a whole row at once? # How to calculate the pointer offset? - for i in range(indices[dim], upperbounds[dim]+1): + for i in range(indices[dim], upperbounds[dim] + 1): indices[dim] = i _safearray.SafeArrayGetElement(self, indices, pobj) result.append(obj.value) else: - for i in range(indices[dim], upperbounds[dim]+1): + for i in range(indices[dim], upperbounds[dim] + 1): indices[dim] = i - result.append(self._get_row(dim+1, indices, lowerbounds, upperbounds)) + result.append( + self._get_row(dim + 1, indices, lowerbounds, upperbounds) + ) indices[dim] = restore - return tuple(result) # for compatibility with pywin32. + return tuple(result) # for compatibility with pywin32. @Patch(POINTER(POINTER(sa_type))) class __(object): - @classmethod def from_param(cls, value): if isinstance(value, cls._type_): @@ -367,7 +381,7 @@ def __setitem__(self, index, value): def _ndarray_to_variant_array(value): - """ Convert an ndarray to VARIANT_dtype array """ + """Convert an ndarray to VARIANT_dtype array""" # Check that variant arrays are supported if comtypes.npsupport.interop.VARIANT_dtype is None: msg = "VARIANT ndarrays require NumPy 1.7 or newer." @@ -379,27 +393,27 @@ def _ndarray_to_variant_array(value): return _datetime64_ndarray_to_variant_array(value) from comtypes.automation import VARIANT + # Empty array - varr = numpy.zeros( - value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F' - ) + varr = numpy.zeros(value.shape, comtypes.npsupport.interop.VARIANT_dtype, order="F") # Convert each value to a variant and put it in the array. varr.flat = [VARIANT(v) for v in value.flat] return varr def _datetime64_ndarray_to_variant_array(value): - """ Convert an ndarray of datetime64 to VARIANT_dtype array """ + """Convert an ndarray of datetime64 to VARIANT_dtype array""" # The OLE automation date format is a floating point value, counting days # since midnight 30 December 1899. Hours and minutes are represented as # fractional days. from comtypes.automation import VT_DATE + numpy = comtypes.npsupport.interop.numpy value = numpy.array(value, "datetime64[ns]") value = value - comtypes.npsupport.interop.com_null_date64 # Convert to days - value = value / numpy.timedelta64(1, 'D') - varr = numpy.zeros(value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F') - varr['vt'] = VT_DATE - varr['_']['VT_R8'].flat = value.flat + value = value / numpy.timedelta64(1, "D") + varr = numpy.zeros(value.shape, comtypes.npsupport.interop.VARIANT_dtype, order="F") + varr["vt"] = VT_DATE + varr["_"]["VT_R8"].flat = value.flat return varr diff --git a/comtypes/server/__init__.py b/comtypes/server/__init__.py index 162b8b85..ad7577e6 100644 --- a/comtypes/server/__init__.py +++ b/comtypes/server/__init__.py @@ -5,12 +5,17 @@ class IClassFactory(comtypes.IUnknown): _iid_ = comtypes.GUID("{00000001-0000-0000-C000-000000000046}") _methods_ = [ - comtypes.STDMETHOD(comtypes.HRESULT, "CreateInstance", - [ctypes.POINTER(comtypes.IUnknown), - ctypes.POINTER(comtypes.GUID), - ctypes.POINTER(ctypes.c_void_p)]), - comtypes.STDMETHOD(comtypes.HRESULT, "LockServer", - [ctypes.c_int])] + comtypes.STDMETHOD( + comtypes.HRESULT, + "CreateInstance", + [ + ctypes.POINTER(comtypes.IUnknown), + ctypes.POINTER(comtypes.GUID), + ctypes.POINTER(ctypes.c_void_p), + ], + ), + comtypes.STDMETHOD(comtypes.HRESULT, "LockServer", [ctypes.c_int]), + ] def CreateInstance(self, punkouter=None, interface=None, dynamic=False): if dynamic: @@ -31,6 +36,7 @@ def CreateInstance(self, punkouter=None, interface=None, dynamic=False): # An interface was specified and obj is already that interface. return obj + # class IExternalConnection(IUnknown): # _iid_ = GUID("{00000019-0000-0000-C000-000000000046}") # _methods_ = [ @@ -40,10 +46,11 @@ def CreateInstance(self, punkouter=None, interface=None, dynamic=False): # The following code is untested: ACTIVEOBJECT_STRONG = 0x0 -ACTIVEOBJECT_WEAK = 0x1 +ACTIVEOBJECT_WEAK = 0x1 oleaut32 = ctypes.oledll.oleaut32 + def RegisterActiveObject(comobj, weak=True): punk = comobj._com_pointers_[comtypes.IUnknown._iid_] clsid = comobj._reg_clsid_ @@ -52,11 +59,11 @@ def RegisterActiveObject(comobj, weak=True): else: flags = ACTIVEOBJECT_STRONG handle = ctypes.c_ulong() - oleaut32.RegisterActiveObject(punk, - ctypes.byref(clsid), - flags, - ctypes.byref(handle)) + oleaut32.RegisterActiveObject( + punk, ctypes.byref(clsid), flags, ctypes.byref(handle) + ) return handle.value + def RevokeActiveObject(handle): oleaut32.RevokeActiveObject(handle, None) diff --git a/comtypes/server/automation.py b/comtypes/server/automation.py index 37d13f14..e38c73a2 100644 --- a/comtypes/server/automation.py +++ b/comtypes/server/automation.py @@ -15,16 +15,21 @@ class VARIANTEnumerator(COMObject): """A universal VARIANTEnumerator class. Instantiate it with a collection of items that support the IDispatch interface.""" + _com_interfaces_ = [IEnumVARIANT] def __init__(self, items): - self.items = items # keep, so that we can restore our iterator (in Reset, and Clone). + self.items = ( + items # keep, so that we can restore our iterator (in Reset, and Clone). + ) self.seq = iter(self.items) super(VARIANTEnumerator, self).__init__() def Next(self, this, celt, rgVar, pCeltFetched): - if not rgVar: return E_POINTER - if not pCeltFetched: pCeltFetched = [None] + if not rgVar: + return E_POINTER + if not pCeltFetched: + pCeltFetched = [None] pCeltFetched[0] = 0 try: for index in range(celt): @@ -58,13 +63,16 @@ def Reset(self, this): # Clone not implemented + ################################################################ # XXX Shouldn't this be a mixin class? # And isn't this class borked anyway? + class COMCollection(COMObject): """Abstract base class which implements Count, Item, and _NewEnum.""" + def __init__(self, itemtype, collection): self.collection = collection self.itemtype = itemtype @@ -74,9 +82,7 @@ def _get_Item(self, this, pathname, pitem): if not pitem: return E_POINTER item = self.itemtype(pathname) - return item.IUnknown_QueryInterface(None, - pointer(pitem[0]._iid_), - pitem) + return item.IUnknown_QueryInterface(None, pointer(pitem[0]._iid_), pitem) def _get_Count(self, this, pcount): if not pcount: @@ -88,6 +94,4 @@ def _get__NewEnum(self, this, penum): if not penum: return E_POINTER enum = VARIANTEnumerator(self.itemtype, self.collection) - return enum.IUnknown_QueryInterface(None, - pointer(IUnknown._iid_), - penum) + return enum.IUnknown_QueryInterface(None, pointer(IUnknown._iid_), penum) diff --git a/comtypes/server/connectionpoints.py b/comtypes/server/connectionpoints.py index a8f99098..004672e8 100644 --- a/comtypes/server/connectionpoints.py +++ b/comtypes/server/connectionpoints.py @@ -6,6 +6,7 @@ from comtypes.automation import IDispatch import logging + logger = logging.getLogger(__name__) __all__ = ["ConnectableObjectMixin"] @@ -13,6 +14,7 @@ class ConnectionPointImpl(COMObject): """This object implements a connectionpoint""" + _com_interfaces_ = [IConnectionPoint] def __init__(self, sink_interface, sink_typeinfo): @@ -64,16 +66,27 @@ def _call_sinks(self, name, *args, **kw): result = p.Invoke(dispid, *args, **kw) except COMError as details: if details.hresult == -2147023174: - logger.warning("_call_sinks(%s, %s, *%s, **%s) failed; removing connection", - self, name, args, kw, - exc_info=True) + logger.warning( + "_call_sinks(%s, %s, *%s, **%s) failed; removing connection", + self, + name, + args, + kw, + exc_info=True, + ) try: del self._connections[key] except KeyError: - pass # connection already gone + pass # connection already gone else: - logger.warning("_call_sinks(%s, %s, *%s, **%s)", self, name, args, kw, - exc_info=True) + logger.warning( + "_call_sinks(%s, %s, *%s, **%s)", + self, + name, + args, + kw, + exc_info=True, + ) else: results.append(result) else: @@ -82,17 +95,29 @@ def _call_sinks(self, name, *args, **kw): result = getattr(p, name)(*args, **kw) except COMError as details: if details.hresult == -2147023174: - logger.warning("_call_sinks(%s, %s, *%s, **%s) failed; removing connection", - self, name, args, kw, - exc_info=True) + logger.warning( + "_call_sinks(%s, %s, *%s, **%s) failed; removing connection", + self, + name, + args, + kw, + exc_info=True, + ) del self._connections[key] else: - logger.warning("_call_sinks(%s, %s, *%s, **%s)", self, name, args, kw, - exc_info=True) + logger.warning( + "_call_sinks(%s, %s, *%s, **%s)", + self, + name, + args, + kw, + exc_info=True, + ) else: results.append(result) return results + class ConnectableObjectMixin(object): """Mixin which implements IConnectionPointContainer. @@ -100,6 +125,7 @@ class ConnectableObjectMixin(object): event. can either be the source interface, or an integer index into the _outgoing_interfaces_ list. """ + def __init__(self): super(ConnectableObjectMixin, self).__init__() self.__connections = {} @@ -127,7 +153,9 @@ def IConnectionPointContainer_FindConnectionPoint(self, this, refiid, ppcp): # no C layer between which will convert the second parameter # from byref() to pointer(). conn = self.__connections[itf] - result = conn.IUnknown_QueryInterface(None, pointer(IConnectionPoint._iid_), ppcp) + result = conn.IUnknown_QueryInterface( + None, pointer(IConnectionPoint._iid_), ppcp + ) logger.debug("connectionpoint found, QI() -> %s", result) return result logger.debug("No connectionpoint found") @@ -141,4 +169,3 @@ def Fire_Event(self, itf, name, *args, **kw): if isinstance(itf, int): itf = self._outgoing_interfaces_[itf] return self.__connections[itf]._call_sinks(name, *args, **kw) - diff --git a/comtypes/server/inprocserver.py b/comtypes/server/inprocserver.py index 3ef8a805..38e4a199 100644 --- a/comtypes/server/inprocserver.py +++ b/comtypes/server/inprocserver.py @@ -5,6 +5,7 @@ import sys import logging + if sys.version_info >= (3, 0): import winreg else: @@ -16,6 +17,7 @@ ################################################################ + class ClassFactory(COMObject): _com_interfaces_ = [IClassFactory] @@ -36,9 +38,11 @@ def IClassFactory_LockServer(self, this, fLock): COMObject.__server__.Unlock() return S_OK + # will be set by py2exe boot script 'from outside' _clsid_to_class = {} + def inproc_find_class(clsid): if _clsid_to_class: return _clsid_to_class[clsid] @@ -65,8 +69,10 @@ def inproc_find_class(clsid): _debug("Found class %s", result) return result + _logging_configured = False + def _setup_logging(clsid): """Read from the registry, and configure the logging module. @@ -82,6 +88,7 @@ def _setup_logging(clsid): except WindowsError: return from comtypes.logutil import NTDebugHandler + handler = NTDebugHandler() try: val, typ = winreg.QueryValueEx(hkey, "format") @@ -104,6 +111,7 @@ def _setup_logging(clsid): level = getattr(logging, level) logging.getLogger(name).setLevel(level) + def DllGetClassObject(rclsid, riid, ppv): COMObject.__run_inprocserver__() @@ -124,13 +132,16 @@ def DllGetClassObject(rclsid, riid, ppv): if not cls: return CLASS_E_CLASSNOTAVAILABLE - result = ClassFactory(cls).IUnknown_QueryInterface(None, ctypes.pointer(iid), ctypes.c_void_p(ppv)) + result = ClassFactory(cls).IUnknown_QueryInterface( + None, ctypes.pointer(iid), ctypes.c_void_p(ppv) + ) _debug("DllGetClassObject() -> %s", result) return result except Exception: _critical("DllGetClassObject", exc_info=True) return E_FAIL + def DllCanUnloadNow(): COMObject.__run_inprocserver__() result = COMObject.__server__.DllCanUnloadNow() diff --git a/comtypes/server/localserver.py b/comtypes/server/localserver.py index f0b61d98..15e4b78b 100644 --- a/comtypes/server/localserver.py +++ b/comtypes/server/localserver.py @@ -4,6 +4,7 @@ from comtypes.hresult import * from comtypes.server import IClassFactory import logging + if sys.version_info >= (3, 0): import queue else: @@ -12,16 +13,18 @@ logger = logging.getLogger(__name__) _debug = logger.debug -REGCLS_SINGLEUSE = 0 # class object only generates one instance -REGCLS_MULTIPLEUSE = 1 # same class object genereates multiple inst. +REGCLS_SINGLEUSE = 0 # class object only generates one instance +REGCLS_MULTIPLEUSE = 1 # same class object genereates multiple inst. REGCLS_MULTI_SEPARATE = 2 # multiple use, but separate control over each -REGCLS_SUSPENDED = 4 # register it as suspended, will be activated -REGCLS_SURROGATE = 8 # must be used when a surrogate process +REGCLS_SUSPENDED = 4 # register it as suspended, will be activated +REGCLS_SURROGATE = 8 # must be used when a surrogate process + def run(classes): classobjects = [ClassFactory(cls) for cls in classes] comtypes.COMObject.__run_localserver__(classobjects) + class ClassFactory(comtypes.COMObject): _com_interfaces_ = [IClassFactory] _locks = 0 @@ -46,12 +49,14 @@ def _register_class(self): cookie = c_ulong() ptr = self._com_pointers_[comtypes.IUnknown._iid_] clsctx = self._cls._reg_clsctx_ - clsctx &= ~comtypes.CLSCTX_INPROC # reset the inproc flags - oledll.ole32.CoRegisterClassObject(byref(comtypes.GUID(self._cls._reg_clsid_)), - ptr, - clsctx, - regcls, - byref(cookie)) + clsctx &= ~comtypes.CLSCTX_INPROC # reset the inproc flags + oledll.ole32.CoRegisterClassObject( + byref(comtypes.GUID(self._cls._reg_clsid_)), + ptr, + clsctx, + regcls, + byref(cookie), + ) self.cookie = cookie def _revoke_class(self): diff --git a/comtypes/server/register.py b/comtypes/server/register.py index 1e162eed..0fb7ce43 100644 --- a/comtypes/server/register.py +++ b/comtypes/server/register.py @@ -36,6 +36,7 @@ python mycomobj.py /nodebug """ import sys, os + if sys.version_info >= (3, 0): import winreg else: @@ -51,16 +52,20 @@ _debug = logging.getLogger(__name__).debug + def get_winerror(exception): try: return exception.winerror except AttributeError: return exception.errno + # a SHDeleteKey function, will remove a registry key with all subkeys. def _non_zero(retval, func, args): if retval: raise WinError(retval) + + SHDeleteKey = windll.shlwapi.SHDeleteKeyW SHDeleteKey.errcheck = _non_zero SHDeleteKey.argtypes = c_ulong, c_wchar_p @@ -68,13 +73,17 @@ def _non_zero(retval, func, args): Set = set -_KEYS = {winreg.HKEY_CLASSES_ROOT: "HKCR", - winreg.HKEY_LOCAL_MACHINE: "HKLM", - winreg.HKEY_CURRENT_USER: "HKCU"} +_KEYS = { + winreg.HKEY_CLASSES_ROOT: "HKCR", + winreg.HKEY_LOCAL_MACHINE: "HKLM", + winreg.HKEY_CURRENT_USER: "HKCU", +} + def _explain(hkey): return _KEYS.get(hkey, hkey) + class Registrar(object): """COM class registration. @@ -84,12 +93,15 @@ class Registrar(object): Registrars _register and _unregister methods which do the actual work. """ + def nodebug(self, cls): """Delete logging entries from the registry.""" clsid = cls._reg_clsid_ try: - _debug('DeleteKey( %s\\CLSID\\%s\\Logging"' % \ - (_explain(winreg.HKEY_CLASSES_ROOT), clsid)) + _debug( + 'DeleteKey( %s\\CLSID\\%s\\Logging"' + % (_explain(winreg.HKEY_CLASSES_ROOT), clsid) + ) hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s" % clsid) winreg.DeleteKey(hkey, "Logging") except WindowsError as detail: @@ -101,20 +113,22 @@ def debug(self, cls, levels, format): # handlers # format clsid = cls._reg_clsid_ - _debug('CreateKey( %s\\CLSID\\%s\\Logging"' % \ - (_explain(winreg.HKEY_CLASSES_ROOT), clsid)) + _debug( + 'CreateKey( %s\\CLSID\\%s\\Logging"' + % (_explain(winreg.HKEY_CLASSES_ROOT), clsid) + ) hkey = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Logging" % clsid) for item in levels: name, value = item.split("=") v = getattr(logging, value) assert isinstance(v, int) - _debug('SetValueEx(levels, %s)' % levels) + _debug("SetValueEx(levels, %s)" % levels) winreg.SetValueEx(hkey, "levels", None, winreg.REG_MULTI_SZ, levels) if format: - _debug('SetValueEx(format, %s)' % format) + _debug("SetValueEx(format, %s)" % format) winreg.SetValueEx(hkey, "format", None, winreg.REG_SZ, format) else: - _debug('DeleteValue(format)') + _debug("DeleteValue(format)") try: winreg.DeleteValue(hkey, "format") except WindowsError as detail: @@ -139,7 +153,7 @@ def _register(self, cls, executable=None): table.sort() _debug("Registering %s", cls) for hkey, subkey, valuename, value in table: - _debug ('[%s\\%s]', _explain(hkey), subkey) + _debug("[%s\\%s]", _explain(hkey), subkey) _debug('%s="%s"', valuename or "@", value) k = winreg.CreateKey(hkey, subkey) winreg.SetValueEx(k, valuename, None, winreg.REG_SZ, str(value)) @@ -195,7 +209,10 @@ def _unregister(self, cls, force=False): _debug("UnRegisterTypeLib(%s, %s, %s)", *tlib) UnRegisterTypeLib(*tlib) except WindowsError as detail: - if not get_winerror(detail) in (TYPE_E_REGISTRYACCESS, TYPE_E_CANTLOADLIBRARY): + if not get_winerror(detail) in ( + TYPE_E_REGISTRYACCESS, + TYPE_E_CANTLOADLIBRARY, + ): raise _debug("Done") @@ -207,6 +224,7 @@ def _get_serverdll(self): windll.kernel32.GetModuleFileNameA(handle, buf, sizeof(buf)) return buf[:] import _ctypes + return _ctypes.__file__ def _get_full_classname(self, cls): @@ -250,13 +268,16 @@ def _registry_entries(self, cls): append = lambda *args: table.append(args) # basic entry - names the comobject - reg_clsid = str(cls._reg_clsid_) # that's the only required attribute for registration + reg_clsid = str( + cls._reg_clsid_ + ) # that's the only required attribute for registration reg_desc = getattr(cls, "_reg_desc_", "") if not reg_desc: # Simple minded algorithm to construct a description from # the progid: - reg_desc = getattr(cls, "_reg_novers_progid_", "") or \ - getattr(cls, "_reg_progid_", "") + reg_desc = getattr(cls, "_reg_novers_progid_", "") or getattr( + cls, "_reg_progid_", "" + ) if reg_desc: reg_desc = reg_desc.replace(".", " ") append(HKCR, "CLSID\\%s" % reg_clsid, "", reg_desc) @@ -264,26 +285,31 @@ def _registry_entries(self, cls): reg_progid = getattr(cls, "_reg_progid_", None) if reg_progid: # for ProgIDFromCLSID: - append(HKCR, "CLSID\\%s\\ProgID" % reg_clsid, "", reg_progid) # 1 + append(HKCR, "CLSID\\%s\\ProgID" % reg_clsid, "", reg_progid) # 1 # for CLSIDFromProgID if reg_desc: - append(HKCR, reg_progid, "", reg_desc) # 2 - append(HKCR, "%s\\CLSID" % reg_progid, "", reg_clsid) # 3 + append(HKCR, reg_progid, "", reg_desc) # 2 + append(HKCR, "%s\\CLSID" % reg_progid, "", reg_clsid) # 3 reg_novers_progid = getattr(cls, "_reg_novers_progid_", None) if reg_novers_progid: - append(HKCR, "CLSID\\%s\\VersionIndependentProgID" % reg_clsid, # 1a - "", reg_novers_progid) + append( + HKCR, + "CLSID\\%s\\VersionIndependentProgID" % reg_clsid, # 1a + "", + reg_novers_progid, + ) if reg_desc: - append(HKCR, reg_novers_progid, "", reg_desc) # 2a - append(HKCR, "%s\\CurVer" % reg_novers_progid, "", reg_progid) # - append(HKCR, "%s\\CLSID" % reg_novers_progid, "", reg_clsid) # 3a + append(HKCR, reg_novers_progid, "", reg_desc) # 2a + append(HKCR, "%s\\CurVer" % reg_novers_progid, "", reg_progid) # + append(HKCR, "%s\\CLSID" % reg_novers_progid, "", reg_clsid) # 3a clsctx = getattr(cls, "_reg_clsctx_", 0) - if clsctx & comtypes.CLSCTX_LOCAL_SERVER \ - and not hasattr(sys, "frozendllhandle"): + if clsctx & comtypes.CLSCTX_LOCAL_SERVER and not hasattr( + sys, "frozendllhandle" + ): exe = sys.executable if " " in exe: exe = '"%s"' % exe @@ -293,28 +319,50 @@ def _registry_entries(self, cls): script = os.path.abspath(sys.modules[cls.__module__].__file__) if " " in script: script = '"%s"' % script - append(HKCR, "CLSID\\%s\\LocalServer32" % reg_clsid, "", "%s %s" % (exe, script)) + append( + HKCR, + "CLSID\\%s\\LocalServer32" % reg_clsid, + "", + "%s %s" % (exe, script), + ) else: append(HKCR, "CLSID\\%s\\LocalServer32" % reg_clsid, "", "%s" % exe) # Register InprocServer32 only when run from script or from # py2exe dll server, not from py2exe exe server. - if clsctx & comtypes.CLSCTX_INPROC_SERVER \ - and getattr(sys, "frozen", None) in (None, "dll"): - append(HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, - "", self._get_serverdll()) + if clsctx & comtypes.CLSCTX_INPROC_SERVER and getattr(sys, "frozen", None) in ( + None, + "dll", + ): + append( + HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, "", self._get_serverdll() + ) # only for non-frozen inproc servers the PythonPath/PythonClass is needed. - if not hasattr(sys, "frozendllhandle") \ - or not comtypes.server.inprocserver._clsid_to_class: - append(HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, - "PythonClass", self._get_full_classname(cls)) - append(HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, - "PythonPath", self._get_pythonpath(cls)) + if ( + not hasattr(sys, "frozendllhandle") + or not comtypes.server.inprocserver._clsid_to_class + ): + append( + HKCR, + "CLSID\\%s\\InprocServer32" % reg_clsid, + "PythonClass", + self._get_full_classname(cls), + ) + append( + HKCR, + "CLSID\\%s\\InprocServer32" % reg_clsid, + "PythonPath", + self._get_pythonpath(cls), + ) reg_threading = getattr(cls, "_reg_threading_", None) if reg_threading is not None: - append(HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, - "ThreadingModel", reg_threading) + append( + HKCR, + "CLSID\\%s\\InprocServer32" % reg_clsid, + "ThreadingModel", + reg_threading, + ) reg_tlib = getattr(cls, "_reg_typelib_", None) if reg_tlib is not None: @@ -322,21 +370,29 @@ def _registry_entries(self, cls): return table + ################################################################ + def register(cls): Registrar().register(cls) + def unregister(cls): Registrar().unregister(cls) + def UseCommandLine(*classes): - usage = """Usage: %s [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]""" % sys.argv[0] - opts, args = w_getopt.w_getopt(sys.argv[1:], - "regserver unregserver embedding l: f: nodebug") + usage = ( + """Usage: %s [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]""" + % sys.argv[0] + ) + opts, args = w_getopt.w_getopt( + sys.argv[1:], "regserver unregserver embedding l: f: nodebug" + ) if not opts: sys.stderr.write(usage + "\n") - return 0 # nothing for us to do + return 0 # nothing for us to do levels = [] format = None @@ -367,9 +423,11 @@ def UseCommandLine(*classes): if runit: import comtypes.server.localserver + comtypes.server.localserver.run(classes) - return 1 # we have done something + return 1 # we have done something + if __name__ == "__main__": UseCommandLine() diff --git a/comtypes/server/w_getopt.py b/comtypes/server/w_getopt.py index 1a3ffbfa..0c45ea91 100644 --- a/comtypes/server/w_getopt.py +++ b/comtypes/server/w_getopt.py @@ -1,6 +1,7 @@ class GetoptError(Exception): pass + def w_getopt(args, options): """A getopt for Windows. @@ -21,17 +22,17 @@ def w_getopt(args, options): arguments = [] while args: if args[0][:1] in "/-": - arg = args[0][1:] # strip the '-' or '/' + arg = args[0][1:] # strip the '-' or '/' arg = arg.lower() - if arg + ':' in options: + if arg + ":" in options: try: opts.append((arg, args[1])) except IndexError: raise GetoptError("option '%s' requires an argument" % args[0]) args = args[1:] elif arg in options: - opts.append((arg, '')) + opts.append((arg, "")) else: raise GetoptError("invalid option '%s'" % args[0]) args = args[1:] @@ -41,6 +42,7 @@ def w_getopt(args, options): return opts, arguments + if __debug__: if __name__ == "__main__": import unittest @@ -48,28 +50,26 @@ def w_getopt(args, options): class TestCase(unittest.TestCase): def test_1(self): args = "-embedding spam /RegServer foo /UnregSERVER blabla".split() - opts, args = w_getopt(args, - "regserver unregserver embedding".split()) - self.assertEqual(opts, - [('embedding', ''), - ('regserver', ''), - ('unregserver', '')]) + opts, args = w_getopt(args, "regserver unregserver embedding".split()) + self.assertEqual( + opts, [("embedding", ""), ("regserver", ""), ("unregserver", "")] + ) self.assertEqual(args, ["spam", "foo", "blabla"]) def test_2(self): args = "/TLB Hello.Tlb HELLO.idl".split() opts, args = w_getopt(args, ["tlb:"]) - self.assertEqual(opts, [('tlb', 'Hello.Tlb')]) - self.assertEqual(args, ['HELLO.idl']) + self.assertEqual(opts, [("tlb", "Hello.Tlb")]) + self.assertEqual(args, ["HELLO.idl"]) def test_3(self): # Invalid option - self.assertRaises(GetoptError, w_getopt, - "/TLIB hello.tlb hello.idl".split(), ["tlb:"]) + self.assertRaises( + GetoptError, w_getopt, "/TLIB hello.tlb hello.idl".split(), ["tlb:"] + ) def test_4(self): # Missing argument - self.assertRaises(GetoptError, w_getopt, - "/TLB".split(), ["tlb:"]) + self.assertRaises(GetoptError, w_getopt, "/TLB".split(), ["tlb:"]) unittest.main() diff --git a/comtypes/shelllink.py b/comtypes/shelllink.py index 55e531ef..4d73c6bb 100644 --- a/comtypes/shelllink.py +++ b/comtypes/shelllink.py @@ -27,57 +27,91 @@ ITEMIDLIST = c_int LPITEMIDLIST = LPCITEMIDLIST = POINTER(ITEMIDLIST) + class IShellLinkA(IUnknown): - _iid_ = GUID('{000214EE-0000-0000-C000-000000000046}') + _iid_ = GUID("{000214EE-0000-0000-C000-000000000046}") _methods_ = [ - COMMETHOD([], HRESULT, 'GetPath', - ( ['in', 'out'], c_char_p, 'pszFile' ), - ( ['in'], c_int, 'cchMaxPath' ), - ( ['in', 'out'], POINTER(WIN32_FIND_DATAA), 'pfd' ), - ( ['in'], DWORD, 'fFlags' )), - COMMETHOD([], HRESULT, 'GetIDList', - ( ['retval', 'out'], POINTER(LPITEMIDLIST), 'ppidl' )), - COMMETHOD([], HRESULT, 'SetIDList', - ( ['in'], LPCITEMIDLIST, 'pidl' )), - COMMETHOD([], HRESULT, 'GetDescription', - ( ['in', 'out'], c_char_p, 'pszName' ), - ( ['in'], c_int, 'cchMaxName' )), - COMMETHOD([], HRESULT, 'SetDescription', - ( ['in'], c_char_p, 'pszName' )), - COMMETHOD([], HRESULT, 'GetWorkingDirectory', - ( ['in', 'out'], c_char_p, 'pszDir' ), - ( ['in'], c_int, 'cchMaxPath' )), - COMMETHOD([], HRESULT, 'SetWorkingDirectory', - ( ['in'], c_char_p, 'pszDir' )), - COMMETHOD([], HRESULT, 'GetArguments', - ( ['in', 'out'], c_char_p, 'pszArgs' ), - ( ['in'], c_int, 'cchMaxPath' )), - COMMETHOD([], HRESULT, 'SetArguments', - ( ['in'], c_char_p, 'pszArgs' )), - COMMETHOD(['propget'], HRESULT, 'Hotkey', - ( ['retval', 'out'], POINTER(c_short), 'pwHotkey' )), - COMMETHOD(['propput'], HRESULT, 'Hotkey', - ( ['in'], c_short, 'pwHotkey' )), - COMMETHOD(['propget'], HRESULT, 'ShowCmd', - ( ['retval', 'out'], POINTER(c_int), 'piShowCmd' )), - COMMETHOD(['propput'], HRESULT, 'ShowCmd', - ( ['in'], c_int, 'piShowCmd' )), - COMMETHOD([], HRESULT, 'GetIconLocation', - ( ['in', 'out'], c_char_p, 'pszIconPath' ), - ( ['in'], c_int, 'cchIconPath' ), - ( ['in', 'out'], POINTER(c_int), 'piIcon' )), - COMMETHOD([], HRESULT, 'SetIconLocation', - ( ['in'], c_char_p, 'pszIconPath' ), - ( ['in'], c_int, 'iIcon' )), - COMMETHOD([], HRESULT, 'SetRelativePath', - ( ['in'], c_char_p, 'pszPathRel' ), - ( ['in'], DWORD, 'dwReserved' )), - COMMETHOD([], HRESULT, 'Resolve', - ( ['in'], c_int, 'hwnd' ), - ( ['in'], DWORD, 'fFlags' )), - COMMETHOD([], HRESULT, 'SetPath', - ( ['in'], c_char_p, 'pszFile' )), - ] + COMMETHOD( + [], + HRESULT, + "GetPath", + (["in", "out"], c_char_p, "pszFile"), + (["in"], c_int, "cchMaxPath"), + (["in", "out"], POINTER(WIN32_FIND_DATAA), "pfd"), + (["in"], DWORD, "fFlags"), + ), + COMMETHOD( + [], + HRESULT, + "GetIDList", + (["retval", "out"], POINTER(LPITEMIDLIST), "ppidl"), + ), + COMMETHOD([], HRESULT, "SetIDList", (["in"], LPCITEMIDLIST, "pidl")), + COMMETHOD( + [], + HRESULT, + "GetDescription", + (["in", "out"], c_char_p, "pszName"), + (["in"], c_int, "cchMaxName"), + ), + COMMETHOD([], HRESULT, "SetDescription", (["in"], c_char_p, "pszName")), + COMMETHOD( + [], + HRESULT, + "GetWorkingDirectory", + (["in", "out"], c_char_p, "pszDir"), + (["in"], c_int, "cchMaxPath"), + ), + COMMETHOD([], HRESULT, "SetWorkingDirectory", (["in"], c_char_p, "pszDir")), + COMMETHOD( + [], + HRESULT, + "GetArguments", + (["in", "out"], c_char_p, "pszArgs"), + (["in"], c_int, "cchMaxPath"), + ), + COMMETHOD([], HRESULT, "SetArguments", (["in"], c_char_p, "pszArgs")), + COMMETHOD( + ["propget"], + HRESULT, + "Hotkey", + (["retval", "out"], POINTER(c_short), "pwHotkey"), + ), + COMMETHOD(["propput"], HRESULT, "Hotkey", (["in"], c_short, "pwHotkey")), + COMMETHOD( + ["propget"], + HRESULT, + "ShowCmd", + (["retval", "out"], POINTER(c_int), "piShowCmd"), + ), + COMMETHOD(["propput"], HRESULT, "ShowCmd", (["in"], c_int, "piShowCmd")), + COMMETHOD( + [], + HRESULT, + "GetIconLocation", + (["in", "out"], c_char_p, "pszIconPath"), + (["in"], c_int, "cchIconPath"), + (["in", "out"], POINTER(c_int), "piIcon"), + ), + COMMETHOD( + [], + HRESULT, + "SetIconLocation", + (["in"], c_char_p, "pszIconPath"), + (["in"], c_int, "iIcon"), + ), + COMMETHOD( + [], + HRESULT, + "SetRelativePath", + (["in"], c_char_p, "pszPathRel"), + (["in"], DWORD, "dwReserved"), + ), + COMMETHOD( + [], HRESULT, "Resolve", (["in"], c_int, "hwnd"), (["in"], DWORD, "fFlags") + ), + COMMETHOD([], HRESULT, "SetPath", (["in"], c_char_p, "pszFile")), + ] def GetPath(self, flags=SLGP_SHORTPATH): buf = create_string_buffer(MAX_PATH) @@ -106,57 +140,91 @@ def GetIconLocation(self): self.__com_GetIconLocation(buf, MAX_PATH, byref(iIcon)) return buf.value, iIcon.value + class IShellLinkW(IUnknown): - _iid_ = GUID('{000214F9-0000-0000-C000-000000000046}') + _iid_ = GUID("{000214F9-0000-0000-C000-000000000046}") _methods_ = [ - COMMETHOD([], HRESULT, 'GetPath', - ( ['in', 'out'], c_wchar_p, 'pszFile' ), - ( ['in'], c_int, 'cchMaxPath' ), - ( ['in', 'out'], POINTER(WIN32_FIND_DATAW), 'pfd' ), - ( ['in'], DWORD, 'fFlags' )), - COMMETHOD([], HRESULT, 'GetIDList', - ( ['retval', 'out'], POINTER(LPITEMIDLIST), 'ppidl' )), - COMMETHOD([], HRESULT, 'SetIDList', - ( ['in'], LPCITEMIDLIST, 'pidl' )), - COMMETHOD([], HRESULT, 'GetDescription', - ( ['in', 'out'], c_wchar_p, 'pszName' ), - ( ['in'], c_int, 'cchMaxName' )), - COMMETHOD([], HRESULT, 'SetDescription', - ( ['in'], c_wchar_p, 'pszName' )), - COMMETHOD([], HRESULT, 'GetWorkingDirectory', - ( ['in', 'out'], c_wchar_p, 'pszDir' ), - ( ['in'], c_int, 'cchMaxPath' )), - COMMETHOD([], HRESULT, 'SetWorkingDirectory', - ( ['in'], c_wchar_p, 'pszDir' )), - COMMETHOD([], HRESULT, 'GetArguments', - ( ['in', 'out'], c_wchar_p, 'pszArgs' ), - ( ['in'], c_int, 'cchMaxPath' )), - COMMETHOD([], HRESULT, 'SetArguments', - ( ['in'], c_wchar_p, 'pszArgs' )), - COMMETHOD(['propget'], HRESULT, 'Hotkey', - ( ['retval', 'out'], POINTER(c_short), 'pwHotkey' )), - COMMETHOD(['propput'], HRESULT, 'Hotkey', - ( ['in'], c_short, 'pwHotkey' )), - COMMETHOD(['propget'], HRESULT, 'ShowCmd', - ( ['retval', 'out'], POINTER(c_int), 'piShowCmd' )), - COMMETHOD(['propput'], HRESULT, 'ShowCmd', - ( ['in'], c_int, 'piShowCmd' )), - COMMETHOD([], HRESULT, 'GetIconLocation', - ( ['in', 'out'], c_wchar_p, 'pszIconPath' ), - ( ['in'], c_int, 'cchIconPath' ), - ( ['in', 'out'], POINTER(c_int), 'piIcon' )), - COMMETHOD([], HRESULT, 'SetIconLocation', - ( ['in'], c_wchar_p, 'pszIconPath' ), - ( ['in'], c_int, 'iIcon' )), - COMMETHOD([], HRESULT, 'SetRelativePath', - ( ['in'], c_wchar_p, 'pszPathRel' ), - ( ['in'], DWORD, 'dwReserved' )), - COMMETHOD([], HRESULT, 'Resolve', - ( ['in'], c_int, 'hwnd' ), - ( ['in'], DWORD, 'fFlags' )), - COMMETHOD([], HRESULT, 'SetPath', - ( ['in'], c_wchar_p, 'pszFile' )), - ] + COMMETHOD( + [], + HRESULT, + "GetPath", + (["in", "out"], c_wchar_p, "pszFile"), + (["in"], c_int, "cchMaxPath"), + (["in", "out"], POINTER(WIN32_FIND_DATAW), "pfd"), + (["in"], DWORD, "fFlags"), + ), + COMMETHOD( + [], + HRESULT, + "GetIDList", + (["retval", "out"], POINTER(LPITEMIDLIST), "ppidl"), + ), + COMMETHOD([], HRESULT, "SetIDList", (["in"], LPCITEMIDLIST, "pidl")), + COMMETHOD( + [], + HRESULT, + "GetDescription", + (["in", "out"], c_wchar_p, "pszName"), + (["in"], c_int, "cchMaxName"), + ), + COMMETHOD([], HRESULT, "SetDescription", (["in"], c_wchar_p, "pszName")), + COMMETHOD( + [], + HRESULT, + "GetWorkingDirectory", + (["in", "out"], c_wchar_p, "pszDir"), + (["in"], c_int, "cchMaxPath"), + ), + COMMETHOD([], HRESULT, "SetWorkingDirectory", (["in"], c_wchar_p, "pszDir")), + COMMETHOD( + [], + HRESULT, + "GetArguments", + (["in", "out"], c_wchar_p, "pszArgs"), + (["in"], c_int, "cchMaxPath"), + ), + COMMETHOD([], HRESULT, "SetArguments", (["in"], c_wchar_p, "pszArgs")), + COMMETHOD( + ["propget"], + HRESULT, + "Hotkey", + (["retval", "out"], POINTER(c_short), "pwHotkey"), + ), + COMMETHOD(["propput"], HRESULT, "Hotkey", (["in"], c_short, "pwHotkey")), + COMMETHOD( + ["propget"], + HRESULT, + "ShowCmd", + (["retval", "out"], POINTER(c_int), "piShowCmd"), + ), + COMMETHOD(["propput"], HRESULT, "ShowCmd", (["in"], c_int, "piShowCmd")), + COMMETHOD( + [], + HRESULT, + "GetIconLocation", + (["in", "out"], c_wchar_p, "pszIconPath"), + (["in"], c_int, "cchIconPath"), + (["in", "out"], POINTER(c_int), "piIcon"), + ), + COMMETHOD( + [], + HRESULT, + "SetIconLocation", + (["in"], c_wchar_p, "pszIconPath"), + (["in"], c_int, "iIcon"), + ), + COMMETHOD( + [], + HRESULT, + "SetRelativePath", + (["in"], c_wchar_p, "pszPathRel"), + (["in"], DWORD, "dwReserved"), + ), + COMMETHOD( + [], HRESULT, "Resolve", (["in"], c_int, "hwnd"), (["in"], DWORD, "fFlags") + ), + COMMETHOD([], HRESULT, "SetPath", (["in"], c_wchar_p, "pszFile")), + ] def GetPath(self, flags=SLGP_SHORTPATH): buf = create_unicode_buffer(MAX_PATH) @@ -185,9 +253,11 @@ def GetIconLocation(self): self.__com_GetIconLocation(buf, MAX_PATH, byref(iIcon)) return buf.value, iIcon.value + class ShellLink(CoClass): """ShellLink class""" - _reg_clsid_ = GUID('{00021401-0000-0000-C000-000000000046}') + + _reg_clsid_ = GUID("{00021401-0000-0000-C000-000000000046}") _idlflags_ = [] _com_interfaces_ = [IShellLinkW, IShellLinkA] @@ -199,8 +269,6 @@ class ShellLink(CoClass): from comtypes.client import CreateObject from comtypes.persist import IPersistFile - - shortcut = CreateObject(ShellLink) print(shortcut) ##help(shortcut) diff --git a/comtypes/test/TestComServer.py b/comtypes/test/TestComServer.py index 1ee9d42a..a0fd8bfd 100644 --- a/comtypes/test/TestComServer.py +++ b/comtypes/test/TestComServer.py @@ -1,5 +1,6 @@ import sys, os import logging + logging.basicConfig() ##logging.basicConfig(level=logging.DEBUG) ##logger = logging.getLogger(__name__) @@ -38,18 +39,18 @@ # interfaces. ISupportErrorInfo is implemented by the COMObject base # class. class TestComServer( - TestComServerLib.TestComServer, # the coclass from the typelib wrapper + TestComServerLib.TestComServer, # the coclass from the typelib wrapper comtypes.server.connectionpoints.ConnectableObjectMixin, - ): +): # The default interface from the typelib MUST be the first # interface, other interfaces can follow - _com_interfaces_ = TestComServerLib.TestComServer._com_interfaces_ + \ - [comtypes.typeinfo.IProvideClassInfo2, - comtypes.errorinfo.ISupportErrorInfo, - comtypes.connectionpoints.IConnectionPointContainer, - ] + _com_interfaces_ = TestComServerLib.TestComServer._com_interfaces_ + [ + comtypes.typeinfo.IProvideClassInfo2, + comtypes.errorinfo.ISupportErrorInfo, + comtypes.connectionpoints.IConnectionPointContainer, + ] # registry entries _reg_threading_ = "Both" @@ -115,7 +116,7 @@ def ITestComServer_Exec(self, this, what): def ITestComServer_Exec2(self, what): exec(what) - _name = u"spam, spam, spam" + _name = "spam, spam, spam" def _get_name(self): return self._name @@ -137,15 +138,18 @@ def ITestComServer_sEtNaMe(self, this, name): # [id(18), helpstring("a method with [in] and [out] args in mixed order")] # HRESULT MixedInOut([in] int a, [out] int *b, [in] int c, [out] int *d); def MixedInOut(self, a, c): - return a+1, c+1 + return a + 1, c + 1 + if __name__ == "__main__": try: from comtypes.server.register import UseCommandLine + # logging.basicConfig(level=logging.DEBUG) UseCommandLine(TestComServer) except Exception: import traceback + traceback.print_exc() if sys.version_info >= (3, 0): input() diff --git a/comtypes/test/TestDispServer.py b/comtypes/test/TestDispServer.py index 0a4c26a2..c693f7ef 100644 --- a/comtypes/test/TestDispServer.py +++ b/comtypes/test/TestDispServer.py @@ -1,5 +1,6 @@ import sys, os import logging + logging.basicConfig() ##logging.basicConfig(level=logging.DEBUG) ##logger = logging.getLogger(__name__) @@ -18,6 +19,7 @@ # in the IDL file if not hasattr(sys, "frozen"): import comtypes.client + # pathname of the type library file tlbfile = os.path.join(os.path.dirname(__file__), "TestDispServer.tlb") # if running as frozen app (dll or exe), the wrapper should be in @@ -37,15 +39,16 @@ # # The ConnectableObjectMixin class provides connectionpoints (events). class TestDispServer( - TestDispServerLib.TestDispServer, # the coclass from the typelib wrapper + TestDispServerLib.TestDispServer, # the coclass from the typelib wrapper comtypes.server.connectionpoints.ConnectableObjectMixin, - ): +): # The default interface from the typelib MUST be the first # interface, other interfaces can follow - _com_interfaces_ = TestDispServerLib.TestDispServer._com_interfaces_ + \ - [comtypes.connectionpoints.IConnectionPointContainer] + _com_interfaces_ = TestDispServerLib.TestDispServer._com_interfaces_ + [ + comtypes.connectionpoints.IConnectionPointContainer + ] # registry entries _reg_threading_ = "Both" @@ -82,7 +85,7 @@ def DTestDispServer_Exec(self, this, what): def DTestDispServer_Exec2(self, what): exec(what) - _name = u"spam, spam, spam" + _name = "spam, spam, spam" # Implementation of the DTestDispServer::Name propget def DTestDispServer__get_name(self, this, pname): @@ -98,6 +101,8 @@ def DTestDispServer__set_name(self, this, name): def DTestDispServer_sEtNaMe(self, name): self._name = name + if __name__ == "__main__": from comtypes.server.register import UseCommandLine + UseCommandLine(TestDispServer) diff --git a/comtypes/test/__init__.py b/comtypes/test/__init__.py index 66bf229d..7879c6b2 100644 --- a/comtypes/test/__init__.py +++ b/comtypes/test/__init__.py @@ -12,7 +12,7 @@ def register_server(source_dir): - """ Register testing server appropriate for the python architecture. + """Register testing server appropriate for the python architecture. ``source_dir`` gives the absolute path to the comtype source in which the 32- and 64-bit testing server, "AvmcIfc.dll" is defined. @@ -29,6 +29,7 @@ def register_server(source_dir): dll.DllRegisterServer() return + class ResourceDenied(Exception): """Test skipped because it requested a disallowed resource. @@ -36,19 +37,24 @@ class ResourceDenied(Exception): has not be enabled. Resources are defined by test modules. """ + def is_resource_enabled(resource): """Test whether a resource is enabled. If the caller's module is __main__ then automatically return True.""" if sys._getframe().f_back.f_globals.get("__name__") == "__main__": return True - result = use_resources is not None and \ - (resource in use_resources or "*" in use_resources) + result = use_resources is not None and ( + resource in use_resources or "*" in use_resources + ) if not result: _unavail[resource] = None return result + _unavail = {} + + def requires(resource, msg=None): """Raise ResourceDenied if the specified resource is not available. @@ -62,8 +68,10 @@ def requires(resource, msg=None): msg = "Use of the `%s' resource not enabled" % resource raise ResourceDenied(msg) + def find_package_modules(package, mask): import fnmatch + if hasattr(package, "__loader__"): path = package.__name__.replace(".", os.path.sep) mask = os.path.join(path, mask) @@ -76,20 +84,23 @@ def find_package_modules(package, mask): if fnmatch.fnmatchcase(fnm, mask): yield "%s.%s" % (package.__name__, os.path.splitext(fnm)[0]) + def get_tests(package, mask, verbosity): """Return a list of skipped test modules, and a list of test cases.""" tests = [] skipped = [] for modname in find_package_modules(package, mask): try: - mod = __import__(modname, globals(), locals(), ['*']) + mod = __import__(modname, globals(), locals(), ["*"]) except ResourceDenied as detail: skipped.append(modname) if verbosity > 1: print("Skipped %s: %s" % (modname, detail), file=sys.stderr) continue except Exception as detail: - print("Warning: could not import %s: %s" % (modname, detail), file=sys.stderr) + print( + "Warning: could not import %s: %s" % (modname, detail), file=sys.stderr + ) continue for name in dir(mod): if name.startswith("_"): @@ -103,14 +114,17 @@ def get_tests(package, mask, verbosity): tests.append(o) return skipped, tests + def usage(): print(__doc__) return 1 + def test_with_refcounts(runner, verbosity, testcase): """Run testcase several times, tracking reference counts.""" import gc import ctypes + ptc = ctypes._pointer_type_cache.copy() cfc = ctypes._c_functype_cache.copy() wfc = ctypes._win_functype_cache.copy() @@ -140,6 +154,7 @@ def cleanup(): elif verbosity: print("%s: ok." % testcase) + class TestRunner(unittest.TextTestRunner): def run(self, test, skipped): "Run the given test case or test suite." @@ -153,17 +168,24 @@ def run(self, test, skipped): result.printErrors() self.stream.writeln(result.separator2) run = result.testsRun - if _unavail: #skipped: + if _unavail: # skipped: requested = list(_unavail.keys()) requested.sort() - self.stream.writeln("Ran %d test%s in %.3fs (%s module%s skipped)" % - (run, run != 1 and "s" or "", timeTaken, - len(skipped), - len(skipped) != 1 and "s" or "")) + self.stream.writeln( + "Ran %d test%s in %.3fs (%s module%s skipped)" + % ( + run, + run != 1 and "s" or "", + timeTaken, + len(skipped), + len(skipped) != 1 and "s" or "", + ) + ) self.stream.writeln("Unavailable resources: %s" % ", ".join(requested)) else: - self.stream.writeln("Ran %d test%s in %.3fs" % - (run, run != 1 and "s" or "", timeTaken)) + self.stream.writeln( + "Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken) + ) self.stream.writeln() if not result.wasSuccessful(): self.stream.write("FAILED (") @@ -171,7 +193,8 @@ def run(self, test, skipped): if failed: self.stream.write("failures=%d" % failed) if errored: - if failed: self.stream.write(", ") + if failed: + self.stream.write(", ") self.stream.write("errors=%d" % errored) self.stream.writeln(")") else: @@ -180,7 +203,7 @@ def run(self, test, skipped): def run_tests(package, mask, verbosity, search_leaks): - """ Run tests for package and return True on failure, False otherwise """ + """Run tests for package and return True on failure, False otherwise""" skipped, testcases = get_tests(package, mask, verbosity) runner = TestRunner(verbosity=verbosity) @@ -196,14 +219,16 @@ def run_tests(package, mask, verbosity, search_leaks): return bool(result.errors) or bool(result.failures) + class BasicTestRunner: def run(self, test): result = unittest.TestResult() test(result) return result -def run(args = []): - """ Run tests and return True on failure, False otherwise """ + +def run(args=[]): + """Run tests and return True on failure, False otherwise""" try: opts, args = getopt.getopt(args, "rqvu:") except getopt.error: @@ -231,4 +256,5 @@ def run(args = []): mask = args[0] import comtypes.test + return run_tests(comtypes.test, mask, verbosity, search_leaks) diff --git a/comtypes/test/find_memleak.py b/comtypes/test/find_memleak.py index a4ce156c..7404fdbf 100644 --- a/comtypes/test/find_memleak.py +++ b/comtypes/test/find_memleak.py @@ -5,31 +5,42 @@ ################################################################ + class PROCESS_MEMORY_COUNTERS(Structure): - _fields_ = [("cb", DWORD), - ("PageFaultCount", DWORD), - ("PeakWorkingSetSize", c_size_t), - ("WorkingSetSize", c_size_t), - ("QuotaPeakPagedPoolUsage", c_size_t), - ("QuotaPagedPoolUsage", c_size_t), - ("QuotaPeakNonPagedPoolUsage", c_size_t), - ("QuotaNonPagedPoolUsage", c_size_t), - ("PagefileUsage", c_size_t), - ("PeakPagefileUsage", c_size_t)] + _fields_ = [ + ("cb", DWORD), + ("PageFaultCount", DWORD), + ("PeakWorkingSetSize", c_size_t), + ("WorkingSetSize", c_size_t), + ("QuotaPeakPagedPoolUsage", c_size_t), + ("QuotaPagedPoolUsage", c_size_t), + ("QuotaPeakNonPagedPoolUsage", c_size_t), + ("QuotaNonPagedPoolUsage", c_size_t), + ("PagefileUsage", c_size_t), + ("PeakPagefileUsage", c_size_t), + ] + def __init__(self): self.cb = sizeof(self) def dump(self): for n, _ in self._fields_[2:]: - print(n, getattr(self, n)/1e6) + print(n, getattr(self, n) / 1e6) + try: - windll.psapi.GetProcessMemoryInfo.argtypes = (HANDLE, POINTER(PROCESS_MEMORY_COUNTERS), DWORD) + windll.psapi.GetProcessMemoryInfo.argtypes = ( + HANDLE, + POINTER(PROCESS_MEMORY_COUNTERS), + DWORD, + ) except WindowsError: # cannot search for memory leaks on Windows CE def find_memleak(func, loops=None): return 0 + else: + def wss(): # Return the working set size (memory used by process) pmi = PROCESS_MEMORY_COUNTERS() @@ -45,7 +56,9 @@ def find_memleak(func, loops=LOOPS): for j in range(loops[0]): for k in range(loops[1]): func() - gc.collect(); gc.collect(); gc.collect() + gc.collect() + gc.collect() + gc.collect() bytes = wss() # call 'func' several times, recording the difference in # memory consumption before and after the call. Repeat this a @@ -54,7 +67,9 @@ def find_memleak(func, loops=LOOPS): for j in range(loops[0]): for k in range(loops[1]): func() - gc.collect(); gc.collect(); gc.collect() + gc.collect() + gc.collect() + gc.collect() # return the increased in process size result = wss() - bytes # Sometimes the process size did decrease, we do not report leaks diff --git a/comtypes/test/runtests.py b/comtypes/test/runtests.py index 56d598e3..cc1578f2 100644 --- a/comtypes/test/runtests.py +++ b/comtypes/test/runtests.py @@ -1,8 +1,10 @@ import sys import comtypes.test + def main(): sys.exit(comtypes.test.run(sys.argv[1:])) + if __name__ == "__main__": main() diff --git a/comtypes/test/setup.py b/comtypes/test/setup.py index 5ba3e299..b0b78879 100644 --- a/comtypes/test/setup.py +++ b/comtypes/test/setup.py @@ -3,4 +3,4 @@ import glob import py2exe -setup(name='test_*', console=glob.glob("test_*.py")) +setup(name="test_*", console=glob.glob("test_*.py")) diff --git a/comtypes/test/test_BSTR.py b/comtypes/test/test_BSTR.py index 17cdeccb..7bc18319 100644 --- a/comtypes/test/test_BSTR.py +++ b/comtypes/test/test_BSTR.py @@ -7,6 +7,7 @@ from comtypes.test.find_memleak import find_memleak + class Test(unittest.TestCase): def check_leaks(self, func, limit=0): bytes = find_memleak(func) @@ -14,38 +15,45 @@ def check_leaks(self, func, limit=0): def test_creation(self): def doit(): - BSTR(u"abcdef" * 100) + BSTR("abcdef" * 100) + # It seems this test is unreliable. Sometimes it leaks 4096 # bytes, sometimes not. Try to workaround that... self.check_leaks(doit, limit=4096) def test_from_param(self): def doit(): - BSTR.from_param(u"abcdef") + BSTR.from_param("abcdef") + self.check_leaks(doit) def test_paramflags(self): prototype = WINFUNCTYPE(c_void_p, BSTR) func = prototype(("SysStringLen", oledll.oleaut32)) func.restype = c_void_p - func.argtypes = (BSTR, ) + func.argtypes = (BSTR,) + def doit(): - func(u"abcdef") - func(u"abc xyz") - func(BSTR(u"abc def")) + func("abcdef") + func("abc xyz") + func(BSTR("abc def")) + self.check_leaks(doit) def test_inargs(self): SysStringLen = windll.oleaut32.SysStringLen - SysStringLen.argtypes = BSTR, + SysStringLen.argtypes = (BSTR,) SysStringLen.restype = c_uint self.assertEqual(SysStringLen("abc xyz"), 7) + def doit(): SysStringLen("abc xyz") - SysStringLen(u"abc xyz") - SysStringLen(BSTR(u"abc def")) + SysStringLen("abc xyz") + SysStringLen(BSTR("abc def")) + self.check_leaks(doit) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_DISPPARAMS.py b/comtypes/test/test_DISPPARAMS.py index 96a231ac..ea89f79e 100644 --- a/comtypes/test/test_DISPPARAMS.py +++ b/comtypes/test/test_DISPPARAMS.py @@ -1,5 +1,6 @@ import unittest as ut + class TestCase(ut.TestCase): def test(self): from comtypes.automation import DISPPARAMS, VARIANT @@ -31,11 +32,13 @@ def X_test_2(self): dp.rgvarg = (VARIANT * 3)(*list(map(VARIANT, args[::-1]))) import gc + gc.collect() self.assertEqual(dp.rgvarg[0].value, 42) self.assertEqual(dp.rgvarg[1].value, "spam") self.assertEqual(dp.rgvarg[2].value, "foo") + if __name__ == "__main__": ut.main() diff --git a/comtypes/test/test_GUID.py b/comtypes/test/test_GUID.py index a8bdbf98..ef8ae1e6 100644 --- a/comtypes/test/test_GUID.py +++ b/comtypes/test/test_GUID.py @@ -2,24 +2,35 @@ import unittest from comtypes import GUID + class Test(unittest.TestCase): def test(self): self.assertEqual(GUID(), GUID()) - self.assertEqual(GUID("{00000000-0000-0000-C000-000000000046}"), - GUID("{00000000-0000-0000-C000-000000000046}")) + self.assertEqual( + GUID("{00000000-0000-0000-C000-000000000046}"), + GUID("{00000000-0000-0000-C000-000000000046}"), + ) - self.assertEqual(str(GUID("{0002DF01-0000-0000-C000-000000000046}")), - "{0002DF01-0000-0000-C000-000000000046}") - self.assertEqual(repr(GUID("{0002DF01-0000-0000-C000-000000000046}")), - 'GUID("{0002DF01-0000-0000-C000-000000000046}")') + self.assertEqual( + str(GUID("{0002DF01-0000-0000-C000-000000000046}")), + "{0002DF01-0000-0000-C000-000000000046}", + ) + self.assertEqual( + repr(GUID("{0002DF01-0000-0000-C000-000000000046}")), + 'GUID("{0002DF01-0000-0000-C000-000000000046}")', + ) self.assertRaises(WindowsError, GUID, "abc") self.assertRaises(WindowsError, GUID.from_progid, "abc") - self.assertRaises(WindowsError, lambda guid: guid.as_progid(), - GUID("{00000000-0000-0000-C000-000000000046}")) + self.assertRaises( + WindowsError, + lambda guid: guid.as_progid(), + GUID("{00000000-0000-0000-C000-000000000046}"), + ) self.assertNotEqual(GUID.create_new(), GUID.create_new()) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_QueryService.py b/comtypes/test/test_QueryService.py index d3c01ad2..d7a00766 100644 --- a/comtypes/test/test_QueryService.py +++ b/comtypes/test/test_QueryService.py @@ -3,14 +3,16 @@ import comtypes from comtypes.client import CreateObject, GetModule -GetModule('oleacc.dll') +GetModule("oleacc.dll") from comtypes.gen.Accessibility import IAccessible -@unittest.skip("This IE test is not working. We need to move it to using some other win32 API.") -class TestCase(unittest.TestCase): +@unittest.skip( + "This IE test is not working. We need to move it to using some other win32 API." +) +class TestCase(unittest.TestCase): def setUp(self): - self.ie = CreateObject('InternetExplorer.application') + self.ie = CreateObject("InternetExplorer.application") def tearDown(self): self.ie.Quit() @@ -23,5 +25,6 @@ def test(self): pacc = sp.QueryService(IAccessible._iid_, IAccessible) self.assertEqual(type(pacc), POINTER(IAccessible)) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_agilent.py b/comtypes/test/test_agilent.py index ba123f0e..8af6f840 100644 --- a/comtypes/test/test_agilent.py +++ b/comtypes/test/test_agilent.py @@ -16,6 +16,7 @@ pass else: + class Test(unittest.TestCase): def test(self): # The point of this test is the ReadWaveform method below, @@ -25,6 +26,7 @@ def test(self): # XXX XXX XXX The following call crashes hard with an accessviolation when # the OANOCACHE environ variable is set. import os + if "OANOCACHE" in os.environ: print("Cannot test. buggy COM object?") return @@ -35,6 +37,7 @@ def test(self): # agDrvr.Initialize("GPIB0::7::INSTR", False, False, "QueryInstrStatus=true") from comtypes.gen import IviScopeLib + iviDrvr = agDrvr.QueryInterface(IviScopeLib.IIviScope) # Get driver Identity properties. Driver initialization not required. @@ -54,7 +57,7 @@ def test(self): # ReadWaveform() takes a sweep and reads the data. # # Definition generated for ReadWaveform(): - #COMMETHOD([helpstring(u'Acquires and returns a waveform on the configured channels.')], + # COMMETHOD([helpstring(u'Acquires and returns a waveform on the configured channels.')], # HRESULT, 'ReadWaveform', # ( ['in'], Agilent546XXTimeOutEnum, 'MaxTime' ), # ( ['in', 'out'], POINTER(_midlSAFEARRAY(c_double)), 'pWaveformArray' ), @@ -67,10 +70,12 @@ def test(self): psaWaveform = _midlSAFEARRAY(c_double).create([]) self._check_result(pMeasurement.ReadWaveform(20000)) self._check_result(pMeasurement.ReadWaveform(20000, pInitialX=9.0)) - self._check_result(pMeasurement.ReadWaveform(20000, pXIncrement=9.0, pInitialX=3.0)) + self._check_result( + pMeasurement.ReadWaveform(20000, pXIncrement=9.0, pInitialX=3.0) + ) self._check_result(pMeasurement.ReadWaveform(20000)) self._check_result(pMeasurement.ReadWaveform(20000, [])) - self._check_result(pMeasurement.ReadWaveform(20000, pWaveformArray = [])) + self._check_result(pMeasurement.ReadWaveform(20000, pWaveformArray=[])) self._check_result(pMeasurement.ReadWaveform(20000, psaWaveform)) self._check_result(pMeasurement.ReadWaveform(20000, pXIncrement=9.0)) @@ -88,6 +93,5 @@ def _check_result(self, xxx_todo_changeme): self.assertEqual(x_increment, 0.0) - if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_avmc.py b/comtypes/test/test_avmc.py index 2bc8155b..26e653ae 100644 --- a/comtypes/test/test_avmc.py +++ b/comtypes/test/test_avmc.py @@ -4,10 +4,13 @@ from comtypes.test.find_memleak import find_memleak -@unittest.skip("This test does not work. Apparently it's supposed to work with the 'avmc' stuff " - "in comtypes/source, but it doesn't. It's not clear to me why.") +@unittest.skip( + "This test does not work. Apparently it's supposed to work with the 'avmc' stuff " + "in comtypes/source, but it doesn't. It's not clear to me why." +) class Test(unittest.TestCase): """Test COM records""" + def test(self): # The ATL COM dll avmc = CreateObject("AvmcIfc.Avmc.1") @@ -36,5 +39,6 @@ def check_leaks(self, func, limit=0): bytes = find_memleak(func) self.assertFalse(bytes > limit, "Leaks %d bytes" % bytes) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_basic.py b/comtypes/test/test_basic.py index 12451cd2..d8b295bb 100644 --- a/comtypes/test/test_basic.py +++ b/comtypes/test/test_basic.py @@ -5,13 +5,15 @@ # XXX leaks references! + def method_count(interface): - return sum([len(base.__dict__.get("_methods_", ())) - for base in interface.__mro__]) + return sum([len(base.__dict__.get("_methods_", ())) for base in interface.__mro__]) + class BasicTest(ut.TestCase): def test_IUnknown(self): from comtypes import IUnknown + self.assertEqual(method_count(IUnknown), 3) def test_release(self): @@ -19,7 +21,7 @@ def test_release(self): def test_refcounts(self): p = POINTER(IUnknown)() - windll.oleaut32.CreateTypeLib2(1, u"blabla", byref(p)) + windll.oleaut32.CreateTypeLib2(1, "blabla", byref(p)) # initial refcount is 2 for i in range(2, 10): self.assertEqual(p.AddRef(), i) @@ -28,7 +30,7 @@ def test_refcounts(self): def test_qi(self): p = POINTER(IUnknown)() - windll.oleaut32.CreateTypeLib2(1, u"blabla", byref(p)) + windll.oleaut32.CreateTypeLib2(1, "blabla", byref(p)) self.assertEqual(p.AddRef(), 2) self.assertEqual(p.Release(), 1) @@ -38,7 +40,7 @@ def test_qi(self): self.assertEqual(p.Release(), 3) self.assertEqual(other.Release(), 2) - del p # calls p.Release() + del p # calls p.Release() self.assertEqual(other.AddRef(), 2) self.assertEqual(other.Release(), 1) @@ -53,14 +55,12 @@ class IMyInterface(IUnknown): self.assertEqual(method_count(IMyInterface), 3) # assigning _methods_ does not work until we have an _iid_! - self.assertRaises(AttributeError, - setattr, IMyInterface, "_methods_", []) + self.assertRaises(AttributeError, setattr, IMyInterface, "_methods_", []) IMyInterface._iid_ = GUID.create_new() IMyInterface._methods_ = [] self.assertEqual(method_count(IMyInterface), 3) - IMyInterface._methods_ = [ - STDMETHOD(HRESULT, "Blah", [])] + IMyInterface._methods_ = [STDMETHOD(HRESULT, "Blah", [])] self.assertEqual(method_count(IMyInterface), 4) def test_heirarchy(self): @@ -85,6 +85,7 @@ def test_make_methods(self): # XXX leaks 53 refs class IBase(IUnknown): _iid_ = GUID.create_new() + class IDerived(IBase): _iid_ = GUID.create_new() @@ -130,5 +131,6 @@ def test_identity(self): def main(): ut.main() + if __name__ == "__main__": main() diff --git a/comtypes/test/test_casesensitivity.py b/comtypes/test/test_casesensitivity.py index 0f708a52..3820fd94 100644 --- a/comtypes/test/test_casesensitivity.py +++ b/comtypes/test/test_casesensitivity.py @@ -1,11 +1,14 @@ import unittest from comtypes.client import GetModule + iem = GetModule("shdocvw.dll") + class TestCase(unittest.TestCase): def test(self): from comtypes.client import GetModule + iem = GetModule("shdocvw.dll") # IDispatch(IUnknown) @@ -28,11 +31,14 @@ def test(self): # names in the base class __map_case__ must also appear in the # subclass. for name in iem.IWebBrowser.__map_case__: - self.assertTrue(name in iem.IWebBrowserApp.__map_case__, "%s missing" % name) + self.assertTrue( + name in iem.IWebBrowserApp.__map_case__, "%s missing" % name + ) self.assertTrue(name in iem.IWebBrowser2.__map_case__, "%s missing" % name) for name in iem.IWebBrowserApp.__map_case__: self.assertTrue(name in iem.IWebBrowser2.__map_case__, "%s missing" % name) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_client.py b/comtypes/test/test_client.py index e2a1030f..e716a709 100644 --- a/comtypes/test/test_client.py +++ b/comtypes/test/test_client.py @@ -40,8 +40,10 @@ def test_abspath(self): self.assertIs(mod, Scripting) @ut.skipUnless( - os.path.splitdrive(Scripting.typelib_path)[0] == os.path.splitdrive(__file__)[0], - "This depends on typelib and test module are in same drive") + os.path.splitdrive(Scripting.typelib_path)[0] + == os.path.splitdrive(__file__)[0], + "This depends on typelib and test module are in same drive", + ) def test_relpath(self): relpath = os.path.relpath(Scripting.typelib_path, __file__) mod = comtypes.client.GetModule(relpath) @@ -71,6 +73,7 @@ def test_clsid(self): def test_ptr_itypelib(self): from comtypes import typeinfo + mod = comtypes.client.GetModule(typeinfo.LoadTypeLibEx("scrrun.dll")) self.assertIs(mod, Scripting) @@ -105,18 +108,22 @@ def _doit(self, mod): def test_symbols_in_comtypes(self): import comtypes + self._doit(comtypes) def test_symbols_in_comtypes_automation(self): import comtypes.automation + self._doit(comtypes.automation) def test_symbols_in_comtypes_typeinfo(self): import comtypes.typeinfo + self._doit(comtypes.typeinfo) def test_symbols_in_comtypes_persist(self): import comtypes.persist + self._doit(comtypes.persist) @@ -137,39 +144,45 @@ def test_clsid_string(self): comtypes.client.CreateObject(str(Scripting.Dictionary._reg_clsid_)) @ut.skip( - "This test uses IE which is not available on all machines anymore. " - "Find another API to use." + "This test uses IE which is not available on all machines anymore. " + "Find another API to use." ) def test_remote(self): - ie = comtypes.client.CreateObject("InternetExplorer.Application", - machine="localhost") + ie = comtypes.client.CreateObject( + "InternetExplorer.Application", machine="localhost" + ) self.assertEqual(ie.Visible, False) ie.Visible = 1 # on a remote machine, this may not work. Probably depends on # how the server is run. self.assertEqual(ie.Visible, True) - self.assertEqual(0, ie.Quit()) # 0 == S_OK + self.assertEqual(0, ie.Quit()) # 0 == S_OK @ut.skip( - "This test uses IE which is not available on all machines anymore. " - "Find another API to use." + "This test uses IE which is not available on all machines anymore. " + "Find another API to use." ) def test_server_info(self): serverinfo = COSERVERINFO() - serverinfo.pwszName = 'localhost' + serverinfo.pwszName = "localhost" pServerInfo = byref(serverinfo) - self.assertRaises(ValueError, comtypes.client.CreateObject, - "InternetExplorer.Application", machine='localhost', - pServerInfo=pServerInfo) - ie = comtypes.client.CreateObject("InternetExplorer.Application", - pServerInfo=pServerInfo) + self.assertRaises( + ValueError, + comtypes.client.CreateObject, + "InternetExplorer.Application", + machine="localhost", + pServerInfo=pServerInfo, + ) + ie = comtypes.client.CreateObject( + "InternetExplorer.Application", pServerInfo=pServerInfo + ) self.assertEqual(ie.Visible, False) ie.Visible = 1 # on a remote machine, this may not work. Probably depends on # how the server is run. self.assertEqual(ie.Visible, True) - self.assertEqual(0, ie.Quit()) # 0 == S_OK + self.assertEqual(0, ie.Quit()) # 0 == S_OK class Test_Constants(ut.TestCase): @@ -225,14 +238,23 @@ def test_progid(self): def test_returns_other_than_enum_members(self): obj = comtypes.client.CreateObject("SAPI.SpVoice") from comtypes.gen import SpeechLib as sapi + consts = comtypes.client.Constants(obj) # int (Constant c_int) self.assertEqual(consts.Speech_Max_Word_Length, sapi.Speech_Max_Word_Length) # str (Constant BSTR) - self.assertEqual(consts.SpeechVoiceSkipTypeSentence, sapi.SpeechVoiceSkipTypeSentence) - self.assertEqual(consts.SpeechAudioFormatGUIDWave, sapi.SpeechAudioFormatGUIDWave) - self.assertEqual(consts.SpeechRegistryLocalMachineRoot, sapi.SpeechRegistryLocalMachineRoot) - self.assertEqual(consts.SpeechGrammarTagDictation, sapi.SpeechGrammarTagDictation) + self.assertEqual( + consts.SpeechVoiceSkipTypeSentence, sapi.SpeechVoiceSkipTypeSentence + ) + self.assertEqual( + consts.SpeechAudioFormatGUIDWave, sapi.SpeechAudioFormatGUIDWave + ) + self.assertEqual( + consts.SpeechRegistryLocalMachineRoot, sapi.SpeechRegistryLocalMachineRoot + ) + self.assertEqual( + consts.SpeechGrammarTagDictation, sapi.SpeechGrammarTagDictation + ) # float (Constant c_float) self.assertEqual(consts.Speech_Default_Weight, sapi.Speech_Default_Weight) diff --git a/comtypes/test/test_collections.py b/comtypes/test/test_collections.py index 7de901fa..943c608b 100644 --- a/comtypes/test/test_collections.py +++ b/comtypes/test/test_collections.py @@ -6,10 +6,9 @@ class Test(unittest.TestCase): - def test_IEnumVARIANT(self): # The XP firewall manager. - fwmgr = CreateObject('HNetCfg.FwMgr') + fwmgr = CreateObject("HNetCfg.FwMgr") # apps has a _NewEnum property that implements IEnumVARIANT services = fwmgr.LocalPolicy.CurrentProfile.Services @@ -51,8 +50,7 @@ def test_IEnumVARIANT(self): # We can now call Next(celt) with celt != 1, the call always returns a # list: cv.Reset() - self.assertEqual(names[:3], - [p.Name for p in cv.Next(3)]) + self.assertEqual(names[:3], [p.Name for p in cv.Next(3)]) # calling Next(0) makes no sense, but should work anyway: self.assertEqual(cv.Next(0), []) @@ -67,32 +65,34 @@ def test_IEnumVARIANT(self): @unittest.skip("This test takes a long time. Do we need it? Can it be rewritten?") def test_leaks_1(self): # The XP firewall manager. - fwmgr = CreateObject('HNetCfg.FwMgr') + fwmgr = CreateObject("HNetCfg.FwMgr") # apps has a _NewEnum property that implements IEnumVARIANT apps = fwmgr.LocalPolicy.CurrentProfile.AuthorizedApplications def doit(): for item in iter(apps): item.ProcessImageFileName + bytes = find_memleak(doit, (20, 20)) self.assertFalse(bytes, "Leaks %d bytes" % bytes) @unittest.skip("This test takes a long time. Do we need it? Can it be rewritten?") def test_leaks_2(self): # The XP firewall manager. - fwmgr = CreateObject('HNetCfg.FwMgr') + fwmgr = CreateObject("HNetCfg.FwMgr") # apps has a _NewEnum property that implements IEnumVARIANT apps = fwmgr.LocalPolicy.CurrentProfile.AuthorizedApplications def doit(): iter(apps).Next(99) + bytes = find_memleak(doit, (20, 20)) self.assertFalse(bytes, "Leaks %d bytes" % bytes) @unittest.skip("This test takes a long time. Do we need it? Can it be rewritten?") def test_leaks_3(self): # The XP firewall manager. - fwmgr = CreateObject('HNetCfg.FwMgr') + fwmgr = CreateObject("HNetCfg.FwMgr") # apps has a _NewEnum property that implements IEnumVARIANT apps = fwmgr.LocalPolicy.CurrentProfile.AuthorizedApplications @@ -100,12 +100,13 @@ def doit(): for i in range(2): for what in iter(apps): pass + bytes = find_memleak(doit, (20, 20)) self.assertFalse(bytes, "Leaks %d bytes" % bytes) class TestCollectionInterface(unittest.TestCase): - """ Test the early-bound collection interface. """ + """Test the early-bound collection interface.""" def setUp(self): self.d = CreateObject("Scripting.Dictionary", dynamic=False) @@ -114,7 +115,7 @@ def tearDown(self): del self.d def assertAccessInterface(self, d): - """ Asserts access via indexing and named property """ + """Asserts access via indexing and named property""" self.assertEqual(d.CompareMode, 42) self.assertEqual(d["foo"], 1) self.assertEqual(d.Item["foo"], d["foo"]) diff --git a/comtypes/test/test_comserver.py b/comtypes/test/test_comserver.py index 2b966eb2..ee0b7cdc 100644 --- a/comtypes/test/test_comserver.py +++ b/comtypes/test/test_comserver.py @@ -9,18 +9,20 @@ def setUpModule(): - raise unittest.SkipTest("This test requires the tests to be run as admin since it tries to " - "register the test COM server. Is this a good idea?") + raise unittest.SkipTest( + "This test requires the tests to be run as admin since it tries to " + "register the test COM server. Is this a good idea?" + ) # If this test is ever NOT skipped, then this line needs to run. Keeping it here for posterity. register(comtypes.test.TestComServer.TestComServer) class TestInproc(unittest.TestCase): - def create_object(self): - return CreateObject("TestComServerLib.TestComServer", - clsctx = comtypes.CLSCTX_INPROC_SERVER) + return CreateObject( + "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_INPROC_SERVER + ) def _find_memleak(self, func): bytes = find_memleak(func) @@ -54,6 +56,7 @@ def test_getname(self): self.assertEqual(pb[0], name) if is_resource_enabled("memleaks"): + def test_get_id(self): obj = self.create_object() self._find_memleak(lambda: obj.id) @@ -64,43 +67,55 @@ def test_get_name(self): def test_set_name(self): obj = self.create_object() + def func(): - obj.name = u"abcde" + obj.name = "abcde" + self._find_memleak(func) def test_SetName(self): obj = self.create_object() + def func(): - obj.SetName(u"abcde") - self._find_memleak(func) + obj.SetName("abcde") + self._find_memleak(func) def test_eval(self): obj = self.create_object() + def func(): return obj.eval("(1, 2, 3)") + self.assertEqual(func(), (1, 2, 3)) self._find_memleak(func) def test_get_typeinfo(self): obj = self.create_object() + def func(): obj.GetTypeInfo(0) obj.GetTypeInfoCount() obj.QueryInterface(comtypes.IUnknown) + self._find_memleak(func) + if is_resource_enabled("ui"): + class TestLocalServer(TestInproc): def create_object(self): - return CreateObject("TestComServerLib.TestComServer", - clsctx = comtypes.CLSCTX_LOCAL_SERVER) + return CreateObject( + "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_LOCAL_SERVER + ) + try: from win32com.client import Dispatch except ImportError: pass else: + class TestInproc_win32com(TestInproc): def create_object(self): return Dispatch("TestComServerLib.TestComServer") @@ -118,9 +133,14 @@ def test_mixedinout(self): pass if is_resource_enabled("ui"): + class TestLocalServer_win32com(TestInproc_win32com): def create_object(self): - return Dispatch("TestComServerLib.TestComServer", clsctx = comtypes.CLSCTX_LOCAL_SERVER) + return Dispatch( + "TestComServerLib.TestComServer", + clsctx=comtypes.CLSCTX_LOCAL_SERVER, + ) + import doctest import comtypes.test.test_comserver @@ -133,8 +153,9 @@ def test(self): # The following functions are never called, they only contain doctests: if sys.version_info >= (3, 0): + def ShowEvents(self): - ''' + """ >>> from comtypes.client import CreateObject, ShowEvents >>> >>> o = CreateObject("TestComServerLib.TestComServer") @@ -147,10 +168,12 @@ def ShowEvents(self): >>> result 2.5 >>> - ''' + """ + else: + def ShowEvents(self): - ''' + """ >>> from comtypes.client import CreateObject, ShowEvents >>> >>> o = CreateObject("TestComServerLib.TestComServer") @@ -163,14 +186,15 @@ def ShowEvents(self): >>> result 2.5 >>> - ''' + """ # The following test, if enabled, works but the testsuit # crashes elsewhere. Is there s problem with SAFEARRAYs? if is_resource_enabled("CRASHES"): + def Fails(self): - ''' + """ >>> from comtypes.client import CreateObject, ShowEvents >>> >>> o = CreateObject("TestComServerLib.TestComServer") @@ -183,7 +207,7 @@ def Fails(self): >>> result (u'32', u'32') >>> - ''' + """ def GetEvents(self): """ @@ -210,5 +234,6 @@ def GetEvents(self): >>> """ + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_createwrappers.py b/comtypes/test/test_createwrappers.py index e0dafe90..3d9fee00 100644 --- a/comtypes/test/test_createwrappers.py +++ b/comtypes/test/test_createwrappers.py @@ -11,17 +11,19 @@ def setUpModule(): - raise unittest.SkipTest("I have no idea what to do with this. It programmatically creates " - "*thousands* of tests and a few dozen of them fail.") + raise unittest.SkipTest( + "I have no idea what to do with this. It programmatically creates " + "*thousands* of tests and a few dozen of them fail." + ) # requires("typelibs") # filter warnings about interfaces without a base interface; they will # be skipped in the code generation. -warnings.filterwarnings("ignore", - "Ignoring interface .* which has no base interface", - UserWarning) +warnings.filterwarnings( + "ignore", "Ignoring interface .* which has no base interface", UserWarning +) # don't print messages when typelib wrappers are generated comtypes.client._generate.__verbose__ = False @@ -34,6 +36,7 @@ def setUpModule(): # This test takes quite some time. It tries to build wrappers for ALL # .dll, .tlb, and .ocx files in the system directory which contain typelibs. + class Test(unittest.TestCase): def setUp(self): "Do not write the generated files into the comtypes.gen directory" @@ -42,10 +45,13 @@ def setUp(self): def tearDown(self): comtypes.client.gen_dir = comtypes.client._find_gen_dir() + number = 0 + def add_test(fname): global number + def test(self): try: comtypes.typeinfo.LoadTypeLibEx(fname) @@ -57,6 +63,7 @@ def test(self): setattr(Test, "test_%d" % number, test) number += 1 + for fname in glob.glob(os.path.join(sysdir, "*.ocx")): add_test(fname) @@ -65,23 +72,26 @@ def test(self): for fname in glob.glob(os.path.join(progdir, r"Microsoft Office\Office*\*.tlb")): if os.path.basename(fname).lower() in ( - "grde50.olb", # UnicodeEncodeError - "xl5de32.olb", # UnicodeEncodeError - "grde50.olb", # UnicodeEncodeError - ): + "grde50.olb", # UnicodeEncodeError + "xl5de32.olb", # UnicodeEncodeError + "grde50.olb", # UnicodeEncodeError + ): continue add_test(fname) for fname in glob.glob(os.path.join(progdir, r"Microsoft Office\Office*\*.olb")): if os.path.basename(fname).lower() in ( - "grde50.olb", # UnicodeEncodeError - "xl5de32.olb", # UnicodeEncodeError - "grde50.olb", # UnicodeEncodeError - ): + "grde50.olb", # UnicodeEncodeError + "xl5de32.olb", # UnicodeEncodeError + "grde50.olb", # UnicodeEncodeError + ): continue add_test(fname) -path = os.path.join(progdir, r"Microsoft Visual Studio .NET 2003\Visual Studio SDKs\DIA SDK\bin\msdia71.dll") +path = os.path.join( + progdir, + r"Microsoft Visual Studio .NET 2003\Visual Studio SDKs\DIA SDK\bin\msdia71.dll", +) if os.path.isfile(path): print("ADD", path) add_test(path) @@ -92,18 +102,17 @@ def test(self): for fname in glob.glob(os.path.join(sysdir, "*.dll")): # these typelibs give errors: if os.path.basename(fname).lower() in ( - "syncom.dll", # interfaces without base interface - "msvidctl.dll", # assignment to None - "scardssp.dll", # assertionerror sizeof() - "sccsccp.dll", # assertionerror sizeof() - + "syncom.dll", # interfaces without base interface + "msvidctl.dll", # assignment to None + "scardssp.dll", # assertionerror sizeof() + "sccsccp.dll", # assertionerror sizeof() # Typeinfo in comsvcs.dll in XP 64-bit SP 1 is broken. # Oleview decompiles this code snippet (^ marks are m): - #[ + # [ # odl, # uuid(C7B67079-8255-42C6-9EC0-6994A3548780) - #] - #interface IAppDomainHelper : IDispatch { + # ] + # interface IAppDomainHelper : IDispatch { # HRESULT _stdcall pfnShutdownCB(void* pv); # HRESULT _stdcall Initialize( # [in] IUnknown* pUnkAD, @@ -116,9 +125,9 @@ def test(self): # [in] IAppDomainHelper __MIDL_0029, # ^^^^^^^^^^^^^^^^ # [in] void* pPool); - #}; + # }; "comsvcs.dll", - ): + ): continue add_test(fname) diff --git a/comtypes/test/test_dict.py b/comtypes/test/test_dict.py index c2e21aa2..1df38d58 100644 --- a/comtypes/test/test_dict.py +++ b/comtypes/test/test_dict.py @@ -90,8 +90,7 @@ def test_dict(self): # iter(d) keys = [x for x in d] - self.assertEqual(d.Keys(), - tuple([x for x in d])) + self.assertEqual(d.Keys(), tuple([x for x in d])) # d[key] = value # d[key] -> value @@ -100,5 +99,6 @@ def test_dict(self): # d(key) -> value self.assertEqual(d("blah"), "blarg") + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_dispinterface.py b/comtypes/test/test_dispinterface.py index 6912c10e..91b7a855 100644 --- a/comtypes/test/test_dispinterface.py +++ b/comtypes/test/test_dispinterface.py @@ -6,8 +6,10 @@ def setUpModule(): - raise unittest.SkipTest("This test requires the tests to be run as admin since it tries to " - "register the test COM server. Is this a good idea?") + raise unittest.SkipTest( + "This test requires the tests to be run as admin since it tries to " + "register the test COM server. Is this a good idea?" + ) # If this test is ever NOT skipped, then this line needs to run. Keeping it here for posterity. register(comtypes.test.TestDispServer.TestDispServer) @@ -16,20 +18,24 @@ def setUpModule(): class Test(unittest.TestCase): if is_resource_enabled("pythoncom"): + def test_win32com(self): # EnsureDispatch is case-sensitive from win32com.client.gencache import EnsureDispatch + d = EnsureDispatch("TestDispServerLib.TestDispServer") self.assertEqual(d.eval("3.14"), 3.14) self.assertEqual(d.eval("1 + 2"), 3) - self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, "foo", None)) self.assertEqual(d.eval2("3.14"), 3.14) self.assertEqual(d.eval2("1 + 2"), 3) - self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, "foo", None)) - d.eval("__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')") + d.eval( + "__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')" + ) server_id = d.eval("id(self)") self.assertEqual(d.id, server_id) @@ -45,25 +51,28 @@ def test_win32com(self): def test_win32com_dyndispatch(self): # dynamic Dispatch is case-IN-sensitive from win32com.client.dynamic import Dispatch + d = Dispatch("TestDispServerLib.TestDispServer") self.assertEqual(d.eval("3.14"), 3.14) self.assertEqual(d.eval("1 + 2"), 3) - self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, "foo", None)) self.assertEqual(d.eval2("3.14"), 3.14) self.assertEqual(d.eval2("1 + 2"), 3) - self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, "foo", None)) - d.eval("__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')") + d.eval( + "__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')" + ) self.assertEqual(d.EVAL("3.14"), 3.14) self.assertEqual(d.EVAL("1 + 2"), 3) - self.assertEqual(d.EVAL("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.EVAL("[1 + 2, 'foo', None]"), (3, "foo", None)) self.assertEqual(d.EVAL2("3.14"), 3.14) self.assertEqual(d.EVAL2("1 + 2"), 3) - self.assertEqual(d.EVAL2("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.EVAL2("[1 + 2, 'foo', None]"), (3, "foo", None)) server_id = d.eval("id(self)") self.assertEqual(d.id, server_id) @@ -81,25 +90,28 @@ def test_win32com_dyndispatch(self): def test_comtypes(self): from comtypes.client import CreateObject + d = CreateObject("TestDispServerLib.TestDispServer") self.assertEqual(d.eval("3.14"), 3.14) self.assertEqual(d.eval("1 + 2"), 3) - self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval("[1 + 2, 'foo', None]"), (3, "foo", None)) self.assertEqual(d.eval2("3.14"), 3.14) self.assertEqual(d.eval2("1 + 2"), 3) - self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.eval2("[1 + 2, 'foo', None]"), (3, "foo", None)) - d.eval("__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')") + d.eval( + "__import__('comtypes.client').client.CreateObject('Scripting.Dictionary')" + ) self.assertEqual(d.EVAL("3.14"), 3.14) self.assertEqual(d.EVAL("1 + 2"), 3) - self.assertEqual(d.EVAL("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.EVAL("[1 + 2, 'foo', None]"), (3, "foo", None)) self.assertEqual(d.EVAL2("3.14"), 3.14) self.assertEqual(d.EVAL2("1 + 2"), 3) - self.assertEqual(d.EVAL2("[1 + 2, 'foo', None]"), (3, 'foo', None)) + self.assertEqual(d.EVAL2("[1 + 2, 'foo', None]"), (3, "foo", None)) server_id = d.eval("id(self)") self.assertEqual(d.id, server_id) @@ -116,9 +128,11 @@ def test_comtypes(self): def test_withjscript(self): import os + jscript = os.path.join(os.path.dirname(__file__), "test_jscript.js") errcode = os.system("cscript -nologo %s" % jscript) self.assertEqual(errcode, 0) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_dyndispatch.py b/comtypes/test/test_dyndispatch.py index af502c95..ef4c8ee1 100644 --- a/comtypes/test/test_dyndispatch.py +++ b/comtypes/test/test_dyndispatch.py @@ -9,7 +9,6 @@ class Test(unittest.TestCase): - def setUp(self): self.d = CreateObject("Scripting.Dictionary", dynamic=True) @@ -72,7 +71,7 @@ def test_named_property_not_iterable(self): self.assertRaises(TypeError, list, self.d.Item) def assertAccessInterface(self, d): - """ Asserts access via indexing and named property """ + """Asserts access via indexing and named property""" self.assertEqual(d.CompareMode, 42) self.assertEqual(d["foo"], 1) self.assertEqual(d.Item["foo"], d["foo"]) diff --git a/comtypes/test/test_excel.py b/comtypes/test/test_excel.py index 8aa9d61e..42e6c12a 100644 --- a/comtypes/test/test_excel.py +++ b/comtypes/test/test_excel.py @@ -19,6 +19,7 @@ try: GetModule(("{00020813-0000-0000-C000-000000000046}",)) # Excel libUUID from comtypes.gen.Excel import xlRangeValueDefault + IMPORT_FAILED = False except (ImportError, OSError): IMPORT_FAILED = True @@ -47,55 +48,52 @@ def test(self): wb = xl.Workbooks.Add() # Test with empty-tuple argument - xl.Range["A1", "C1"].Value[()] = (10,"20",31.4) # XXX: in Python >= 3.8.x, cannot set values to A1:C1 - xl.Range["A2:C2"].Value[()] = ('x','y','z') + xl.Range["A1", "C1"].Value[()] = ( + 10, + "20", + 31.4, + ) # XXX: in Python >= 3.8.x, cannot set values to A1:C1 + xl.Range["A2:C2"].Value[()] = ("x", "y", "z") # Test with empty slice argument - xl.Range["A3:C3"].Value[:] = ('3','2','1') + xl.Range["A3:C3"].Value[:] = ("3", "2", "1") # not implemented: # xl.Range["A4:C4"].Value = ("3", "2" ,"1") # call property to retrieve value - expected_values = ((10.0, 20.0, 31.4), - ("x", "y", "z"), - (3.0, 2.0, 1.0)) + expected_values = ((10.0, 20.0, 31.4), ("x", "y", "z"), (3.0, 2.0, 1.0)) # XXX: in Python >= 3.8.x, fails below - self.assertEqual(xl.Range["A1:C3"].Value(), - expected_values) + self.assertEqual(xl.Range["A1:C3"].Value(), expected_values) # index with empty tuple - self.assertEqual(xl.Range["A1:C3"].Value[()], - expected_values) + self.assertEqual(xl.Range["A1:C3"].Value[()], expected_values) # index with empty slice - self.assertEqual(xl.Range["A1:C3"].Value[:], - expected_values) - self.assertEqual(xl.Range["A1:C3"].Value[xlRangeValueDefault], - expected_values) - self.assertEqual(xl.Range["A1", "C3"].Value[()], - expected_values) + self.assertEqual(xl.Range["A1:C3"].Value[:], expected_values) + self.assertEqual(xl.Range["A1:C3"].Value[xlRangeValueDefault], expected_values) + self.assertEqual(xl.Range["A1", "C3"].Value[()], expected_values) # Test for iteration support in "Range" interface iter(xl.Range["A1:C3"]) - self.assertEqual([c.Value() for c in xl.Range["A1:C3"]], - [10.0, 20.0, 31.4, - "x", "y", "z", - 3.0, 2.0, 1.0]) + self.assertEqual( + [c.Value() for c in xl.Range["A1:C3"]], + [10.0, 20.0, 31.4, "x", "y", "z", 3.0, 2.0, 1.0], + ) # With pywin32, one could write xl.Cells(a, b) # With comtypes, one must write xl.Cells.Item(1, b) for i in range(20): val = "Hi %d" % i - xl.Cells.Item[i+1,i+1].Value[()] = val - self.assertEqual(xl.Cells.Item[i+1, i+1].Value[()], val) + xl.Cells.Item[i + 1, i + 1].Value[()] = val + self.assertEqual(xl.Cells.Item[i + 1, i + 1].Value[()], val) for i in range(20): val = "Hi %d" % i - xl.Cells(i+1,i+1).Value[()] = val - self.assertEqual(xl.Cells(i+1, i+1).Value[()], val) + xl.Cells(i + 1, i + 1).Value[()] = val + self.assertEqual(xl.Cells(i + 1, i + 1).Value[()], val) # test dates out with Excel xl.Range["A5"].Value[()] = "Excel time" xl.Range["B5"].Formula = "=Now()" - self.assertEqual(xl.Cells.Item[5,2].Formula, "=NOW()") + self.assertEqual(xl.Cells.Item[5, 2].Formula, "=NOW()") xl.Range["A6"].Calculate() excel_time = xl.Range["B5"].Value[()] @@ -108,15 +106,17 @@ def test(self): # some random code, grabbed from c.l.p sh = wb.Worksheets[1] - sh.Cells.Item[1,1].Value[()] = "Hello World!" - sh.Cells.Item[3,3].Value[()] = "Hello World!" - sh.Range[sh.Cells.Item[1,1],sh.Cells.Item[3,3]].Copy(sh.Cells.Item[4,1]) - sh.Range[sh.Cells.Item[4,1],sh.Cells.Item[6,3]].Select() + sh.Cells.Item[1, 1].Value[()] = "Hello World!" + sh.Cells.Item[3, 3].Value[()] = "Hello World!" + sh.Range[sh.Cells.Item[1, 1], sh.Cells.Item[3, 3]].Copy(sh.Cells.Item[4, 1]) + sh.Range[sh.Cells.Item[4, 1], sh.Cells.Item[6, 3]].Select() @unittest.skipIf(IMPORT_FAILED, "This depends on Excel.") -@unittest.skip("There is difference of `Range.Value` behavior " - "between Python >= 3.8.x and Python <= 3.7.x.") +@unittest.skip( + "There is difference of `Range.Value` behavior " + "between Python >= 3.8.x and Python <= 3.7.x." +) class Test_EarlyBind(BaseBindTest, unittest.TestCase): dynamic = False diff --git a/comtypes/test/test_findgendir.py b/comtypes/test/test_findgendir.py index c1025976..bd38e5f2 100644 --- a/comtypes/test/test_findgendir.py +++ b/comtypes/test/test_findgendir.py @@ -15,10 +15,12 @@ imgbase = os.path.splitext(os.path.basename(sys.executable))[0] + class Test(unittest.TestCase): """Test the comtypes.client._find_gen_dir() function in several simulated environments. """ + def setUp(self): # save the original comtypes.gen modules and create a # substitute with an empty __path__. @@ -54,26 +56,32 @@ def test_frozen_dll(self): ma, mi = sys.version_info[:2] # %TEMP%\comtypes_cache\-25 # the image is python25.dll - path = os.path.join(tempfile.gettempdir(), - r"comtypes_cache\%s%d%d-%d%d" % (imgbase, ma, mi, ma, mi)) + path = os.path.join( + tempfile.gettempdir(), + r"comtypes_cache\%s%d%d-%d%d" % (imgbase, ma, mi, ma, mi), + ) gen_dir = comtypes.client._find_gen_dir() self.assertEqual(path, gen_dir) def test_frozen_console_exe(self): sys.frozen = "console_exe" # %TEMP%\comtypes_cache\-25 - path = os.path.join(tempfile.gettempdir(), - r"comtypes_cache\%s-%d%d" % ( - imgbase, sys.version_info[0], sys.version_info[1])) + path = os.path.join( + tempfile.gettempdir(), + r"comtypes_cache\%s-%d%d" + % (imgbase, sys.version_info[0], sys.version_info[1]), + ) gen_dir = comtypes.client._find_gen_dir() self.assertEqual(path, gen_dir) def test_frozen_windows_exe(self): sys.frozen = "windows_exe" # %TEMP%\comtypes_cache\-25 - path = os.path.join(tempfile.gettempdir(), - r"comtypes_cache\%s-%d%d" % ( - imgbase, sys.version_info[0], sys.version_info[1])) + path = os.path.join( + tempfile.gettempdir(), + r"comtypes_cache\%s-%d%d" + % (imgbase, sys.version_info[0], sys.version_info[1]), + ) gen_dir = comtypes.client._find_gen_dir() self.assertEqual(path, gen_dir) @@ -81,5 +89,6 @@ def test_frozen_windows_exe(self): def main(): unittest.main() + if __name__ == "__main__": main() diff --git a/comtypes/test/test_getactiveobj.py b/comtypes/test/test_getactiveobj.py index 120ec7d3..f15c80b5 100644 --- a/comtypes/test/test_getactiveobj.py +++ b/comtypes/test/test_getactiveobj.py @@ -8,8 +8,10 @@ def setUpModule(): - raise unittest.SkipTest("External test dependencies like this seem bad. Find a different " - "built-in win32 API to use.") + raise unittest.SkipTest( + "External test dependencies like this seem bad. Find a different " + "built-in win32 API to use." + ) class Test(unittest.TestCase): @@ -18,7 +20,6 @@ def tearDown(self): self.w1.Quit() del self.w1 - def test(self): try: comtypes.client.GetActiveObject("Word.Application") @@ -34,13 +35,15 @@ def test(self): w2 = comtypes.client.GetActiveObject("Word.Application") # check if they are referring to the same object - self.assertEqual(w1.QueryInterface(comtypes.IUnknown), - w2.QueryInterface(comtypes.IUnknown)) + self.assertEqual( + w1.QueryInterface(comtypes.IUnknown), w2.QueryInterface(comtypes.IUnknown) + ) w1.Quit() del self.w1 import time + time.sleep(1) try: @@ -51,7 +54,9 @@ def test(self): else: raise AssertionError("COMError not raised") - self.assertRaises(WindowsError, comtypes.client.GetActiveObject, "Word.Application") + self.assertRaises( + WindowsError, comtypes.client.GetActiveObject, "Word.Application" + ) if __name__ == "__main__": diff --git a/comtypes/test/test_ie.py b/comtypes/test/test_ie.py index c10e6f39..82cc04fc 100644 --- a/comtypes/test/test_ie.py +++ b/comtypes/test/test_ie.py @@ -8,8 +8,10 @@ def setUpModule(): - raise ut.SkipTest("External test dependencies like this seem bad. Find a different built-in " - "win32 API to use.") + raise ut.SkipTest( + "External test dependencies like this seem bad. Find a different built-in " + "win32 API to use." + ) class EventSink: @@ -44,19 +46,23 @@ def DocumentComplete(self, this, *args): class POINT(Structure): - _fields_ = [("x", c_long), - ("y", c_long)] + _fields_ = [("x", c_long), ("y", c_long)] + class MSG(Structure): - _fields_ = [("hWnd", c_ulong), - ("message", c_uint), - ("wParam", c_ulong), - ("lParam", c_ulong), - ("time", c_ulong), - ("pt", POINT)] + _fields_ = [ + ("hWnd", c_ulong), + ("message", c_uint), + ("wParam", c_ulong), + ("lParam", c_ulong), + ("time", c_ulong), + ("pt", POINT), + ] + def PumpWaitingMessages(): from ctypes import windll, byref + user32 = windll.user32 msg = MSG() PM_REMOVE = 0x0001 @@ -64,12 +70,14 @@ def PumpWaitingMessages(): user32.TranslateMessage(byref(msg)) user32.DispatchMessageA(byref(msg)) -class Test(ut.TestCase): +class Test(ut.TestCase): def tearDown(self): import gc + gc.collect() import time + time.sleep(2) def test_default_eventinterface(self): @@ -79,15 +87,23 @@ def test_default_eventinterface(self): ie.Visible = True ie.Navigate2(URL="http://docs.python.org/", Flags=0) import time + for i in range(50): PumpWaitingMessages() time.sleep(0.1) ie.Visible = False ie.Quit() - self.assertEqual(sink._events, ['OnVisible', 'BeforeNavigate2', - 'NavigateComplete2', 'DocumentComplete', - 'OnVisible']) + self.assertEqual( + sink._events, + [ + "OnVisible", + "BeforeNavigate2", + "NavigateComplete2", + "DocumentComplete", + "OnVisible", + ], + ) del ie del conn @@ -96,19 +112,22 @@ def test_nondefault_eventinterface(self): sink = EventSink() ie = CreateObject("InternetExplorer.Application") import comtypes.gen.SHDocVw as mod + conn = GetEvents(ie, sink, interface=mod.DWebBrowserEvents) ie.Visible = True ie.Navigate2(Flags=0, URL="http://docs.python.org/") import time + for i in range(50): PumpWaitingMessages() time.sleep(0.1) ie.Visible = False ie.Quit() - self.assertEqual(sink._events, ['BeforeNavigate', 'NavigateComplete']) + self.assertEqual(sink._events, ["BeforeNavigate", "NavigateComplete"]) del ie + if __name__ == "__main__": ut.main() diff --git a/comtypes/test/test_msscript.py b/comtypes/test/test_msscript.py index 827beccc..84568abf 100644 --- a/comtypes/test/test_msscript.py +++ b/comtypes/test/test_msscript.py @@ -27,15 +27,15 @@ def test_jscript(self): # dispproperties varies, depending on the length of the list we pass # to Eval): # - #class JScriptTypeInfo(comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0.IDispatch): + # class JScriptTypeInfo(comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0.IDispatch): # 'JScript Type Info' # _iid_ = GUID('{C59C6B12-F6C1-11CF-8835-00A0C911E8B2}') # _idlflags_ = [] # _methods_ = [] - #JScriptTypeInfo._disp_methods_ = [ + # JScriptTypeInfo._disp_methods_ = [ # DISPPROPERTY([dispid(9522932)], VARIANT, '0'), # DISPPROPERTY([dispid(9522976)], VARIANT, '1'), - #] + # ] # # Although the exact interface members vary, the guid stays # the same. Don't think that's allowed by COM standards - is @@ -56,19 +56,18 @@ def test_jscript(self): tinfo_2 = engine.Eval("[1, 2, 3, 4]")._comobj.GetTypeInfo(0) tinfo_3 = engine.Eval("[1, 2, 3, 4, 5]")._comobj.GetTypeInfo(0) - self.assertEqual(tinfo_1.GetTypeAttr().cVars, 3) self.assertEqual(tinfo_2.GetTypeAttr().cVars, 4) self.assertEqual(tinfo_3.GetTypeAttr().cVars, 5) # These tests simply describe the current behaviour ;-) - self.assertEqual(tinfo_1.GetTypeAttr().guid, - tinfo_1.GetTypeAttr().guid) + self.assertEqual(tinfo_1.GetTypeAttr().guid, tinfo_1.GetTypeAttr().guid) ## print (res[0], res[1], res[2]) ## print len(res) engine.Reset() + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_npsupport.py b/comtypes/test/test_npsupport.py index c33f383e..6f8c94af 100644 --- a/comtypes/test/test_npsupport.py +++ b/comtypes/test/test_npsupport.py @@ -17,7 +17,7 @@ _midlSAFEARRAY, VARIANT, VT_VARIANT, - VARIANT_BOOL + VARIANT_BOOL, ) from comtypes.safearray import safearray_as_ndarray @@ -42,6 +42,7 @@ def get_ndarray(sa): def com_refcnt(o): """Return the COM refcount of an interface pointer""" import gc + gc.collect() gc.collect() o.AddRef() @@ -60,12 +61,14 @@ def decorator_enabled_disabled(func): @functools.wraps(func) def call_enabled(self): from comtypes import npsupport + npsupport.enable() func(self) @functools.wraps(func) def call_disabled(self): from comtypes import npsupport + if npsupport.enabled: raise EnvironmentError( "Expected numpy interop not to be enabled but it is." @@ -115,12 +118,14 @@ def test_nested_contexts(self): ) def test_datetime64_ndarray(self): comtypes.npsupport.enable() - dates = numpy.array([ - numpy.datetime64("2000-01-01T05:30:00", "s"), - numpy.datetime64("1800-01-01T05:30:00", "ms"), - numpy.datetime64("2014-03-07T00:12:56", "us"), - numpy.datetime64("2000-01-01T12:34:56", "ns"), - ]) + dates = numpy.array( + [ + numpy.datetime64("2000-01-01T05:30:00", "s"), + numpy.datetime64("1800-01-01T05:30:00", "ms"), + numpy.datetime64("2014-03-07T00:12:56", "us"), + numpy.datetime64("2000-01-01T12:34:56", "ns"), + ] + ) t = _midlSAFEARRAY(VARIANT) sa = t.from_param(dates) @@ -148,7 +153,7 @@ def test_UDT_ndarray(self): if arr.dtype is numpy.dtype(object): data = [(x.red, x.green, x.blue) for x in arr] else: - float_dtype = numpy.dtype('float64') + float_dtype = numpy.dtype("float64") self.assertIs(arr.dtype[0], float_dtype) self.assertIs(arr.dtype[1], float_dtype) self.assertIs(arr.dtype[2], float_dtype) @@ -226,6 +231,7 @@ def test_VT_UNKNOWN_multi_ndarray(self): self.assertTrue(a is t) from comtypes.typeinfo import CreateTypeLib + # will never be saved to disk punk = CreateTypeLib("spam").QueryInterface(IUnknown) @@ -242,7 +248,7 @@ def test_VT_UNKNOWN_multi_ndarray(self): arr = get_ndarray(sa) self.assertTrue(isinstance(arr, numpy.ndarray)) self.assertEqual(numpy.dtype(object), arr.dtype) - self.assertTrue((arr == (punk,)*4).all()) + self.assertTrue((arr == (punk,) * 4).all()) self.assertEqual(initial + 8, com_refcnt(punk)) del arr @@ -294,7 +300,7 @@ def setUp(self): @enabled_disabled(disabled_error=ValueError) def test_double(self): - for dtype in ('float32', 'float64'): + for dtype in ("float32", "float64"): # because of FLOAT rounding errors, whi will only work for # certain values! a = numpy.array([1.0, 2.0, 3.0, 4.5], dtype=dtype) @@ -304,8 +310,16 @@ def test_double(self): @enabled_disabled(disabled_error=ValueError) def test_int(self): - for dtype in ('int8', 'int16', 'int32', 'int64', 'uint8', - 'uint16', 'uint32', 'uint64'): + for dtype in ( + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + ): a = numpy.array((1, 1, 1, 1), dtype=dtype) v = VARIANT() v.value = a @@ -316,7 +330,7 @@ def test_datetime64(self): dates = [ numpy.datetime64("2000-01-01T05:30:00", "s"), numpy.datetime64("1800-01-01T05:30:00", "ms"), - numpy.datetime64("2000-01-01T12:34:56", "us") + numpy.datetime64("2000-01-01T12:34:56", "us"), ] for date in dates: @@ -332,8 +346,7 @@ def test_datetime64(self): def test_mixed(self): comtypes.npsupport.enable() now = datetime.datetime.now() - a = numpy.array( - [11, "22", None, True, now, Decimal("3.14")]).reshape(2, 3) + a = numpy.array([11, "22", None, True, now, Decimal("3.14")]).reshape(2, 3) v = VARIANT() v.value = a self.assertTrue((v.value == a).all()) diff --git a/comtypes/test/test_outparam.py b/comtypes/test/test_outparam.py index 797929e1..de349670 100644 --- a/comtypes/test/test_outparam.py +++ b/comtypes/test/test_outparam.py @@ -13,27 +13,24 @@ else: text_type = unicode + class IMalloc(IUnknown): _iid_ = GUID("{00000002-0000-0000-C000-000000000046}") _methods_ = [ - COMMETHOD([], c_void_p, "Alloc", - ([], c_ulong, "cb")), - COMMETHOD([], c_void_p, "Realloc", - ([], c_void_p, "pv"), - ([], c_ulong, "cb")), - COMMETHOD([], None, "Free", - ([], c_void_p, "py")), - COMMETHOD([], c_ulong, "GetSize", - ([], c_void_p, "pv")), - COMMETHOD([], c_int, "DidAlloc", - ([], c_void_p, "pv")), - COMMETHOD([], None, "HeapMinimize") # 25 - ] + COMMETHOD([], c_void_p, "Alloc", ([], c_ulong, "cb")), + COMMETHOD([], c_void_p, "Realloc", ([], c_void_p, "pv"), ([], c_ulong, "cb")), + COMMETHOD([], None, "Free", ([], c_void_p, "py")), + COMMETHOD([], c_ulong, "GetSize", ([], c_void_p, "pv")), + COMMETHOD([], c_int, "DidAlloc", ([], c_void_p, "pv")), + COMMETHOD([], None, "HeapMinimize"), # 25 + ] + malloc = POINTER(IMalloc)() oledll.ole32.CoGetMalloc(1, byref(malloc)) assert bool(malloc) + def from_outparm(self): if not self: return None @@ -42,8 +39,11 @@ def from_outparm(self): raise ValueError("memory was NOT allocated by CoTaskMemAlloc") windll.ole32.CoTaskMemFree(self) return result + + c_wchar_p.__ctypes_from_outparam__ = from_outparm + def comstring(text, typ=c_wchar_p): text = text_type(text) size = (len(text) + 1) * sizeof(c_wchar) @@ -53,6 +53,7 @@ def comstring(text, typ=c_wchar_p): memmove(mem, text, size) return ptr + class Test(unittest.TestCase): @unittest.skip("This fails for reasons I don't understand yet") def test_c_char(self): @@ -67,12 +68,13 @@ def test_c_char(self): z = comstring("spam, spam, and spam") # (x.__ctypes_from_outparam__(), x.__ctypes_from_outparam__()) - print((x.__ctypes_from_outparam__(), None)) #x.__ctypes_from_outparam__()) + print((x.__ctypes_from_outparam__(), None)) # x.__ctypes_from_outparam__()) # print comstring("Hello, World", c_wchar_p).__ctypes_from_outparam__() # print comstring("Hello, World", c_wchar_p).__ctypes_from_outparam__() # print comstring("Hello, World", c_wchar_p).__ctypes_from_outparam__() # print comstring("Hello, World", c_wchar_p).__ctypes_from_outparam__() + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_propputref.py b/comtypes/test/test_propputref.py index f6501162..8f6c7537 100644 --- a/comtypes/test/test_propputref.py +++ b/comtypes/test/test_propputref.py @@ -3,8 +3,11 @@ from comtypes.client import CreateObject from comtypes.automation import VARIANT + class Test(unittest.TestCase): - @unittest.skip("Fails on creating `TestComServerLib.TestComServer`. Figure out why.") + @unittest.skip( + "Fails on creating `TestComServerLib.TestComServer`. Figure out why." + ) def test(self, dynamic=False): d = CreateObject("Scripting.Dictionary", dynamic=dynamic) s = CreateObject("TestComServerLib.TestComServer", dynamic=dynamic) @@ -32,5 +35,6 @@ def test(self, dynamic=False): def test_dispatch(self): return self.test(dynamic=True) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_safearray.py b/comtypes/test/test_safearray.py index 3d4b0835..e0fc03ce 100644 --- a/comtypes/test/test_safearray.py +++ b/comtypes/test/test_safearray.py @@ -7,7 +7,17 @@ from comtypes import BSTR, IUnknown from comtypes._safearray import SafeArrayGetVartype -from comtypes.automation import VARIANT, VARIANT_BOOL, VT_ARRAY, VT_BSTR, VT_I4, VT_R4, VT_R8, VT_VARIANT, _midlSAFEARRAY +from comtypes.automation import ( + VARIANT, + VARIANT_BOOL, + VT_ARRAY, + VT_BSTR, + VT_I4, + VT_R4, + VT_R8, + VT_VARIANT, + _midlSAFEARRAY, +) from comtypes.safearray import safearray_as_ndarray from comtypes.test import is_resource_enabled from comtypes.test.find_memleak import find_memleak @@ -22,6 +32,7 @@ def get_array(sa): def com_refcnt(o): """Return the COM refcount of an interface pointer""" import gc + gc.collect() gc.collect() o.AddRef() @@ -62,15 +73,12 @@ def test_float_array(self): self.assertEqual(tuple(a.tolist()), v.value) def test_2dim_array(self): - data = ((1, 2, 3, 4), - (5, 6, 7, 8), - (9, 10, 11, 12)) + data = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) v = VARIANT(data) self.assertEqual(v.value, data) class SafeArrayTestCase(unittest.TestCase): - def test_equality(self): a = _midlSAFEARRAY(c_long) b = _midlSAFEARRAY(c_long) @@ -83,10 +91,8 @@ def test_equality(self): self.assertNotEqual(a, c) # XXX remove: - self.assertEqual((a._itemtype_, a._vartype_), - (c_long, VT_I4)) - self.assertEqual((c._itemtype_, c._vartype_), - (BSTR, VT_BSTR)) + self.assertEqual((a._itemtype_, a._vartype_), (c_long, VT_I4)) + self.assertEqual((c._itemtype_, c._vartype_), (BSTR, VT_BSTR)) def test_VT_BSTR(self): t = _midlSAFEARRAY(BSTR) @@ -148,6 +154,7 @@ def test_VT_UNKNOWN_1(self): self.assertTrue(a is t) from comtypes.typeinfo import CreateTypeLib + # will never be saved to disk punk = CreateTypeLib("spam").QueryInterface(IUnknown) @@ -175,6 +182,7 @@ def test_VT_UNKNOWN_multi(self): self.assertTrue(a is t) from comtypes.typeinfo import CreateTypeLib + # will never be saved to disk punk = CreateTypeLib("spam").QueryInterface(IUnknown) @@ -187,7 +195,7 @@ def test_VT_UNKNOWN_multi(self): # Unpacking the array must not change the refcount, and must # return an equal object. - self.assertEqual((punk,)*4, sa[0]) + self.assertEqual((punk,) * 4, sa[0]) self.assertEqual(initial + 4, com_refcnt(punk)) del sa @@ -209,14 +217,16 @@ def test_VT_UNKNOWN_multi(self): a, b = com_refcnt(plib), com_refcnt(punk) sa = t.from_param([plib, punk, plib]) -#### self.failUnlessEqual((plib, punk, plib), sa[0]) - self.assertEqual((a+2, b+1), (com_refcnt(plib), com_refcnt(punk))) + #### self.failUnlessEqual((plib, punk, plib), sa[0]) + self.assertEqual((a + 2, b + 1), (com_refcnt(plib), com_refcnt(punk))) del sa self.assertEqual((a, b), (com_refcnt(plib), com_refcnt(punk))) - @unittest.skip("This fails with a 'library not registered' error. Need to figure out how to " - "register TestComServerLib (without admin if possible).") + @unittest.skip( + "This fails with a 'library not registered' error. Need to figure out how to " + "register TestComServerLib (without admin if possible)." + ) def test_UDT(self): from comtypes.gen.TestComServerLib import MYCOLOR @@ -225,11 +235,14 @@ def test_UDT(self): sa = t.from_param([MYCOLOR(0, 0, 0), MYCOLOR(1, 2, 3)]) - self.assertEqual([(x.red, x.green, x.blue) for x in sa[0]], - [(0.0, 0.0, 0.0), (1.0, 2.0, 3.0)]) + self.assertEqual( + [(x.red, x.green, x.blue) for x in sa[0]], + [(0.0, 0.0, 0.0), (1.0, 2.0, 3.0)], + ) def doit(): t.from_param([MYCOLOR(0, 0, 0), MYCOLOR(1, 2, 3)]) + bytes = find_memleak(doit) self.assertFalse(bytes, "Leaks %d bytes" % bytes) @@ -256,7 +269,7 @@ def doit(): # PyObject *PyCom_PyObjectFromVariant(const VARIANT *var) unpack = _dll.PyCom_PyObjectFromVariant unpack.restype = py_object - unpack.argtypes = POINTER(VARIANT), + unpack.argtypes = (POINTER(VARIANT),) # c:/sf/pywin32/com/win32com/src/oleargs.cpp 54 # BOOL PyCom_VariantFromPyObject(PyObject *obj, VARIANT *var) @@ -283,20 +296,20 @@ def test_2dim(self): self.assertEqual(unpack(variant), data) def test_3dim(self): - data = ( ( (1, 2), (3, 4), (5, 6) ), - ( (7, 8), (9, 10), (11, 12) ) ) + data = (((1, 2), (3, 4), (5, 6)), ((7, 8), (9, 10), (11, 12))) variant = pack(data) self.assertEqual(variant.value, data) self.assertEqual(unpack(variant), data) def test_4dim(self): - data = ( ( ( ( 1, 2), ( 3, 4) ), - ( ( 5, 6), ( 7, 8) ) ), - ( ( ( 9, 10), (11, 12) ), - ( (13, 14), (15, 16) ) ) ) + data = ( + (((1, 2), (3, 4)), ((5, 6), (7, 8))), + (((9, 10), (11, 12)), ((13, 14), (15, 16))), + ) variant = pack(data) self.assertEqual(variant.value, data) self.assertEqual(unpack(variant), data) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_sapi.py b/comtypes/test/test_sapi.py index b32e9a7d..4b92c764 100644 --- a/comtypes/test/test_sapi.py +++ b/comtypes/test/test_sapi.py @@ -5,6 +5,7 @@ import os, unittest, tempfile from comtypes.client import CreateObject + class Test(unittest.TestCase): def test(self, dynamic=False): engine = CreateObject("SAPI.SpVoice", dynamic=dynamic) @@ -28,5 +29,6 @@ def test(self, dynamic=False): def test_dyndisp(self): return self.test(dynamic=True) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_server.py b/comtypes/test/test_server.py index 5051ef13..eefb004d 100644 --- a/comtypes/test/test_server.py +++ b/comtypes/test/test_server.py @@ -5,9 +5,6 @@ import comtypes.typeinfo, comtypes.client - - - class TypeLib(object): """This class collects IDL code fragments and eventually writes them into a .IDL file. The compile() method compiles the IDL file @@ -15,6 +12,7 @@ class TypeLib(object): registered with atexit that will unregister the typelib at program exit. """ + def __init__(self, lib): self.lib = lib self.interfaces = [] @@ -29,9 +27,12 @@ def coclass(self, definition): self.coclasses.append(definition) def __str__(self): - header = '''import "oaidl.idl"; + header = ( + """import "oaidl.idl"; import "ocidl.idl"; - %s {''' % self.lib + %s {""" + % self.lib + ) body = "\n".join([str(itf) for itf in self.interfaces]) footer = "\n".join(self.coclasses) + "}" return "\n".join((header, body, footer)) @@ -44,8 +45,10 @@ def compile(self): tlb_path = os.path.join(curdir, "mylib.tlb") if not os.path.isfile(idl_path) or open(idl_path, "r").read() != code: open(idl_path, "w").write(code) - os.system(r'call "%%VS71COMNTOOLS%%vsvars32.bat" && ' - r'midl /nologo %s /tlb %s' % (idl_path, tlb_path)) + os.system( + r'call "%%VS71COMNTOOLS%%vsvars32.bat" && ' + r"midl /nologo %s /tlb %s" % (idl_path, tlb_path) + ) # Register the typelib... tlib = comtypes.typeinfo.LoadTypeLib(tlb_path) # create the wrapper module... @@ -53,8 +56,8 @@ def compile(self): # Unregister the typelib at interpreter exit... attr = tlib.GetLibAttr() guid, major, minor = attr.guid, attr.wMajorVerNum, attr.wMinorVerNum - ## atexit.register(comtypes.typeinfo.UnRegisterTypeLib, - ## guid, major, minor) + ## atexit.register(comtypes.typeinfo.UnRegisterTypeLib, + ## guid, major, minor) return tlb_path class Interface(object): @@ -75,25 +78,31 @@ def __str__(self): tlb = TypeLib("[uuid(f4f74946-4546-44bd-a073-9ea6f9fe78cb)] library TestLib") - itf = tlb.interface("""[object, + itf = tlb.interface( + """[object, oleautomation, dual, uuid(ed978f5f-cc45-4fcc-a7a6-751ffa8dfedd)] - interface IMyInterface : IDispatch""") + interface IMyInterface : IDispatch""" + ) - outgoing = tlb.interface("""[object, + outgoing = tlb.interface( + """[object, oleautomation, dual, uuid(f7c48a90-64ea-4bb8-abf1-b3a3aa996848)] - interface IMyEventInterface : IDispatch""") + interface IMyEventInterface : IDispatch""" + ) - tlb.coclass(""" + tlb.coclass( + """ [uuid(fa9de8f4-20de-45fc-b079-648572428817)] coclass MyServer { [default] interface IMyInterface; [default, source] interface IMyEventInterface; }; - """) + """ + ) # The purpose of the MyServer class is to locate three separate code # section snippets closely together: @@ -103,14 +112,17 @@ def __str__(self): # 3. The unittest(s) for the COM method. # from comtypes.server.connectionpoints import ConnectableObjectMixin + class MyServer(comtypes.CoClass, ConnectableObjectMixin): - _reg_typelib_ = ('{f4f74946-4546-44bd-a073-9ea6f9fe78cb}', 0, 0) - _reg_clsid_ = comtypes.GUID('{fa9de8f4-20de-45fc-b079-648572428817}') + _reg_typelib_ = ("{f4f74946-4546-44bd-a073-9ea6f9fe78cb}", 0, 0) + _reg_clsid_ = comtypes.GUID("{fa9de8f4-20de-45fc-b079-648572428817}") ################ # definition - itf.add("""[id(100), propget] HRESULT Name([out, retval] BSTR *pname); - [id(100), propput] HRESULT Name([in] BSTR name);""") + itf.add( + """[id(100), propget] HRESULT Name([out, retval] BSTR *pname); + [id(100), propput] HRESULT Name([in] BSTR name);""" + ) # implementation Name = "foo" # test @@ -122,21 +134,27 @@ def test_Name(self): ################ # definition - itf.add("[id(101)] HRESULT MixedInOut([in] int a, [out] int *b, [in] int c, [out] int *d);") + itf.add( + "[id(101)] HRESULT MixedInOut([in] int a, [out] int *b, [in] int c, [out] int *d);" + ) # implementation def MixedInOut(self, a, c): - return a+1, c+1 - #test + return a + 1, c + 1 + + # test def test_MixedInOut(self): p = wrap(self.create()) self.assertEqual(p.MixedInOut(1, 2), (2, 3)) ################ # definition - itf.add("[id(102)] HRESULT MultiInOutArgs([in, out] int *pa, [in, out] int *pb);") + itf.add( + "[id(102)] HRESULT MultiInOutArgs([in, out] int *pa, [in, out] int *pb);" + ) # implementation def MultiInOutArgs(self, pa, pb): return pa[0] * 3, pb[0] * 4 + # test def test_MultiInOutArgs(self): p = wrap(self.create()) @@ -145,13 +163,13 @@ def test_MultiInOutArgs(self): ################ # definition itf.add("HRESULT MultiInOutArgs2([in, out] int *pa, [out] int *pb);") - ## # implementation - ## def MultiInOutArgs2(self, pa): - ## return pa[0] * 3, pa[0] * 4 - ## # test - ## def test_MultiInOutArgs2(self): - ## p = wrap(self.create()) - ## self.assertEqual(p.MultiInOutArgs2(42), (126, 168)) + ## # implementation + ## def MultiInOutArgs2(self, pa): + ## return pa[0] * 3, pa[0] * 4 + ## # test + ## def test_MultiInOutArgs2(self): + ## p = wrap(self.create()) + ## self.assertEqual(p.MultiInOutArgs2(42), (126, 168)) ################ # definition @@ -159,6 +177,7 @@ def test_MultiInOutArgs(self): # implementation def MultiInOutArgs3(self): return 42, 43 + # test def test_MultiInOutArgs3(self): p = wrap(self.create()) @@ -170,29 +189,37 @@ def test_MultiInOutArgs3(self): # implementation def MultiInOutArgs4(self, pb): return pb[0] + 3, pb[0] + 4 + # test def test_MultiInOutArgs4(self): p = wrap(self.create()) res = p.MultiInOutArgs4(pb=32) - ## print "MultiInOutArgs4", res - itf.add("""HRESULT GetStackTrace([in] ULONG FrameOffset, + ## print "MultiInOutArgs4", res + + itf.add( + """HRESULT GetStackTrace([in] ULONG FrameOffset, [in, out] INT *Frames, [in] ULONG FramesSize, - [out, optional] ULONG *FramesFilled);""") + [out, optional] ULONG *FramesFilled);""" + ) + def GetStackTrace(self, this, *args): - ## print "GetStackTrace", args + ## print "GetStackTrace", args return 0 + def test_GetStackTrace(self): p = wrap(self.create()) from ctypes import c_int, POINTER, pointer + frames = (c_int * 5)() res = p.GetStackTrace(42, frames, 5) - ## print "RES_1", res + ## print "RES_1", res frames = pointer(c_int(5)) res = p.GetStackTrace(42, frames, 0) - ## print "RES_2", res + + ## print "RES_2", res # It is unlear to me if this is allowed or not. Apparently there # are typelibs that define such an argument type, but it may be @@ -208,7 +235,6 @@ def test_GetStackTrace(self): # such an array cannot be created. itf.add("""HRESULT dummy([in] SAFEARRAY(VARIANT *) foo);""") - # Test events. itf.add("""HRESULT DoSomething();""") outgoing.add("""[id(103)] HRESULT OnSomething();""") @@ -216,14 +242,18 @@ def test_GetStackTrace(self): def DoSomething(self): "Implement the DoSomething method" self.Fire_Event(0, "OnSomething") + # test def test_events(self): p = wrap(self.create()) + class Handler(object): called = 0 + def OnSomething(self, this): "Handles the OnSomething event" self.called += 1 + handler = Handler() ev = comtypes.client.GetEvents(p, handler) p.DoSomething() @@ -231,9 +261,11 @@ def OnSomething(self, this): class Handler(object): called = 0 + def IMyEventInterface_OnSomething(self): "Handles the OnSomething event" self.called += 1 + handler = Handler() ev = comtypes.client.GetEvents(p, handler) p.DoSomething() @@ -242,17 +274,22 @@ def IMyEventInterface_OnSomething(self): # events with out-parameters (these are probably very unlikely...) itf.add("""HRESULT DoSomethingElse();""") outgoing.add("""[id(104)] HRESULT OnSomethingElse([out, retval] int *px);""") + def DoSomethingElse(self): "Implement the DoSomething method" self.Fire_Event(0, "OnSomethingElse") + def test_DoSomethingElse(self): p = wrap(self.create()) + class Handler(object): called = 0 + def OnSomethingElse(self): "Handles the OnSomething event" self.called += 1 return 42 + handler = Handler() ev = comtypes.client.GetEvents(p, handler) p.DoSomethingElse() @@ -260,10 +297,12 @@ def OnSomethingElse(self): class Handler(object): called = 0 + def OnSomethingElse(self, this, presult): "Handles the OnSomething event" self.called += 1 presult[0] = 42 + handler = Handler() ev = comtypes.client.GetEvents(p, handler) p.DoSomethingElse() @@ -276,9 +315,11 @@ def OnSomethingElse(self, this, presult): from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2 from comtypes.connectionpoints import IConnectionPointContainer - MyServer._com_interfaces_ = [TestLib.IMyInterface, - IProvideClassInfo2, - IConnectionPointContainer] + MyServer._com_interfaces_ = [ + TestLib.IMyInterface, + IProvideClassInfo2, + IConnectionPointContainer, + ] MyServer._outgoing_interfaces_ = [TestLib.IMyEventInterface] ################################################################ @@ -291,13 +332,17 @@ def __init__(self, *args): def create(self): obj = MyServer() return obj.QueryInterface(comtypes.IUnknown) + except: import unittest class TestSkipped(unittest.TestCase): - @unittest.skip("This file causes a WindowsError. Needs investigated and fixed.") + @unittest.skip( + "This file causes a WindowsError. Needs investigated and fixed." + ) def test_server_module_skipped(self): pass + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_showevents.py b/comtypes/test/test_showevents.py index 6b991d3e..d6bf001c 100644 --- a/comtypes/test/test_showevents.py +++ b/comtypes/test/test_showevents.py @@ -15,7 +15,10 @@ def check_output(self, want, got, optionflags): def load_tests(loader, tests, ignore): import comtypes.test.test_showevents - tests.addTests(doctest.DocTestSuite(comtypes.test.test_showevents, checker=SixDocChecker())) + + tests.addTests( + doctest.DocTestSuite(comtypes.test.test_showevents, checker=SixDocChecker()) + ) return tests diff --git a/comtypes/test/test_subinterface.py b/comtypes/test/test_subinterface.py index fb6a6548..6bf7eebb 100644 --- a/comtypes/test/test_subinterface.py +++ b/comtypes/test/test_subinterface.py @@ -2,10 +2,13 @@ from comtypes import IUnknown, GUID from ctypes import * + def test_main(): from test import test_support + test_support.run_unittest(Test) + class Test(unittest.TestCase): def test_subinterface(self): class ISub(IUnknown): diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index dcf2385d..eaad4c73 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -3,8 +3,14 @@ from ctypes import POINTER, byref from comtypes import GUID, COMError from comtypes.automation import DISPATCH_METHOD -from comtypes.typeinfo import LoadTypeLibEx, LoadRegTypeLib, \ - QueryPathOfRegTypeLib, TKIND_INTERFACE, TKIND_DISPATCH, TKIND_ENUM +from comtypes.typeinfo import ( + LoadTypeLibEx, + LoadRegTypeLib, + QueryPathOfRegTypeLib, + TKIND_INTERFACE, + TKIND_DISPATCH, + TKIND_ENUM, +) class Test(unittest.TestCase): diff --git a/comtypes/test/test_urlhistory.py b/comtypes/test/test_urlhistory.py index e10b4e0e..ce3bb2b0 100644 --- a/comtypes/test/test_urlhistory.py +++ b/comtypes/test/test_urlhistory.py @@ -17,6 +17,7 @@ class _(object): def __ctypes_from_outparam__(self): from comtypes.util import cast_field + result = type(self)() for n, _ in self._fields_: setattr(result, n, getattr(self, n)) @@ -25,25 +26,32 @@ def __ctypes_from_outparam__(self): windll.ole32.CoTaskMemFree(cast_field(self, "pwcsTitle", c_void_p)) return result + from comtypes.test.find_memleak import find_memleak + class Test(unittest.TestCase): def check_leaks(self, func): bytes = find_memleak(func, (5, 10)) self.assertFalse(bytes, "Leaks %d bytes" % bytes) - @unittest.skip("This fails with: `TypeError: iter() returned non-iterator of type 'POINTER(IEnumSTATURL)'`") + @unittest.skip( + "This fails with: `TypeError: iter() returned non-iterator of type 'POINTER(IEnumSTATURL)'`" + ) def test_creation(self): hist = CreateObject(urlhistLib.UrlHistory) for x in hist.EnumURLS(): x.pwcsUrl, x.pwcsTitle # print (x.pwcsUrl, x.pwcsTitle) # print x + def doit(): for x in hist.EnumURLs(): pass + doit() self.check_leaks(doit) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_variant.py b/comtypes/test/test_variant.py index 47840089..5687d04b 100644 --- a/comtypes/test/test_variant.py +++ b/comtypes/test/test_variant.py @@ -5,14 +5,44 @@ import sys import unittest from ctypes import ( - POINTER, byref, c_byte, c_char, c_double, c_float, c_int, c_int64, c_short, c_ubyte, c_uint, - c_uint64, c_ushort, pointer, + POINTER, + byref, + c_byte, + c_char, + c_double, + c_float, + c_int, + c_int64, + c_short, + c_ubyte, + c_uint, + c_uint64, + c_ushort, + pointer, ) from comtypes import GUID, IUnknown from comtypes.automation import ( - DISPPARAMS, VARIANT, VT_BSTR, VT_BYREF, VT_CY, VT_DATE, VT_DECIMAL, VT_EMPTY, VT_ERROR, VT_I1, - VT_I2, VT_I4, VT_I8, VT_NULL, VT_R4, VT_R8, VT_UI1, VT_UI2, VT_UI4, VT_UI8, + DISPPARAMS, + VARIANT, + VT_BSTR, + VT_BYREF, + VT_CY, + VT_DATE, + VT_DECIMAL, + VT_EMPTY, + VT_ERROR, + VT_I1, + VT_I2, + VT_I4, + VT_I8, + VT_NULL, + VT_R4, + VT_R8, + VT_UI1, + VT_UI2, + VT_UI4, + VT_UI8, ) from comtypes.test.find_memleak import find_memleak from comtypes.typeinfo import LoadRegTypeLib @@ -27,7 +57,6 @@ def get_refcnt(comptr): class VariantTestCase(unittest.TestCase): - def test_constants(self): empty = VARIANT.empty self.assertEqual(empty.vt, VT_EMPTY) @@ -47,7 +76,7 @@ def test_com_refcounts(self): rc = get_refcnt(tlb) p = tlb.QueryInterface(IUnknown) - self.assertEqual(get_refcnt(tlb), rc+1) + self.assertEqual(get_refcnt(tlb), rc + 1) del p self.assertEqual(get_refcnt(tlb), rc) @@ -59,12 +88,12 @@ def test_com_pointers(self): rc = get_refcnt(tlb) v = VARIANT(tlb) - self.assertEqual(get_refcnt(tlb), rc+1) + self.assertEqual(get_refcnt(tlb), rc + 1) p = v.value - self.assertEqual(get_refcnt(tlb), rc+2) + self.assertEqual(get_refcnt(tlb), rc + 2) del p - self.assertEqual(get_refcnt(tlb), rc+1) + self.assertEqual(get_refcnt(tlb), rc + 1) v.value = None self.assertEqual(get_refcnt(tlb), rc) @@ -90,7 +119,7 @@ def test_pythonobjects(self): if sys.version_info >= (3, 0): objects = [None, 42, 3.14, True, False, "abc", "abc", 7] else: - objects = [None, 42, 3.14, True, False, "abc", u"abc", 7] + objects = [None, 42, 3.14, True, False, "abc", "abc", 7] for x in objects: v = VARIANT(x) self.assertEqual(x, v.value) @@ -98,16 +127,16 @@ def test_pythonobjects(self): def test_integers(self): v = VARIANT() - int_type = int if sys.version_info >= (3,0) else (int, long) + int_type = int if sys.version_info >= (3, 0) else (int, long) - if (hasattr(sys, "maxint")): + if hasattr(sys, "maxint"): # this test doesn't work in Python 3000 v.value = sys.maxsize self.assertEqual(v.value, sys.maxsize) self.assertIsInstance(v.value, int_type) v.value += 1 - self.assertEqual(v.value, sys.maxsize+1) + self.assertEqual(v.value, sys.maxsize + 1) self.assertIsInstance(v.value, int_type) v.value = 1 @@ -124,7 +153,7 @@ def test_datetime(self): self.assertEqual(v.value, now) def test_decimal_as_currency(self): - value = decimal.Decimal('3.14') + value = decimal.Decimal("3.14") v = VARIANT() v.value = value @@ -136,23 +165,22 @@ def test_decimal_as_decimal(self): v.vt = VT_DECIMAL v.decVal.Lo64 = 1234 v.decVal.scale = 3 - self.assertEqual(v.value, decimal.Decimal('1.234')) + self.assertEqual(v.value, decimal.Decimal("1.234")) v.decVal.sign = 0x80 - self.assertEqual(v.value, decimal.Decimal('-1.234')) + self.assertEqual(v.value, decimal.Decimal("-1.234")) v.decVal.scale = 28 - self.assertEqual(v.value, decimal.Decimal('-1.234e-25')) + self.assertEqual(v.value, decimal.Decimal("-1.234e-25")) v.decVal.scale = 12 v.decVal.Hi32 = 100 - self.assertEqual( - v.value, decimal.Decimal('-1844674407.370955162834')) + self.assertEqual(v.value, decimal.Decimal("-1844674407.370955162834")) @unittest.skip("This test causes python(3?) to crash.") def test_BSTR(self): v = VARIANT() - v.value = u"abc\x00123\x00" + v.value = "abc\x00123\x00" self.assertEqual(v.value, "abc\x00123\x00") v.value = None @@ -168,13 +196,15 @@ def test_empty_BSTR(self): v.value = "" self.assertEqual(v.vt, VT_BSTR) - @unittest.skip("Fails on creating `TestComServerLib.TestComServer`. Library not registered.") + @unittest.skip( + "Fails on creating `TestComServerLib.TestComServer`. Library not registered." + ) def test_UDT(self): from comtypes.gen.TestComServerLib import MYCOLOR + v = VARIANT(MYCOLOR(red=1.0, green=2.0, blue=3.0)) value = v.value - self.assertEqual((1.0, 2.0, 3.0), - (value.red, value.green, value.blue)) + self.assertEqual((1.0, 2.0, 3.0), (value.red, value.green, value.blue)) def func(): v = VARIANT(MYCOLOR(red=1.0, green=2.0, blue=3.0)) @@ -185,18 +215,19 @@ def func(): def test_ctypes_in_variant(self): v = VARIANT() - objs = [(c_ubyte(3), VT_UI1), - (c_char(b"x"), VT_UI1), - (c_byte(3), VT_I1), - (c_ushort(3), VT_UI2), - (c_short(3), VT_I2), - (c_uint(3), VT_UI4), - (c_uint64(2**64), VT_UI8), - (c_int(3), VT_I4), - (c_int64(2**32), VT_I8), - (c_double(3.14), VT_R8), - (c_float(3.14), VT_R4), - ] + objs = [ + (c_ubyte(3), VT_UI1), + (c_char(b"x"), VT_UI1), + (c_byte(3), VT_I1), + (c_ushort(3), VT_UI2), + (c_short(3), VT_I2), + (c_uint(3), VT_UI4), + (c_uint64(2**64), VT_UI8), + (c_int(3), VT_I4), + (c_int64(2**32), VT_I8), + (c_double(3.14), VT_R8), + (c_float(3.14), VT_R4), + ] for value, vt in objs: v.value = value self.assertEqual(v.vt, vt) @@ -218,7 +249,9 @@ def test_byref(self): def test_repr(self): self.assertEqual(repr(VARIANT(c_int(42))), "VARIANT(vt=0x3, 42)") - self.assertEqual(repr(VARIANT(byref(c_int(42)))), "VARIANT(vt=0x4003, byref(42))") + self.assertEqual( + repr(VARIANT(byref(c_int(42)))), "VARIANT(vt=0x4003, byref(42))" + ) self.assertEqual(repr(VARIANT.empty), "VARIANT.empty") self.assertEqual(repr(VARIANT.null), "VARIANT.null") self.assertEqual(repr(VARIANT.missing), "VARIANT.missing") @@ -227,6 +260,7 @@ def test_repr(self): class ArrayTest(unittest.TestCase): def test_double(self): import array + for typecode in "df": # because of FLOAT rounding errors, whi will only work for # certain values! @@ -237,12 +271,14 @@ def test_double(self): def test_int(self): import array + for typecode in "bhiBHIlL": a = array.array(typecode, (1, 1, 1, 1)) v = VARIANT() v.value = a self.assertEqual(v.value, (1, 1, 1, 1)) + ################################################################ def run_test(rep, msg, func=None, previous={}, results={}): # items = [None] * rep @@ -251,11 +287,16 @@ def run_test(rep, msg, func=None, previous={}, results={}): func = eval("lambda: %s" % msg, locals) items = range(rep) from time import clock + start = clock() for i in items: - func(); func(); func(); func(); func() + func() + func() + func() + func() + func() stop = clock() - duration = (stop-start)*1e6/5/rep + duration = (stop - start) * 1e6 / 5 / rep try: prev = previous[msg] except KeyError: @@ -263,7 +304,9 @@ def run_test(rep, msg, func=None, previous={}, results={}): delta = 0.0 else: delta = duration / prev * 100.0 - print("%40s: %7.1f us, time = %5.1f%%" % (msg, duration, delta), file=sys.stderr) + print( + "%40s: %7.1f us, time = %5.1f%%" % (msg, duration, delta), file=sys.stderr + ) results[msg] = duration return delta @@ -272,6 +315,7 @@ def check_perf(rep=20000): from ctypes import c_int, byref from comtypes.automation import VARIANT import comtypes.automation + print(comtypes.automation) variable = c_int() by_var = byref(variable) @@ -305,11 +349,19 @@ def check_perf(rep=20000): print("Average duration %.1f%%" % (d / 10)) # cPickle.dump(results, open("result.pickle", "wb")) -if __name__ == '__main__': + +if __name__ == "__main__": try: unittest.main() except SystemExit: pass import comtypes - print("Running benchmark with comtypes %s/Python %s ..." % (comtypes.__version__, sys.version.split()[0],)) + + print( + "Running benchmark with comtypes %s/Python %s ..." + % ( + comtypes.__version__, + sys.version.split()[0], + ) + ) check_perf() diff --git a/comtypes/test/test_win32com_interop.py b/comtypes/test/test_win32com_interop.py index 7be1a5a9..d7560cf4 100644 --- a/comtypes/test/test_win32com_interop.py +++ b/comtypes/test/test_win32com_interop.py @@ -12,6 +12,7 @@ try: import pythoncom import win32com.client + skip = False # We use the PyCom_PyObjectFromIUnknown function in pythoncom25.dll to # convert a comtypes COM pointer into a pythoncom COM pointer. @@ -34,8 +35,10 @@ def setUpModule(): if skip: - raise unittest.SkipTest("This test requires the pythoncom library installed. If this is " - "important tests then we need to add dev dependencies to the project that include pythoncom.") + raise unittest.SkipTest( + "This test requires the pythoncom library installed. If this is " + "important tests then we need to add dev dependencies to the project that include pythoncom." + ) def comtypes2pywin(ptr, interface=None): @@ -52,24 +55,31 @@ def comtypes2pywin(ptr, interface=None): interface = IUnknown return _PyCom_PyObjectFromIUnknown(ptr, byref(interface._iid_), True) + ################################################################ + def comtypes_get_refcount(ptr): """Helper function for testing: return the COM reference count of a comtypes COM object""" ptr.AddRef() return ptr.Release() + from comtypes import COMObject + class MyComObject(COMObject): """A completely trivial COM object implementing IDispatch. Calling any methods will return the error code E_NOTIMPL (except the IUnknown methods; they are implemented in the base class.""" + _com_interfaces_ = [IDispatch] + ################################################################ + class Test(unittest.TestCase): def tearDown(self): if hasattr(self, "ie"): @@ -104,5 +114,6 @@ def test_ie(self): del p, disp self.assertEqual(comtypes_get_refcount(ie), 1) + if __name__ == "__main__": unittest.main() diff --git a/comtypes/test/test_wmi.py b/comtypes/test/test_wmi.py index d4770aaa..a93512fe 100644 --- a/comtypes/test/test_wmi.py +++ b/comtypes/test/test_wmi.py @@ -31,6 +31,7 @@ def test_wmi(self): # So, the one that's referenced onm WbemScripting will be used, whether the actual # typelib is available or not. XXX from comtypes.gen import WbemScripting + WbemScripting.wbemPrivilegeCreateToken for item in disks: @@ -52,9 +53,12 @@ def test_wmi(self): # print "\t", (prop.Name, prop.Value) self.assertEqual(len(item.Properties_), item.Properties_.Count) self.assertEqual(len(item.Properties_), len(result)) - self.assertTrue(isinstance(item.Properties_["Description"].Value, text_type)) + self.assertTrue( + isinstance(item.Properties_["Description"].Value, text_type) + ) # len(obj) is forwared to obj.Count self.assertEqual(len(disks), disks.Count) + if __name__ == "__main__": ut.main() diff --git a/comtypes/test/test_word.py b/comtypes/test/test_word.py index 5ddfbb23..d1e6370a 100644 --- a/comtypes/test/test_word.py +++ b/comtypes/test/test_word.py @@ -5,8 +5,11 @@ import comtypes.client try: - comtypes.client.GetModule(('{00020905-0000-0000-C000-000000000046}',)) # Word libUUID + comtypes.client.GetModule( + ("{00020905-0000-0000-C000-000000000046}",) + ) # Word libUUID from comtypes.gen import Word + IMPORT_FAILED = False except (ImportError, OSError): IMPORT_FAILED = True @@ -58,12 +61,12 @@ def test(self): for i, para in enumerate(doc.Paragraphs): f = para.Range.Font - f.ColorIndex = i+1 + f.ColorIndex = i + 1 f.Size = 12 + (2 * i) time.sleep(0.5) - doc.Close(SaveChanges = Word.wdDoNotSaveChanges) + doc.Close(SaveChanges=Word.wdDoNotSaveChanges) del word, w2 diff --git a/comtypes/tools/codegenerator.py b/comtypes/tools/codegenerator.py index 0574efa5..5da3cf5d 100644 --- a/comtypes/tools/codegenerator.py +++ b/comtypes/tools/codegenerator.py @@ -7,6 +7,7 @@ import os import sys import textwrap + if sys.version_info >= (3, 0): import io else: @@ -18,7 +19,13 @@ if TYPE_CHECKING: from typing import ( - Any, Dict, Iterator, List, Optional, Tuple, Union as _UnionT, + Any, + Dict, + Iterator, + List, + Optional, + Tuple, + Union as _UnionT, ) @@ -32,8 +39,11 @@ class lcid(object): def __repr__(self): return "_lcid" + + lcid = lcid() + class dispid(object): def __init__(self, memid): self.memid = memid @@ -41,6 +51,7 @@ def __init__(self, memid): def __repr__(self): return "dispid(%s)" % self.memid + class helpstring(object): def __init__(self, text): self.text = text @@ -54,29 +65,23 @@ def __repr__(self): "unsigned char": "c_ubyte", "signed char": "c_byte", "char": "c_char", - "wchar_t": "c_wchar", - "short unsigned int": "c_ushort", "short int": "c_short", - "long unsigned int": "c_ulong", "long int": "c_long", "long signed int": "c_long", - "unsigned int": "c_uint", "int": "c_int", - "long long unsigned int": "c_ulonglong", "long long int": "c_longlong", - "double": "c_double", "float": "c_float", - # Hm... "void": "None", } + def get_real_type(tp): if type(tp) is typedesc.Typedef: return get_real_type(tp.typ) @@ -84,12 +89,14 @@ def get_real_type(tp): return get_real_type(tp.typ) return tp + ASSUME_STRINGS = True + def _calc_packing(struct, fields, pack, isStruct): # Try a certain packing, raise PackingError if field offsets, # total size ot total alignment is wrong. - if struct.size is None: # incomplete struct + if struct.size is None: # incomplete struct return -1 if struct.name in dont_assert_size: return None @@ -98,11 +105,11 @@ def _calc_packing(struct, fields, pack, isStruct): total_align = struct.bases[0].align else: size = 0 - total_align = 8 # in bits + total_align = 8 # in bits for i, f in enumerate(fields): - if f.bits: # this code cannot handle bit field sizes. + if f.bits: # this code cannot handle bit field sizes. # print "##XXX FIXME" - return -2 # XXX FIXME + return -2 # XXX FIXME s, a = storage(f.typ) if pack is not None: a = min(pack, a) @@ -125,10 +132,11 @@ def _calc_packing(struct, fields, pack, isStruct): if size != struct.size: raise PackingError("total size (%s/%s)" % (size, struct.size)) + def calc_packing(struct, fields): # try several packings, starting with unspecified packing isStruct = isinstance(struct, typedesc.Structure) - for pack in [None, 16*8, 8*8, 4*8, 2*8, 1*8]: + for pack in [None, 16 * 8, 8 * 8, 4 * 8, 2 * 8, 1 * 8]: try: _calc_packing(struct, fields, pack, isStruct) except PackingError as details: @@ -141,16 +149,19 @@ def calc_packing(struct, fields): raise PackingError("PACKING FAILED: %s" % details) + class PackingError(Exception): pass + # XXX These should be filtered out in gccxmlparser. dont_assert_size = set( [ - "__si_class_type_info_pseudo", - "__class_type_info_pseudo", + "__si_class_type_info_pseudo", + "__class_type_info_pseudo", ] - ) +) + def storage(t): # return the size and alignment of a type @@ -161,16 +172,19 @@ def storage(t): return s * (int(t.max) - int(t.min) + 1), a return int(t.size), int(t.align) + ################################################################ + def name_wrapper_module(tlib): """Determine the name of a typelib wrapper module""" libattr = tlib.GetLibAttr() - modname = "_%s_%s_%s_%s" % \ - (str(libattr.guid)[1:-1].replace("-", "_"), - libattr.lcid, - libattr.wMajorVerNum, - libattr.wMinorVerNum) + modname = "_%s_%s_%s_%s" % ( + str(libattr.guid)[1:-1].replace("-", "_"), + libattr.lcid, + libattr.wMajorVerNum, + libattr.wMinorVerNum, + ) return "comtypes.gen.%s" % modname @@ -184,6 +198,7 @@ def name_friendly_module(tlib): return return "comtypes.gen.%s" % modulename + ################################################################ @@ -261,10 +276,7 @@ def _make_noargs(self): def _make_withargs(self): # type: () -> None code = ( - " COMMETHOD(\n" - " %r,\n" - " %s,\n" - " '%s'," + " COMMETHOD(\n" " %r,\n" " %s,\n" " '%s'," ) % self._get_common_elms() print(code, file=self._stream) arglist = [_to_arg_definition(*i) for i in self._iter_args()] @@ -317,11 +329,11 @@ def _iter_args(self): idlflags = list(_f) # shallow copy to avoid side effects if isinstance(typ, typedesc.ComInterface): type_name = "OPENARRAY" - if 'in' not in idlflags: - idlflags.append('in') + if "in" not in idlflags: + idlflags.append("in") else: type_name = self._to_type_name(typ) - if 'lcid' in idlflags:# and 'in' in idlflags: + if "lcid" in idlflags: # and 'in' in idlflags: default = lcid else: default = _defval @@ -370,10 +382,7 @@ def _make_noargs(self): def _make_withargs(self): # type: () -> None code = ( - " DISPMETHOD(\n" - " %r,\n" - " %s,\n" - " '%s'," + " DISPMETHOD(\n" " %r,\n" " %s,\n" " '%s'," ) % self._get_common_elms() print(code, file=self._stream) arglist = [_to_arg_definition(*i) for i in self._iter_args()] @@ -419,7 +428,6 @@ def _get_common_elms(self): class CodeGenerator(object): - def __init__(self, known_symbols=None): self.stream = io.StringIO() self.imports = ImportedNamespaces() @@ -427,8 +435,8 @@ def __init__(self, known_symbols=None): self._to_type_name = TypeNamer() self.known_symbols = known_symbols or {} - self.done = set() # type descriptions that have been generated - self.names = set() # names that have been generated + self.done = set() # type descriptions that have been generated + self.names = set() # names that have been generated self.externals = [] # typelibs imported to generated module self.last_item_class = False @@ -463,8 +471,9 @@ def _make_relative_path(self, path1, path2): """ path1 = os.path.abspath(path1) path2 = os.path.abspath(path2) - common = os.path.commonprefix([os.path.normcase(path1), - os.path.normcase(path2)]) + common = os.path.commonprefix( + [os.path.normcase(path1), os.path.normcase(path2)] + ) if not os.path.isdir(common): return path1 if not common.endswith("\\"): @@ -472,8 +481,8 @@ def _make_relative_path(self, path1, path2): if not os.path.isdir(path2): path2 = os.path.dirname(path2) # strip the common prefix - path1 = path1[len(common):] - path2 = path2[len(common):] + path1 = path1[len(common) :] + path2 = path2[len(common) :] parts2 = path2.split("\\") return "..\\" * len(parts2) + path1 @@ -494,13 +503,16 @@ def _generate_typelib_path(self, filename): else: # relative path; make relative to comtypes.gen. path = self._make_relative_path(filename, comtypes.gen.__path__[0]) - self.imports.add('os') - definition = "os.path.normpath(\n" \ - " os.path.abspath(os.path.join(os.path.dirname(__file__),\n" \ + self.imports.add("os") + definition = ( + "os.path.normpath(\n" + " os.path.abspath(os.path.join(os.path.dirname(__file__),\n" " %r)))" % path + ) self.declarations.add("typelib_path", definition) - p = os.path.normpath(os.path.abspath(os.path.join(comtypes.gen.__path__[0], - path))) + p = os.path.normpath( + os.path.abspath(os.path.join(comtypes.gen.__path__[0], path)) + ) assert os.path.isfile(p) def generate_code(self, items, filename): @@ -510,8 +522,7 @@ def generate_code(self, items, filename): if filename is not None: # get full path to DLL first (os.stat can't work with relative DLL paths properly) loaded_typelib = typeinfo.LoadTypeLib(filename) - full_filename = tlbparser.get_tlib_filename( - loaded_typelib) + full_filename = tlbparser.get_tlib_filename(loaded_typelib) while full_filename and not os.path.exists(full_filename): full_filename = os.path.split(full_filename)[0] @@ -540,8 +551,8 @@ def generate_code(self, items, filename): self.imports.add("ctypes", "*") # HACK: wildcard import is so ugly. if tlib_mtime is not None: - logger.debug("filename: \"%s\": tlib_mtime: %s", filename, tlib_mtime) - self.imports.add('comtypes', '_check_version') + logger.debug('filename: "%s": tlib_mtime: %s', filename, tlib_mtime) + self.imports.add("comtypes", "_check_version") output = io.StringIO() if filename is not None: # Hm, what is the CORRECT encoding? @@ -555,15 +566,14 @@ def generate_code(self, items, filename): names = ", ".join(repr(str(n)) for n in self.names) dunder_all = "__all__ = [%s]" % names if len(dunder_all) > 80: - wrapper = textwrap.TextWrapper(subsequent_indent=" ", - initial_indent=" ", - break_long_words=False) + wrapper = textwrap.TextWrapper( + subsequent_indent=" ", initial_indent=" ", break_long_words=False + ) dunder_all = "__all__ = [\n%s\n]" % "\n".join(wrapper.wrap(names)) print(dunder_all, file=output) print(file=output) if tlib_mtime is not None: - print("_check_version(%r, %f)" % (version, tlib_mtime), - file=output) + print("_check_version(%r, %f)" % (version, tlib_mtime), file=output) return output.getvalue() def need_VARIANT_imports(self, value): @@ -578,7 +588,7 @@ def _to_docstring(self, orig, depth=1): # increasing `depth` by one increases indentation by one indent = " " * depth # some chars are replaced to avoid causing a `SyntaxError` - repled = orig.replace("\\", r"\\").replace("\"", r"'") + repled = orig.replace("\\", r"\\").replace('"', r"'") return '%s"""%s"""' % (indent, repled) def ArrayType(self, tp): @@ -633,7 +643,7 @@ def Typedef(self, tp): def FundamentalType(self, item): # type: (typedesc.FundamentalType) -> None - pass # we should check if this is known somewhere + pass # we should check if this is known somewhere def StructureHead(self, head): # type: (typedesc.StructureHead) -> None @@ -653,9 +663,17 @@ def StructureHead(self, head): self.last_item_class = True - method_names = [m.name for m in head.struct.members if type(m) is typedesc.Method] - print("class %s(%s):" % (head.struct.name, ", ".join(basenames)), file=self.stream) - print(" _iid_ = GUID('{}') # please look up iid and fill in!", file=self.stream) + method_names = [ + m.name for m in head.struct.members if type(m) is typedesc.Method + ] + print( + "class %s(%s):" % (head.struct.name, ", ".join(basenames)), + file=self.stream, + ) + print( + " _iid_ = GUID('{}') # please look up iid and fill in!", + file=self.stream, + ) if "Enum" in method_names: print(" def __iter__(self):", file=self.stream) print(" return self.Enum()", file=self.stream) @@ -697,7 +715,10 @@ def StructureHead(self, head): print("class %s(Structure):" % head.struct.name, file=self.stream) if hasattr(head.struct, "_recordinfo_"): - print(" _recordinfo_ = %r" % (head.struct._recordinfo_,), file=self.stream) + print( + " _recordinfo_ = %r" % (head.struct._recordinfo_,), + file=self.stream, + ) else: print(" pass", file=self.stream) print(file=self.stream) @@ -753,6 +774,7 @@ def StructureBody(self, body): except PackingError as details: # if packing fails, write a warning comment to the output. import warnings + message = "Structure %s: %s" % (body.struct.name, details) warnings.warn(message, UserWarning) print("# WARNING: %s" % details, file=self.stream) @@ -780,28 +802,46 @@ def StructureBody(self, body): else: fieldname = "_" unnamed_index += 1 - print(" # Unnamed field renamed to '%s'" % fieldname, file=self.stream) + print( + " # Unnamed field renamed to '%s'" % fieldname, + file=self.stream, + ) else: fieldname = f.name if f.bits is None: - print(" ('%s', %s)," % (fieldname, self._to_type_name(f.typ)), file=self.stream) + print( + " ('%s', %s)," % (fieldname, self._to_type_name(f.typ)), + file=self.stream, + ) else: - print(" ('%s', %s, %s)," % (fieldname, self._to_type_name(f.typ), f.bits), file=self.stream) + print( + " ('%s', %s, %s)," + % (fieldname, self._to_type_name(f.typ), f.bits), + file=self.stream, + ) print("]", file=self.stream) if body.struct.size is None: print(file=self.stream) - msg = ("# The size provided by the typelib is incorrect.\n" - "# The size and alignment check for %s is skipped.") + msg = ( + "# The size provided by the typelib is incorrect.\n" + "# The size and alignment check for %s is skipped." + ) print(msg % body.struct.name, file=self.stream) elif body.struct.name not in dont_assert_size: print(file=self.stream) size = body.struct.size // 8 - print("assert sizeof(%s) == %s, sizeof(%s)" % \ - (body.struct.name, size, body.struct.name), file=self.stream) + print( + "assert sizeof(%s) == %s, sizeof(%s)" + % (body.struct.name, size, body.struct.name), + file=self.stream, + ) align = body.struct.align // 8 - print("assert alignment(%s) == %s, alignment(%s)" % \ - (body.struct.name, align, body.struct.name), file=self.stream) + print( + "assert alignment(%s) == %s, alignment(%s)" + % (body.struct.name, align, body.struct.name), + file=self.stream, + ) if methods: self.imports.add("comtypes", "COMMETHOD") @@ -823,11 +863,14 @@ def StructureBody(self, body): " [], \n" " %s,\n" " '%s',\n" - ) % (self._to_type_name(m.returns), m.name), - file=self.stream + ) + % (self._to_type_name(m.returns), m.name), + file=self.stream, ) for a in m.iterArgTypes(): - print(" ([], %s),\n" % self._to_type_name(a), file=self.stream) + print( + " ([], %s),\n" % self._to_type_name(a), file=self.stream + ) print(" ),", file=self.stream) print("]", file=self.stream) @@ -857,7 +900,10 @@ def TypeLib(self, lib): if lib.name: print(" name = %r" % lib.name, file=self.stream) - print(" _reg_typelib_ = (%r, %r, %r)" % (lib.guid, lib.major, lib.minor), file=self.stream) + print( + " _reg_typelib_ = (%r, %r, %r)" % (lib.guid, lib.major, lib.minor), + file=self.stream, + ) print(file=self.stream) print(file=self.stream) @@ -871,9 +917,10 @@ def External(self, ext): def Constant(self, tp): # type: (typedesc.Constant) -> None self.last_item_class = False - print("%s = %r # Constant %s" % (tp.name, - tp.value, - self._to_type_name(tp.typ)), file=self.stream) + print( + "%s = %r # Constant %s" % (tp.name, tp.value, self._to_type_name(tp.typ)), + file=self.stream, + ) self.names.add(tp.name) def SAFEARRAYType(self, sa): @@ -928,7 +975,10 @@ def CoClass(self, coclass): libid = coclass.tlibattr.guid wMajor, wMinor = coclass.tlibattr.wMajorVerNum, coclass.tlibattr.wMinorVerNum - print(" _reg_typelib_ = (%r, %s, %s)" % (str(libid), wMajor, wMinor), file=self.stream) + print( + " _reg_typelib_ = (%r, %s, %s)" % (str(libid), wMajor, wMinor), + file=self.stream, + ) print(file=self.stream) print(file=self.stream) @@ -938,13 +988,13 @@ def CoClass(self, coclass): sources = [] for item in coclass.interfaces: # item is (interface class, impltypeflags) - if item[1] & 2: # IMPLTYPEFLAG_FSOURCE + if item[1] & 2: # IMPLTYPEFLAG_FSOURCE # source interface where = sources else: # sink interface where = implemented - if item[1] & 1: # IMPLTYPEFLAG_FDEAULT + if item[1] & 1: # IMPLTYPEFLAG_FDEAULT # The default interface should be the first item on the list where.insert(0, self._to_type_name(item[0])) else: @@ -952,10 +1002,16 @@ def CoClass(self, coclass): if implemented: self.last_item_class = False - print("%s._com_interfaces_ = [%s]" % (coclass.name, ", ".join(implemented)), file=self.stream) + print( + "%s._com_interfaces_ = [%s]" % (coclass.name, ", ".join(implemented)), + file=self.stream, + ) if sources: self.last_item_class = False - print("%s._outgoing_interfaces_ = [%s]" % (coclass.name, ", ".join(sources)), file=self.stream) + print( + "%s._outgoing_interfaces_ = [%s]" % (coclass.name, ", ".join(sources)), + file=self.stream, + ) self.names.add(coclass.name) @@ -1054,7 +1110,10 @@ def ComInterfaceBody(self, body): print("]", file=self.stream) print(file=self.stream) - print("################################################################", file=self.stream) + print( + "################################################################", + file=self.stream, + ) print("# code template for %s implementation" % body.itf.name, file=self.stream) print("# class %s_Impl(object):" % body.itf.name, file=self.stream) @@ -1064,38 +1123,59 @@ def ComInterfaceBody(self, body): # m.arguments is a sequence of tuples: # (argtype, argname, idlflags, docstring) # Some typelibs have unnamed method parameters! - inargs = [a[1] or '' for a in m.arguments - if not 'out' in a[2]] - outargs = [a[1] or '' for a in m.arguments - if 'out' in a[2]] - if 'propget' in m.idlflags: + inargs = [a[1] or "" for a in m.arguments if not "out" in a[2]] + outargs = [a[1] or "" for a in m.arguments if "out" in a[2]] + if "propget" in m.idlflags: methods.setdefault(m.name, [0, inargs, outargs, m.doc])[0] |= 1 - elif 'propput' in m.idlflags: - methods.setdefault(m.name, [0, inargs[:-1], inargs[-1:], m.doc])[0] |= 2 + elif "propput" in m.idlflags: + methods.setdefault(m.name, [0, inargs[:-1], inargs[-1:], m.doc])[ + 0 + ] |= 2 else: methods[m.name] = [0, inargs, outargs, m.doc] for name, (typ, inargs, outargs, doc) in methods.items(): - if typ == 0: # method - print("# def %s(%s):" % (name, ", ".join(["self"] + inargs)), file=self.stream) + if typ == 0: # method + print( + "# def %s(%s):" % (name, ", ".join(["self"] + inargs)), + file=self.stream, + ) print("# %r" % (doc or "-no docstring-"), file=self.stream) print("# #return %s" % (", ".join(outargs)), file=self.stream) - elif typ == 1: # propget + elif typ == 1: # propget print("# @property", file=self.stream) - print("# def %s(%s):" % (name, ", ".join(["self"] + inargs)), file=self.stream) + print( + "# def %s(%s):" % (name, ", ".join(["self"] + inargs)), + file=self.stream, + ) print("# %r" % (doc or "-no docstring-"), file=self.stream) print("# #return %s" % (", ".join(outargs)), file=self.stream) - elif typ == 2: # propput - print("# def _set(%s):" % ", ".join(["self"] + inargs + outargs), file=self.stream) + elif typ == 2: # propput + print( + "# def _set(%s):" % ", ".join(["self"] + inargs + outargs), + file=self.stream, + ) print("# %r" % (doc or "-no docstring-"), file=self.stream) - print("# %s = property(fset = _set, doc = _set.__doc__)" % name, file=self.stream) - elif typ == 3: # propget + propput - print("# def _get(%s):" % ", ".join(["self"] + inargs), file=self.stream) + print( + "# %s = property(fset = _set, doc = _set.__doc__)" % name, + file=self.stream, + ) + elif typ == 3: # propget + propput + print( + "# def _get(%s):" % ", ".join(["self"] + inargs), + file=self.stream, + ) print("# %r" % (doc or "-no docstring-"), file=self.stream) print("# #return %s" % (", ".join(outargs)), file=self.stream) - print("# def _set(%s):" % ", ".join(["self"] + inargs + outargs), file=self.stream) + print( + "# def _set(%s):" % ", ".join(["self"] + inargs + outargs), + file=self.stream, + ) print("# %r" % (doc or "-no docstring-"), file=self.stream) - print("# %s = property(_get, _set, doc = _set.__doc__)" % name, file=self.stream) + print( + "# %s = property(_get, _set, doc = _set.__doc__)" % name, + file=self.stream, + ) else: raise RuntimeError("BUG") print("#", file=self.stream) @@ -1172,8 +1252,11 @@ def make_ComMethod(self, m, isdual): self.last_item_class = False for typ, _, _, default in m.arguments: if isinstance(typ, typedesc.ComInterface): - self.declarations.add("OPENARRAY", "POINTER(c_ubyte)", - "hack, see comtypes/tools/codegenerator.py") + self.declarations.add( + "OPENARRAY", + "POINTER(c_ubyte)", + "hack, see comtypes/tools/codegenerator.py", + ) if default is not None: self.need_VARIANT_imports(default) @@ -1215,9 +1298,9 @@ def __call__(self, t): return t.name if isinstance(t, typedesc.PointerType): _t, pcnt = self._inspect_PointerType(t) - return "%s%s%s" % ("POINTER("*pcnt, self(_t), ")"*pcnt) + return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt) elif isinstance(t, typedesc.ArrayType): - return "%s * %s" % (self(t.typ), int(t.max)+1) + return "%s * %s" % (self(t.typ), int(t.max) + 1) elif isinstance(t, typedesc.FunctionType): args = [self(x) for x in [t.returns] + list(t.iterArgTypes())] if "__stdcall__" in t.attributes: @@ -1234,7 +1317,7 @@ def __call__(self, t): elif isinstance(t, typedesc.Enumeration): if t.name: return t.name - return "c_int" # enums are integers + return "c_int" # enums are integers elif isinstance(t, typedesc.EnumValue): if keyword.iskeyword(t.name): return t.name + "_" @@ -1271,6 +1354,7 @@ def __init__(self): self.data = {} else: from collections import OrderedDict + self.data = OrderedDict() def add(self, name1, name2=None, symbols=None): @@ -1358,9 +1442,9 @@ def _make_line(self, from_, imports, for_stub): if for_stub: import_ = "\n".join(" %s as %s," % (n, n) for n in imports) else: - wrapper = textwrap.TextWrapper(subsequent_indent=" ", - initial_indent=" ", - break_long_words=False) + wrapper = textwrap.TextWrapper( + subsequent_indent=" ", initial_indent=" ", break_long_words=False + ) import_ = "\n".join(wrapper.wrap(import_)) code = "from %s import (\n%s\n)" % (from_, import_) return code @@ -1390,6 +1474,7 @@ def __init__(self): self.data = {} else: from collections import OrderedDict + self.data = OrderedDict() def add(self, alias, definition, comment=None): diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index 8657f8fa..ec8b9a1f 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -9,7 +9,14 @@ if TYPE_CHECKING: from typing import ( - Any, Callable, Dict, List, Optional, Type, TypeVar, Tuple, + Any, + Callable, + Dict, + List, + Optional, + Type, + TypeVar, + Tuple, Union as _UnionT, ) from ctypes import _CData, _Pointer @@ -22,10 +29,10 @@ ################################ + def PTR(typ): - return typedesc.PointerType(typ, - sizeof(c_void_p)*8, - alignment(c_void_p)*8) + return typedesc.PointerType(typ, sizeof(c_void_p) * 8, alignment(c_void_p) * 8) + # basic C data types, with size and alignment in bits char_type = typedesc.FundamentalType("char", 8, 8) @@ -48,65 +55,73 @@ def PTR(typ): VARIANT_BOOL_type = typedesc.Typedef("VARIANT_BOOL", short_type) HRESULT_type = typedesc.Typedef("HRESULT", ulong_type) -VARIANT_type = typedesc.Structure("VARIANT", - align=alignment(automation.VARIANT)*8, - members=[], bases=[], - size=sizeof(automation.VARIANT)*8) +VARIANT_type = typedesc.Structure( + "VARIANT", + align=alignment(automation.VARIANT) * 8, + members=[], + bases=[], + size=sizeof(automation.VARIANT) * 8, +) IDISPATCH_type = typedesc.Typedef("IDispatch", None) IUNKNOWN_type = typedesc.Typedef("IUnknown", None) -DECIMAL_type = typedesc.Structure("DECIMAL", - align=alignment(automation.DECIMAL)*8, - members=[], bases=[], - size=sizeof(automation.DECIMAL)*8) +DECIMAL_type = typedesc.Structure( + "DECIMAL", + align=alignment(automation.DECIMAL) * 8, + members=[], + bases=[], + size=sizeof(automation.DECIMAL) * 8, +) + def midlSAFEARRAY(typ): return typedesc.SAFEARRAYType(typ) + # faked COM data types -CURRENCY_type = longlong_type # slightly wrong; should be scaled by 10000 - use subclass of longlong? -DATE_type = double_type # not *that* wrong... +CURRENCY_type = longlong_type # slightly wrong; should be scaled by 10000 - use subclass of longlong? +DATE_type = double_type # not *that* wrong... COMTYPES = { - automation.VT_I2: short_type, # 2 - automation.VT_I4: int_type, # 3 - automation.VT_R4: float_type, # 4 - automation.VT_R8: double_type, # 5 - automation.VT_CY: CURRENCY_type, # 6 - automation.VT_DATE: DATE_type, # 7 - automation.VT_BSTR: BSTR_type, # 8 - automation.VT_DISPATCH: PTR(IDISPATCH_type), # 9 - automation.VT_ERROR: SCODE_type, # 10 - automation.VT_BOOL: VARIANT_BOOL_type, # 11 - automation.VT_VARIANT: VARIANT_type, # 12 - automation.VT_UNKNOWN: PTR(IUNKNOWN_type), # 13 - automation.VT_DECIMAL: DECIMAL_type, # 14 - - automation.VT_I1: char_type, # 16 - automation.VT_UI1: uchar_type, # 17 - automation.VT_UI2: ushort_type, # 18 - automation.VT_UI4: ulong_type, # 19 - automation.VT_I8: longlong_type, # 20 - automation.VT_UI8: ulonglong_type, # 21 - automation.VT_INT: int_type, # 22 - automation.VT_UINT: uint_type, # 23 - automation.VT_VOID: typedesc.FundamentalType("void", 0, 0), # 24 - automation.VT_HRESULT: HRESULT_type, # 25 - automation.VT_LPSTR: PTR(char_type), # 30 - automation.VT_LPWSTR: PTR(wchar_t_type), # 31 + automation.VT_I2: short_type, # 2 + automation.VT_I4: int_type, # 3 + automation.VT_R4: float_type, # 4 + automation.VT_R8: double_type, # 5 + automation.VT_CY: CURRENCY_type, # 6 + automation.VT_DATE: DATE_type, # 7 + automation.VT_BSTR: BSTR_type, # 8 + automation.VT_DISPATCH: PTR(IDISPATCH_type), # 9 + automation.VT_ERROR: SCODE_type, # 10 + automation.VT_BOOL: VARIANT_BOOL_type, # 11 + automation.VT_VARIANT: VARIANT_type, # 12 + automation.VT_UNKNOWN: PTR(IUNKNOWN_type), # 13 + automation.VT_DECIMAL: DECIMAL_type, # 14 + automation.VT_I1: char_type, # 16 + automation.VT_UI1: uchar_type, # 17 + automation.VT_UI2: ushort_type, # 18 + automation.VT_UI4: ulong_type, # 19 + automation.VT_I8: longlong_type, # 20 + automation.VT_UI8: ulonglong_type, # 21 + automation.VT_INT: int_type, # 22 + automation.VT_UINT: uint_type, # 23 + automation.VT_VOID: typedesc.FundamentalType("void", 0, 0), # 24 + automation.VT_HRESULT: HRESULT_type, # 25 + automation.VT_LPSTR: PTR(char_type), # 30 + automation.VT_LPWSTR: PTR(wchar_t_type), # 31 } -#automation.VT_PTR = 26 # below -#automation.VT_SAFEARRAY = 27 -#automation.VT_CARRAY = 28 # below -#automation.VT_USERDEFINED = 29 # below +# automation.VT_PTR = 26 # below +# automation.VT_SAFEARRAY = 27 +# automation.VT_CARRAY = 28 # below +# automation.VT_USERDEFINED = 29 # below -#automation.VT_RECORD = 36 +# automation.VT_RECORD = 36 -#automation.VT_ARRAY = 8192 -#automation.VT_BYREF = 16384 +# automation.VT_ARRAY = 8192 +# automation.VT_BYREF = 16384 ################################################################ + class Parser(object): if TYPE_CHECKING: tlib = hints.AnnoField() # type: typeinfo.ITypeLib @@ -121,7 +136,9 @@ def make_type(self, tdesc, tinfo): typ = self.make_type(arraydesc.tdescElem, tinfo) for i in range(arraydesc.cDims): typ = typedesc.ArrayType( - typ, arraydesc.rgbounds[i].lLbound, arraydesc.rgbounds[i].cElements-1 + typ, + arraydesc.rgbounds[i].lLbound, + arraydesc.rgbounds[i].cElements - 1, ) return typ elif tdesc.vt == automation.VT_PTR: @@ -136,10 +153,13 @@ def make_type(self, tdesc, tinfo): tlib_name = get_tlib_filename(self.tlib) if tlib_name is None: tlib_name = "unknown typelib" - message = "\n\tGetRefTypeInfo failed in %s: %s\n\tgenerating type '%s' instead" % \ - (tlib_name, details, type_name) + message = ( + "\n\tGetRefTypeInfo failed in %s: %s\n\tgenerating type '%s' instead" + % (tlib_name, details, type_name) + ) import warnings - warnings.warn(message, UserWarning); + + warnings.warn(message, UserWarning) result = typedesc.Structure( type_name, align=8, members=[], bases=[], size=0 ) @@ -175,13 +195,15 @@ def ParseEnum(self, tinfo, ta): # TKIND_RECORD = 1 def ParseRecord(self, tinfo, ta): # type: (typeinfo.ITypeInfo, typeinfo.TYPEATTR) -> typedesc.Structure - members = [] # will be filled later + members = [] # will be filled later struct_name, doc, helpcntext, helpfile = tinfo.GetDocumentation(-1) - struct = typedesc.Structure(struct_name, - align=ta.cbAlignment*8, - members=members, - bases=[], - size=ta.cbSizeInstance*8) + struct = typedesc.Structure( + struct_name, + align=ta.cbAlignment * 8, + members=members, + bases=[], + size=ta.cbSizeInstance * 8, + ) self._register(struct_name, struct) tlib, _ = tinfo.GetContainingTypeLib() @@ -194,10 +216,13 @@ def ParseRecord(self, tinfo, ta): struct.align = 64 if ta.guid: - struct._recordinfo_ = (str(tlib_ta.guid), - tlib_ta.wMajorVerNum, tlib_ta.wMinorVerNum, - tlib_ta.lcid, - str(ta.guid)) + struct._recordinfo_ = ( + str(tlib_ta.guid), + tlib_ta.wMajorVerNum, + tlib_ta.wMinorVerNum, + tlib_ta.lcid, + str(ta.guid), + ) for i in range(ta.cVars): vd = tinfo.GetVarDesc(i) @@ -205,10 +230,7 @@ def ParseRecord(self, tinfo, ta): offset = vd._.oInst * 8 assert vd.varkind == typeinfo.VAR_PERINSTANCE typ = self.make_type(vd.elemdescVar.tdesc, tinfo) - field = typedesc.Field(name, - typ, - None, # bits - offset) + field = typedesc.Field(name, typ, None, offset) # bits members.append(field) return struct @@ -224,7 +246,7 @@ def ParseModule(self, tinfo, ta): fd = tinfo.GetFuncDesc(i) dllname, func_name, ordinal = tinfo.GetDllEntry(fd.memid, fd.invkind) func_doc = tinfo.GetDocumentation(fd.memid)[1] - assert 0 == fd.cParamsOpt # XXX + assert 0 == fd.cParamsOpt # XXX returns = self.make_type(fd.elemdescFunc.tdesc, tinfo) if fd.callconv == typeinfo.CC_CDECL: @@ -267,14 +289,17 @@ def ParseInterface(self, tinfo, ta): if itf_name != "IOleControlTypes": message = "Ignoring interface %s which has no base interface" % itf_name import warnings - warnings.warn(message, UserWarning); + + warnings.warn(message, UserWarning) return None - itf = typedesc.ComInterface(itf_name, - members=[], - base=None, - iid=str(ta.guid), - idlflags=self.interface_type_flags(ta.wTypeFlags)) + itf = typedesc.ComInterface( + itf_name, + members=[], + base=None, + iid=str(ta.guid), + idlflags=self.interface_type_flags(ta.wTypeFlags), + ) if itf_doc: itf.doc = itf_doc self._register(itf_name, itf) @@ -292,20 +317,26 @@ def ParseInterface(self, tinfo, ta): func_name, func_doc = tinfo.GetDocumentation(fd.memid)[:2] assert fd.funckind == typeinfo.FUNC_PUREVIRTUAL returns = self.make_type(fd.elemdescFunc.tdesc, tinfo) - names = tinfo.GetNames(fd.memid, fd.cParams+1) + names = tinfo.GetNames(fd.memid, fd.cParams + 1) names.append("rhs") - names = names[:fd.cParams + 1] + names = names[: fd.cParams + 1] assert len(names) == fd.cParams + 1 flags = self.func_flags(fd.wFuncFlags) flags += self.inv_kind(fd.invkind) - mth = typedesc.ComMethod(fd.invkind, fd.memid, func_name, returns, flags, func_doc) + mth = typedesc.ComMethod( + fd.invkind, fd.memid, func_name, returns, flags, func_doc + ) for p in range(fd.cParams): typ = self.make_type(fd.lprgelemdescParam[p].tdesc, tinfo) - name = names[p+1] + name = names[p + 1] flags = fd.lprgelemdescParam[p]._.paramdesc.wParamFlags if flags & typeinfo.PARAMFLAG_FHASDEFAULT: # XXX should be handled by VARIANT itself - var = fd.lprgelemdescParam[p]._.paramdesc.pparamdescex[0].varDefaultValue + var = ( + fd.lprgelemdescParam[p] + ._.paramdesc.pparamdescex[0] + .varDefaultValue + ) default = var.value # type: Any else: default = None @@ -328,11 +359,13 @@ def ParseDispatch(self, tinfo, ta): tibase = tinfo.GetRefTypeInfo(hr) base = self.parse_typeinfo(tibase) members = [] - itf = typedesc.DispInterface(itf_name, - members=members, - base=base, - iid=str(ta.guid), - idlflags=self.interface_type_flags(ta.wTypeFlags)) + itf = typedesc.DispInterface( + itf_name, + members=members, + base=base, + iid=str(ta.guid), + idlflags=self.interface_type_flags(ta.wTypeFlags), + ) if doc is not None: itf.doc = str(doc.split("\0")[0]) self._register(itf_name, itf) @@ -346,7 +379,9 @@ def ParseDispatch(self, tinfo, ta): assert vd.varkind == typeinfo.VAR_DISPATCH var_name, var_doc = tinfo.GetDocumentation(vd.memid)[0:2] typ = self.make_type(vd.elemdescVar.tdesc, tinfo) - mth = typedesc.DispProperty(vd.memid, var_name, typ, self.var_flags(vd.wVarFlags), var_doc) + mth = typedesc.DispProperty( + vd.memid, var_name, typ, self.var_flags(vd.wVarFlags), var_doc + ) itf.members.append(mth) # At least the EXCEL typelib lists the IUnknown and IDispatch @@ -356,9 +391,17 @@ def ParseDispatch(self, tinfo, ta): # CLF: 12/14/2012 Do this in a way that does not exclude other methods. # I have encountered typlibs where only "QueryInterface", "AddRef" # and "Release" are to be skipped. - ignored_names = set(["QueryInterface", "AddRef", "Release", - "GetTypeInfoCount", "GetTypeInfo", - "GetIDsOfNames", "Invoke"]) + ignored_names = set( + [ + "QueryInterface", + "AddRef", + "Release", + "GetTypeInfoCount", + "GetTypeInfo", + "GetIDsOfNames", + "Invoke", + ] + ) for i in range(ta.cFuncs): fd = tinfo.GetFuncDesc(i) @@ -368,17 +411,21 @@ def ParseDispatch(self, tinfo, ta): assert fd.funckind == typeinfo.FUNC_DISPATCH returns = self.make_type(fd.elemdescFunc.tdesc, tinfo) - names = tinfo.GetNames(fd.memid, fd.cParams+1) + names = tinfo.GetNames(fd.memid, fd.cParams + 1) names.append("rhs") - names = names[:fd.cParams + 1] - assert len(names) == fd.cParams + 1 # function name first, then parameter names + names = names[: fd.cParams + 1] + assert ( + len(names) == fd.cParams + 1 + ) # function name first, then parameter names flags = self.func_flags(fd.wFuncFlags) flags += self.inv_kind(fd.invkind) - mth = typedesc.DispMethod(fd.memid, fd.invkind, func_name, returns, flags, func_doc) + mth = typedesc.DispMethod( + fd.memid, fd.invkind, func_name, returns, flags, func_doc + ) for p in range(fd.cParams): descparam = fd.lprgelemdescParam[p] typ = self.make_type(descparam.tdesc, tinfo) - name = names[p+1] + name = names[p + 1] flags = descparam._.paramdesc.wParamFlags if flags & typeinfo.PARAMFLAG_FHASDEFAULT: var = descparam._.paramdesc.pparamdescex[0].varDefaultValue # type: ignore @@ -391,105 +438,115 @@ def ParseDispatch(self, tinfo, ta): def inv_kind(self, invkind): # type: (int) -> List[str] - NAMES = {automation.DISPATCH_METHOD: [], - automation.DISPATCH_PROPERTYPUT: ["propput"], - automation.DISPATCH_PROPERTYPUTREF: ["propputref"], - automation.DISPATCH_PROPERTYGET: ["propget"]} + NAMES = { + automation.DISPATCH_METHOD: [], + automation.DISPATCH_PROPERTYPUT: ["propput"], + automation.DISPATCH_PROPERTYPUTREF: ["propputref"], + automation.DISPATCH_PROPERTYGET: ["propget"], + } return NAMES[invkind] def func_flags(self, flags): # type: (int) -> List[str] # map FUNCFLAGS values to idl attributes - NAMES = {typeinfo.FUNCFLAG_FRESTRICTED: "restricted", - typeinfo.FUNCFLAG_FSOURCE: "source", - typeinfo.FUNCFLAG_FBINDABLE: "bindable", - typeinfo.FUNCFLAG_FREQUESTEDIT: "requestedit", - typeinfo.FUNCFLAG_FDISPLAYBIND: "displaybind", - typeinfo.FUNCFLAG_FDEFAULTBIND: "defaultbind", - typeinfo.FUNCFLAG_FHIDDEN: "hidden", - typeinfo.FUNCFLAG_FUSESGETLASTERROR: "usesgetlasterror", - typeinfo.FUNCFLAG_FDEFAULTCOLLELEM: "defaultcollelem", - typeinfo.FUNCFLAG_FUIDEFAULT: "uidefault", - typeinfo.FUNCFLAG_FNONBROWSABLE: "nonbrowsable", - # typeinfo.FUNCFLAG_FREPLACEABLE: "???", - typeinfo.FUNCFLAG_FIMMEDIATEBIND: "immediatebind"} + NAMES = { + typeinfo.FUNCFLAG_FRESTRICTED: "restricted", + typeinfo.FUNCFLAG_FSOURCE: "source", + typeinfo.FUNCFLAG_FBINDABLE: "bindable", + typeinfo.FUNCFLAG_FREQUESTEDIT: "requestedit", + typeinfo.FUNCFLAG_FDISPLAYBIND: "displaybind", + typeinfo.FUNCFLAG_FDEFAULTBIND: "defaultbind", + typeinfo.FUNCFLAG_FHIDDEN: "hidden", + typeinfo.FUNCFLAG_FUSESGETLASTERROR: "usesgetlasterror", + typeinfo.FUNCFLAG_FDEFAULTCOLLELEM: "defaultcollelem", + typeinfo.FUNCFLAG_FUIDEFAULT: "uidefault", + typeinfo.FUNCFLAG_FNONBROWSABLE: "nonbrowsable", + # typeinfo.FUNCFLAG_FREPLACEABLE: "???", + typeinfo.FUNCFLAG_FIMMEDIATEBIND: "immediatebind", + } return [NAMES[bit] for bit in NAMES if bit & flags] def param_flags(self, flags): # type: (int) -> List[str] # map PARAMFLAGS values to idl attributes - NAMES = {typeinfo.PARAMFLAG_FIN: "in", - typeinfo.PARAMFLAG_FOUT: "out", - typeinfo.PARAMFLAG_FLCID: "lcid", - typeinfo.PARAMFLAG_FRETVAL: "retval", - typeinfo.PARAMFLAG_FOPT: "optional", - # typeinfo.PARAMFLAG_FHASDEFAULT: "", - # typeinfo.PARAMFLAG_FHASCUSTDATA: "", - } + NAMES = { + typeinfo.PARAMFLAG_FIN: "in", + typeinfo.PARAMFLAG_FOUT: "out", + typeinfo.PARAMFLAG_FLCID: "lcid", + typeinfo.PARAMFLAG_FRETVAL: "retval", + typeinfo.PARAMFLAG_FOPT: "optional", + # typeinfo.PARAMFLAG_FHASDEFAULT: "", + # typeinfo.PARAMFLAG_FHASCUSTDATA: "", + } return [NAMES[bit] for bit in NAMES if bit & flags] def coclass_type_flags(self, flags): # type: (int) -> List[str] # map TYPEFLAGS values to idl attributes - NAMES = {typeinfo.TYPEFLAG_FAPPOBJECT: "appobject", - # typeinfo.TYPEFLAG_FCANCREATE: - typeinfo.TYPEFLAG_FLICENSED: "licensed", - # typeinfo.TYPEFLAG_FPREDECLID: - typeinfo.TYPEFLAG_FHIDDEN: "hidden", - typeinfo.TYPEFLAG_FCONTROL: "control", - typeinfo.TYPEFLAG_FDUAL: "dual", - typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible", - typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation", - typeinfo.TYPEFLAG_FRESTRICTED: "restricted", - typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable", - # typeinfo.TYPEFLAG_FREPLACEABLE: - # typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this - typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind", - typeinfo.TYPEFLAG_FPROXY: "proxy", - } + NAMES = { + typeinfo.TYPEFLAG_FAPPOBJECT: "appobject", + # typeinfo.TYPEFLAG_FCANCREATE: + typeinfo.TYPEFLAG_FLICENSED: "licensed", + # typeinfo.TYPEFLAG_FPREDECLID: + typeinfo.TYPEFLAG_FHIDDEN: "hidden", + typeinfo.TYPEFLAG_FCONTROL: "control", + typeinfo.TYPEFLAG_FDUAL: "dual", + typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible", + typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation", + typeinfo.TYPEFLAG_FRESTRICTED: "restricted", + typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable", + # typeinfo.TYPEFLAG_FREPLACEABLE: + # typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this + typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind", + typeinfo.TYPEFLAG_FPROXY: "proxy", + } NEGATIVE_NAMES = {typeinfo.TYPEFLAG_FCANCREATE: "noncreatable"} - return [NAMES[bit] for bit in NAMES if bit & flags] + \ - [NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags)] + return [NAMES[bit] for bit in NAMES if bit & flags] + [ + NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags) + ] def interface_type_flags(self, flags): # type: (int) -> List[str] # map TYPEFLAGS values to idl attributes - NAMES = {typeinfo.TYPEFLAG_FAPPOBJECT: "appobject", - # typeinfo.TYPEFLAG_FCANCREATE: - typeinfo.TYPEFLAG_FLICENSED: "licensed", - # typeinfo.TYPEFLAG_FPREDECLID: - typeinfo.TYPEFLAG_FHIDDEN: "hidden", - typeinfo.TYPEFLAG_FCONTROL: "control", - typeinfo.TYPEFLAG_FDUAL: "dual", - typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible", - typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation", - typeinfo.TYPEFLAG_FRESTRICTED: "restricted", - typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable", - # typeinfo.TYPEFLAG_FREPLACEABLE: - # typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this - typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind", - typeinfo.TYPEFLAG_FPROXY: "proxy", - } + NAMES = { + typeinfo.TYPEFLAG_FAPPOBJECT: "appobject", + # typeinfo.TYPEFLAG_FCANCREATE: + typeinfo.TYPEFLAG_FLICENSED: "licensed", + # typeinfo.TYPEFLAG_FPREDECLID: + typeinfo.TYPEFLAG_FHIDDEN: "hidden", + typeinfo.TYPEFLAG_FCONTROL: "control", + typeinfo.TYPEFLAG_FDUAL: "dual", + typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible", + typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation", + typeinfo.TYPEFLAG_FRESTRICTED: "restricted", + typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable", + # typeinfo.TYPEFLAG_FREPLACEABLE: + # typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this + typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind", + typeinfo.TYPEFLAG_FPROXY: "proxy", + } NEGATIVE_NAMES = {} - return [NAMES[bit] for bit in NAMES if bit & flags] + \ - [NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags)] + return [NAMES[bit] for bit in NAMES if bit & flags] + [ + NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags) + ] def var_flags(self, flags): # type: (int) -> List[str] - NAMES = {typeinfo.VARFLAG_FREADONLY: "readonly", - typeinfo.VARFLAG_FSOURCE: "source", - typeinfo.VARFLAG_FBINDABLE: "bindable", - typeinfo.VARFLAG_FREQUESTEDIT: "requestedit", - typeinfo.VARFLAG_FDISPLAYBIND: "displaybind", - typeinfo.VARFLAG_FDEFAULTBIND: "defaultbind", - typeinfo.VARFLAG_FHIDDEN: "hidden", - typeinfo.VARFLAG_FRESTRICTED: "restricted", - typeinfo.VARFLAG_FDEFAULTCOLLELEM: "defaultcollelem", - typeinfo.VARFLAG_FUIDEFAULT: "uidefault", - typeinfo.VARFLAG_FNONBROWSABLE: "nonbrowsable", - typeinfo.VARFLAG_FREPLACEABLE: "replaceable", - typeinfo.VARFLAG_FIMMEDIATEBIND: "immediatebind" - } + NAMES = { + typeinfo.VARFLAG_FREADONLY: "readonly", + typeinfo.VARFLAG_FSOURCE: "source", + typeinfo.VARFLAG_FBINDABLE: "bindable", + typeinfo.VARFLAG_FREQUESTEDIT: "requestedit", + typeinfo.VARFLAG_FDISPLAYBIND: "displaybind", + typeinfo.VARFLAG_FDEFAULTBIND: "defaultbind", + typeinfo.VARFLAG_FHIDDEN: "hidden", + typeinfo.VARFLAG_FRESTRICTED: "restricted", + typeinfo.VARFLAG_FDEFAULTCOLLELEM: "defaultcollelem", + typeinfo.VARFLAG_FUIDEFAULT: "uidefault", + typeinfo.VARFLAG_FNONBROWSABLE: "nonbrowsable", + typeinfo.VARFLAG_FREPLACEABLE: "replaceable", + typeinfo.VARFLAG_FIMMEDIATEBIND: "immediatebind", + } return [NAMES[bit] for bit in NAMES if bit & flags] # TKIND_COCLASS = 5 @@ -499,10 +556,9 @@ def ParseCoClass(self, tinfo, ta): # version, control, hidden, and appobject coclass_name, doc = tinfo.GetDocumentation(-1)[0:2] tlibattr = tinfo.GetContainingTypeLib()[0].GetLibAttr() - coclass = typedesc.CoClass(coclass_name, - str(ta.guid), - self.coclass_type_flags(ta.wTypeFlags), - tlibattr) + coclass = typedesc.CoClass( + coclass_name, str(ta.guid), self.coclass_type_flags(ta.wTypeFlags), tlibattr + ) if doc is not None: coclass.doc = doc self._register(coclass_name, coclass) @@ -529,11 +585,13 @@ def ParseUnion(self, tinfo, ta): # type: (typeinfo.ITypeInfo, typeinfo.TYPEATTR) -> typedesc.Union union_name, doc, helpcntext, helpfile = tinfo.GetDocumentation(-1) members = [] - union = typedesc.Union(union_name, - align=ta.cbAlignment*8, - members=members, - bases=[], - size=ta.cbSizeInstance*8) + union = typedesc.Union( + union_name, + align=ta.cbAlignment * 8, + members=members, + bases=[], + size=ta.cbSizeInstance * 8, + ) self._register(union_name, union) tlib, _ = tinfo.GetContainingTypeLib() @@ -551,10 +609,7 @@ def ParseUnion(self, tinfo, ta): offset = vd._.oInst * 8 assert vd.varkind == typeinfo.VAR_PERINSTANCE typ = self.make_type(vd.elemdescVar.tdesc, tinfo) - field = typedesc.Field(name, - typ, - None, # bits - offset) + field = typedesc.Field(name, typ, None, offset) # bits members.append(field) return union @@ -603,15 +658,15 @@ def parse_typeinfo(self, tinfo): ta = tinfo.GetTypeAttr() tkind = ta.typekind - if tkind == typeinfo.TKIND_ENUM: # 0 + if tkind == typeinfo.TKIND_ENUM: # 0 return self.ParseEnum(tinfo, ta) - elif tkind == typeinfo.TKIND_RECORD: # 1 + elif tkind == typeinfo.TKIND_RECORD: # 1 return self.ParseRecord(tinfo, ta) - elif tkind == typeinfo.TKIND_MODULE: # 2 + elif tkind == typeinfo.TKIND_MODULE: # 2 return self.ParseModule(tinfo, ta) - elif tkind == typeinfo.TKIND_INTERFACE: # 3 + elif tkind == typeinfo.TKIND_INTERFACE: # 3 return self.ParseInterface(tinfo, ta) - elif tkind == typeinfo.TKIND_DISPATCH: # 4 + elif tkind == typeinfo.TKIND_DISPATCH: # 4 try: # GetRefTypeOfImplType(-1) returns the custom portion # of a dispinterface, if it is dual @@ -623,11 +678,11 @@ def parse_typeinfo(self, tinfo): ta = tinfo.GetTypeAttr() assert ta.typekind == typeinfo.TKIND_INTERFACE return self.ParseInterface(tinfo, ta) - elif tkind == typeinfo.TKIND_COCLASS: # 5 + elif tkind == typeinfo.TKIND_COCLASS: # 5 return self.ParseCoClass(tinfo, ta) - elif tkind == typeinfo.TKIND_ALIAS: # 6 + elif tkind == typeinfo.TKIND_ALIAS: # 6 return self.ParseAlias(tinfo, ta) - elif tkind == typeinfo.TKIND_UNION: # 7 + elif tkind == typeinfo.TKIND_UNION: # 7 return self.ParseUnion(tinfo, ta) else: print("NYI", tkind) @@ -636,9 +691,9 @@ def parse_typeinfo(self, tinfo): def parse_LibraryDescription(self): la = self.tlib.GetLibAttr() name, doc = self.tlib.GetDocumentation(-1)[:2] - desc = typedesc.TypeLib(name, - str(la.guid), la.wMajorVerNum, la.wMinorVerNum, - doc) + desc = typedesc.TypeLib( + name, str(la.guid), la.wMajorVerNum, la.wMinorVerNum, doc + ) self._register(None, desc) ################################################################ @@ -651,18 +706,22 @@ def parse(self): self.parse_typeinfo(tinfo) return self.items + class TlbFileParser(Parser): "Parses a type library from a file" + def __init__(self, path): # XXX DOESN'T LOOK CORRECT: We should NOT register the typelib. - self.tlib = typeinfo.LoadTypeLibEx(path)#, regkind=typeinfo.REGKIND_REGISTER) + self.tlib = typeinfo.LoadTypeLibEx(path) # , regkind=typeinfo.REGKIND_REGISTER) self.items = {} + class TypeLibParser(Parser): def __init__(self, tlib): self.tlib = tlib self.items = {} + ################################################################ # some interesting typelibs @@ -707,11 +766,13 @@ def __init__(self, tlib): # path = r"c:\vc98\include\activscp.tlb" + def get_tlib_filename(tlib): # seems if the typelib is not registered, there's no way to # determine the filename. from ctypes import windll, byref from comtypes import BSTR + la = tlib.GetLibAttr() name = BSTR() try: @@ -719,12 +780,9 @@ def get_tlib_filename(tlib): except AttributeError: # Windows CE doesn't have this function return None - if 0 == windll.oleaut32.QueryPathOfRegTypeLib(byref(la.guid), - la.wMajorVerNum, - la.wMinorVerNum, - 0, # lcid - byref(name) - ): + if 0 == windll.oleaut32.QueryPathOfRegTypeLib( + byref(la.guid), la.wMajorVerNum, la.wMinorVerNum, 0, byref(name) # lcid + ): full_filename = name.value.split("\0")[0] if not os.path.isabs(full_filename): # workaround Windows 7 bug in QueryPathOfRegTypeLib returning relative path @@ -737,10 +795,12 @@ def get_tlib_filename(tlib): return full_filename return None + def _py2exe_hint(): # If the tlbparser is frozen, we need to include these import comtypes.persist import comtypes.typeinfo import comtypes.automation + # -eof- diff --git a/comtypes/tools/typedesc.py b/comtypes/tools/typedesc.py index 036d0a34..d828dea9 100644 --- a/comtypes/tools/typedesc.py +++ b/comtypes/tools/typedesc.py @@ -20,7 +20,13 @@ def __init__(self, name, guid, major, minor, doc=None): self.doc = doc def __repr__(self): - return "" % (self.name, self.guid, self.major, self.minor) + return "" % ( + self.name, + self.guid, + self.major, + self.minor, + ) + class Constant(object): def __init__(self, name, typ, value): @@ -29,6 +35,7 @@ def __init__(self, name, typ, value): self.typ = typ self.value = value + class External(object): def __init__(self, tlib, name, size, align, docs=None): # type: (ITypeLib, str, int, int, Optional[Tuple[str, str]]) -> None @@ -46,12 +53,14 @@ def get_head(self): # codegen might call this return self + class SAFEARRAYType(object): def __init__(self, typ): # type: (Any) -> None self.typ = typ self.align = self.size = ctypes.sizeof(ctypes.c_void_p) * 8 + class ComMethod(object): # custom COM method, parsed from typelib def __init__(self, invkind, memid, name, returns, idlflags, doc): @@ -68,6 +77,7 @@ def add_argument(self, typ, name, idlflags, default): # type: (Any, str, List[str], Optional[Any]) -> None self.arguments.append((typ, name, idlflags, default)) + class DispMethod(object): # dispatchable COM method, parsed from typelib def __init__(self, dispid, invkind, name, returns, idlflags, doc): @@ -84,6 +94,7 @@ def add_argument(self, typ, name, idlflags, default): # type: (Any, str, List[str], Optional[Any]) -> None self.arguments.append((typ, name, idlflags, default)) + class DispProperty(object): # dispatchable COM property, parsed from typelib def __init__(self, dispid, name, typ, idlflags, doc): @@ -94,16 +105,19 @@ def __init__(self, dispid, name, typ, idlflags, doc): self.idlflags = idlflags self.doc = doc + class DispInterfaceHead(object): def __init__(self, itf): # type: (DispInterface) -> None self.itf = itf + class DispInterfaceBody(object): def __init__(self, itf): # type: (DispInterface) -> None self.itf = itf + class DispInterface(object): def __init__(self, name, members, base, iid, idlflags): # type: (str, List[_UnionT[DispMethod, DispProperty]], Any, str, List[str]) -> None @@ -123,16 +137,19 @@ def get_head(self): # type: () -> DispInterfaceHead return self.itf_head + class ComInterfaceHead(object): def __init__(self, itf): # type: (ComInterface) -> None self.itf = itf + class ComInterfaceBody(object): def __init__(self, itf): # type: (ComInterface) -> None self.itf = itf + class ComInterface(object): def __init__(self, name, members, base, iid, idlflags): # type: (str, List[ComMethod], Any, str, List[str]) -> None @@ -152,6 +169,7 @@ def get_head(self): # type: () -> ComInterfaceHead return self.itf_head + class CoClass(object): def __init__(self, name, clsid, idlflags, tlibattr): # type: (str, str, List[str], TLIBATTR) -> None diff --git a/comtypes/tools/typedesc_base.py b/comtypes/tools/typedesc_base.py index 59f4af96..9d054952 100644 --- a/comtypes/tools/typedesc_base.py +++ b/comtypes/tools/typedesc_base.py @@ -9,12 +9,13 @@ class Argument(object): "a Parameter in the argument list of a callable (Function, Method, ...)" + def __init__(self, atype, name): self.atype = atype self.name = name -class _HasArgs(object): +class _HasArgs(object): def __init__(self): self.arguments = [] @@ -37,6 +38,7 @@ def fixup_argtypes(self, typemap): ################ + class Alias(object): # a C preprocessor alias, like #define A B def __init__(self, name, alias, typ=None): @@ -44,6 +46,7 @@ def __init__(self, name, alias, typ=None): self.alias = alias self.typ = typ + class Macro(object): # a C preprocessor definition with arguments def __init__(self, name, args, body): @@ -54,98 +57,127 @@ def __init__(self, name, args, body): self.args = args self.body = body + class File(object): def __init__(self, name): self.name = name + class Function(_HasArgs): location = None + def __init__(self, name, returns, attributes, extern): _HasArgs.__init__(self) self.name = name self.returns = returns - self.attributes = attributes # dllimport, __stdcall__, __cdecl__ + self.attributes = attributes # dllimport, __stdcall__, __cdecl__ self.extern = extern + class Constructor(_HasArgs): location = None + def __init__(self, name): _HasArgs.__init__(self) self.name = name + class OperatorFunction(_HasArgs): location = None + def __init__(self, name, returns): _HasArgs.__init__(self) self.name = name self.returns = returns + class FunctionType(_HasArgs): location = None + def __init__(self, returns, attributes): _HasArgs.__init__(self) self.returns = returns self.attributes = attributes + class Method(_HasArgs): location = None + def __init__(self, name, returns): _HasArgs.__init__(self) self.name = name self.returns = returns + class FundamentalType(object): location = None + def __init__(self, name, size, align): self.name = name if name != "void": self.size = int(size) self.align = int(align) + class PointerType(object): location = None + def __init__(self, typ, size, align): self.typ = typ self.size = int(size) self.align = int(align) + class Typedef(object): location = None + def __init__(self, name, typ): self.name = name self.typ = typ + class ArrayType(object): location = None + def __init__(self, typ, min, max): # type: (Any, int, int) -> None self.typ = typ self.min = min self.max = max + class StructureHead(object): location = None + def __init__(self, struct): # type: (_Struct_Union_Base) -> None self.struct = struct + class StructureBody(object): location = None + def __init__(self, struct): # type: (_Struct_Union_Base) -> None self.struct = struct + class _Struct_Union_Base(object): if TYPE_CHECKING: name = comtypes.hints.AnnoField() # type: str align = comtypes.hints.AnnoField() # type: int - members = comtypes.hints.AnnoField() # type: List[_UnionT[Field, Method, Constructor]] + members = ( + comtypes.hints.AnnoField() + ) # type: List[_UnionT[Field, Method, Constructor]] bases = comtypes.hints.AnnoField() # type: List[_Struct_Union_Base] artificial = comtypes.hints.AnnoField() # type: Optional[Any] size = comtypes.hints.AnnoField() # type: Optional[int] - _recordinfo_ = comtypes.hints.AnnoField() # type: Tuple[str, int, int, int, str] + _recordinfo_ = ( + comtypes.hints.AnnoField() + ) # type: Tuple[str, int, int, int, str] location = None + def __init__(self): self.struct_body = StructureBody(self) self.struct_head = StructureHead(self) @@ -158,6 +190,7 @@ def get_head(self): # type: () -> StructureHead return self.struct_head + class Structure(_Struct_Union_Base): def __init__(self, name, align, members, bases, size, artificial=None): # type: (str, SupportsInt, List[Field], List[Any], Optional[SupportsInt], Optional[Any]) -> None @@ -172,6 +205,7 @@ def __init__(self, name, align, members, bases, size, artificial=None): self.size = None super(Structure, self).__init__() + class Union(_Struct_Union_Base): def __init__(self, name, align, members, bases, size, artificial=None): # type: (str, SupportsInt, List[Field], List[Any], Optional[SupportsInt], Optional[Any]) -> None @@ -186,6 +220,7 @@ def __init__(self, name, align, members, bases, size, artificial=None): self.size = None super(Union, self).__init__() + class Field(object): def __init__(self, name, typ, bits, offset): # type: (str, Any, Optional[Any], SupportsInt) -> None @@ -194,14 +229,17 @@ def __init__(self, name, typ, bits, offset): self.bits = bits self.offset = int(offset) + class CvQualifiedType(object): def __init__(self, typ, const, volatile): self.typ = typ self.const = const self.volatile = volatile + class Enumeration(object): location = None + def __init__(self, name, size, align): # type: (str, SupportsInt, SupportsInt) -> None self.name = name @@ -213,6 +251,7 @@ def add_value(self, v): # type: (EnumValue) -> None self.values.append(v) + class EnumValue(object): def __init__(self, name, value, enumeration): # type: (str, int, Enumeration) -> None @@ -220,11 +259,14 @@ def __init__(self, name, value, enumeration): self.value = value self.enumeration = enumeration + class Variable(object): location = None + def __init__(self, name, typ, init=None): self.name = name self.typ = typ self.init = init + ################################################################ diff --git a/comtypes/typeinfo.py b/comtypes/typeinfo.py index 1c05645b..0ac30a4a 100644 --- a/comtypes/typeinfo.py +++ b/comtypes/typeinfo.py @@ -10,20 +10,43 @@ from ctypes import * from ctypes.wintypes import DWORD, LONG, UINT, ULONG, WCHAR, WORD from comtypes import ( - BSTR, COMMETHOD, _GUID, GUID, IID, IUnknown, STDMETHOD, TYPE_CHECKING, + BSTR, + COMMETHOD, + _GUID, + GUID, + IID, + IUnknown, + STDMETHOD, + TYPE_CHECKING, ) from comtypes.automation import ( - DISPID, DISPPARAMS, EXCEPINFO, LCID, SCODE, VARIANT, VARIANTARG, VARTYPE, + DISPID, + DISPPARAMS, + EXCEPINFO, + LCID, + SCODE, + VARIANT, + VARIANTARG, + VARTYPE, tagVARIANT, ) if TYPE_CHECKING: from ctypes import _CData, _Pointer from typing import ( - Any, Callable, List, Optional, overload, Sequence, Type, TypeVar, - Tuple, Union as _UnionT, + Any, + Callable, + List, + Optional, + overload, + Sequence, + Type, + TypeVar, + Tuple, + Union as _UnionT, ) from comtypes import hints + _CT = TypeVar("_CT", bound=_CData) _T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown) @@ -44,20 +67,20 @@ ################################################################ # enums -tagSYSKIND = c_int # enum +tagSYSKIND = c_int # enum SYS_WIN16 = 0 SYS_WIN32 = 1 SYS_MAC = 2 SYS_WIN64 = 3 SYSKIND = tagSYSKIND -tagREGKIND = c_int # enum +tagREGKIND = c_int # enum REGKIND_DEFAULT = 0 REGKIND_REGISTER = 1 REGKIND_NONE = 2 REGKIND = tagREGKIND -tagTYPEKIND = c_int # enum +tagTYPEKIND = c_int # enum TKIND_ENUM = 0 TKIND_RECORD = 1 TKIND_MODULE = 2 @@ -69,14 +92,14 @@ TKIND_MAX = 8 TYPEKIND = tagTYPEKIND -tagINVOKEKIND = c_int # enum +tagINVOKEKIND = c_int # enum INVOKE_FUNC = 1 INVOKE_PROPERTYGET = 2 INVOKE_PROPERTYPUT = 4 INVOKE_PROPERTYPUTREF = 8 INVOKEKIND = tagINVOKEKIND -tagDESCKIND = c_int # enum +tagDESCKIND = c_int # enum DESCKIND_NONE = 0 DESCKIND_FUNCDESC = 1 DESCKIND_VARDESC = 2 @@ -85,14 +108,14 @@ DESCKIND_MAX = 5 DESCKIND = tagDESCKIND -tagVARKIND = c_int # enum +tagVARKIND = c_int # enum VAR_PERINSTANCE = 0 VAR_STATIC = 1 VAR_CONST = 2 VAR_DISPATCH = 3 VARKIND = tagVARKIND -tagFUNCKIND = c_int # enum +tagFUNCKIND = c_int # enum FUNC_VIRTUAL = 0 FUNC_PUREVIRTUAL = 1 FUNC_NONVIRTUAL = 2 @@ -100,7 +123,7 @@ FUNC_DISPATCH = 4 FUNCKIND = tagFUNCKIND -tagCALLCONV = c_int # enum +tagCALLCONV = c_int # enum CC_FASTCALL = 0 CC_CDECL = 1 CC_MSCPASCAL = 2 @@ -119,7 +142,7 @@ IMPLTYPEFLAG_FRESTRICTED = 4 IMPLTYPEFLAG_FDEFAULTVTABLE = 8 -tagTYPEFLAGS = c_int # enum +tagTYPEFLAGS = c_int # enum TYPEFLAG_FAPPOBJECT = 1 TYPEFLAG_FCANCREATE = 2 TYPEFLAG_FLICENSED = 4 @@ -137,7 +160,7 @@ TYPEFLAG_FPROXY = 16384 TYPEFLAGS = tagTYPEFLAGS -tagFUNCFLAGS = c_int # enum +tagFUNCFLAGS = c_int # enum FUNCFLAG_FRESTRICTED = 1 FUNCFLAG_FSOURCE = 2 FUNCFLAG_FBINDABLE = 4 @@ -153,7 +176,7 @@ FUNCFLAG_FIMMEDIATEBIND = 4096 FUNCFLAGS = tagFUNCFLAGS -tagVARFLAGS = c_int # enum +tagVARFLAGS = c_int # enum VARFLAG_FREADONLY = 1 VARFLAG_FSOURCE = 2 VARFLAG_FBINDABLE = 4 @@ -181,6 +204,7 @@ ################################################################ # a helper + def _deref_with_release(ptr, release): # type: (_Pointer[_CT], Callable[..., Any]) -> _CT # Given a POINTER instance, return the pointed to value. @@ -190,42 +214,52 @@ def _deref_with_release(ptr, release): result.__ref__ = weakref.ref(result, lambda dead: release(ptr)) return result + # interfaces + class ITypeLib(IUnknown): _iid_ = GUID("{00020402-0000-0000-C000-000000000046}") # type-checking only methods use the default implementation that comtypes # automatically creates for COM methods. if TYPE_CHECKING: + def GetTypeInfoCount(self): # type: () -> int """Return the number of type informations""" raise + def GetTypeInfo(self, index): # type: (int) -> ITypeInfo """Load type info by index""" raise + def GetTypeInfoType(self, index): # type: (int) -> int """Return the TYPEKIND of type information""" raise + def GetTypeInfoOfGuid(self, guid): # type: (GUID) -> ITypeInfo """Return type information for a guid""" raise + def GetTypeComp(self): # type: () -> ITypeComp """Return an ITypeComp pointer.""" raise + def GetDocumentation(self, index): # type: (int) -> Tuple[str, str, int, Optional[str]] """Return documentation for a type description.""" raise + def ReleaseTLibAttr(self, ptla): # type: (_Pointer[TLIBATTR]) -> int """Release TLIBATTR""" raise + _GetLibAttr = hints.AnnoField() # type: Callable[[], _Pointer[TLIBATTR]] def GetLibAttr(self): @@ -241,6 +275,7 @@ def IsName(self, name, lHashVal=0): library, or None. """ from ctypes import create_unicode_buffer + namebuf = create_unicode_buffer(name) found = BOOL() self.__com_IsName(namebuf, lHashVal, byref(found)) # type: ignore @@ -260,16 +295,21 @@ def FindName(self, name, lHashVal=0): return memid.value, tinfo # type: ignore return None + ################ if TYPE_CHECKING: + @overload def fix_name(name): # type: (None) -> None pass + @overload def fix_name(name): # type: (str) -> str pass + + def fix_name(name): # Some typelibs contain BSTR with embedded NUL characters, # probably the len of the BSTR is wrong. @@ -277,47 +317,58 @@ def fix_name(name): return name return name.split("\0")[0] + class ITypeInfo(IUnknown): _iid_ = GUID("{00020401-0000-0000-C000-000000000046}") if TYPE_CHECKING: + def GetTypeComp(self): # type: () -> ITypeComp """Return ITypeComp pointer for this type""" raise + def GetRefTypeOfImplType(self, index): # type: (int) -> int """Get the reftype of an implemented type""" raise + def GetImplTypeFlags(self, index): # type: (int) -> int """Get IMPLTYPEFLAGS""" raise + # not yet wrapped # STDMETHOD(HRESULT, 'Invoke', [PVOID, MEMBERID, WORD, POINTER(DISPPARAMS), POINTER(VARIANT), POINTER(EXCEPINFO), POINTER(UINT)]), def GetDllEntry(self, memid, invkind): # type: (int, int) -> Tuple[Optional[str], Optional[str], int] """Return the dll name, function name, and ordinal for a function and invkind.""" raise + def GetRefTypeInfo(self, href): # type: (int) -> ITypeInfo """Get type info for reftype""" raise + def GetMops(self, index): # type: (int) -> Optional[str] """Get marshalling opcodes (whatever that is...)""" raise + def GetContainingTypeLib(self): # type: () -> Tuple[ITypeLib, int] """Return index into and the containing type lib itself""" raise + ReleaseTypeAttr = hints.AnnoField() # type: Callable[[_Pointer[TYPEATTR]], int] ReleaseFuncDesc = hints.AnnoField() # type: Callable[[_Pointer[FUNCDESC]], int] ReleaseVarDesc = hints.AnnoField() # type: Callable[[_Pointer[VARDESC]], int] _GetTypeAttr = hints.AnnoField() # type: Callable[[], _Pointer[TYPEATTR]] _GetFuncDesc = hints.AnnoField() # type: Callable[[int], _Pointer[FUNCDESC]] _GetVarDesc = hints.AnnoField() # type: Callable[[int], _Pointer[VARDESC]] - _GetDocumentation = hints.AnnoField() # type: Callable[[int], Tuple[str, str, int, Optional[str]]] + _GetDocumentation = ( + hints.AnnoField() + ) # type: Callable[[int], Tuple[str, str, int, Optional[str]]] def GetTypeAttr(self): """Return the TYPEATTR for this type""" @@ -342,7 +393,7 @@ def GetNames(self, memid, count=1): names = (BSTR * count)() cnames = c_uint() self.__com_GetNames(memid, names, count, byref(cnames)) # type: ignore - return names[:cnames.value] + return names[: cnames.value] def GetIDsOfNames(self, *names): # type: (str) -> List[int] @@ -366,8 +417,10 @@ def CreateInstance(self, punkouter=None, interface=IUnknown, iid=None): iid = interface._iid_ return self._CreateInstance(punkouter, byref(interface._iid_)) # type: ignore + ################ + class ITypeComp(IUnknown): _iid_ = GUID("{00020403-0000-0000-C000-000000000046}") @@ -381,11 +434,15 @@ def Bind(self, name, flags=0, lHashVal=0): kind = desckind.value if kind == DESCKIND_FUNCDESC: fd = bindptr.lpfuncdesc[0] - fd.__ref__ = weakref.ref(fd, lambda dead: ti.ReleaseFuncDesc(bindptr.lpfuncdesc)) + fd.__ref__ = weakref.ref( + fd, lambda dead: ti.ReleaseFuncDesc(bindptr.lpfuncdesc) + ) return "function", fd elif kind == DESCKIND_VARDESC: vd = bindptr.lpvardesc[0] - vd.__ref__ = weakref.ref(vd, lambda dead: ti.ReleaseVarDesc(bindptr.lpvardesc)) + vd.__ref__ = weakref.ref( + vd, lambda dead: ti.ReleaseVarDesc(bindptr.lpvardesc) + ) return "variable", vd elif kind == DESCKIND_TYPECOMP: return "type", bindptr.lptcomp @@ -405,18 +462,23 @@ def BindType(self, name, lHashVal=0): ################ + class ICreateTypeLib(IUnknown): _iid_ = GUID("{00020406-0000-0000-C000-000000000046}") # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2149 + class ICreateTypeLib2(ICreateTypeLib): _iid_ = GUID("{0002040F-0000-0000-C000-000000000046}") + class ICreateTypeInfo(IUnknown): _iid_ = GUID("{00020405-0000-0000-C000-000000000046}") # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 915 if TYPE_CHECKING: - _SetFuncAndParamNames = hints.AnnoField() # Callable[[int, Array[c_wchar_p], int], int] + _SetFuncAndParamNames = ( + hints.AnnoField() + ) # Callable[[int, Array[c_wchar_p], int], int] def SetFuncAndParamNames(self, index, *names): # type: (int, str) -> int @@ -425,6 +487,7 @@ def SetFuncAndParamNames(self, index, *names): rgszNames[i] = n return self._SetFuncAndParamNames(index, rgszNames, len(names)) + class IRecordInfo(IUnknown): # C:/vc98/include/OAIDL.H 5974 _iid_ = GUID("{0000002F-0000-0000-C000-000000000046}") @@ -439,59 +502,83 @@ def GetFieldNames(self, *args): # XXX Should SysFreeString the array contents. How to? return result -IRecordInfo._methods_ = [ - COMMETHOD([], HRESULT, 'RecordInit', - (['in'], c_void_p, 'pvNew')), - COMMETHOD([], HRESULT, 'RecordClear', - (['in'], c_void_p, 'pvExisting')), - COMMETHOD([], HRESULT, 'RecordCopy', - (['in'], c_void_p, 'pvExisting'), - (['in'], c_void_p, 'pvNew')), - COMMETHOD([], HRESULT, 'GetGuid', - (['out'], POINTER(GUID), 'pguid')), - COMMETHOD([], HRESULT, 'GetName', - (['out'], POINTER(BSTR), 'pbstrName')), - COMMETHOD([], HRESULT, 'GetSize', - (['out'], POINTER(c_ulong), 'pcbSize')), - COMMETHOD([], HRESULT, 'GetTypeInfo', - (['out'], POINTER(POINTER(ITypeInfo)), 'ppTypeInfo')), - COMMETHOD([], HRESULT, 'GetField', - (['in'], c_void_p, 'pvData'), - (['in'], c_wchar_p, 'szFieldName'), - (['out'], POINTER(VARIANT), 'pvarField')), - COMMETHOD([], HRESULT, 'GetFieldNoCopy', - (['in'], c_void_p, 'pvData'), - (['in'], c_wchar_p, 'szFieldName'), - (['out'], POINTER(VARIANT), 'pvarField'), - (['out'], POINTER(c_void_p), 'ppvDataCArray')), - COMMETHOD([], HRESULT, 'PutField', - (['in'], c_ulong, 'wFlags'), - (['in'], c_void_p, 'pvData'), - (['in'], c_wchar_p, 'szFieldName'), - (['in'], POINTER(VARIANT), 'pvarField')), - COMMETHOD([], HRESULT, 'PutFieldNoCopy', - (['in'], c_ulong, 'wFlags'), - (['in'], c_void_p, 'pvData'), - (['in'], c_wchar_p, 'szFieldName'), - (['in'], POINTER(VARIANT), 'pvarField')), - COMMETHOD([], HRESULT, 'GetFieldNames', - (['in', 'out'], POINTER(c_ulong), 'pcNames'), - (['in'], POINTER(BSTR), 'rgBstrNames')), - COMMETHOD([], BOOL, 'IsMatchingType', - (['in'], POINTER(IRecordInfo))), - COMMETHOD([], HRESULT, 'RecordCreate'), - COMMETHOD([], HRESULT, 'RecordCreateCopy', - (['in'], c_void_p, 'pvSource'), - (['out'], POINTER(c_void_p), 'ppvDest')), - COMMETHOD([], HRESULT, 'RecordDestroy', - (['in'], c_void_p, 'pvRecord'))] +IRecordInfo._methods_ = [ + COMMETHOD([], HRESULT, "RecordInit", (["in"], c_void_p, "pvNew")), + COMMETHOD([], HRESULT, "RecordClear", (["in"], c_void_p, "pvExisting")), + COMMETHOD( + [], + HRESULT, + "RecordCopy", + (["in"], c_void_p, "pvExisting"), + (["in"], c_void_p, "pvNew"), + ), + COMMETHOD([], HRESULT, "GetGuid", (["out"], POINTER(GUID), "pguid")), + COMMETHOD([], HRESULT, "GetName", (["out"], POINTER(BSTR), "pbstrName")), + COMMETHOD([], HRESULT, "GetSize", (["out"], POINTER(c_ulong), "pcbSize")), + COMMETHOD( + [], HRESULT, "GetTypeInfo", (["out"], POINTER(POINTER(ITypeInfo)), "ppTypeInfo") + ), + COMMETHOD( + [], + HRESULT, + "GetField", + (["in"], c_void_p, "pvData"), + (["in"], c_wchar_p, "szFieldName"), + (["out"], POINTER(VARIANT), "pvarField"), + ), + COMMETHOD( + [], + HRESULT, + "GetFieldNoCopy", + (["in"], c_void_p, "pvData"), + (["in"], c_wchar_p, "szFieldName"), + (["out"], POINTER(VARIANT), "pvarField"), + (["out"], POINTER(c_void_p), "ppvDataCArray"), + ), + COMMETHOD( + [], + HRESULT, + "PutField", + (["in"], c_ulong, "wFlags"), + (["in"], c_void_p, "pvData"), + (["in"], c_wchar_p, "szFieldName"), + (["in"], POINTER(VARIANT), "pvarField"), + ), + COMMETHOD( + [], + HRESULT, + "PutFieldNoCopy", + (["in"], c_ulong, "wFlags"), + (["in"], c_void_p, "pvData"), + (["in"], c_wchar_p, "szFieldName"), + (["in"], POINTER(VARIANT), "pvarField"), + ), + COMMETHOD( + [], + HRESULT, + "GetFieldNames", + (["in", "out"], POINTER(c_ulong), "pcNames"), + (["in"], POINTER(BSTR), "rgBstrNames"), + ), + COMMETHOD([], BOOL, "IsMatchingType", (["in"], POINTER(IRecordInfo))), + COMMETHOD([], HRESULT, "RecordCreate"), + COMMETHOD( + [], + HRESULT, + "RecordCreateCopy", + (["in"], c_void_p, "pvSource"), + (["out"], POINTER(c_void_p), "ppvDest"), + ), + COMMETHOD([], HRESULT, "RecordDestroy", (["in"], c_void_p, "pvRecord")), +] ################################################################ # functions _oleaut32 = oledll.oleaut32 + def GetRecordInfoFromTypeInfo(tinfo): # type: (ITypeInfo) -> IRecordInfo "Return an IRecordInfo pointer to the UDT described in tinfo" @@ -499,30 +586,42 @@ def GetRecordInfoFromTypeInfo(tinfo): _oleaut32.GetRecordInfoFromTypeInfo(tinfo, byref(ri)) return ri # type: ignore + def GetRecordInfoFromGuids(rGuidTypeLib, verMajor, verMinor, lcid, rGuidTypeInfo): # type: (str, int, int, int, str) -> IRecordInfo ri = POINTER(IRecordInfo)() - _oleaut32.GetRecordInfoFromGuids(byref(GUID(rGuidTypeLib)), - verMajor, verMinor, lcid, - byref(GUID(rGuidTypeInfo)), - byref(ri)) + _oleaut32.GetRecordInfoFromGuids( + byref(GUID(rGuidTypeLib)), + verMajor, + verMinor, + lcid, + byref(GUID(rGuidTypeInfo)), + byref(ri), + ) return ri # type: ignore + def LoadRegTypeLib(guid, wMajorVerNum, wMinorVerNum, lcid=0): # type: (_UnionT[str, GUID], int, int, int) -> ITypeLib """Load a registered type library""" tlib = POINTER(ITypeLib)() - _oleaut32.LoadRegTypeLib(byref(GUID(guid)), wMajorVerNum, wMinorVerNum, lcid, byref(tlib)) + _oleaut32.LoadRegTypeLib( + byref(GUID(guid)), wMajorVerNum, wMinorVerNum, lcid, byref(tlib) + ) return tlib # type: ignore + if hasattr(_oleaut32, "LoadTypeLibEx"): + def LoadTypeLibEx(szFile, regkind=REGKIND_NONE): # type: (str, int) -> ITypeLib "Load, and optionally register a type library file" ptl = POINTER(ITypeLib)() _oleaut32.LoadTypeLibEx(c_wchar_p(szFile), regkind, byref(ptl)) return ptl # type: ignore + else: + def LoadTypeLibEx(szFile, regkind=REGKIND_NONE): # type: (str, int) -> ITypeLib "Load, and optionally register a type library file" @@ -530,6 +629,7 @@ def LoadTypeLibEx(szFile, regkind=REGKIND_NONE): _oleaut32.LoadTypeLib(c_wchar_p(szFile), byref(ptl)) return ptl # type: ignore + def LoadTypeLib(szFile): # type: (str) -> ITypeLib "Load and register a type library file" @@ -537,16 +637,21 @@ def LoadTypeLib(szFile): _oleaut32.LoadTypeLib(c_wchar_p(szFile), byref(tlib)) return tlib # type: ignore + def UnRegisterTypeLib(libID, wVerMajor, wVerMinor, lcid=0, syskind=SYS_WIN32): # type: (str, int, int, int, int) -> int "Unregister a registered type library" - return _oleaut32.UnRegisterTypeLib(byref(GUID(libID)), wVerMajor, wVerMinor, lcid, syskind) + return _oleaut32.UnRegisterTypeLib( + byref(GUID(libID)), wVerMajor, wVerMinor, lcid, syskind + ) + def RegisterTypeLib(tlib, fullpath, helpdir=None): # type: (ITypeLib, str, Optional[str]) -> int "Register a type library in the registry" return _oleaut32.RegisterTypeLib(tlib, c_wchar_p(fullpath), c_wchar_p(helpdir)) + def CreateTypeLib(filename, syskind=SYS_WIN32): # type: (str, int) -> ICreateTypeLib2 "Return a ICreateTypeLib2 pointer" @@ -554,16 +659,21 @@ def CreateTypeLib(filename, syskind=SYS_WIN32): _oleaut32.CreateTypeLib2(syskind, c_wchar_p(filename), byref(ctlib)) return ctlib # type: ignore + def QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid=0): # type: (str, int, int, int) -> str "Return the path of a registered type library" pathname = BSTR() - _oleaut32.QueryPathOfRegTypeLib(byref(GUID(libid)), wVerMajor, wVerMinor, lcid, byref(pathname)) + _oleaut32.QueryPathOfRegTypeLib( + byref(GUID(libid)), wVerMajor, wVerMinor, lcid, byref(pathname) + ) return pathname.value.split("\0")[0] + ################################################################ # Structures + class tagTLIBATTR(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 4437 if TYPE_CHECKING: @@ -575,10 +685,18 @@ class tagTLIBATTR(Structure): wLibFlags = hints.AnnoField() # type: int def __repr__(self): - return "TLIBATTR(GUID=%s, Version=%s.%s, LCID=%s, FLags=0x%x)" % \ - (self.guid, self.wMajorVerNum, self.wMinorVerNum, self.lcid, self.wLibFlags) + return "TLIBATTR(GUID=%s, Version=%s.%s, LCID=%s, FLags=0x%x)" % ( + self.guid, + self.wMajorVerNum, + self.wMinorVerNum, + self.lcid, + self.wLibFlags, + ) + + TLIBATTR = tagTLIBATTR + class tagTYPEATTR(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 672 if TYPE_CHECKING: @@ -602,10 +720,18 @@ class tagTYPEATTR(Structure): idldescType = hints.AnnoField() # type: IDLDESC def __repr__(self): - return "TYPEATTR(GUID=%s, typekind=%s, funcs=%s, vars=%s, impltypes=%s)" % \ - (self.guid, self.typekind, self.cFuncs, self.cVars, self.cImplTypes) + return "TYPEATTR(GUID=%s, typekind=%s, funcs=%s, vars=%s, impltypes=%s)" % ( + self.guid, + self.typekind, + self.cFuncs, + self.cVars, + self.cImplTypes, + ) + + TYPEATTR = tagTYPEATTR + class tagFUNCDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 769 if TYPE_CHECKING: @@ -623,10 +749,22 @@ class tagFUNCDESC(Structure): wFuncFlags = hints.AnnoField() # type: int def __repr__(self): - return "FUNCDESC(memid=%s, cParams=%s, cParamsOpt=%s, callconv=%s, invkind=%s, funckind=%s)" % \ - (self.memid, self.cParams, self.cParamsOpt, self.callconv, self.invkind, self.funckind) + return ( + "FUNCDESC(memid=%s, cParams=%s, cParamsOpt=%s, callconv=%s, invkind=%s, funckind=%s)" + % ( + self.memid, + self.cParams, + self.cParamsOpt, + self.callconv, + self.invkind, + self.funckind, + ) + ) + + FUNCDESC = tagFUNCDESC + class tagVARDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 803 if TYPE_CHECKING: @@ -636,28 +774,42 @@ class tagVARDESC(Structure): elemdescVar = hints.AnnoField() # type: ELEMDESC wVarFlags = hints.AnnoField() # type: int varkind = hints.AnnoField() # type: int + + VARDESC = tagVARDESC + class tagBINDPTR(Union): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3075 if TYPE_CHECKING: lpfuncdesc = hints.AnnoField() # type: _Pointer[FUNCDESC] lpvardesc = hints.AnnoField() # type: _Pointer[VARDESC] lptcomp = hints.AnnoField() # type: ITypeComp + + BINDPTR = tagBINDPTR + + class tagTYPEDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 582 if TYPE_CHECKING: _ = hints.AnnoField() # type: N11tagTYPEDESC5DOLLAR_203E vt = hints.AnnoField() # type: int + + TYPEDESC = tagTYPEDESC + + class tagIDLDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 633 if TYPE_CHECKING: dwReserved = hints.AnnoField() # type: int wIDLFlags = hints.AnnoField() # type: int + + IDLDESC = tagIDLDESC + class tagARRAYDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 594 if TYPE_CHECKING: @@ -665,178 +817,272 @@ class tagARRAYDESC(Structure): cDims = hints.AnnoField() # type: int rgbounds = hints.AnnoField() # type: Sequence[SAFEARRAYBOUND] + ################################################################ # interface vtbl definitions ICreateTypeLib._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2149 - COMMETHOD([], HRESULT, 'CreateTypeInfo', - (['in'], LPOLESTR, 'szName'), - (['in'], TYPEKIND, 'tkind'), - (['out'], POINTER(POINTER(ICreateTypeInfo)), 'ppCTInfo')), - STDMETHOD(HRESULT, 'SetName', [LPOLESTR]), - STDMETHOD(HRESULT, 'SetVersion', [WORD, WORD]), - STDMETHOD(HRESULT, 'SetGuid', [POINTER(GUID)]), - STDMETHOD(HRESULT, 'SetDocString', [LPOLESTR]), - STDMETHOD(HRESULT, 'SetHelpFileName', [LPOLESTR]), - STDMETHOD(HRESULT, 'SetHelpContext', [DWORD]), - STDMETHOD(HRESULT, 'SetLcid', [LCID]), - STDMETHOD(HRESULT, 'SetLibFlags', [UINT]), - STDMETHOD(HRESULT, 'SaveAllChanges', []), + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2149 + COMMETHOD( + [], + HRESULT, + "CreateTypeInfo", + (["in"], LPOLESTR, "szName"), + (["in"], TYPEKIND, "tkind"), + (["out"], POINTER(POINTER(ICreateTypeInfo)), "ppCTInfo"), + ), + STDMETHOD(HRESULT, "SetName", [LPOLESTR]), + STDMETHOD(HRESULT, "SetVersion", [WORD, WORD]), + STDMETHOD(HRESULT, "SetGuid", [POINTER(GUID)]), + STDMETHOD(HRESULT, "SetDocString", [LPOLESTR]), + STDMETHOD(HRESULT, "SetHelpFileName", [LPOLESTR]), + STDMETHOD(HRESULT, "SetHelpContext", [DWORD]), + STDMETHOD(HRESULT, "SetLcid", [LCID]), + STDMETHOD(HRESULT, "SetLibFlags", [UINT]), + STDMETHOD(HRESULT, "SaveAllChanges", []), ] ICreateTypeLib2._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2444 - STDMETHOD(HRESULT, 'DeleteTypeInfo', [POINTER(ITypeInfo)]), - STDMETHOD(HRESULT, 'SetCustData', [POINTER(GUID), POINTER(VARIANT)]), - STDMETHOD(HRESULT, 'SetHelpStringContext', [ULONG]), - STDMETHOD(HRESULT, 'SetHelpStringDll', [LPOLESTR]), - ] + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2444 + STDMETHOD(HRESULT, "DeleteTypeInfo", [POINTER(ITypeInfo)]), + STDMETHOD(HRESULT, "SetCustData", [POINTER(GUID), POINTER(VARIANT)]), + STDMETHOD(HRESULT, "SetHelpStringContext", [ULONG]), + STDMETHOD(HRESULT, "SetHelpStringDll", [LPOLESTR]), +] ITypeLib._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 4455 - COMMETHOD([], UINT, 'GetTypeInfoCount'), - COMMETHOD([], HRESULT, 'GetTypeInfo', - (['in'], UINT, 'index'), - (['out'], POINTER(POINTER(ITypeInfo)))), - COMMETHOD([], HRESULT, 'GetTypeInfoType', - (['in'], UINT, 'index'), - (['out'], POINTER(TYPEKIND))), - COMMETHOD([], HRESULT, 'GetTypeInfoOfGuid', - (['in'], POINTER(GUID)), - (['out'], POINTER(POINTER(ITypeInfo)))), - COMMETHOD([], HRESULT, 'GetLibAttr', - (['out'], POINTER(POINTER(TLIBATTR)))), - COMMETHOD([], HRESULT, 'GetTypeComp', - (['out'], POINTER(POINTER(ITypeComp)))), - COMMETHOD([], HRESULT, 'GetDocumentation', - (['in'], INT, 'index'), - (['out'], POINTER(BSTR)), - (['out'], POINTER(BSTR)), - (['out'], POINTER(DWORD)), - (['out'], POINTER(BSTR))), - COMMETHOD([], HRESULT, 'IsName', - # IsName changes the casing of the passed in name to - # match that in the type library. In the automatically - # wrapped version of this method, ctypes would pass a - # Python unicode string which would then be changed - - # very bad. So we have (see above) to implement the - # IsName method manually. - (['in', 'out'], LPOLESTR, 'name'), - (['in', 'optional'], DWORD, 'lHashVal', 0), - (['out'], POINTER(BOOL))), - STDMETHOD(HRESULT, 'FindName', [LPOLESTR, DWORD, POINTER(POINTER(ITypeInfo)), - POINTER(MEMBERID), POINTER(USHORT)]), - COMMETHOD([], None, 'ReleaseTLibAttr', - (['in'], POINTER(TLIBATTR))) + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 4455 + COMMETHOD([], UINT, "GetTypeInfoCount"), + COMMETHOD( + [], + HRESULT, + "GetTypeInfo", + (["in"], UINT, "index"), + (["out"], POINTER(POINTER(ITypeInfo))), + ), + COMMETHOD( + [], + HRESULT, + "GetTypeInfoType", + (["in"], UINT, "index"), + (["out"], POINTER(TYPEKIND)), + ), + COMMETHOD( + [], + HRESULT, + "GetTypeInfoOfGuid", + (["in"], POINTER(GUID)), + (["out"], POINTER(POINTER(ITypeInfo))), + ), + COMMETHOD([], HRESULT, "GetLibAttr", (["out"], POINTER(POINTER(TLIBATTR)))), + COMMETHOD([], HRESULT, "GetTypeComp", (["out"], POINTER(POINTER(ITypeComp)))), + COMMETHOD( + [], + HRESULT, + "GetDocumentation", + (["in"], INT, "index"), + (["out"], POINTER(BSTR)), + (["out"], POINTER(BSTR)), + (["out"], POINTER(DWORD)), + (["out"], POINTER(BSTR)), + ), + COMMETHOD( + [], + HRESULT, + "IsName", + # IsName changes the casing of the passed in name to + # match that in the type library. In the automatically + # wrapped version of this method, ctypes would pass a + # Python unicode string which would then be changed - + # very bad. So we have (see above) to implement the + # IsName method manually. + (["in", "out"], LPOLESTR, "name"), + (["in", "optional"], DWORD, "lHashVal", 0), + (["out"], POINTER(BOOL)), + ), + STDMETHOD( + HRESULT, + "FindName", + [ + LPOLESTR, + DWORD, + POINTER(POINTER(ITypeInfo)), + POINTER(MEMBERID), + POINTER(USHORT), + ], + ), + COMMETHOD([], None, "ReleaseTLibAttr", (["in"], POINTER(TLIBATTR))), ] ITypeInfo._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3230 - COMMETHOD([], HRESULT, 'GetTypeAttr', - (['out'], POINTER(POINTER(TYPEATTR)), 'ppTypeAttr')), - COMMETHOD([], HRESULT, 'GetTypeComp', - (['out'], POINTER(POINTER(ITypeComp)))), - COMMETHOD([], HRESULT, 'GetFuncDesc', - (['in'], UINT, 'index'), - (['out'], POINTER(POINTER(FUNCDESC)))), - COMMETHOD([], HRESULT, 'GetVarDesc', - (['in'], UINT, 'index'), - (['out'], POINTER(POINTER(VARDESC)))), - STDMETHOD(HRESULT, 'GetNames', [MEMBERID, POINTER(BSTR), UINT, POINTER(UINT)]), - COMMETHOD([], HRESULT, 'GetRefTypeOfImplType', - (['in'], UINT, 'index'), - (['out'], POINTER(HREFTYPE))), - COMMETHOD([], HRESULT, 'GetImplTypeFlags', - (['in'], UINT, 'index'), - (['out'], POINTER(INT))), + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3230 + COMMETHOD( + [], HRESULT, "GetTypeAttr", (["out"], POINTER(POINTER(TYPEATTR)), "ppTypeAttr") + ), + COMMETHOD([], HRESULT, "GetTypeComp", (["out"], POINTER(POINTER(ITypeComp)))), + COMMETHOD( + [], + HRESULT, + "GetFuncDesc", + (["in"], UINT, "index"), + (["out"], POINTER(POINTER(FUNCDESC))), + ), + COMMETHOD( + [], + HRESULT, + "GetVarDesc", + (["in"], UINT, "index"), + (["out"], POINTER(POINTER(VARDESC))), + ), + STDMETHOD(HRESULT, "GetNames", [MEMBERID, POINTER(BSTR), UINT, POINTER(UINT)]), + COMMETHOD( + [], + HRESULT, + "GetRefTypeOfImplType", + (["in"], UINT, "index"), + (["out"], POINTER(HREFTYPE)), + ), + COMMETHOD( + [], + HRESULT, + "GetImplTypeFlags", + (["in"], UINT, "index"), + (["out"], POINTER(INT)), + ), # STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(LPOLESTR), UINT, POINTER(MEMBERID)]), # this one changed, to accept c_wchar_p array - STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(c_wchar_p), UINT, POINTER(MEMBERID)]), - STDMETHOD(HRESULT, 'Invoke', [PVOID, MEMBERID, WORD, POINTER(DISPPARAMS), POINTER(VARIANT), POINTER(EXCEPINFO), POINTER(UINT)]), - - COMMETHOD([], HRESULT, 'GetDocumentation', - (['in'], MEMBERID, 'memid'), - (['out'], POINTER(BSTR), 'pBstrName'), - (['out'], POINTER(BSTR), 'pBstrDocString'), - (['out'], POINTER(DWORD), 'pdwHelpContext'), - (['out'], POINTER(BSTR), 'pBstrHelpFile')), - COMMETHOD([], HRESULT, 'GetDllEntry', - (['in'], MEMBERID, 'index'), - (['in'], INVOKEKIND, 'invkind'), - (['out'], POINTER(BSTR), 'pBstrDllName'), - (['out'], POINTER(BSTR), 'pBstrName'), - (['out'], POINTER(WORD), 'pwOrdinal')), - COMMETHOD([], HRESULT, 'GetRefTypeInfo', - (['in'], HREFTYPE, 'hRefType'), - (['out'], POINTER(POINTER(ITypeInfo)))), - STDMETHOD(HRESULT, 'AddressOfMember', [MEMBERID, INVOKEKIND, POINTER(PVOID)]), - COMMETHOD([], HRESULT, 'CreateInstance', - (['in'], POINTER(IUnknown), 'pUnkOuter'), - (['in'], POINTER(IID), 'refiid'), - (['out'], POINTER(POINTER(IUnknown)))), - COMMETHOD([], HRESULT, 'GetMops', - (['in'], MEMBERID, 'memid'), - (['out'], POINTER(BSTR))), - COMMETHOD([], HRESULT, 'GetContainingTypeLib', - (['out'], POINTER(POINTER(ITypeLib))), - (['out'], POINTER(UINT))), - COMMETHOD([], None, 'ReleaseTypeAttr', - (['in'], POINTER(TYPEATTR))), - COMMETHOD([], None, 'ReleaseFuncDesc', - (['in'], POINTER(FUNCDESC))), - COMMETHOD([], None, 'ReleaseVarDesc', - (['in'], POINTER(VARDESC))), + STDMETHOD(HRESULT, "GetIDsOfNames", [POINTER(c_wchar_p), UINT, POINTER(MEMBERID)]), + STDMETHOD( + HRESULT, + "Invoke", + [ + PVOID, + MEMBERID, + WORD, + POINTER(DISPPARAMS), + POINTER(VARIANT), + POINTER(EXCEPINFO), + POINTER(UINT), + ], + ), + COMMETHOD( + [], + HRESULT, + "GetDocumentation", + (["in"], MEMBERID, "memid"), + (["out"], POINTER(BSTR), "pBstrName"), + (["out"], POINTER(BSTR), "pBstrDocString"), + (["out"], POINTER(DWORD), "pdwHelpContext"), + (["out"], POINTER(BSTR), "pBstrHelpFile"), + ), + COMMETHOD( + [], + HRESULT, + "GetDllEntry", + (["in"], MEMBERID, "index"), + (["in"], INVOKEKIND, "invkind"), + (["out"], POINTER(BSTR), "pBstrDllName"), + (["out"], POINTER(BSTR), "pBstrName"), + (["out"], POINTER(WORD), "pwOrdinal"), + ), + COMMETHOD( + [], + HRESULT, + "GetRefTypeInfo", + (["in"], HREFTYPE, "hRefType"), + (["out"], POINTER(POINTER(ITypeInfo))), + ), + STDMETHOD(HRESULT, "AddressOfMember", [MEMBERID, INVOKEKIND, POINTER(PVOID)]), + COMMETHOD( + [], + HRESULT, + "CreateInstance", + (["in"], POINTER(IUnknown), "pUnkOuter"), + (["in"], POINTER(IID), "refiid"), + (["out"], POINTER(POINTER(IUnknown))), + ), + COMMETHOD( + [], HRESULT, "GetMops", (["in"], MEMBERID, "memid"), (["out"], POINTER(BSTR)) + ), + COMMETHOD( + [], + HRESULT, + "GetContainingTypeLib", + (["out"], POINTER(POINTER(ITypeLib))), + (["out"], POINTER(UINT)), + ), + COMMETHOD([], None, "ReleaseTypeAttr", (["in"], POINTER(TYPEATTR))), + COMMETHOD([], None, "ReleaseFuncDesc", (["in"], POINTER(FUNCDESC))), + COMMETHOD([], None, "ReleaseVarDesc", (["in"], POINTER(VARDESC))), ] ITypeComp._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3090 - STDMETHOD(HRESULT, 'Bind', - [LPOLESTR, DWORD, WORD, POINTER(POINTER(ITypeInfo)), - POINTER(DESCKIND), POINTER(BINDPTR)]), - STDMETHOD(HRESULT, 'BindType', - [LPOLESTR, DWORD, POINTER(POINTER(ITypeInfo)), POINTER(POINTER(ITypeComp))]), + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3090 + STDMETHOD( + HRESULT, + "Bind", + [ + LPOLESTR, + DWORD, + WORD, + POINTER(POINTER(ITypeInfo)), + POINTER(DESCKIND), + POINTER(BINDPTR), + ], + ), + STDMETHOD( + HRESULT, + "BindType", + [LPOLESTR, DWORD, POINTER(POINTER(ITypeInfo)), POINTER(POINTER(ITypeComp))], + ), ] ICreateTypeInfo._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 915 - STDMETHOD(HRESULT, 'SetGuid', [POINTER(GUID)]), - STDMETHOD(HRESULT, 'SetTypeFlags', [UINT]), - STDMETHOD(HRESULT, 'SetDocString', [LPOLESTR]), - STDMETHOD(HRESULT, 'SetHelpContext', [DWORD]), - STDMETHOD(HRESULT, 'SetVersion', [WORD, WORD]), -# STDMETHOD(HRESULT, 'AddRefTypeInfo', [POINTER(ITypeInfo), POINTER(HREFTYPE)]), - COMMETHOD([], HRESULT, 'AddRefTypeInfo', - (['in'], POINTER(ITypeInfo)), - (['out'], POINTER(HREFTYPE))), - STDMETHOD(HRESULT, 'AddFuncDesc', [UINT, POINTER(FUNCDESC)]), - STDMETHOD(HRESULT, 'AddImplType', [UINT, HREFTYPE]), - STDMETHOD(HRESULT, 'SetImplTypeFlags', [UINT, INT]), - STDMETHOD(HRESULT, 'SetAlignment', [WORD]), - STDMETHOD(HRESULT, 'SetSchema', [LPOLESTR]), - STDMETHOD(HRESULT, 'AddVarDesc', [UINT, POINTER(VARDESC)]), - STDMETHOD(HRESULT, 'SetFuncAndParamNames', [UINT, POINTER(c_wchar_p), UINT]), - STDMETHOD(HRESULT, 'SetVarName', [UINT, LPOLESTR]), - STDMETHOD(HRESULT, 'SetTypeDescAlias', [POINTER(TYPEDESC)]), - STDMETHOD(HRESULT, 'DefineFuncAsDllEntry', [UINT, LPOLESTR, LPOLESTR]), - STDMETHOD(HRESULT, 'SetFuncDocString', [UINT, LPOLESTR]), - STDMETHOD(HRESULT, 'SetVarDocString', [UINT, LPOLESTR]), - STDMETHOD(HRESULT, 'SetFuncHelpContext', [UINT, DWORD]), - STDMETHOD(HRESULT, 'SetVarHelpContext', [UINT, DWORD]), - STDMETHOD(HRESULT, 'SetMops', [UINT, BSTR]), - STDMETHOD(HRESULT, 'SetTypeIdldesc', [POINTER(IDLDESC)]), - STDMETHOD(HRESULT, 'LayOut', []), + # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 915 + STDMETHOD(HRESULT, "SetGuid", [POINTER(GUID)]), + STDMETHOD(HRESULT, "SetTypeFlags", [UINT]), + STDMETHOD(HRESULT, "SetDocString", [LPOLESTR]), + STDMETHOD(HRESULT, "SetHelpContext", [DWORD]), + STDMETHOD(HRESULT, "SetVersion", [WORD, WORD]), + # STDMETHOD(HRESULT, 'AddRefTypeInfo', [POINTER(ITypeInfo), POINTER(HREFTYPE)]), + COMMETHOD( + [], + HRESULT, + "AddRefTypeInfo", + (["in"], POINTER(ITypeInfo)), + (["out"], POINTER(HREFTYPE)), + ), + STDMETHOD(HRESULT, "AddFuncDesc", [UINT, POINTER(FUNCDESC)]), + STDMETHOD(HRESULT, "AddImplType", [UINT, HREFTYPE]), + STDMETHOD(HRESULT, "SetImplTypeFlags", [UINT, INT]), + STDMETHOD(HRESULT, "SetAlignment", [WORD]), + STDMETHOD(HRESULT, "SetSchema", [LPOLESTR]), + STDMETHOD(HRESULT, "AddVarDesc", [UINT, POINTER(VARDESC)]), + STDMETHOD(HRESULT, "SetFuncAndParamNames", [UINT, POINTER(c_wchar_p), UINT]), + STDMETHOD(HRESULT, "SetVarName", [UINT, LPOLESTR]), + STDMETHOD(HRESULT, "SetTypeDescAlias", [POINTER(TYPEDESC)]), + STDMETHOD(HRESULT, "DefineFuncAsDllEntry", [UINT, LPOLESTR, LPOLESTR]), + STDMETHOD(HRESULT, "SetFuncDocString", [UINT, LPOLESTR]), + STDMETHOD(HRESULT, "SetVarDocString", [UINT, LPOLESTR]), + STDMETHOD(HRESULT, "SetFuncHelpContext", [UINT, DWORD]), + STDMETHOD(HRESULT, "SetVarHelpContext", [UINT, DWORD]), + STDMETHOD(HRESULT, "SetMops", [UINT, BSTR]), + STDMETHOD(HRESULT, "SetTypeIdldesc", [POINTER(IDLDESC)]), + STDMETHOD(HRESULT, "LayOut", []), ] + class IProvideClassInfo(IUnknown): _iid_ = GUID("{B196B283-BAB4-101A-B69C-00AA00341D07}") if TYPE_CHECKING: GetClassInfo = hints.AnnoField() # type: Callable[[], ITypeInfo] _methods_ = [ # Returns the ITypeInfo interface for the object's coclass type information. - COMMETHOD([], HRESULT, "GetClassInfo", - ( ['out'], POINTER(POINTER(ITypeInfo)), "ppTI" ) ) - ] + COMMETHOD( + [], HRESULT, "GetClassInfo", (["out"], POINTER(POINTER(ITypeInfo)), "ppTI") + ) + ] + class IProvideClassInfo2(IProvideClassInfo): _iid_ = GUID("{A6BC3AC0-DBAA-11CE-9DE3-00AA004BB851}") @@ -844,10 +1090,14 @@ class IProvideClassInfo2(IProvideClassInfo): GetGUID = hints.AnnoField() # type: Callable[[int], GUID] _methods_ = [ # Returns the GUID for the object's outgoing IID for its default event set. - COMMETHOD([], HRESULT, "GetGUID", - ( ['in'], DWORD, "dwGuidKind" ), - ( ['out', 'retval'], POINTER(GUID), "pGUID" )) - ] + COMMETHOD( + [], + HRESULT, + "GetGUID", + (["in"], DWORD, "dwGuidKind"), + (["out", "retval"], POINTER(GUID), "pGUID"), + ) + ] ################################################################ @@ -855,170 +1105,190 @@ class IProvideClassInfo2(IProvideClassInfo): tagTLIBATTR._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 4437 - ('guid', GUID), - ('lcid', LCID), - ('syskind', SYSKIND), - ('wMajorVerNum', WORD), - ('wMinorVerNum', WORD), - ('wLibFlags', WORD), + ("guid", GUID), + ("lcid", LCID), + ("syskind", SYSKIND), + ("wMajorVerNum", WORD), + ("wMinorVerNum", WORD), + ("wLibFlags", WORD), ] + + class N11tagTYPEDESC5DOLLAR_203E(Union): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 584 if TYPE_CHECKING: lptdesc = hints.AnnoField() # type: TYPEDESC lpadesc = hints.AnnoField() # type: tagARRAYDESC hreftype = hints.AnnoField() # type: int + + N11tagTYPEDESC5DOLLAR_203E._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 584 - ('lptdesc', POINTER(tagTYPEDESC)), - ('lpadesc', POINTER(tagARRAYDESC)), - ('hreftype', HREFTYPE), + ("lptdesc", POINTER(tagTYPEDESC)), + ("lpadesc", POINTER(tagARRAYDESC)), + ("hreftype", HREFTYPE), ] -tagTYPEDESC._anonymous_ = ('_',) +tagTYPEDESC._anonymous_ = ("_",) tagTYPEDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 582 # Unnamed field renamed to '_' - ('_', N11tagTYPEDESC5DOLLAR_203E), - ('vt', VARTYPE), + ("_", N11tagTYPEDESC5DOLLAR_203E), + ("vt", VARTYPE), ] tagIDLDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 633 - ('dwReserved', ULONG_PTR), - ('wIDLFlags', USHORT), + ("dwReserved", ULONG_PTR), + ("wIDLFlags", USHORT), ] tagTYPEATTR._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 672 - ('guid', GUID), - ('lcid', LCID), - ('dwReserved', DWORD), - ('memidConstructor', MEMBERID), - ('memidDestructor', MEMBERID), - ('lpstrSchema', LPOLESTR), - ('cbSizeInstance', DWORD), - ('typekind', TYPEKIND), - ('cFuncs', WORD), - ('cVars', WORD), - ('cImplTypes', WORD), - ('cbSizeVft', WORD), - ('cbAlignment', WORD), - ('wTypeFlags', WORD), - ('wMajorVerNum', WORD), - ('wMinorVerNum', WORD), - ('tdescAlias', TYPEDESC), - ('idldescType', IDLDESC), + ("guid", GUID), + ("lcid", LCID), + ("dwReserved", DWORD), + ("memidConstructor", MEMBERID), + ("memidDestructor", MEMBERID), + ("lpstrSchema", LPOLESTR), + ("cbSizeInstance", DWORD), + ("typekind", TYPEKIND), + ("cFuncs", WORD), + ("cVars", WORD), + ("cImplTypes", WORD), + ("cbSizeVft", WORD), + ("cbAlignment", WORD), + ("wTypeFlags", WORD), + ("wMajorVerNum", WORD), + ("wMinorVerNum", WORD), + ("tdescAlias", TYPEDESC), + ("idldescType", IDLDESC), ] + + class N10tagVARDESC5DOLLAR_205E(Union): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 807 if TYPE_CHECKING: oInst = hints.AnnoField() # type: int lpvarValue = hints.AnnoField() # type: VARIANT + + N10tagVARDESC5DOLLAR_205E._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 807 - ('oInst', DWORD), - ('lpvarValue', POINTER(VARIANT)), + ("oInst", DWORD), + ("lpvarValue", POINTER(VARIANT)), ] + + class tagELEMDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 661 if TYPE_CHECKING: tdesc = hints.AnnoField() # type: TYPEDESC _ = hints.AnnoField() # type: N11tagELEMDESC5DOLLAR_204E + + class N11tagELEMDESC5DOLLAR_204E(Union): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 663 if TYPE_CHECKING: idldesc = hints.AnnoField() # type: IDLDESC paramdesc = hints.AnnoField() # type: PARAMDESC + class tagPARAMDESC(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 609 if TYPE_CHECKING: pparamdescex = hints.AnnoField() # type: tagPARAMDESCEX wParamFlags = hints.AnnoField() # type: int + class tagPARAMDESCEX(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 601 if TYPE_CHECKING: cBytes = hints.AnnoField() # type: int varDefaultValue = hints.AnnoField() # type: VARIANTARG + + LPPARAMDESCEX = POINTER(tagPARAMDESCEX) tagPARAMDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 609 - ('pparamdescex', LPPARAMDESCEX), - ('wParamFlags', USHORT), + ("pparamdescex", LPPARAMDESCEX), + ("wParamFlags", USHORT), ] PARAMDESC = tagPARAMDESC N11tagELEMDESC5DOLLAR_204E._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 663 - ('idldesc', IDLDESC), - ('paramdesc', PARAMDESC), + ("idldesc", IDLDESC), + ("paramdesc", PARAMDESC), ] tagELEMDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 661 - ('tdesc', TYPEDESC), + ("tdesc", TYPEDESC), # Unnamed field renamed to '_' - ('_', N11tagELEMDESC5DOLLAR_204E), + ("_", N11tagELEMDESC5DOLLAR_204E), ] ELEMDESC = tagELEMDESC tagVARDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 803 - ('memid', MEMBERID), - ('lpstrSchema', LPOLESTR), + ("memid", MEMBERID), + ("lpstrSchema", LPOLESTR), # Unnamed field renamed to '_' - ('_', N10tagVARDESC5DOLLAR_205E), - ('elemdescVar', ELEMDESC), - ('wVarFlags', WORD), - ('varkind', VARKIND), + ("_", N10tagVARDESC5DOLLAR_205E), + ("elemdescVar", ELEMDESC), + ("wVarFlags", WORD), + ("varkind", VARKIND), ] tagBINDPTR._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3075 - ('lpfuncdesc', POINTER(FUNCDESC)), - ('lpvardesc', POINTER(VARDESC)), - ('lptcomp', POINTER(ITypeComp)), + ("lpfuncdesc", POINTER(FUNCDESC)), + ("lpvardesc", POINTER(VARDESC)), + ("lptcomp", POINTER(ITypeComp)), ] tagFUNCDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 769 - ('memid', MEMBERID), - ('lprgscode', POINTER(SCODE)), - ('lprgelemdescParam', POINTER(ELEMDESC)), - ('funckind', FUNCKIND), - ('invkind', INVOKEKIND), - ('callconv', CALLCONV), - ('cParams', SHORT), - ('cParamsOpt', SHORT), - ('oVft', SHORT), - ('cScodes', SHORT), - ('elemdescFunc', ELEMDESC), - ('wFuncFlags', WORD), + ("memid", MEMBERID), + ("lprgscode", POINTER(SCODE)), + ("lprgelemdescParam", POINTER(ELEMDESC)), + ("funckind", FUNCKIND), + ("invkind", INVOKEKIND), + ("callconv", CALLCONV), + ("cParams", SHORT), + ("cParamsOpt", SHORT), + ("oVft", SHORT), + ("cScodes", SHORT), + ("elemdescFunc", ELEMDESC), + ("wFuncFlags", WORD), ] tagPARAMDESCEX._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 601 - ('cBytes', DWORD), - ('varDefaultValue', VARIANTARG), + ("cBytes", DWORD), + ("varDefaultValue", VARIANTARG), ] + class tagSAFEARRAYBOUND(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 226 if TYPE_CHECKING: cElements = hints.AnnoField() # type: int lLbound = hints.AnnoField() # type: int _fields_ = [ - ('cElements', DWORD), - ('lLbound', LONG), + ("cElements", DWORD), + ("lLbound", LONG), ] + + SAFEARRAYBOUND = tagSAFEARRAYBOUND tagARRAYDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 594 - ('tdescElem', TYPEDESC), - ('cDims', USHORT), - ('rgbounds', SAFEARRAYBOUND * 1), + ("tdescElem", TYPEDESC), + ("cDims", USHORT), + ("rgbounds", SAFEARRAYBOUND * 1), ] +# fmt: off __known_symbols__ = [ "tagARRAYDESC", "BINDPTR", "tagBINDPTR", "CALLCONV", "tagCALLCONV", "CC_CDECL", "CC_FASTCALL", "CC_FPFASTCALL", "CC_MACPASCAL", "CC_MAX", @@ -1066,3 +1336,4 @@ class tagSAFEARRAYBOUND(Structure): "VARFLAG_FRESTRICTED", "VARFLAG_FSOURCE", "VARFLAG_FUIDEFAULT", "VARFLAGS", "tagVARFLAGS", "VARKIND", "tagVARKIND", ] +# fmt: on diff --git a/comtypes/util.py b/comtypes/util.py index 67012ff9..a04118cd 100644 --- a/comtypes/util.py +++ b/comtypes/util.py @@ -3,6 +3,7 @@ """ from ctypes import * + def _calc_offset(): # Internal helper function that calculates where the object # returned by a byref() call stores the pointer. @@ -11,24 +12,29 @@ def _calc_offset(): # object that a byref() call returns): class PyCArgObject(Structure): class value(Union): - _fields_ = [("c", c_char), - ("h", c_short), - ("i", c_int), - ("l", c_long), - ("q", c_longlong), - ("d", c_double), - ("f", c_float), - ("p", c_void_p)] + _fields_ = [ + ("c", c_char), + ("h", c_short), + ("i", c_int), + ("l", c_long), + ("q", c_longlong), + ("d", c_double), + ("f", c_float), + ("p", c_void_p), + ] + # # Thanks to Lenard Lindstrom for this tip: # sizeof(PyObject_HEAD) is the same as object.__basicsize__. # - _fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__), - ("pffi_type", c_void_p), - ("tag", c_char), - ("value", value), - ("obj", c_void_p), - ("size", c_int)] + _fields_ = [ + ("PyObject_HEAD", c_byte * object.__basicsize__), + ("pffi_type", c_void_p), + ("tag", c_char), + ("value", value), + ("obj", c_void_p), + ("size", c_int), + ] _anonymous_ = ["value"] @@ -42,22 +48,23 @@ class value(Union): argobj = PyCArgObject.from_address(id(ref)) - if argobj.obj != id(obj) or \ - argobj.p != addressof(obj) or \ - argobj.tag != 'P': + if argobj.obj != id(obj) or argobj.p != addressof(obj) or argobj.tag != "P": raise RuntimeError("PyCArgObject field definitions incorrect") - return PyCArgObject.p.offset # offset of the pointer field + return PyCArgObject.p.offset # offset of the pointer field + ################################################################ # # byref_at # -def byref_at(obj, offset, - _byref=byref, - _c_void_p_from_address = c_void_p.from_address, - _byref_pointer_offset = _calc_offset() - ): +def byref_at( + obj, + offset, + _byref=byref, + _c_void_p_from_address=c_void_p.from_address, + _byref_pointer_offset=_calc_offset(), +): """byref_at(cobj, offset) behaves similar this C code: (((char *)&obj) + offset) @@ -68,8 +75,7 @@ def byref_at(obj, offset, ref = _byref(obj) # Change the pointer field in the created byref object by adding # 'offset' to it: - _c_void_p_from_address(id(ref) - + _byref_pointer_offset).value += offset + _c_void_p_from_address(id(ref) + _byref_pointer_offset).value += offset return ref @@ -77,21 +83,24 @@ def byref_at(obj, offset, # # cast_field # -def cast_field(struct, fieldname, fieldtype, offset=0, - _POINTER=POINTER, - _byref_at=byref_at, - _byref=byref, - _divmod=divmod, - _sizeof=sizeof, - ): +def cast_field( + struct, + fieldname, + fieldtype, + offset=0, + _POINTER=POINTER, + _byref_at=byref_at, + _byref=byref, + _divmod=divmod, + _sizeof=sizeof, +): """cast_field(struct, fieldname, fieldtype) Return the contents of a struct field as it it were of type 'fieldtype'. """ fieldoffset = getattr(type(struct), fieldname).offset - return cast(_byref_at(struct, fieldoffset), - _POINTER(fieldtype))[0] + return cast(_byref_at(struct, fieldoffset), _POINTER(fieldtype))[0] __all__ = ["byref_at", "cast_field"] diff --git a/comtypes/viewobject.py b/comtypes/viewobject.py index f340a1e1..84840a05 100644 --- a/comtypes/viewobject.py +++ b/comtypes/viewobject.py @@ -6,154 +6,213 @@ from comtypes import GUID from comtypes import IUnknown + class tagPALETTEENTRY(Structure): _fields_ = [ - ('peRed', c_ubyte), - ('peGreen', c_ubyte), - ('peBlue', c_ubyte), - ('peFlags', c_ubyte), - ] + ("peRed", c_ubyte), + ("peGreen", c_ubyte), + ("peBlue", c_ubyte), + ("peFlags", c_ubyte), + ] + + assert sizeof(tagPALETTEENTRY) == 4, sizeof(tagPALETTEENTRY) assert alignment(tagPALETTEENTRY) == 1, alignment(tagPALETTEENTRY) + class tagLOGPALETTE(Structure): _pack_ = 2 _fields_ = [ - ('palVersion', c_ushort), - ('palNumEntries', c_ushort), - ('palPalEntry', POINTER(tagPALETTEENTRY)), - ] + ("palVersion", c_ushort), + ("palNumEntries", c_ushort), + ("palPalEntry", POINTER(tagPALETTEENTRY)), + ] + + assert sizeof(tagLOGPALETTE) == 8, sizeof(tagLOGPALETTE) assert alignment(tagLOGPALETTE) == 2, alignment(tagLOGPALETTE) + class tagDVTARGETDEVICE(Structure): _fields_ = [ - ('tdSize', c_ulong), - ('tdDriverNameOffset', c_ushort), - ('tdDeviceNameOffset', c_ushort), - ('tdPortNameOffset', c_ushort), - ('tdExtDevmodeOffset', c_ushort), - ('tdData', POINTER(c_ubyte)), - ] + ("tdSize", c_ulong), + ("tdDriverNameOffset", c_ushort), + ("tdDeviceNameOffset", c_ushort), + ("tdPortNameOffset", c_ushort), + ("tdExtDevmodeOffset", c_ushort), + ("tdData", POINTER(c_ubyte)), + ] + + assert sizeof(tagDVTARGETDEVICE) == 16, sizeof(tagDVTARGETDEVICE) assert alignment(tagDVTARGETDEVICE) == 4, alignment(tagDVTARGETDEVICE) + class tagExtentInfo(Structure): _fields_ = [ - ('cb', c_ulong), - ('dwExtentMode', c_ulong), - ('sizelProposed', SIZEL), - ] + ("cb", c_ulong), + ("dwExtentMode", c_ulong), + ("sizelProposed", SIZEL), + ] + def __init__(self, *args, **kw): self.cb = sizeof(self) super(tagExtentInfo, self).__init__(*args, **kw) + def __repr__(self): size = (self.sizelProposed.cx, self.sizelProposed.cy) - return "" % (self.dwExtentMode, - size, - id(self)) + return "" % ( + self.dwExtentMode, + size, + id(self), + ) + + assert sizeof(tagExtentInfo) == 16, sizeof(tagExtentInfo) assert alignment(tagExtentInfo) == 4, alignment(tagExtentInfo) DVEXTENTINFO = tagExtentInfo -IAdviseSink = IUnknown # fake the interface +IAdviseSink = IUnknown # fake the interface + class IViewObject(IUnknown): _case_insensitive_ = False - _iid_ = GUID('{0000010D-0000-0000-C000-000000000046}') + _iid_ = GUID("{0000010D-0000-0000-C000-000000000046}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'Draw', - ( ['in'], c_ulong, 'dwDrawAspect' ), - ( ['in'], c_int, 'lindex' ), - ( ['in'], c_void_p, 'pvAspect' ), - ( ['in'], POINTER(tagDVTARGETDEVICE), 'ptd' ), - ( ['in'], HDC, 'hdcTargetDev' ), - ( ['in'], HDC, 'hdcDraw' ), - ( ['in'], POINTER(_RECTL), 'lprcBounds' ), - ( ['in'], POINTER(_RECTL), 'lprcWBounds' ), - ( ['in'], c_void_p, 'pfnContinue' ), # a pointer to a callback function - ( ['in'], c_ulong, 'dwContinue')), - COMMETHOD([], HRESULT, 'GetColorSet', - ( ['in'], c_ulong, 'dwDrawAspect' ), - ( ['in'], c_int, 'lindex' ), - ( ['in'], c_void_p, 'pvAspect' ), - ( ['in'], POINTER(tagDVTARGETDEVICE), 'ptd' ), - ( ['in'], HDC, 'hicTargetDev' ), - ( ['out'], POINTER(POINTER(tagLOGPALETTE)), 'ppColorSet' )), - COMMETHOD([], HRESULT, 'Freeze', - ( ['in'], c_ulong, 'dwDrawAspect' ), - ( ['in'], c_int, 'lindex' ), - ( ['in'], c_void_p, 'pvAspect' ), - ( ['out'], POINTER(c_ulong), 'pdwFreeze' )), - COMMETHOD([], HRESULT, 'Unfreeze', - ( ['in'], c_ulong, 'dwFreeze' )), - COMMETHOD([], HRESULT, 'SetAdvise', - ( ['in'], c_ulong, 'dwAspect' ), - ( ['in'], c_ulong, 'advf' ), - ( ['in'], POINTER(IAdviseSink), 'pAdvSink' )), - COMMETHOD([], HRESULT, 'GetAdvise', - ( ['out'], POINTER(c_ulong), 'pdwAspect' ), - ( ['out'], POINTER(c_ulong), 'pAdvf' ), - ( ['out'], POINTER(POINTER(IAdviseSink)), 'ppAdvSink' )), - ] + COMMETHOD( + [], + HRESULT, + "Draw", + (["in"], c_ulong, "dwDrawAspect"), + (["in"], c_int, "lindex"), + (["in"], c_void_p, "pvAspect"), + (["in"], POINTER(tagDVTARGETDEVICE), "ptd"), + (["in"], HDC, "hdcTargetDev"), + (["in"], HDC, "hdcDraw"), + (["in"], POINTER(_RECTL), "lprcBounds"), + (["in"], POINTER(_RECTL), "lprcWBounds"), + (["in"], c_void_p, "pfnContinue"), # a pointer to a callback function + (["in"], c_ulong, "dwContinue"), + ), + COMMETHOD( + [], + HRESULT, + "GetColorSet", + (["in"], c_ulong, "dwDrawAspect"), + (["in"], c_int, "lindex"), + (["in"], c_void_p, "pvAspect"), + (["in"], POINTER(tagDVTARGETDEVICE), "ptd"), + (["in"], HDC, "hicTargetDev"), + (["out"], POINTER(POINTER(tagLOGPALETTE)), "ppColorSet"), + ), + COMMETHOD( + [], + HRESULT, + "Freeze", + (["in"], c_ulong, "dwDrawAspect"), + (["in"], c_int, "lindex"), + (["in"], c_void_p, "pvAspect"), + (["out"], POINTER(c_ulong), "pdwFreeze"), + ), + COMMETHOD([], HRESULT, "Unfreeze", (["in"], c_ulong, "dwFreeze")), + COMMETHOD( + [], + HRESULT, + "SetAdvise", + (["in"], c_ulong, "dwAspect"), + (["in"], c_ulong, "advf"), + (["in"], POINTER(IAdviseSink), "pAdvSink"), + ), + COMMETHOD( + [], + HRESULT, + "GetAdvise", + (["out"], POINTER(c_ulong), "pdwAspect"), + (["out"], POINTER(c_ulong), "pAdvf"), + (["out"], POINTER(POINTER(IAdviseSink)), "ppAdvSink"), + ), + ] + class IViewObject2(IViewObject): _case_insensitive_ = False - _iid_ = GUID('{00000127-0000-0000-C000-000000000046}') + _iid_ = GUID("{00000127-0000-0000-C000-000000000046}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'GetExtent', - ( ['in'], c_ulong, 'dwDrawAspect' ), - ( ['in'], c_int, 'lindex' ), - ( ['in'], POINTER(tagDVTARGETDEVICE), 'ptd' ), - ( ['out'], POINTER(SIZEL), 'lpsizel' )), - ] + COMMETHOD( + [], + HRESULT, + "GetExtent", + (["in"], c_ulong, "dwDrawAspect"), + (["in"], c_int, "lindex"), + (["in"], POINTER(tagDVTARGETDEVICE), "ptd"), + (["out"], POINTER(SIZEL), "lpsizel"), + ), + ] + class IViewObjectEx(IViewObject2): _case_insensitive_ = False - _iid_ = GUID('{3AF24292-0C96-11CE-A0CF-00AA00600AB8}') + _iid_ = GUID("{3AF24292-0C96-11CE-A0CF-00AA00600AB8}") _idlflags_ = [] _methods_ = [ - COMMETHOD([], HRESULT, 'GetRect', - ( ['in'], c_ulong, 'dwAspect' ), - ( ['out'], POINTER(_RECTL), 'pRect' )), - COMMETHOD([], HRESULT, 'GetViewStatus', - ( ['out'], POINTER(c_ulong), 'pdwStatus' )), - COMMETHOD([], HRESULT, 'QueryHitPoint', - ( ['in'], c_ulong, 'dwAspect' ), - ( ['in'], POINTER(tagRECT), 'pRectBounds' ), - ( ['in'], tagPOINT, 'ptlLoc' ), - ( ['in'], c_int, 'lCloseHint' ), - ( ['out'], POINTER(c_ulong), 'pHitResult' )), - COMMETHOD([], HRESULT, 'QueryHitRect', - ( ['in'], c_ulong, 'dwAspect' ), - ( ['in'], POINTER(tagRECT), 'pRectBounds' ), - ( ['in'], POINTER(tagRECT), 'pRectLoc' ), - ( ['in'], c_int, 'lCloseHint' ), - ( ['out'], POINTER(c_ulong), 'pHitResult' )), - COMMETHOD([], HRESULT, 'GetNaturalExtent', - ( ['in'], c_ulong, 'dwAspect' ), - ( ['in'], c_int, 'lindex' ), - ( ['in'], POINTER(tagDVTARGETDEVICE), 'ptd' ), - ( ['in'], HDC, 'hicTargetDev' ), - ( ['in'], POINTER(tagExtentInfo), 'pExtentInfo' ), - ( ['out'], POINTER(SIZEL), 'pSizel' )), - ] - - -DVASPECT = c_int # enum -DVASPECT_CONTENT = 1 -DVASPECT_THUMBNAIL = 2 -DVASPECT_ICON = 4 -DVASPECT_DOCPRINT = 8 - -DVASPECT2 = c_int # enum + COMMETHOD( + [], + HRESULT, + "GetRect", + (["in"], c_ulong, "dwAspect"), + (["out"], POINTER(_RECTL), "pRect"), + ), + COMMETHOD( + [], HRESULT, "GetViewStatus", (["out"], POINTER(c_ulong), "pdwStatus") + ), + COMMETHOD( + [], + HRESULT, + "QueryHitPoint", + (["in"], c_ulong, "dwAspect"), + (["in"], POINTER(tagRECT), "pRectBounds"), + (["in"], tagPOINT, "ptlLoc"), + (["in"], c_int, "lCloseHint"), + (["out"], POINTER(c_ulong), "pHitResult"), + ), + COMMETHOD( + [], + HRESULT, + "QueryHitRect", + (["in"], c_ulong, "dwAspect"), + (["in"], POINTER(tagRECT), "pRectBounds"), + (["in"], POINTER(tagRECT), "pRectLoc"), + (["in"], c_int, "lCloseHint"), + (["out"], POINTER(c_ulong), "pHitResult"), + ), + COMMETHOD( + [], + HRESULT, + "GetNaturalExtent", + (["in"], c_ulong, "dwAspect"), + (["in"], c_int, "lindex"), + (["in"], POINTER(tagDVTARGETDEVICE), "ptd"), + (["in"], HDC, "hicTargetDev"), + (["in"], POINTER(tagExtentInfo), "pExtentInfo"), + (["out"], POINTER(SIZEL), "pSizel"), + ), + ] + + +DVASPECT = c_int # enum +DVASPECT_CONTENT = 1 +DVASPECT_THUMBNAIL = 2 +DVASPECT_ICON = 4 +DVASPECT_DOCPRINT = 8 + +DVASPECT2 = c_int # enum DVASPECT_OPAQUE = 16 DVASPECT_TRANSPARENT = 32 -DVEXTENTMODE = c_int # enum +DVEXTENTMODE = c_int # enum # Container asks the object how big it wants to be to exactly fit its content: DVEXTENT_CONTENT = 0 # The container proposes a size to the object for its use in resizing: