diff --git a/comtypes/GUID.py b/comtypes/GUID.py index adabe905..e50f26e8 100644 --- a/comtypes/GUID.py +++ b/comtypes/GUID.py @@ -6,14 +6,14 @@ def binary(obj): return bytes(obj) else: def binary(obj): - return buffer(obj) + return buffer(obj) # NOQA if sys.version_info >= (3, 0): text_type = str base_text_type = str else: - text_type = unicode - base_text_type = basestring + text_type = unicode # NOQA + base_text_type = basestring # NOQA BYTE = c_byte WORD = c_ushort @@ -28,16 +28,19 @@ def binary(obj): _CLSIDFromProgID = _ole32.CLSIDFromProgID _CoCreateGuid = _ole32.CoCreateGuid + # 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)] - - def __init__(self, name=None): + _fields_ = [ + ("Data1", DWORD), + ("Data2", WORD), + ("Data3", WORD), + ("Data4", BYTE * 8) + ] + + def __init__(self, name=None): # NOQA if name is not None: _CLSIDFromString(text_type(name), byref(self)) @@ -50,19 +53,23 @@ def __unicode__(self): result = p.value _CoTaskMemFree(p) return result + __str__ = __unicode__ def __cmp__(self, other): if isinstance(other, GUID): - return cmp(binary(self), binary(other)) + return cmp(binary(self), binary(other)) # NOQA + return -1 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,10 +80,9 @@ 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_ + progid = progid._reg_clsid_ # NOQA if isinstance(progid, cls): return progid elif isinstance(progid, base_text_type): @@ -89,7 +95,7 @@ def from_progid(cls, progid): raise TypeError("Cannot construct guid from %r" % progid) def as_progid(self): - "Convert a GUID into a progid" + """Convert a GUID into a progid""" progid = c_wchar_p() _ProgIDFromCLSID(byref(self), byref(progid)) result = progid.value @@ -98,7 +104,7 @@ def as_progid(self): @classmethod def create_new(cls): - "Create a brand new guid" + """Create a brand new guid""" guid = cls() _CoCreateGuid(byref(guid)) return guid diff --git a/comtypes/__init__.py b/comtypes/__init__.py index 1e5d7619..fc451943 100644 --- a/comtypes/__init__.py +++ b/comtypes/__init__.py @@ -3,36 +3,37 @@ import atexit from ctypes import * -from ctypes import _SimpleCData +from ctypes import _SimpleCData # NOQA from _ctypes import COMError import logging import os import sys import types -################################################################ +################################################################ def add_metaclass(metaclass): """Class decorator from six.py for creating a class with a metaclass. Copyright (c) 2010-2020 Benjamin Peterson - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. """ def wrapper(cls): orig_vars = cls.__dict__.copy() @@ -49,8 +50,8 @@ def wrapper(cls): return metaclass(cls.__name__, cls.__bases__, orig_vars) return wrapper -################################################################ +################################################################ # type hinting symbols # # `if TYPE_CHECKING:` code block must not be executed because `TYPE_CHECKING` @@ -59,7 +60,7 @@ def wrapper(cls): # if sys.version_info >= (3, 5): from typing import TYPE_CHECKING -else: # typehints in this package don't support Py<3.5 due to importing symbols. +else: # typehints in this package don't support Py<3.5 due to importing symbols TYPE_CHECKING = False # # Annotations must be placed in a `# type:` comment in according to PEP484. @@ -69,43 +70,54 @@ def wrapper(cls): # `typing.get_type_hints` or `typing.get_origin`. # if TYPE_CHECKING: - from ctypes import _CData # only in `typeshed`, private in runtime + from ctypes import _CData # NOQA # 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 + from ctypes import _Pointer # NOQA # 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 + from typing import ( + Any, + ClassVar, + overload, + TypeVar, + List, Type, + Callable, + Optional + ) + # utilities or workarounds for annotations. from comtypes import hints as hints ################################################################ -from comtypes.GUID import GUID -from comtypes import patcher -from comtypes._npsupport import interop as npsupport -from comtypes._memberspec import ( - ComMemberGenerator, _ComMemberSpec, DispMemberGenerator, _DispMemberSpec, - _encode_idl, _resolve_argspec, +from comtypes.GUID import GUID # NOQA +from comtypes import patcher # NOQA +from comtypes._npsupport import interop as npsupport # NOQA +from comtypes._memberspec import ( # NOQA + ComMemberGenerator, + _ComMemberSpec, + DispMemberGenerator, + _DispMemberSpec, + _encode_idl, + _resolve_argspec, ) ################################################################ if sys.version_info >= (3, 0): text_type = str else: - text_type = unicode + text_type = unicode # NOQA _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 @@ -120,28 +132,33 @@ def _check_version(actual, tlib_cached_mtime=None): if actual != required: raise ImportError("Wrong version") if not hasattr(sys, "frozen"): - g = sys._getframe(1).f_globals + g = sys._getframe(1).f_globals # NOQA tlb_path = g.get("typelib_path") try: tlib_curr_mtime = os.stat(tlb_path).st_mtime except (OSError, TypeError): return - if not tlib_cached_mtime or abs(tlib_curr_mtime - tlib_cached_mtime) >= 1: + 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 PyInstanceMethod_Type = type(pythonapi.PyInstanceMethod_New(id)) - def instancemethod(func, inst, cls): + def instancemethod(func, inst, _): mth = PyInstanceMethod_Type(func) if inst is None: return mth return mth.__get__(inst) else: def instancemethod(func, inst, cls): - return types.MethodType(func, inst, cls) + return types.MethodType(func, inst, cls) # NOQA + class ReturnHRESULT(Exception): """ReturnHRESULT(hresult, text) @@ -150,9 +167,9 @@ class ReturnHRESULT(Exception): without logging an error. """ -##class IDLWarning(UserWarning): -## "Warn about questionable type information" +# class IDLWarning(UserWarning): +# "Warn about questionable type information" _GUID = GUID IID = GUID DWORD = c_ulong @@ -190,7 +207,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 @@ -202,26 +219,30 @@ 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 -COINIT_MULTITHREADED = 0x0 +# use this for functions that don't return a HRESULT +_ole32_nohresult = windll.ole32 + +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 @@ -231,6 +252,7 @@ def CoInitializeEx(flags=None): # CoUninitialize is called when Python is shut down. CoInitializeEx() + # We need to have CoUninitialize for multithreaded model where we have # to initialize and uninitialize COM for every new thread (except main) # in which we are using COM @@ -239,9 +261,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, @@ -249,16 +273,19 @@ def _shutdown(func=_ole32_nohresult.CoUninitialize, # False. _debug("Calling CoUninitialize()") if __debug__: - func() + func() # NOQA 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) ################################################################ @@ -270,6 +297,7 @@ 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 @@ -284,9 +312,9 @@ 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. @@ -302,10 +330,10 @@ class _cominterface_meta(type): _com_shutting_down = False # Creates also a POINTER type for the newly created class. - def __new__(cls, name, bases, namespace): + def __new__(mcs, name, bases, namespace): methods = namespace.pop("_methods_", None) dispmethods = namespace.pop("_disp_methods_", None) - new_cls = type.__new__(cls, name, bases, namespace) + new_cls = type.__new__(mcs, name, bases, namespace) if methods is not None: new_cls._methods_ = methods @@ -331,23 +359,25 @@ def __new__(cls, name, bases, namespace): {"__com_interface__": new_cls, "_needs_com_addref_": None}) - from ctypes import _pointer_type_cache + from ctypes import _pointer_type_cache # NOQA _pointer_type_cache[new_cls] = p if new_cls._case_insensitive_: @patcher.Patch(p) - class CaseInsensitive(object): + class CaseInsensitive(object): # NOQA # case insensitive attributes for COM methods and properties - def __getattr__(self, name): - """Implement case insensitive access to methods and properties""" + def __getattr__(self, nme): + """ + Implement case insensitive access to methods and properties + """ try: - fixed_name = self.__map_case__[name.lower()] + fixed_name = self.__map_case__[nme.lower()] except KeyError: - raise AttributeError(name) - if fixed_name != name: # prevent unbounded recursion + raise AttributeError(nme) + if fixed_name != nme: # prevent unbounded recursion return getattr(self, fixed_name) - raise AttributeError(name) + raise AttributeError(nme) # __setattr__ is pretty heavy-weight, because it is called for # EVERY attribute assignment. Settings a non-com attribute @@ -355,14 +385,18 @@ def __getattr__(self, name): # function it takes 0.7 sec - 12 times slower. # # 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) + def __setattr__(self, nme, value): + """ + Implement case insensitive access to methods and properties + """ + object.__setattr__( + self, + self.__map_case__.get(nme.lower(), nme), + value + ) @patcher.Patch(POINTER(p)) - class ReferenceFix(object): + class ReferenceFix(object): # NOQA def __setitem__(self, index, value): # We override the __setitem__ method of the # POINTER(POINTER(interface)) type, so that the COM @@ -383,7 +417,7 @@ def __setitem__(self, index, value): # CopyComPointer should do if index != 0. if bool(value): value.AddRef() - super(POINTER(p), self).__setitem__(index, value) + super(POINTER(p), self).__setitem__(index, value) # NOQA return from _ctypes import CopyComPointer CopyComPointer(value, self) @@ -395,7 +429,7 @@ def __setattr__(self, name, value): # XXX I'm no longer sure why the code generator generates # "_methods_ = []" in the interface definition, and later # overrides this by "Interface._methods_ = [...] -## assert self.__dict__.get("_methods_", None) is None + # assert self.__dict__.get("_methods_", None) is None self._make_methods(value) self._make_specials() elif name == "_disp_methods_": @@ -420,7 +454,7 @@ def has_name(name): @patcher.Patch(self) class _(object): def __len__(self): - "Return the the 'self.Count' property." + """Return the the 'self.Count' property.""" return self.Count if has_name("Item"): @@ -430,14 +464,14 @@ class _(object): # calling the instance (Not sure this makes sense, but # win32com does this also). def __call__(self, *args, **kw): - "Return 'self.Item(*args, **kw)'" + """Return 'self.Item(*args, **kw)'""" return self.Item(*args, **kw) # does this make sense? It seems that all standard typelibs I've # seen so far that support .Item also support ._NewEnum @patcher.no_replace def __getitem__(self, index): - "Return 'self.Item(index)'" + """Return 'self.Item(index)'""" # Handle tuples and all-slice if isinstance(index, tuple): args = index @@ -464,7 +498,7 @@ def __getitem__(self, index): @patcher.no_replace def __setitem__(self, index, value): - "Attempt 'self.Item[index] = value'" + """Attempt 'self.Item[index] = value'""" try: self.Item[index] = value except COMError as err: @@ -481,10 +515,10 @@ def __setitem__(self, index, value): @patcher.Patch(self) class _(object): def __iter__(self): - "Return an iterator over the _NewEnum collection." - # This method returns a pointer to _some_ _NewEnum interface. - # It relies on the fact that the code generator creates next() - # methods for them automatically. + """Return an iterator over the _NewEnum collection.""" + # This method returns a pointer to _some_ _NewEnum + # interface. It relies on the fact that the code + # generator creates next() methods for them automatically. # # Better would maybe to return an object that # implements the Python iterator protocol, and @@ -497,8 +531,8 @@ def __iter__(self): enum = enum() if hasattr(enum, "Next"): return enum - # _NewEnum returns an IUnknown pointer, QueryInterface() it to - # IEnumVARIANT + # _NewEnum returns an IUnknown pointer, + # QueryInterface() it to IEnumVARIANT from comtypes.automation import IEnumVARIANT return enum.QueryInterface(IEnumVARIANT) @@ -537,16 +571,21 @@ def _make_dispmethods(self, methods): self.__map_case__[name.lower()] = name def __get_baseinterface_methodcount(self): - "Return the number of com methods in the base interfaces" + """Return the number of com methods in the base interfaces""" + itf = None try: + result = 0 for itf in self.mro()[1:-1]: result += len(itf.__dict__["_methods_"]) + return result except KeyError as err: (name,) = err.args if name == "_methods_": - raise TypeError("baseinterface '%s' has no _methods_" % itf.__name__) + raise TypeError( + "baseinterface '%s' has no _methods_" % itf.__name__ + ) raise def _make_methods(self, methods): @@ -571,36 +610,40 @@ def _make_methods(self, methods): setattr(self, "_%s__com_%s" % (self.__name__, name), raw_mth) mth = instancemethod(func, None, self) if not is_prop: - # We install the method in the class, except when it's a property. - # And we make sure we don't overwrite a property that's already present. + # We install the method in the class, except when it's a + # property. And we make sure we don't overwrite a property + # that's already present. mthname = name if not hasattr(self, name) else ("_%s" % name) setattr(self, mthname, mth) # For a method, this is the real name. - # For a property, this is the name WITHOUT the _set_ or _get_ prefix. + # For a property, this is the name WITHOUT the + # _set_ or _get_ prefix. if self._case_insensitive_: self.__map_case__[name.lower()] = name if is_prop: self.__map_case__[name[5:].lower()] = name[5:] # create public properties / attribute accessors for name, accessor in member_gen.properties(): - # Again, we should not overwrite class attributes that are already present. + # Again, we should not overwrite class attributes that + # are already present. propname = name if not hasattr(self, name) else ("_%s" % name) setattr(self, propname, accessor) # COM is case insensitive 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" + """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" + """base class for COM interface pointer classes""" def __del__(self, _debug=logger.debug): - "Release the COM refcount we own." + """Release the COM refcount we own.""" if self: # comtypes calls CoUninitialize() when the atexit handlers # runs. CoUninitialize() cleans up the COM objects that @@ -609,7 +652,7 @@ def __del__(self, _debug=logger.debug): # this may give a protection fault. So we need the # _com_shutting_down flag. # - if not type(self)._com_shutting_down: + if not type(self)._com_shutting_down: # NOQA _debug("Release %s", self) self.Release() @@ -623,14 +666,22 @@ def __cmp__(self, other): if not isinstance(other, _compointer_base): 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) + # 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 + ) 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 + # 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 + ) def __hash__(self): """Return the hash value of the pointer.""" @@ -644,20 +695,26 @@ def __get_value(self): def __repr__(self): ptr = super(_compointer_base, self).value - return "<%s ptr=0x%x at %x>" % (self.__class__.__name__, ptr or 0, id(self)) + return "<%s ptr=0x%x at %x>" % ( + self.__class__.__name__, + ptr or 0, + id(self) + ) # This fixes the problem when there are multiple python interface types - # wrapping the same COM interface. This could happen because some interfaces - # are contained in multiple typelibs. + # wrapping the same COM interface. This could happen because some + # interfaces are contained in multiple typelibs. # # It also allows to pass a CoClass instance to an api # expecting a COM interface. @classmethod def from_param(cls, value): - """Convert 'value' into a COM pointer to the interface. + """ + Convert 'value' into a COM pointer to the interface. This method accepts a COM pointer, or a CoClass instance - which is QueryInterface()d.""" + which is QueryInterface()d. + """ if value is None: return None # CLF: 2013-01-18 @@ -672,7 +729,7 @@ def from_param(cls, value): return value # Accept an CoClass instance which exposes the interface required. try: - table = value._com_pointers_ + table = value._com_pointers_ # NOQA except AttributeError: pass else: @@ -681,14 +738,15 @@ def from_param(cls, value): return table[cls._iid_] except KeyError: raise TypeError("Interface %s not supported" % cls._iid_) - return value.QueryInterface(cls.__com_interface__) + return value.QueryInterface(cls.__com_interface__) # NOQA -################################################################ +################################################################ class BSTR(_SimpleCData): - "The windows BSTR data type" + """The windows BSTR data type""" _type_ = "X" _needsfree = False + def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self.value) @@ -713,45 +771,67 @@ 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." + """Specifies the helpstring for a COM method or property.""" + class defaultvalue(object): - "Specifies the default value for parameters marked optional." + """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." + """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. +# 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" + """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) + """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, ()) + """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: # DISPPROPERTY([5, 'readonly'], OLE_YSIZE_HIMETRIC, 'Height'), # DISPMETHOD( -# [6], None, 'Render', ([], c_int, 'hdc'), ([], c_int, 'x'), ([], c_int, 'y') +# [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. + """ + Specifies a COM method slot with idlflags. XXX should explain the sematics of the arguments. """ @@ -780,7 +860,8 @@ def COMMETHOD(idlflags, restype, methodname, *argspec): _T_IUnknown = TypeVar("_T_IUnknown", bound="IUnknown") class _IUnknown_Base(c_void_p): - """This is workaround to avoid false-positive of static type checking. + """ + This is workaround to avoid false-positive of static type checking. `IUnknown` behaves as a ctypes type, and `POINTER` can take it. This behavior is defined by some metaclasses in runtime. @@ -794,9 +875,11 @@ class _IUnknown_Base(c_void_p): else: _IUnknown_Base = object + @add_metaclass(_cominterface_meta) class IUnknown(_IUnknown_Base): - """The most basic COM interface. + """ + The most basic COM interface. Each subclasses of IUnknown must define these class attributes: @@ -818,10 +901,11 @@ class IUnknown(_IUnknown_Base): ] # type: ClassVar[List[_ComMemberSpec]] # NOTE: Why not `QueryInterface(T) -> _Pointer[T]`? - # Any static type checkers is not able to provide members of `T` from `_Pointer[T]`, - # regardless of the pointer is able to access members of contents in runtime. - # And if `isinstance(p, POINTER(T))` is `True`, then `isinstance(p, T)` is also `True`. - # So returning `T` is not a lie, and good way to know what members the class has. + # Any static type checkers is not able to provide members of `T` from + # `_Pointer[T]`, regardless of the pointer is able to access members of + # contents in runtime. And if `isinstance(p, POINTER(T))` is `True`, then + # `isinstance(p, T)` is also `True`. So returning `T` is not a lie, and + # good way to know what members the class has. def QueryInterface(self, interface, iid=None): # type: (Type[_T_IUnknown], Optional[GUID]) -> _T_IUnknown """QueryInterface(interface) -> instance""" @@ -854,9 +938,12 @@ class IPersist(IUnknown): _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. @@ -867,6 +954,7 @@ class IServiceProvider(IUnknown): _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 # interface and it returns a pointer to that interface) def QueryService(self, serviceIID, interface): @@ -876,24 +964,28 @@ 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 @@ -902,10 +994,12 @@ 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_), # NOQA + byref(punk) + ) return punk # type: ignore @@ -916,14 +1010,17 @@ 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 + """ + The basic windows api to create a COM class object and return a pointer to an interface. """ if clsctx is None: @@ -931,8 +1028,14 @@ def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): if interface is None: interface = IUnknown p = POINTER(interface)() - iid = interface._iid_ - _ole32.CoCreateInstance(byref(clsid), punkouter, clsctx, byref(iid), byref(p)) + iid = interface._iid_ # NOQA + _ole32.CoCreateInstance( + byref(clsid), + punkouter, + clsctx, + byref(iid), + byref(p) + ) return p # type: ignore @@ -941,11 +1044,13 @@ def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): 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: @@ -954,11 +1059,13 @@ def CoGetClassObject(clsid, clsctx=None, pServerInfo=None, interface=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_, # NOQA + byref(p) + ) return p # type: ignore @@ -967,11 +1074,13 @@ def CoGetClassObject(clsid, clsctx=None, pServerInfo=None, interface=None): 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""" @@ -983,14 +1092,18 @@ 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)), @@ -1001,8 +1114,11 @@ class _COAUTHIDENTITY(Structure): ('PasswordLength', c_ulong), ('Flags', c_ulong), ] + + COAUTHIDENTITY = _COAUTHIDENTITY + class _COAUTHINFO(Structure): _fields_ = [ ('dwAuthnSvc', c_ulong), @@ -1013,8 +1129,11 @@ class _COAUTHINFO(Structure): ('pAuthIdentityData', POINTER(_COAUTHIDENTITY)), ('dwCapabilities', c_ulong), ] + + COAUTHINFO = _COAUTHINFO + class _COSERVERINFO(Structure): _fields_ = [ ('dwReserved1', c_ulong), @@ -1022,15 +1141,25 @@ class _COSERVERINFO(Structure): ('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_ = [ @@ -1039,9 +1168,12 @@ class tagBIND_OPTS(Structure): ('grfMode', c_ulong), ('dwTickCountDeadline', c_ulong) ] + + # XXX Add __init__ which sets cbStruct? BIND_OPTS = tagBIND_OPTS + class tagBIND_OPTS2(Structure): _fields_ = [ ('cbStruct', c_ulong), @@ -1053,10 +1185,13 @@ class tagBIND_OPTS2(Structure): ('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_ = [ @@ -1068,49 +1203,73 @@ class _SEC_WINNT_AUTH_IDENTITY(Structure): ('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)), ] + + SOLE_AUTHENTICATION_INFO = _SOLE_AUTHENTICATION_INFO + class _SOLE_AUTHENTICATION_LIST(Structure): _fields_ = [ ('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 + """ + The basic windows api to create a COM class object and return a pointer to an interface, possibly on another machine. Passing both "machine" and "pServerInfo" results in a ValueError. """ 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: @@ -1124,24 +1283,27 @@ def CoCreateInstanceEx(clsid, interface=None, if interface is None: interface = IUnknown multiqi = MULTI_QI() - multiqi.pIID = pointer(interface._iid_) # type: ignore - _ole32.CoCreateInstanceEx(byref(clsid), - None, - clsctx, - pServerInfo, - 1, - byref(multiqi)) + multiqi.pIID = pointer(interface._iid_) # NOQA # type: ignore + _ole32.CoCreateInstanceEx( + byref(clsid), + None, + clsctx, + pServerInfo, + 1, + byref(multiqi) + ) return cast(multiqi.pItf, POINTER(interface)) # type: ignore ################################################################ -from comtypes._comobject import COMObject +from comtypes._comobject import COMObject # NOQA # What's a coclass? # a POINTER to a coclass is allowed as parameter in a function declaration: # http://msdn.microsoft.com/library/en-us/midl/midl/oleautomation.asp -from comtypes._meta import _coclass_meta +from comtypes._meta import _coclass_meta # NOQA + @add_metaclass(_coclass_meta) class CoClass(COMObject): diff --git a/comtypes/_comobject.py b/comtypes/_comobject.py index af36fa01..4681d261 100644 --- a/comtypes/_comobject.py +++ b/comtypes/_comobject.py @@ -1,18 +1,40 @@ 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 -import os import sys -from comtypes import COMError, ReturnHRESULT, instancemethod, _encode_idl -from comtypes.errorinfo import ISupportErrorInfo, ReportException, ReportError +from comtypes import ( + COMError, + ReturnHRESULT, + instancemethod, + _encode_idl +) +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 @@ -25,7 +47,7 @@ if sys.version_info >= (3, 0): int_types = (int, ) else: - int_types = (int, long) + int_types = (int, long) # NOQA ################################################################ # COM object implementation @@ -42,7 +64,7 @@ class E_NotImplemented(Exception): def HRESULT_FROM_WIN32(errcode): - "Convert a Windows error code into a HRESULT value." + """Convert a Windows error code into a HRESULT value.""" if errcode is None: return 0x80000000 if errcode & 0x80000000: @@ -51,10 +73,11 @@ def HRESULT_FROM_WIN32(errcode): def winerror(exc): - """Return the windows error code from a WindowsError or COMError - instance.""" + """ + Return the windows error code from a WindowsError or COMError instance. + """ if isinstance(exc, COMError): - return exc.hresult + return exc.hresult # NOQA elif isinstance(exc, WindowsError): code = exc.winerror if isinstance(code, int_types): @@ -63,14 +86,21 @@ 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): + def _not_implemented(*_): """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,29 +113,46 @@ 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_, # NOQA + 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) - return ReportException(E_FAIL, interface._iid_, clsid=clsid) + except: # NOQA + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True + ) + return ReportException(E_FAIL, interface._iid_, clsid=clsid) # NOQA 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]) call_with_this.has_outargs = has_outargs + return call_with_this @@ -114,9 +161,11 @@ def call_with_this(*args, **kw): def hack(inst, mth, paramflags, interface, mthname): if paramflags is None: return catch_errors(inst, mth, paramflags, interface, mthname) + code = mth.__code__ if code.co_varnames[1:2] == ("this",): return catch_errors(inst, mth, paramflags, interface, mthname) + dirflags = [f[0] for f in paramflags] # An argument is an input arg either if flags are NOT set in the # idl file, or if the flags contain 'in'. In other words, the @@ -126,30 +175,31 @@ 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) - ## XXX Remove this: -## if args_in != code.co_argcount - 1: -## return catch_errors(inst, mth, interface, mthname) + # XXX Remove this: + # if args_in != code.co_argcount - 1: + # return catch_errors(inst, mth, interface, mthname) clsid = getattr(inst, "_reg_clsid_", None) - def call_without_this(this, *args): + def call_without_this(_, *args): # Method implementations could check for and return E_POINTER # themselves. Or an error will be raised when # 'outargs[i][0] = value' is executed. -## for a in outargs: -## if not a: -## return E_POINTER + # for a in outargs: + # 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]) + for arg in args_in_idx: + inargs.append(args[arg]) try: result = mth(*inargs) if args_out == 1: @@ -158,16 +208,25 @@ def call_without_this(this, *args): if len(result) != args_out: msg = "Method should have returned a %s-tuple" % args_out raise ValueError(msg) - for i, value in enumerate(result): - args[args_out_idx[i]][0] = value + for index, value in enumerate(result): + args[args_out_idx[index]][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_, # NOQA + 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,24 +234,49 @@ 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_, # NOQA + 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) + return ReportException( + hr, + interface._iid_, # NOQA + 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) - return ReportException(E_FAIL, interface._iid_, clsid=clsid) + except: # NOQA + _error( + "Exception in %s.%s implementation:", + interface.__name__, + mthname, + exc_info=True + ) + return ReportException( + E_FAIL, + interface._iid_, # NOQA + clsid=clsid + ) return S_OK + if args_out: call_without_this.has_outargs = True + return call_without_this @@ -220,7 +304,7 @@ def find_method(self, fq_name, mthname): def find_impl(self, interface, mthname, paramflags, idlflags): fq_name = "%s_%s" % (interface.__name__, mthname) - if interface._case_insensitive_: + if interface._case_insensitive_: # NOQA # simple name, like 'QueryInterface' mthname = self.names.get(mthname.lower(), mthname) # qualified name, like 'IUnknown_QueryInterface' @@ -231,7 +315,7 @@ def find_impl(self, interface, mthname, paramflags, idlflags): except AttributeError: pass propname = mthname[5:] # strip the '_get_' or '_set' prefix - if interface._case_insensitive_: + if interface._case_insensitive_: # NOQA propname = self.names.get(propname.lower(), propname) # propput and propget is done with 'normal' attribute access, # but only for COM properties that do not take additional @@ -241,28 +325,34 @@ 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): # - def set(self, value): + def _set(self, value): # NOQA try: # XXX this may not be correct is the object implements # _get_PropName but not _set_PropName setattr(self, propname, value) except AttributeError: raise E_NotImplemented() - return instancemethod(set, self.inst, type(self.inst)) + + return instancemethod(_set, self.inst, type(self.inst)) def getter(self, propname): - def get(self): + def _get(self): # NOQA try: return getattr(self, propname) except AttributeError: raise E_NotImplemented() - return instancemethod(get, self.inst, type(self.inst)) + + return instancemethod(_get, self.inst, type(self.inst)) def _create_vtbl_type(fields, itf): @@ -271,10 +361,13 @@ def _create_vtbl_type(fields, itf): 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 = {} @@ -332,9 +425,9 @@ def run(self, classobjects): self.run_sta() for obj in classobjects: - obj._revoke_class() + obj._revoke_class() # NOQA - def run_sta(self): + def run_sta(self): # NOQA from comtypes import messageloop messageloop.run() @@ -342,11 +435,11 @@ def run_mta(self): if sys.version_info >= (3, 0): import queue else: - import Queue as queue + import Queue as queue # NOQA self._queue = queue.Queue() self._queue.get() - def Lock(self): + def Lock(self): # NOQA oledll.ole32.CoAddRefServerProcess() def Unlock(self): @@ -372,7 +465,7 @@ def Unlock(self): def DllCanUnloadNow(self): if self.locks.value: return S_FALSE - if COMObject._instances_: + if COMObject._instances_: # NOQA return S_FALSE return S_OK @@ -410,21 +503,26 @@ def __prepare_comobject(self): # attribute) # # Add these if they are not listed in _com_interfaces_. - interfaces = tuple(self._com_interfaces_) + interfaces = tuple(self._com_interfaces_) # NOQA if ISupportErrorInfo not in interfaces: 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: interfaces += (IPersist,) + for itf in interfaces[::-1]: self.__make_interface_pointer(itf) @@ -435,21 +533,24 @@ def __make_interface_pointer(self, itf): # iterate over interface inheritance in reverse order to build the # virtual function table, and leave out the 'object' base class. finder = self._get_method_finder_(itf) + interface = None + for interface in itf.__mro__[-2::-1]: - iids.append(interface._iid_) - for m in interface._methods_: + iids.append(interface._iid_) # NOQA + for m in interface._methods_: # NOQA restype, mthname, argtypes, paramflags, idlflags, helptext = m proto = WINFUNCTYPE(restype, c_void_p, *argtypes) fields.append((mthname, proto)) mth = finder.get_impl(interface, mthname, paramflags, idlflags) methods.append(proto(mth)) + Vtbl = _create_vtbl_type(tuple(fields), itf) vtbl = Vtbl(*methods) for iid in iids: self._com_pointers_[iid] = pointer(pointer(vtbl)) if hasattr(itf, "_disp_methods_"): self._dispimpl_ = {} - for m in itf._disp_methods_: + for m in itf._disp_methods_: # NOQA what, mthname, idlflags, restype, argspec = m ################# # What we have: @@ -488,32 +589,52 @@ def __make_interface_pointer(self, itf): invkind = 1 # DISPATCH_METHOD if restype: argspec = argspec + ((['out'], restype, ""),) - self.__make_dispentry(finder, interface, mthname, - idlflags, argspec, invkind) + 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 + self.__make_dispentry( + finder, + interface, + "_get_" + mthname, + idlflags, + argspec, + 2 # DISPATCH_PROPERTYGET + ) + if 'readonly' not 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 +674,11 @@ 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,47 +689,61 @@ 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) _debug("%r.AddRef() -> %s", self, result) + return result def _final_release_(self): - """This method may be overridden in subclasses - to free allocated resources or so.""" + """ + This method may be overridden in subclasses + 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 # argument. result = __InterlockedDecrement(self._refcnt) _debug("%r.Release() -> %s", self, result) + if result == 0: self._final_release_() self.__unkeep__(self) # Hm, why isn't this cleaned up by the cycle gc? - self._com_pointers_ = {} + self._com_pointers_ = {} # NOQA + return result - def IUnknown_QueryInterface(self, this, riid, ppvObj, _debug=_debug): + def IUnknown_QueryInterface(self, _, riid, ppvObj, _debug=_debug): # XXX This is probably too slow. # riid[0].hashcode() alone takes 33 us! iid = riid[0] @@ -618,15 +756,18 @@ def IUnknown_QueryInterface(self, this, riid, ppvObj, _debug=_debug): return E_NOINTERFACE def QueryInterface(self, interface): - "Query the object for an interface pointer" + """Query the object for an interface pointer""" # This method is NOT the implementation of # IUnknown::QueryInterface, instead it is supposed to be # called on an COMObject by user code. It allows to get COM # interface pointers from COMObject instances. - ptr = self._com_pointers_.get(interface._iid_, None) + ptr = self._com_pointers_.get(interface._iid_, None) # NOQA 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)) @@ -634,7 +775,7 @@ def QueryInterface(self, interface): ################################################################ # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation - def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, this, riid): + def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, _, riid): if riid[0] in self._com_pointers_: return S_OK return S_FALSE @@ -643,10 +784,10 @@ def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, this, riid): # IProvideClassInfo::GetClassInfo implementation def IProvideClassInfo_GetClassInfo(self): try: - self.__typelib + self.__typelib # NOQA except AttributeError: raise WindowsError(E_NOTIMPL) - return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_) + return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_) # NOQA ################################################################ # IProvideClassInfo2::GetGUID implementation @@ -655,7 +796,7 @@ def IProvideClassInfo2_GetGUID(self, dwGuidKind): # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1 if dwGuidKind != 1: raise WindowsError(E_INVALIDARG) - return self._outgoing_interfaces_[0]._iid_ + return self._outgoing_interfaces_[0]._iid_ # NOQA ################################################################ # IDispatch methods @@ -663,18 +804,18 @@ def IProvideClassInfo2_GetGUID(self, dwGuidKind): def __typeinfo(self): # XXX Looks like this better be a static property, set by the # code that sets __typelib also... - iid = self._com_interfaces_[0]._iid_ - return self.__typelib.GetTypeInfoOfGuid(iid) + iid = self._com_interfaces_[0]._iid_ # NOQA + return self.__typelib.GetTypeInfoOfGuid(iid) # NOQA def IDispatch_GetTypeInfoCount(self): try: - self.__typelib + self.__typelib # NOQA except AttributeError: return 0 else: return 1 - def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo): + def IDispatch_GetTypeInfo(self, _, itinfo, __, ptinfo): if itinfo != 0: return DISP_E_BADINDEX try: @@ -683,8 +824,15 @@ 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, + _, + __, + rgszNames, + cNames, + ___, + 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 +840,25 @@ 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, + _, + __, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr + ): try: self._dispimpl_ except AttributeError: @@ -712,11 +874,17 @@ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, # This call uses windll instead of oledll so that a failed # call to DispInvoke will return a HRESULT instead of raising # an error. - interface = self._com_interfaces_[0] - ptr = self._com_pointers_[interface._iid_] + interface = self._com_interfaces_[0] # NOQA + ptr = self._com_pointers_[interface._iid_] # NOQA return windll.oleaut32.DispInvoke( - ptr, tinfo, dispIdMember, wFlags, pDispParams, pVarResult, - pExcepInfo, puArgErr + ptr, + tinfo, + dispIdMember, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr ) try: @@ -758,8 +926,10 @@ 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)))) @@ -775,6 +945,7 @@ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags, ################################################################ # IPersist interface def IPersist_GetClassID(self): - return self._reg_clsid_ + return self._reg_clsid_ # NOQA + __all__ = ["COMObject"] diff --git a/comtypes/_memberspec.py b/comtypes/_memberspec.py index 6cbfd520..a25f49a0 100644 --- a/comtypes/_memberspec.py +++ b/comtypes/_memberspec.py @@ -4,9 +4,17 @@ from comtypes import TYPE_CHECKING if TYPE_CHECKING: - from comtypes import _CData + from comtypes import _CData # NOQA 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] @@ -40,9 +48,11 @@ def _unpack_argspec(idl, typ, name=None, defval=_NOTHING): def _resolve_argspec(items): # type: (Tuple[ArgSpecElmType, ...]) -> Tuple[Tuple[ParamFlagType, ...], Tuple[Type[_CData], ...]] - """Unpacks and converts from argspec to paramflags and argtypes. + """ + Unpacks and converts from argspec to paramflags and argtypes. - - paramflags is a sequence of `(pflags: int, argname: str, | None[, defval: Any])`. + - paramflags is a sequence of + `(pflags: int, argname: str, | None[, defval: Any])`. - argtypes is a sequence of `type[_CData]`. """ from comtypes.automation import VARIANT @@ -59,7 +69,8 @@ def _resolve_argspec(items): elif typ is ctypes.POINTER(VARIANT): defval = ctypes.pointer(VARIANT.missing) else: - # msg = ("'optional' only allowed for VARIANT and VARIANT*, not for %s" % typ.__name__) + # msg = ("'optional' only allowed for VARIANT and + # VARIANT*, not for %s" % typ.__name__) # warnings.warn(msg, IDLWarning, stacklevel=2) defval = typ() if defval is _NOTHING: @@ -73,6 +84,7 @@ 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], ...] @@ -98,7 +110,14 @@ 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 @@ -123,7 +142,13 @@ 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.what, self.name, self.idlflags, self.restype, self.argspec): + for item in ( + self.what, + self.name, + self.idlflags, + self.restype, + self.argspec + ): yield item @@ -141,6 +166,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 @@ -155,13 +181,13 @@ def call_with_inout(self, *args, **kw): name = info[1] # [in, out] parameters are passed as pointers, # this is the pointed-to type: - atyp = argtypes[i]._type_ + atyp = argtypes[i]._type_ # NOQA # Get the actual parameter, either as positional or # keyword arg. try: try: - v = args[i] + v = args[i] # NOQA except IndexError: v = kw[name] except KeyError: @@ -186,6 +212,7 @@ def call_with_inout(self, *args, **kw): else: v = atyp.from_param(v) assert not isinstance(v, BYREFTYPE) + outargs[outnum] = v outnum += 1 if len(args) > i: @@ -201,10 +228,12 @@ def call_with_inout(self, *args, **kw): if len(outargs) == 1: rescode = rescode.__ctypes_from_outparam__() return rescode + rescode = list(rescode) for outnum, o in outargs.items(): rescode[outnum] = o.__ctypes_from_outparam__() return rescode + return call_with_inout @@ -226,22 +255,29 @@ def add_propputref(self, name, doc, nargs, func): def __iter__(self): # type: () -> Iterator[Tuple[str, Optional[str], int, Optional[Callable[..., Any]], Optional[Callable[..., Any]]]] - for (name, doc, nargs), (fget, propput, propputref) in self._data.items(): + for ( + (name, doc, nargs), (fget, propput, propputref) + ) in self._data.items(): if propput is not None and propputref is not None: # Create a setter method that examines the argument type # 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]): + + def put_or_putref(self, *args): # NOQA + if comtypes._is_object(args[-1]): # NOQA return putref(self, *args) + return put(self, *args) + fset = put_or_putref + elif propputref is not None: fset = propputref else: fset = propput - yield (name, doc, nargs, fget, fset) + + yield (name, doc, nargs, fget, fset) # NOQA class PropertyGenerator(object): @@ -276,8 +312,13 @@ def __iter__(self): # Hm, must be a descriptor where the __get__ method # returns a bound object having __getitem__ and # __setitem__ methods. - prop = named_property("%s.%s" % (self._cls_name, name), fget, fset, doc) - yield (name, prop) + prop = named_property( + "%s.%s" % (self._cls_name, name), + fget, + fset, + doc + ) + yield (name, prop) # NOQA def to_propget_keys(self, m): # type: (_MemberSpec) -> Tuple[str, Optional[str], int] @@ -340,7 +381,8 @@ def __init__(self, cls_name, vtbl_offset, iid): self._vtbl_offset = vtbl_offset self._iid = iid self._props = ComPropertyGenerator(cls_name) - # sequence of (name: str, func: Callable, raw_func: Callable, is_prop: bool) + # sequence of + # (name: str, func: Callable, raw_func: Callable, is_prop: bool) self._mths = [] # type: List[Tuple[str, Callable[..., Any], Callable[..., Any], bool]] self._member_index = 0 @@ -354,23 +396,32 @@ def add(self, m): # If the method returns a HRESULT, we pass the interface iid, # so that we can request error info for the interface. iid = self._iid if m.restype == ctypes.HRESULT else None - raw_func = proto(vidx, m.name, None, iid) # low level - func = self._fix_args(m, proto(vidx, m.name, m.paramflags, iid)) # high level + + # low level + raw_func = proto(vidx, m.name, None, iid) + # high level + func = self._fix_args(m, proto(vidx, m.name, m.paramflags, iid)) + func.__doc__ = m.doc func.__name__ = m.name # for pyhelp + is_prop = m.is_prop() if is_prop: self._props.add(m, func) + self._mths.append((m.name, func, raw_func, is_prop)) self._member_index += 1 - def _fix_args(self, m, func): + def _fix_args(self, m, func): # NOQA # type: (_ComMemberSpec, Callable[..., Any]) -> Callable[..., Any] - """This is a workaround. See `_fix_inout_args` docstring and comments.""" + """ + 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 def methods(self): @@ -384,68 +435,91 @@ class DispMemberGenerator(object): 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) + # sequence of + # (name: str, func_or_prop: Callable | property, is_prop: 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 + # XXX does not yet work for properties with parameters + assert not m.argspec is_prop = True accessor = self._make_disp_property(m) self._items.append((m.name, accessor, is_prop)) else: # DISPMETHOD func = self._make_disp_method(m) func.__name__ = m.name + is_prop = m.is_prop() if is_prop: self._props.add(m, func) else: self._items.append((m.name, func, is_prop)) - def _make_disp_property(self, m): + def _make_disp_property(self, m): # NOQA # 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 + invkind = 8 if comtypes._is_object(value) else 4 # NOQA + return obj.Invoke(memid, value, _invkind=invkind) + return property(fget, fset) # Should the funcs/mths we create have restype and/or argtypes attributes? - def _make_disp_method(self, m): + def _make_disp_method(self, m): # NOQA # 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 + # DISPATCH_PROPERTYGET + return obj.Invoke(memid, _invkind=2, *args, **kw) + return getfunc + elif "propput" in m.idlflags: def putfunc(obj, *args, **kw): - return obj.Invoke(memid, _invkind=4, *args, **kw) # DISPATCH_PROPERTYPUT + # DISPATCH_PROPERTYPUT + return obj.Invoke(memid, _invkind=4, *args, **kw) + return putfunc + elif "propputref" in m.idlflags: def putreffunc(obj, *args, **kw): - return obj.Invoke(memid, _invkind=8, *args, **kw) # DISPATCH_PROPERTYPUTREF + # DISPATCH_PROPERTYPUTREF + return obj.Invoke(memid, _invkind=8, *args, **kw) + 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 + # DISPATCH_METHOD + return obj.Invoke(memid, _invkind=1, *args, **kw) + return func def items(self): @@ -469,24 +543,29 @@ def __init__(self, name, fget, fset, instance): def __getitem__(self, index): if self.fget is None: raise TypeError("unsubscriptable object") + if isinstance(index, tuple): return self.fget(self.instance, *index) - elif index == comtypes._all_slice: + + elif index == comtypes._all_slice: # NOQA return self.fget(self.instance) + else: return self.fget(self.instance, index) def __call__(self, *args): if self.fget is None: raise TypeError("object is not callable") + return self.fget(self.instance, *args) def __setitem__(self, index, value): if self.fset is None: raise TypeError("object does not support item assignment") + if isinstance(index, tuple): self.fset(self.instance, *(index + (value,))) - elif index == comtypes._all_slice: + elif index == comtypes._all_slice: # NOQA self.fset(self.instance, value) else: self.fset(self.instance, index, value) @@ -510,6 +589,7 @@ def __init__(self, name, fget=None, fset=None, doc=None): def __get__(self, instance, owner=None): if instance is None: return self + return bound_named_property(self.name, self.fget, self.fset, instance) # Make this a data descriptor diff --git a/comtypes/_meta.py b/comtypes/_meta.py index 2d26b15d..d4420ae3 100644 --- a/comtypes/_meta.py +++ b/comtypes/_meta.py @@ -2,6 +2,7 @@ from ctypes import POINTER, c_void_p, cast import comtypes + ################################################################ # metaclass for CoClass (in comtypes/__init__.py) @@ -10,15 +11,17 @@ def _wrap_coclass(self): # but we really want this interface: itf = self._com_interfaces_[0] punk = cast(self, POINTER(itf)) - result = punk.QueryInterface(itf) + result = punk.QueryInterface(itf) # NOQA 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: # @@ -38,24 +41,29 @@ class _coclass_meta(type): # POINTER(...) type gets a __ctypes_from_outparam__ method which # will QueryInterface for the default interface: the first one on # the coclass' _com_interfaces_ list. - def __new__(cls, name, bases, namespace): - klass = type.__new__(cls, name, bases, namespace) + def __new__(mcs, name, bases, namespace): + klass = type.__new__(mcs, name, bases, namespace) if bases == (object,): return klass # XXX We should insist that a _reg_clsid_ is present. 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), - }) - from ctypes import _pointer_type_cache + 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 # NOQA _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..f904c45f 100644 --- a/comtypes/_npsupport.py +++ b/comtypes/_npsupport.py @@ -1,11 +1,12 @@ -""" Consolidation of numpy support utilities. """ +"""Consolidation of numpy support utilities. """ import sys is_64bits = sys.maxsize > 2**32 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): @@ -16,7 +17,8 @@ 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. @@ -25,6 +27,7 @@ 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,18 +129,21 @@ 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 + import numpy # NOQA # if that succeeded we can be enabled self.enabled = True self.VARIANT_dtype = self._make_variant_dtype() self.typecodes = self._check_ctypeslib_typecodes() - self.com_null_date64 = self.numpy.datetime64("1899-12-30T00:00:00", "ns") + self.com_null_date64 = self.numpy.datetime64( + "1899-12-30T00:00:00", + "ns" + ) interop = Interop() diff --git a/comtypes/_safearray.py b/comtypes/_safearray.py index 76e41b9d..653211be 100644 --- a/comtypes/_safearray.py +++ b/comtypes/_safearray.py @@ -5,14 +5,14 @@ from comtypes import HRESULT, GUID ################################################################ -##if __debug__: -## from ctypeslib.dynamic_module import include -## include("""\ -## #define UNICODE -## #define NO_STRICT -## #include -## """, -## persist=True) +# if __debug__: +# from ctypeslib.dynamic_module import include +# include("""\ +# #define UNICODE +# #define NO_STRICT +# #include +# """, +# persist=True) ################################################################ @@ -22,13 +22,17 @@ _oleaut32 = WinDLL("oleaut32") + class tagSAFEARRAYBOUND(Structure): _fields_ = [ ('cElements', DWORD), ('lLbound', LONG), -] + ] + + SAFEARRAYBOUND = tagSAFEARRAYBOUND + class tagSAFEARRAY(Structure): _fields_ = [ ('cDims', USHORT), @@ -37,7 +41,9 @@ class tagSAFEARRAY(Structure): ('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 338a0110..36daab50 100644 --- a/comtypes/automation.py +++ b/comtypes/automation.py @@ -5,25 +5,38 @@ import sys from ctypes import * -from ctypes import _Pointer +from ctypes import _Pointer # NOQA 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 +from ctypes.wintypes import DWORD, LONG, UINT, VARIANT_BOOL, WORD if TYPE_CHECKING: from typing import ( - Any, Callable, ClassVar, List, Optional, Tuple, Union as _UnionT, + Any, + Callable, + ClassVar, + List, + Optional, + Union as _UnionT, ) from comtypes import hints @@ -33,9 +46,9 @@ class _safearray(object): str_types = (str, ) base_text_type = str else: - int_types = (int, long) - str_types = (unicode, str) - base_text_type = basestring + int_types = (int, long) # NOQA + str_types = (unicode, str) # NOQA + base_text_type = basestring # NOQA LCID = DWORD DISPID = LONG @@ -67,7 +80,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 @@ -123,24 +136,30 @@ class _safearray(object): class tagCY(Structure): - _fields_ = [("int64", c_longlong)] + _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. - """ digits = (self.Hi32 << 64) + self.Lo64 decimal_str = "{0}{1}e-{2}".format( @@ -170,8 +189,11 @@ 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,24 +212,32 @@ 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)] + + _fields_ = [ + ("__VARIANT_NAME_1", U_VARIANT1) + ] + _anonymous_ = ["__VARIANT_NAME_1"] - def __init__(self, *args): + def __init__(self, *args): # NOQA if args: self.value = args[0] @@ -249,8 +279,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 @@ -268,6 +301,7 @@ def _set_value(self, value): # it did work. self.vt = VT_I4 return + # try VT_UI4 next. if value >= 0: u.VT_UI4 = value @@ -275,6 +309,7 @@ def _set_value(self, value): # did work. self.vt = VT_UI4 return + # try VT_I8 next. if value >= 0: u.VT_I8 = value @@ -282,6 +317,7 @@ def _set_value(self, value): # did work. self.vt = VT_I8 return + # try VT_UI8 next. if value >= 0: u.VT_UI8 = value @@ -289,9 +325,11 @@ def _set_value(self, value): # did work. self.vt = VT_UI8 return + # VT_R8 is last resort. self.vt = VT_R8 u.VT_R8 = float(value) + elif isinstance(value, (float, c_double)): self.vt = VT_R8 self._.VT_R8 = value @@ -302,7 +340,11 @@ 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. self.vt = VT_DATE self._.VT_R8 = com_days elif comtypes.npsupport.isdatetime64(value): @@ -322,13 +364,13 @@ def _set_value(self, value): elif isinstance(value, (list, tuple)): obj = _midlSAFEARRAY(VARIANT).create(value) memmove(byref(self._), byref(obj), sizeof(obj)) - self.vt = VT_ARRAY | obj._vartype_ + self.vt = VT_ARRAY | obj._vartype_ # NOQA elif isinstance(value, array.array): vartype = _arraycode_to_vartype[value.typecode] typ = _vartype_to_ctype[vartype] obj = _midlSAFEARRAY(typ).create(value) memmove(byref(self._), byref(obj), sizeof(obj)) - self.vt = VT_ARRAY | obj._vartype_ + self.vt = VT_ARRAY | obj._vartype_ # NOQA elif comtypes.npsupport.isndarray(value): # Try to convert a simple array of basic types. descr = value.dtype.descr[0][1] @@ -338,10 +380,11 @@ def _set_value(self, value): obj = _midlSAFEARRAY(VARIANT).create(value) else: obj = _midlSAFEARRAY(typ).create(value) + memmove(byref(self._), byref(obj), sizeof(obj)) - self.vt = VT_ARRAY | obj._vartype_ + self.vt = VT_ARRAY | obj._vartype_ # NOQA elif isinstance(value, Structure) and hasattr(value, "_recordinfo_"): - guids = value._recordinfo_ + guids = value._recordinfo_ # NOQA from comtypes.typeinfo import GetRecordInfoFromGuids ri = GetRecordInfoFromGuids(*guids) self.vt = VT_RECORD @@ -351,7 +394,7 @@ def _set_value(self, value): self._.pRecInfo = ri self._.pvRecord = ri.RecordCreateCopy(byref(value)) elif isinstance(getattr(value, "_comobj", None), POINTER(IDispatch)): - CopyComPointer(value._comobj, byref(self._)) + CopyComPointer(value._comobj, byref(self._)) # NOQA self.vt = VT_DISPATCH elif isinstance(value, VARIANT): _VariantCopy(self, value) @@ -383,7 +426,7 @@ def _set_value(self, value): self.vt = VT_UI8 self._.VT_UI8 = value elif isinstance(value, _byref_type): - ref = value._obj + ref = value._obj # NOQA self._.c_void_p = addressof(ref) self.__keepref = value self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF @@ -440,7 +483,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 +494,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() @@ -493,56 +536,53 @@ def _get_value(self, dynamic=False): def __getitem__(self, index): if index != 0: raise IndexError(index) - if self.vt == VT_BYREF|VT_VARIANT: - v = VARIANT() + if self.vt == VT_BYREF | VT_VARIANT: # apparently VariantCopyInd doesn't work always with # VT_BYREF|VT_VARIANT, so do it manually. - v = cast(self._.c_void_p, POINTER(VARIANT))[0] - return v.value + var = cast(self._.c_void_p, POINTER(VARIANT))[0] + return var.value else: - v = VARIANT() - _VariantCopyInd(v, self) - return v.value + var = VARIANT() + _VariantCopyInd(var, self) + return var.value # these are missing: -## getter[VT_ERROR] -## getter[VT_ARRAY] -## getter[VT_BYREF|VT_UI1] -## getter[VT_BYREF|VT_I2] -## getter[VT_BYREF|VT_I4] -## getter[VT_BYREF|VT_R4] -## getter[VT_BYREF|VT_R8] -## getter[VT_BYREF|VT_BOOL] -## getter[VT_BYREF|VT_ERROR] -## getter[VT_BYREF|VT_CY] -## getter[VT_BYREF|VT_DATE] -## getter[VT_BYREF|VT_BSTR] -## getter[VT_BYREF|VT_UNKNOWN] -## getter[VT_BYREF|VT_DISPATCH] -## getter[VT_BYREF|VT_ARRAY] -## getter[VT_BYREF|VT_VARIANT] -## getter[VT_BYREF] -## getter[VT_BYREF|VT_DECIMAL] -## getter[VT_BYREF|VT_I1] -## getter[VT_BYREF|VT_UI2] -## getter[VT_BYREF|VT_UI4] -## getter[VT_BYREF|VT_INT] -## getter[VT_BYREF|VT_UINT] +# getter[VT_ERROR] +# getter[VT_ARRAY] +# getter[VT_BYREF|VT_UI1] +# getter[VT_BYREF|VT_I2] +# getter[VT_BYREF|VT_I4] +# getter[VT_BYREF|VT_R4] +# getter[VT_BYREF|VT_R8] +# getter[VT_BYREF|VT_BOOL] +# getter[VT_BYREF|VT_ERROR] +# getter[VT_BYREF|VT_CY] +# getter[VT_BYREF|VT_DATE] +# getter[VT_BYREF|VT_BSTR] +# getter[VT_BYREF|VT_UNKNOWN] +# getter[VT_BYREF|VT_DISPATCH] +# getter[VT_BYREF|VT_ARRAY] +# getter[VT_BYREF|VT_VARIANT] +# getter[VT_BYREF] +# getter[VT_BYREF|VT_DECIMAL] +# getter[VT_BYREF|VT_I1] +# getter[VT_BYREF|VT_UI2] +# getter[VT_BYREF|VT_UI4] +# getter[VT_BYREF|VT_INT] +# getter[VT_BYREF|VT_UINT] value = property(_get_value, _set_value) def __ctypes_from_outparam__(self): # XXX Manual resource management, because of the VARIANT bug: - result = self.value + result = self.value # NOQA self.value = None return result def ChangeType(self, typecode): - _VariantChangeType(self, - self, - 0, - typecode) + _VariantChangeType(self, self, 0, typecode) + VARIANT = tagVARIANT VARIANTARG = VARIANT @@ -550,7 +590,12 @@ def ChangeType(self, typecode): _oleaut32 = OleDLL("oleaut32") _VariantChangeType = _oleaut32.VariantChangeType -_VariantChangeType.argtypes = (POINTER(VARIANT), POINTER(VARIANT), c_ushort, VARTYPE) +_VariantChangeType.argtypes = ( + POINTER(VARIANT), + POINTER(VARIANT), + c_ushort, + VARTYPE +) _VariantClear = _oleaut32.VariantClear _VariantClear.argtypes = (POINTER(VARIANT),) @@ -570,11 +615,12 @@ def ChangeType(self, typecode): VARIANT.empty = VARIANT() VARIANT.missing = v = VARIANT() v.vt = VT_ERROR -v._.VT_I4 = 0x80020004 +v._.VT_I4 = 0x80020004 # NOQA del v _carg_obj = type(byref(c_int())) -from ctypes import Array as _CArrayType +from ctypes import Array as _CArrayType # NOQA + @comtypes.patcher.Patch(POINTER(VARIANT)) class _(object): @@ -589,12 +635,12 @@ def from_param(cls, arg): if isinstance(arg, POINTER(VARIANT)): return arg # accept byref(VARIANT) instance - if isinstance(arg, _carg_obj) and isinstance(arg._obj, VARIANT): + if isinstance(arg, _carg_obj) and isinstance(arg._obj, VARIANT): # NOQA return arg # accept VARIANT instance if isinstance(arg, VARIANT): return byref(arg) - if isinstance(arg, _CArrayType) and arg._type_ is VARIANT: + if isinstance(arg, _CArrayType) and arg._type_ is VARIANT: # NOQA # accept array of VARIANTs return arg # anything else which can be converted to a VARIANT. @@ -605,12 +651,14 @@ 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'] _dynamic = False + def __iter__(self): return self @@ -630,44 +678,59 @@ def next(self): def __getitem__(self, index): self.Reset() # Does not yet work. -## if isinstance(index, slice): -## self.Skip(index.start or 0) -## return self.Next(index.stop or sys.maxint) + # if isinstance(index, slice): + # self.Skip(index.start or 0) + # return self.Next(index.stop or sys.maxint) self.Skip(index) item, fetched = self.Next(1) if fetched: return item + raise IndexError def Next(self, celt): fetched = c_ulong() if celt == 1: - v = VARIANT() - self.__com_Next(celt, v, fetched) - 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]] - for v in array: - v.value = None + var = VARIANT() + self.__com_Next(celt, var, fetched) + return var._get_value(dynamic=self._dynamic), fetched.value # NOQA + + arry = (VARIANT * celt)() + self.__com_Next(celt, arry, fetched) + result = [ + item._get_value(dynamic=self._dynamic) # NOQA + for item in arry[:fetched.value] + ] + + for item in arry: + item.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, '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, 'Clone', + (['out'], POINTER(POINTER(IEnumVARIANT)), 'ppenum') + ), ] -##from _ctypes import VARIANT_set -##import new -##VARIANT.value = property(VARIANT._get_value, new.instancemethod(VARIANT_set, None, VARIANT)) +# from _ctypes import VARIANT_set +# import new +# VARIANT.value = property(VARIANT._get_value, +# new.instancemethod(VARIANT_set, None, VARIANT)) class tagEXCEPINFO(Structure): @@ -683,9 +746,17 @@ 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), @@ -694,18 +765,21 @@ def __repr__(self): ('bstrHelpFile', BSTR), ('dwHelpContext', DWORD), ('pvReserved', c_void_p), -## ('pfnDeferredFillIn', WINFUNCTYPE(HRESULT, POINTER(tagEXCEPINFO))), + # ('pfnDeferredFillIn', WINFUNCTYPE(HRESULT, POINTER(tagEXCEPINFO))), ('pfnDeferredFillIn', c_void_p), ('scode', SCODE), ] + EXCEPINFO = tagEXCEPINFO + class tagDISPPARAMS(Structure): if TYPE_CHECKING: rgvarg = hints.AnnoField() # type: Array[VARIANT] rgdispidNamedArgs = hints.AnnoField() # type: _Pointer[DISPID] cArgs = hints.AnnoField() # type: int cNamedArgs = hints.AnnoField() # type: int + _fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 696 ('rgvarg', POINTER(VARIANTARG)), @@ -713,10 +787,13 @@ class tagDISPPARAMS(Structure): ('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 @@ -744,29 +821,49 @@ def __del__(self): 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]] # NOQA _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): @@ -793,20 +890,30 @@ def _invoke(self, memid, invkind, lcid, *args): dp = DISPPARAMS() if args: - array = (VARIANT * len(args))() + arry = (VARIANT * len(args))() for i, a in enumerate(args[::-1]): - array[i].value = a + arry[i].value = a dp.cArgs = len(args) if invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): dp.cNamedArgs = 1 dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT)) - dp.rgvarg = array - self.__com_Invoke(memid, riid_null, lcid, invkind, - dp, var, None, argerr) - return var._get_value(dynamic=True) + dp.rgvarg = arry + + self.__com_Invoke( + memid, + riid_null, + lcid, + invkind, + dp, + var, + None, + argerr + ) + + return var._get_value(dynamic=True) # NOQA def Invoke(self, dispid, *args, **kw): # type: (int, Any, Any) -> Any @@ -818,8 +925,9 @@ def Invoke(self, dispid, *args, **kw): # The *CALLING* code is responsible for releasing all strings and # 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 + # For comtypes this is handled in DISPPARAMS.__del__ and + # VARIANT.__del__. + _invkind = kw.pop("_invkind", 1) # DISPATCH_METHOD _lcid = kw.pop("_lcid", 0) if kw: raise ValueError("named parameters not yet implemented") @@ -827,39 +935,52 @@ def Invoke(self, dispid, *args, **kw): result = VARIANT() excepinfo = EXCEPINFO() argerr = c_uint() - - if _invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): # propput - array = (VARIANT * len(args))() + # propput + if _invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): + arry = (VARIANT * len(args))() for i, a in enumerate(args[::-1]): - array[i].value = a + arry[i].value = a dp = DISPPARAMS() dp.cArgs = len(args) dp.cNamedArgs = 1 - dp.rgvarg = array + dp.rgvarg = arry dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT)) else: - array = (VARIANT * len(args))() + arry = (VARIANT * len(args))() for i, a in enumerate(args[::-1]): - array[i].value = a + arry[i].value = a dp = DISPPARAMS() dp.cArgs = len(args) dp.cNamedArgs = 0 - dp.rgvarg = array + dp.rgvarg = arry 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 # when you try to set a property and you have not @@ -873,13 +994,17 @@ 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) - # XXX Would separate methods for _METHOD, _PROPERTYGET and _PROPERTYPUT be better? + return result._get_value(dynamic=True) # NOQA + + # XXX Would separate methods for _METHOD, _PROPERTYGET + # and _PROPERTYPUT be better? ################################################################ @@ -936,25 +1061,26 @@ 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, + # POINTER(IUnknown): VT_UNKNOWN, + # POINTER(IDispatch): VT_DISPATCH, } + _vartype_to_ctype = {} for c, v in _ctype_to_vartype.items(): _vartype_to_ctype[v] = c -_vartype_to_ctype[VT_INT] = _vartype_to_ctype[VT_I4] + +_vartype_to_ctype[VT_INT] = _vartype_to_ctype[VT_I4] # NOQA _vartype_to_ctype[VT_UINT] = _vartype_to_ctype[VT_UI4] _ctype_to_vartype[c_char] = VT_UI1 - try: from comtypes.safearray import _midlSAFEARRAY except (ImportError, AttributeError): @@ -970,7 +1096,7 @@ def Invoke(self, dispid, *args, **kw): 'EXCEPINFO', 'tagEXCEPINFO', 'IDispatch', 'IEnumVARIANT', 'IID_NULL', 'INVOKE_FUNC', 'INVOKE_PROPERTYGET', 'INVOKE_PROPERTYPUT', 'INVOKE_PROPERTYPUTREF', 'INVOKEKIND', 'tagINVOKEKIND', '_midlSAFEARRAY', - 'SCODE', '_SysAllocStringLen', 'VARENUM', 'VARIANT','tagVARIANT', + 'SCODE', '_SysAllocStringLen', 'VARENUM', 'VARIANT', 'tagVARIANT', 'VARIANTARG', '_VariantChangeType', '_VariantClear', '_VariantCopy', '_VariantCopyInd', 'VARTYPE', 'VT_ARRAY', 'VT_BLOB', 'VT_BLOB_OBJECT', 'VT_BOOL', 'VT_BSTR', 'VT_BSTR_BLOB', 'VT_BYREF', 'VT_CARRAY', 'VT_CF', diff --git a/comtypes/client/__init__.py b/comtypes/client/__init__.py index ea1cc57d..d0359734 100644 --- a/comtypes/client/__init__.py +++ b/comtypes/client/__init__.py @@ -1,5 +1,5 @@ -'''comtypes.client - High level client level COM support package. -''' +"""comtypes.client - High level client level COM support package.""" + ################################################################ # @@ -15,6 +15,9 @@ import sys import comtypes +from comtypes.hresult import * # NOQA +import comtypes.automation +import comtypes.typeinfo from comtypes.hresult import * from comtypes import ( automation, CoClass, GUID, IUnknown, TYPE_CHECKING, typeinfo, @@ -26,9 +29,14 @@ from comtypes.client._code_cache import _find_gen_dir gen_dir = _find_gen_dir() -import comtypes.gen -### for testing -##gen_dir = None + +# for testing +# gen_dir = None +import comtypes.gen # NOQA + + +# for testing +# gen_dir = None if TYPE_CHECKING: from typing import Any, Optional, overload, Type, TypeVar, Union as _UnionT @@ -50,7 +58,8 @@ def wrap_outparam(punk): def GetBestInterface(punk): # type: (Any) -> Any - """Try to QueryInterface a COM pointer to the 'most useful' + """ + Try to QueryInterface a COM pointer to the 'most useful' interface. Get type information for the provided object, either via @@ -58,23 +67,31 @@ 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: try: pci = punk.QueryInterface(typeinfo.IProvideClassInfo) logger.debug("Does implement IProvideClassInfo") except comtypes.COMError: - # Some COM objects support IProvideClassInfo2, but not IProvideClassInfo. + # 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): if tinfo.GetImplTypeFlags(index) == 1: break @@ -82,11 +99,14 @@ def GetBestInterface(punk): if ta.cImplTypes != 1: # Hm, should we use dynamic now? raise TypeError("No default interface found") + # Only one interface implemented, use that (even if # not marked as default). index = 0 + href = tinfo.GetRefTypeOfImplType(index) tinfo = tinfo.GetRefTypeInfo(href) + except comtypes.COMError: logger.debug("Does NOT implement IProvideClassInfo/IProvideClassInfo2") try: @@ -94,28 +114,33 @@ def GetBestInterface(punk): except comtypes.COMError: logger.debug("No Dispatch interface: %s", punk) return punk + try: tinfo = pdisp.GetTypeInfo(0) except comtypes.COMError: pdisp = comtypes.client.dynamic.Dispatch(pdisp) logger.debug("IDispatch.GetTypeInfo(0) failed: %s" % pdisp) return pdisp + typeattr = tinfo.GetTypeAttr() logger.debug("Default interface is %s", typeattr.guid) try: punk.QueryInterface(comtypes.IUnknown, typeattr.guid) except comtypes.COMError: - logger.debug("Does not implement default interface, returning dynamic object") + 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) # Python interface class interface = getattr(mod, itf_name) logger.debug("Implements default interface from typeinfo %s", interface) + # QI for this interface # XXX # What to do if this fails? @@ -131,11 +156,15 @@ def GetBestInterface(punk): result = punk.QueryInterface(interface) logger.debug("Final result is %s", result) return result + + # backwards compatibility: wrap = GetBestInterface # Should we do this for POINTER(IUnknown) also? -ctypes.POINTER(automation.IDispatch).__ctypes_from_outparam__ = wrap_outparam # type: ignore +ctypes.POINTER(automation.IDispatch).__ctypes_from_outparam__ = ( # NOQA + wrap_outparam +) # type: ignore ################################################################ # @@ -146,13 +175,17 @@ def GetBestInterface(punk): 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): + + +def GetActiveObject(progid, interface=None, dynamic=False): # NOQA # type: (_UnionT[str, CoClass, GUID], Optional[Any], bool) -> Any - """Return a pointer to a running COM object that has been + """ + Return a pointer to a running COM object that has been registered with COM. 'progid' may be a string like "Excel.Application", @@ -168,9 +201,11 @@ def GetActiveObject(progid, interface=None, dynamic=False): interface = automation.IDispatch elif interface is None: interface = getattr(progid, "_com_interfaces_", [None])[0] + obj = comtypes.GetActiveObject(clsid, interface=interface) if dynamic: return comtypes.client.dynamic.Dispatch(obj) + return _manage(obj, clsid, interface=interface) @@ -187,20 +222,27 @@ def _manage(obj, clsid, interface): 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. + """ + Create and return the class factory for a COM object. 'clsctx' specifies how to create the object, use the CLSCTX_... constants. - 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO instance - 'interface' may be used to request an interface other than IClassFactory + 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO + instance 'interface' may be used to request an interface other than + IClassFactory """ clsid = GUID.from_progid(progid) return comtypes.CoGetClassObject(clsid, clsctx, pServerInfo, interface) @@ -211,18 +253,31 @@ def GetClassObject(progid, 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 # NOQA + 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() + """ + Create a COM object from 'progid', and try to QueryInterface() it to the most useful interface, generating typelib support on demand. A pointer to this interface is returned. @@ -233,8 +288,8 @@ def CreateObject(progid, # which object to create 'machine' allows to specify a remote machine to create the object on. 'interface' allows to force a certain interface 'dynamic=True' will return a dynamic dispatch object - 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO instance - This supercedes 'machine'. + 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO + instance This supercedes 'machine'. You can also later request to receive events with GetEvents(). """ @@ -243,24 +298,49 @@ def CreateObject(progid, # which object to create if dynamic: if interface: raise ValueError("interface and dynamic are mutually exclusive") + interface = automation.IDispatch 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) - obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=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,\ - pServerInfo=%s)", - clsid, clsctx, interface, machine, pServerInfo) + logger.debug( + "CoCreateInstanceEx(%s, clsctx=%s, " + "interface=%s, machine=%s, pServerInfo=%s)", + 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) @@ -269,26 +349,31 @@ def CreateObject(progid, # which object to create 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): + + +def CoGetObject(displayname, interface=None, dynamic=False): # NOQA # type: (str, Optional[Type[comtypes.IUnknown]], bool) -> Any - """Create an object by calling CoGetObject(displayname). + """ + Create an object by calling CoGetObject(displayname). Additional parameters have the same meaning as in CreateObject(). """ if dynamic: if interface is not None: raise ValueError("interface and dynamic are mutually exclusive") + interface = automation.IDispatch + 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) __all__ = [ diff --git a/comtypes/client/_code_cache.py b/comtypes/client/_code_cache.py index 7202bf29..4797528e 100644 --- a/comtypes/client/_code_cache.py +++ b/comtypes/client/_code_cache.py @@ -1,11 +1,19 @@ -"""comtypes.client._code_cache helper module. +""" +comtypes.client._code_cache helper module. The main function is _find_gen_dir(), which on-demand creates the comtypes.gen package and returns a directory where generated code can be written to. """ -import ctypes, logging, os, sys, tempfile, types +import ctypes +import logging +import os +import sys +import tempfile +import types from ctypes import wintypes + + logger = logging.getLogger(__name__) @@ -21,7 +29,8 @@ def _ensure_list(path): def _find_gen_dir(): - """Create, if needed, and return a directory where automatically + r""" + Create, if needed, and return a directory where automatically generated modules will be created. Usually, this is the directory 'Lib/site-packages/comtypes/gen'. @@ -39,26 +48,30 @@ def _find_gen_dir(): '%TEMP%\comtypes_cache\-25'. """ _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 # where generated modules are placed. ftype = getattr(sys, "frozen", None) version_str = "%d%d" % sys.version_info[:2] - if ftype == None: + + if ftype is None: # Python script subdir = r"Python\Python%s\comtypes_cache" % version_str basedir = _get_appdata_dir() elif ftype == "dll": # dll created with py2exe - path = _get_module_filename(sys.frozendllhandle) + path = _get_module_filename(sys.frozendllhandle) # NOQA base = os.path.splitext(os.path.basename(path))[0] 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) @@ -66,70 +79,111 @@ def _find_gen_dir(): gen_dir = os.path.join(basedir, subdir) if not os.path.exists(gen_dir): - logger.info("Creating writeable comtypes cache directory: '%s'", gen_dir) + logger.info( + "Creating writeable comtypes cache directory: '%s'", + gen_dir + ) + os.makedirs(gen_dir) + gen_path.append(gen_dir) + result = os.path.abspath(gen_path[-1]) 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] +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")) + comtypes_path = os.path.abspath( + os.path.join(comtypes.__path__[0], "gen") + ) + if not os.path.isdir(comtypes_path): os.mkdir(comtypes_path) - logger.info("Created comtypes.gen directory: '%s'", comtypes_path) + logger.info( + "Created comtypes.gen directory: '%s'", + comtypes_path + ) + comtypes_init = os.path.join(comtypes_path, "__init__.py") + if not os.path.exists(comtypes_init): logger.info("Writing __init__.py file: '%s'", comtypes_init) ofi = open(comtypes_init, "w") - ofi.write("# comtypes.gen package, directory for generated files.\n") + ofi.write( + "# comtypes.gen package, directory for generated files.\n" + ) ofi.close() except (OSError, IOError) as details: logger.info("Creating comtypes.gen package failed: %s", details) - module = sys.modules["comtypes.gen"] = types.ModuleType("comtypes.gen") + module = sys.modules["comtypes.gen"] = ( + types.ModuleType("comtypes.gen") + ) comtypes.gen = module 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.""" + """ + Check if the first part, if any, on path is a directory in + which we can create files. + """ if not path: return False + # 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.""" + """ + Call the Windows GetModuleFileName function which determines + the path from a module handle. + """ path = ctypes.create_unicode_buffer(MAX_PATH) if GetModuleFileName(hmodule, path, MAX_PATH): 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""" + """ + Return the 'file system directory that serves as a common + repository for application-specific data' - CSIDL_APPDATA + """ path = ctypes.create_unicode_buffer(MAX_PATH) # get u'C:\\Documents and Settings\\\\Application Data' SHGetSpecialFolderPath(0, path, CSIDL_APPDATA, True) diff --git a/comtypes/client/_constants.py b/comtypes/client/_constants.py index 554b9c45..86534d20 100644 --- a/comtypes/client/_constants.py +++ b/comtypes/client/_constants.py @@ -10,10 +10,11 @@ import comtypes.automation import comtypes.typeinfo + if sys.version_info >= (3, 0): base_text_type = str else: - base_text_type = basestring + base_text_type = basestring # NOQA class _frozen_attr_dict(dict): @@ -54,7 +55,8 @@ class Constants(object): as attributes. Examples: - >>> c = Constants('scrrun.dll') # load `Scripting` consts, enums, and alias + >>> # load `Scripting` consts, enums, and alias + >>> c = Constants('scrrun.dll') >>> c.IOMode.ForReading # returns enumeration member value 1 >>> c.ForReading # returns constant value @@ -82,6 +84,7 @@ def __init__(self, obj): else: obj = obj.QueryInterface(comtypes.automation.IDispatch) tlib, index = obj.GetTypeInfo(0).GetContainingTypeLib() + consts, enums, alias = self._get_bound_namespaces(tlib) self.consts = _frozen_attr_dict(consts) self.enums = _frozen_attr_dict(enums) @@ -93,26 +96,34 @@ def _get_bound_namespaces(self, tlib): for i in range(tlib.GetTypeInfoCount()): tinfo = tlib.GetTypeInfo(i) ta = tinfo.GetTypeAttr() + if ta.typekind == comtypes.typeinfo.TKIND_ALIAS: alias.update(self._get_ref_names(tinfo, ta)) + members = self._get_members(tinfo, ta) + if ta.typekind == comtypes.typeinfo.TKIND_ENUM: enums[tinfo.GetDocumentation(-1)[0]] = members + consts.update(members) + return consts, enums, alias - def _get_ref_names(self, tinfo, ta): + def _get_ref_names(self, tinfo, ta): # NOQA try: - refinfo = tinfo.GetRefTypeInfo(ta.tdescAlias._.hreftype) + refinfo = tinfo.GetRefTypeInfo(ta.tdescAlias._.hreftype) # NOQA except comtypes.COMError: return {} + if refinfo.GetTypeAttr().typekind != comtypes.typeinfo.TKIND_ENUM: return {} + friendly_name = tinfo.GetDocumentation(-1)[0] real_name = refinfo.GetDocumentation(-1)[0] + return {friendly_name: real_name} - def _get_members(self, tinfo, ta): + def _get_members(self, tinfo, ta): # NOQA members = {} for i in range(ta.cVars): vdesc = tinfo.GetVarDesc(i) @@ -124,7 +135,9 @@ def _get_members(self, tinfo, ta): # if comtypes.tools.__warn_on_munge__: # print("# Fixing keyword as VAR_CONST for %s" % name) name += "_" - members[name] = vdesc._.lpvarValue[0].value + + members[name] = vdesc._.lpvarValue[0].value # NOQA + return _frozen_attr_dict(members) def __getattr__(self, name): diff --git a/comtypes/client/_events.py b/comtypes/client/_events.py index 23aa92d4..18ab863e 100644 --- a/comtypes/client/_events.py +++ b/comtypes/client/_events.py @@ -8,8 +8,11 @@ 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 @@ -18,8 +21,10 @@ def __init__(self, source, interface, receiver): self._connect(source, interface, receiver) def _connect(self, source, interface, receiver): - cpc = source.QueryInterface(comtypes.connectionpoints.IConnectionPointContainer) - self.cp = cpc.FindConnectionPoint(ctypes.byref(interface._iid_)) + cpc = source.QueryInterface( + comtypes.connectionpoints.IConnectionPointContainer + ) + self.cp = cpc.FindConnectionPoint(ctypes.byref(interface._iid_)) # NOQA logger.debug("Start advise %s", interface) self.cookie = self.cp.Advise(receiver) self.receiver = receiver @@ -40,6 +45,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 @@ -58,6 +64,7 @@ def FindOutgoingInterface(source): tlib, index = tinfo.GetContainingTypeLib() GetModule(tlib) interface = comtypes.com_interface_registry[str(guid)] + logger.debug("%s using sinkinterface %s", source, interface) return interface @@ -66,24 +73,29 @@ def FindOutgoingInterface(source): # comtypes.client): clsid = source.__dict__.get('__clsid') try: - interface = comtypes.com_coclass_registry[clsid]._outgoing_interfaces_[0] + interface = ( + comtypes.com_coclass_registry[clsid]._outgoing_interfaces_[0] # NOQA + ) except KeyError: pass else: logger.debug("%s using sinkinterface from clsid %s", source, interface) return interface -## interface = find_single_connection_interface(source) -## if interface: -## return interface + # interface = find_single_connection_interface(source) + # if interface: + # return interface 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 # determine which one to use. - cpc = source.QueryInterface(comtypes.connectionpoints.IConnectionPointContainer) + cpc = source.QueryInterface( + comtypes.connectionpoints.IConnectionPointContainer + ) enum = cpc.EnumConnectionPoints() iid = enum.next().GetConnectionInterface() try: @@ -94,13 +106,18 @@ def find_single_connection_interface(source): except KeyError: return None else: - logger.debug("%s using sinkinterface from iid %s", source, interface) + logger.debug( + "%s using sinkinterface from iid %s", + source, + interface + ) return interface else: logger.debug("%s has more than one connection point", 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' @@ -109,19 +126,22 @@ def report_errors(func): def error_printer(self, this, *args, **kw): try: return func(self, this, *args, **kw) - except: + except: # NOQA traceback.print_exc() raise else: def error_printer(*args, **kw): try: return func(*args, **kw) - except: + except: # NOQA traceback.print_exc() raise return error_printer -from comtypes._comobject import _MethodFinder + +from comtypes._comobject import _MethodFinder # NOQA + + class _SinkMethodFinder(_MethodFinder): """Special MethodFinder, for finding and decorating event handler methods. Looks for methods on two objects. Also decorates the @@ -143,9 +163,11 @@ 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,6 +180,7 @@ def _find_method(self, fq_name, mthname): except AttributeError: return getattr(self.sink, mthname) + def CreateEventReceiver(interface, handler): class Sink(comtypes.COMObject): @@ -172,11 +195,13 @@ 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_"): - finder = sink._get_method_finder_(interface) + if ( + issubclass(interface, comtypes.automation.IDispatch) and + not hasattr(sink, "_dispimpl_") + ): + finder = sink._get_method_finder_(interface) # NOQA dispimpl = sink._dispimpl_ = {} - for m in interface._methods_: + for m in interface._methods_: # NOQA restype, mthname, argtypes, paramflags, idlflags, helptext = m # Can dispid be at a different index? Should check code generator... # ...but hand-written code should also work... @@ -188,6 +213,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,35 +228,48 @@ def GetEvents(source, sink, interface=None): rcv = CreateEventReceiver(interface, sink) return _AdviseConnection(source, interface, rcv) + class EventDumper(object): """Universal sink for COM events.""" def __getattr__(self, name): - "Create event handler methods on demand" + """Create event handler methods on demand""" 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? + + def handler(self, this, *args, **kw): # NOQA + # 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 + """ + Receive COM events from 'source'. A special event sink will be used that first prints the names of events that are found in the outgoing interface, and will also print out the events when they are fired. """ - return comtypes.client.GetEvents(source, sink=EventDumper(), interface=interface) + 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 + """ + This following code waits for 'timeout' seconds in the way required for COM, internally doing the correct things depending on the COM appartment of the current thread. It is possible to terminate the message loop by pressing CTRL+C, which will raise @@ -260,24 +299,30 @@ def PumpEvents(timeout): handles = _handles_type(hevt) RPC_S_CALLPENDING = -2147417835 -## @ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint) +# @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) + + 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())) + 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..73e7179a 100644 --- a/comtypes/client/_generate.py +++ b/comtypes/client/_generate.py @@ -5,17 +5,21 @@ import os import sys import types + + if sys.version_info >= (3, 0): base_text_type = str import winreg else: - base_text_type = basestring - import _winreg as winreg + base_text_type = basestring # NOQA + import _winreg as winreg # NOQA + from comtypes import GUID, TYPE_CHECKING, typeinfo import comtypes.client from comtypes.tools import codegenerator, tlbparser + if TYPE_CHECKING: from typing import Any, Tuple, List, Optional, Dict, Union as _UnionT @@ -29,14 +33,17 @@ 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) def _resolve_filename(tlib_string, dirpath): # type: (str, str) -> Tuple[str, bool] - """Tries to make sense of a type library specified as a string. + """ + Tries to make sense of a type library specified as a string. Args: tlib_string: type library designator @@ -55,10 +62,12 @@ def _resolve_filename(tlib_string, dirpath): abspath = os.path.normpath(os.path.join(dirpath, tlib_string)) if os.path.exists(abspath): return abspath, True + # try with respect to cwd (if _getmodule executed from command line) abspath = os.path.abspath(tlib_string) if os.path.exists(abspath): return abspath, True + # Otherwise it may still be that the file is on Windows search # path for typelibs, and we leave the pathname alone. return tlib_string, False @@ -66,7 +75,8 @@ def _resolve_filename(tlib_string, dirpath): def GetModule(tlib): # type: (_UnionT[Any, typeinfo.ITypeLib]) -> types.ModuleType - """Create a module wrapping a COM typelibrary on demand. + """ + Create a module wrapping a COM typelibrary on demand. 'tlib' must be ... - an `ITypeLib` COM pointer instance @@ -111,31 +121,42 @@ def GetModule(tlib): tlib_string = tlib # if a relative pathname is used, we try to interpret it relative to # the directory of the calling module (if not from command line) - frame = sys._getframe(1) + frame = sys._getframe(1) # NOQA _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: - # try to get path after loading, but this only works if already registered + # try to get path after loading, but + # this only works if already registered pathname = tlbparser.get_tlib_filename(tlib) if pathname is None: - logger.info("GetModule(%s): could not resolve to a filename", 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)! + # 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) else: pathname = None tlib = _load_tlib(tlib) + logger.debug("GetModule(%s)", tlib.GetLibAttr()) # create and import the real typelib wrapper module mod = _create_wrapper_module(tlib, pathname) - # try to get the friendly-name, if not, returns the real typelib wrapper module + # try to get the friendly-name, if not, + # returns the real typelib wrapper module modulename = codegenerator.name_friendly_module(tlib) if modulename is None: return mod + if sys.version_info < (3, 0): modulename = modulename.encode("mbcs") + # create and import the friendly-named module return _create_friendly_module(tlib, modulename) @@ -145,31 +166,51 @@ def _load_tlib(obj): """Load a pointer of ITypeLib on demand.""" # obj is a filepath or a ProgID if isinstance(obj, base_text_type): - # in any case, attempt to load and if tlib_string is not valid, then raise + # in any case, attempt to load and if + # tlib_string is not valid, then raise # as "OSError: [WinError -2147312566] Error loading type library/DLL" return typeinfo.LoadTypeLibEx(obj) + # obj is a tlib GUID contain a clsid 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 elif isinstance(obj, (tuple, list)): libid, ver = obj[0], obj[1:] if not ver: # case of version numbers are not containing - with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"TypeLib\%s" % libid) as key: - ver = [int(v, base=16) for v in winreg.EnumKey(key, 0).split(".")] + with winreg.OpenKey( + winreg.HKEY_CLASSES_ROOT, r"TypeLib\%s" % libid + ) as key: + ver = [ + int(v, base=16) for v in winreg.EnumKey(key, 0).split(".") + ] + return typeinfo.LoadRegTypeLib(GUID(libid), *ver) + # obj is a COMObject implementation elif hasattr(obj, "_reg_libid_"): - return typeinfo.LoadRegTypeLib(GUID(obj._reg_libid_), *obj._reg_version_) + return typeinfo.LoadRegTypeLib( + GUID(obj._reg_libid_), # NOQA + *obj._reg_version_ # NOQA + ) + # obj is a pointer of ITypeLib elif isinstance(obj, ctypes.POINTER(typeinfo.ITypeLib)): return obj # type: ignore + raise TypeError("'%r' is not supported type for loading typelib" % obj) @@ -180,9 +221,11 @@ def _create_module_in_file(modulename, code): filename = "%s.py" % modulename.split(".")[-1] with open(os.path.join(comtypes.client.gen_dir, filename), "w") as ofi: print(code, file=ofi) + # clear the import cache to make sure Python sees newly created modules if hasattr(importlib, "invalidate_caches"): importlib.invalidate_caches() + return _my_import(modulename) @@ -191,6 +234,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, "") @@ -209,6 +253,7 @@ def _create_friendly_module(tlib, modulename): logger.info("Could not import %s: %s", modulename, details) else: return mod + # the module is always regenerated if the import fails logger.info("# Generating %s", modulename) # determine the Python module name @@ -218,6 +263,7 @@ def _create_friendly_module(tlib, modulename): code += "__name__ = '%s'" % modulename if comtypes.client.gen_dir is None: return _create_module_in_memory(modulename, code) + return _create_module_in_file(modulename, code) @@ -231,18 +277,23 @@ def _create_wrapper_module(tlib, pathname): return _my_import(modulename) except Exception as details: logger.info("Could not import %s: %s", modulename, details) + # generate the module since it doesn't exist or is out of date logger.info("# Generating %s", modulename) p = tlbparser.TypeLibParser(tlib) if pathname is None: pathname = tlbparser.get_tlib_filename(tlib) + items = list(p.parse().values()) codegen = codegenerator.CodeGenerator(_get_known_symbols()) code = codegen.generate_code(items, filename=pathname) + for ext_tlib in codegen.externals: # generates dependency COM-lib modules GetModule(ext_tlib) + if comtypes.client.gen_dir is None: return _create_module_in_memory(modulename, code) + return _create_module_in_file(modulename, code) @@ -262,12 +313,14 @@ def _get_known_symbols(): names = mod.__known_symbols__ # type: List[str] else: names = list(mod.__dict__) + for name in names: known_symbols[name] = mod.__name__ + return known_symbols -################################################################ +################################################################ if __name__ == "__main__": # When started as script, generate typelib wrapper from .tlb file. diff --git a/comtypes/client/dynamic.py b/comtypes/client/dynamic.py index 52e1ac45..0fc7065d 100644 --- a/comtypes/client/dynamic.py +++ b/comtypes/client/dynamic.py @@ -5,7 +5,7 @@ import comtypes.client import comtypes.client.lazybind -from comtypes import COMError, IUnknown, _is_object +from comtypes import COMError, IUnknown, _is_object # NOQA import comtypes.hresult as hres # These errors generally mean the property or method exists, @@ -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. @@ -40,35 +42,44 @@ def __init__(self, _id, _obj): self._obj = _obj def __call__(self, *args): - return self._obj._comobj.Invoke(self._id, *args) + return self._obj._comobj.Invoke(self._id, *args) # NOQA def __getitem__(self, *args): - return self._obj._comobj.Invoke(self._id, *args, - **dict(_invkind=comtypes.automation.DISPATCH_PROPERTYGET)) + return self._obj._comobj.Invoke( # NOQA + 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( # NOQA + 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( # NOQA + 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 + # Tiny optimization: trying not to use GetIDsOfNames more than once + self.__dict__["_ids"] = {} 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): if not isinstance(other, _Dispatch): return 1 - return cmp(self._comobj, other._comobj) + + return cmp(self._comobj, other._comobj) # NOQA def __hash__(self): return hash(self._comobj) @@ -78,17 +89,20 @@ def __getitem__(self, index): if index > 0: if 0 != enum.Skip(index): raise IndexError("index out of range") + item, fetched = enum.Next(1) if not fetched: raise IndexError("index out of range") + return item def QueryInterface(self, *args): - "QueryInterface is forwarded to the real com object." + """QueryInterface is forwarded to the real com object.""" return self._comobj.QueryInterface(*args) def _FlagAsMethod(self, *names): - """Flag these attribute names as being methods. + """ + Flag these attribute names as being methods. Some objects do not correctly differentiate methods and properties, leading to problems when calling these methods. @@ -104,8 +118,11 @@ def _FlagAsMethod(self, *names): def __getattr__(self, name): if name.startswith("__") and name.endswith("__"): raise AttributeError(name) -## tc = self._comobj.GetTypeInfo(0).QueryInterface(comtypes.typeinfo.ITypeComp) -## dispid = tc.Bind(name)[1].memid + # tc = self._comobj.GetTypeInfo(0).QueryInterface( + # comtypes.typeinfo.ITypeComp + # ) + # dispid = tc.Bind(name)[1].memid + dispid = self._ids.get(name) if not dispid: dispid = self._comobj.GetIDsOfNames(name)[0] @@ -127,7 +144,7 @@ def __getattr__(self, name): else: # The line break is important for 2to3 to work correctly raise - except: + except: # NOQA # The line break is important for 2to3 to work correctly raise @@ -138,6 +155,7 @@ def __setattr__(self, name, value): if not dispid: dispid = self._comobj.GetIDsOfNames(name)[0] self._ids[name] = dispid + # Detect whether to use DISPATCH_PROPERTYPUT or # DISPATCH_PROPERTYPUTREF flags = 8 if _is_object(value) else 4 @@ -146,9 +164,12 @@ def __setattr__(self, name, value): def __iter__(self): return _Collection(self.__enum()) -## def __setitem__(self, index, value): -## self._comobj.Invoke(-3, index, value, -## _invkind=comtypes.automation.DISPATCH_PROPERTYPUT|comtypes.automation.DISPATCH_PROPERTYPUTREF) + # def __setitem__(self, index, value): + # self._comobj.Invoke(-3, index, value, + # _invkind=comtypes.automation.DISPATCH_PROPERTYPUT| + # comtypes.automation.DISPATCH_PROPERTYPUTREF + # ) + class _Collection(object): def __init__(self, enum): @@ -170,4 +191,5 @@ def next(self): def __iter__(self): return self + __all__ = ["Dispatch"] diff --git a/comtypes/client/lazybind.py b/comtypes/client/lazybind.py index 4705e4a7..2a7c1146 100644 --- a/comtypes/client/lazybind.py +++ b/comtypes/client/lazybind.py @@ -1,25 +1,28 @@ import comtypes import comtypes.automation -from comtypes.automation import IEnumVARIANT -from comtypes.automation import DISPATCH_METHOD -from comtypes.automation import DISPATCH_PROPERTYGET -from comtypes.automation import DISPATCH_PROPERTYPUT -from comtypes.automation import DISPATCH_PROPERTYPUTREF - -from comtypes.automation import DISPID_VALUE -from comtypes.automation import DISPID_NEWENUM +from comtypes.automation import ( + IEnumVARIANT, + DISPATCH_METHOD, + DISPATCH_PROPERTYGET, + DISPATCH_PROPERTYPUT, + DISPATCH_PROPERTYPUTREF, + DISPID_VALUE, + DISPID_NEWENUM +) from comtypes.typeinfo import FUNC_PUREVIRTUAL, FUNC_DISPATCH class FuncDesc(object): - """Stores important FUNCDESC properties by copying them from a + """ + 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,54 +41,71 @@ 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( # NOQA + 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( # NOQA + self.get.memid, + self.get.invkind, + 0 + ) + return self.disp._comobj._invoke( # NOQA + 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( # NOQA + self.get.memid, + self.get.invkind, + 0, + *args + ) def __setitem__(self, name, value): # See discussion in Dispatch.__setattr__ below. if self.put is None and self.putref is None: raise TypeError("object does not support item assignment") - if comtypes._is_object(value): + + if comtypes._is_object(value): # NOQA descr = self.putref or self.put 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( # NOQA + 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( # NOQA + descr.memid, + descr.invkind, + 0, + value + ) else: - self.disp._comobj._invoke(descr.memid, - descr.invkind, - 0, - name, - value) + self.disp._comobj._invoke( # NOQA + 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) @@ -103,7 +123,8 @@ def __iter__(self): # objects do not (could be added, would probably be expensive) class Dispatch(object): - """Dynamic dispatch for an object the exposes type information. + """ + Dynamic dispatch for an object the exposes type information. Binding at runtime is done via ITypeComp::Bind calls. """ def __init__(self, comobj, tinfo): @@ -111,11 +132,13 @@ def __init__(self, comobj, tinfo): self.__dict__["_tinfo"] = tinfo self.__dict__["_tcomp"] = tinfo.GetTypeComp() self.__dict__["_tdesc"] = {} -## self.__dict__["_iid"] = tinfo.GetTypeAttr().guid + # self.__dict__["_iid"] = tinfo.GetTypeAttr().guid def __bind(self, name, invkind): - """Bind (name, invkind) and return a FuncDesc instance or - None. Results (even unsuccessful ones) are cached.""" + """ + Bind (name, invkind) and return a FuncDesc instance or + None. Results (even unsuccessful ones) are cached. + """ # We could cache the info in the class instead of the # instance, but we would need an additional key for that: # self._iid @@ -130,25 +153,29 @@ 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 def QueryInterface(self, *args): - "QueryInterface is forwarded to the real com object." + """QueryInterface is forwarded to the real com object.""" return self._comobj.QueryInterface(*args) def __cmp__(self, other): if not isinstance(other, Dispatch): return 1 - return cmp(self._comobj, other._comobj) + return cmp(self._comobj, other._comobj) # NOQA def __eq__(self, other): - return isinstance(other, Dispatch) and \ - self._comobj == other._comobj + return ( + isinstance(other, Dispatch) and + self._comobj == other._comobj # NOQA + ) def __hash__(self): return hash(self._comobj) @@ -157,29 +184,47 @@ def __getattr__(self, name): """Get a COM attribute.""" if name.startswith("__") and name.endswith("__"): raise AttributeError(name) + # check for propget or method descr = self.__bind(name, DISPATCH_METHOD | DISPATCH_PROPERTYGET) if descr is None: raise AttributeError(name) + if descr.invkind == DISPATCH_PROPERTYGET: # DISPATCH_PROPERTYGET if descr.funckind == FUNC_DISPATCH: if descr.cParams == 0: - return self._comobj._invoke(descr.memid, descr.invkind, 0) + return self._comobj._invoke( # NOQA + descr.memid, + descr.invkind, + 0 + ) elif descr.funckind == FUNC_PUREVIRTUAL: # FUNC_PUREVIRTUAL descriptions contain the property # itself as a parameter. if descr.cParams == 1: - return self._comobj._invoke(descr.memid, descr.invkind, 0) + return self._comobj._invoke( # NOQA + descr.memid, + descr.invkind, + 0 + ) else: - raise RuntimeError("funckind %d not yet implemented" % descr.funckind) + raise RuntimeError( + "funckind %d not yet implemented" % descr.funckind + ) + put = self.__bind(name, DISPATCH_PROPERTYPUT) putref = self.__bind(name, DISPATCH_PROPERTYPUTREF) return NamedProperty(self, descr, put, putref) else: # DISPATCH_METHOD def caller(*args): - return self._comobj._invoke(descr.memid, descr.invkind, 0, *args) + return self._comobj._invoke( # NOQA + descr.memid, + descr.invkind, + 0, + *args + ) try: caller.__name__ = name except TypeError: @@ -210,20 +255,28 @@ def __setattr__(self, name, value): putref = self.__bind(name, DISPATCH_PROPERTYPUTREF) if not put and not putref: raise AttributeError(name) - if comtypes._is_object(value): + + if comtypes._is_object(value): # NOQA descr = putref or put else: descr = put or putref if descr.cParams == 1: - self._comobj._invoke(descr.memid, descr.invkind, 0, value) + self._comobj._invoke( # NOQA + descr.memid, + descr.invkind, + 0, + value + ) return raise AttributeError(name) def __call__(self, *args): - return self._comobj._invoke(DISPID_VALUE, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0, - *args) + return self._comobj._invoke( # NOQA + DISPID_VALUE, + DISPATCH_METHOD | DISPATCH_PROPERTYGET, + 0, + *args + ) def __getitem__(self, arg): if isinstance(arg, tuple): @@ -234,15 +287,17 @@ def __getitem__(self, arg): args = (arg,) try: - return self._comobj._invoke(DISPID_VALUE, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0, - *args) + return self._comobj._invoke( # NOQA + DISPID_VALUE, + DISPATCH_METHOD | DISPATCH_PROPERTYGET, + 0, + *args + ) except comtypes.COMError: - return iter(self)[arg] + return list(iter(self))[arg] def __setitem__(self, name, value): - if comtypes._is_object(value): + if comtypes._is_object(value): # NOQA invkind = DISPATCH_PROPERTYPUTREF else: invkind = DISPATCH_PROPERTYPUT @@ -253,15 +308,19 @@ def __setitem__(self, name, value): args = (value,) else: args = (name, value) - return self._comobj._invoke(DISPID_VALUE, - invkind, - 0, - *args) + return self._comobj._invoke( # NOQA + DISPID_VALUE, + invkind, + 0, + *args + ) def __iter__(self): - punk = self._comobj._invoke(DISPID_NEWENUM, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - 0) + punk = self._comobj._invoke( # NOQA + 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..b4bc3c2e 100644 --- a/comtypes/connectionpoints.py +++ b/comtypes/connectionpoints.py @@ -1,25 +1,31 @@ import sys from ctypes import * -from comtypes import IUnknown, COMMETHOD, GUID, HRESULT, dispid +from comtypes import IUnknown, COMMETHOD, GUID, HRESULT _GUID = GUID + class tagCONNECTDATA(Structure): _fields_ = [ ('pUnk', POINTER(IUnknown)), ('dwCookie', c_ulong), ] + + CONNECTDATA = tagCONNECTDATA + ################################################################ class IConnectionPointContainer(IUnknown): _iid_ = GUID('{B196B284-BAB4-101A-B69C-00AA00341D07}') _idlflags_ = [] + class IConnectionPoint(IUnknown): _iid_ = GUID('{B196B286-BAB4-101A-B69C-00AA00341D07}') _idlflags_ = [] + class IEnumConnections(IUnknown): _iid_ = GUID('{B196B287-BAB4-101A-B69C-00AA00341D07}') _idlflags_ = [] @@ -40,6 +46,7 @@ def next(self): raise StopIteration return cp + class IEnumConnectionPoints(IUnknown): _iid_ = GUID('{B196B285-BAB4-101A-B69C-00AA00341D07}') _idlflags_ = [] @@ -60,50 +67,77 @@ def next(self): 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, '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, '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, '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, 'Clone', + (['out'], POINTER(POINTER(IEnumConnectionPoints)), 'ppEnum') + ), ] diff --git a/comtypes/errorinfo.py b/comtypes/errorinfo.py index 3440850e..c7622250 100644 --- a/comtypes/errorinfo.py +++ b/comtypes/errorinfo.py @@ -9,53 +9,81 @@ if sys.version_info >= (3, 0): base_text_type = str else: - base_text_type = basestring + base_text_type = basestring # NOQA + 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 +91,20 @@ 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 +121,21 @@ def ReportError(text, iid, except WindowsError: pass else: - ei.SetSource(progid) # progid for the class or application that created the error + # progid for the class or application that created the error + ei.SetSource(progid) + _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,10 +146,17 @@ 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 + ) + -__all__ = ["ICreateErrorInfo", "IErrorInfo", "ISupportErrorInfo", - "ReportError", "ReportException", - "SetErrorInfo", "GetErrorInfo", "CreateErrorInfo"] +__all__ = [ + "ICreateErrorInfo", "IErrorInfo", "ISupportErrorInfo", "ReportError", + "ReportException", "SetErrorInfo", "GetErrorInfo", "CreateErrorInfo" +] diff --git a/comtypes/git.py b/comtypes/git.py index ef9f60ab..a6cf8bf6 100644 --- a/comtypes/git.py +++ b/comtypes/git.py @@ -4,33 +4,46 @@ between different threading appartments. """ from ctypes import * -from comtypes import IUnknown, STDMETHOD, COMMETHOD, \ - GUID, HRESULT, CoCreateInstance, CLSCTX_INPROC_SERVER +from comtypes import ( + IUnknown, + STDMETHOD, + 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() - self.__com_RegisterInterfaceInGlobal(obj, interface._iid_, cookie) - return cookie.value + ckie = DWORD() + self.__com_RegisterInterfaceInGlobal(obj, interface._iid_, ckie) + return ckie.value - def GetInterfaceFromGlobal(self, cookie, interface=IUnknown): + def GetInterfaceFromGlobal(self, ckie, interface=IUnknown): ptr = POINTER(interface)() - self.__com_GetInterfaceFromGlobal(cookie, interface._iid_, ptr) + self.__com_GetInterfaceFromGlobal(ckie, interface._iid_, ptr) return ptr - def RevokeInterfaceFromGlobal(self, cookie): - self.__com_RevokeInterfaceFromGlobal(cookie) + def RevokeInterfaceFromGlobal(self, ckie): + self.__com_RevokeInterfaceFromGlobal(ckie) # It was a pain to get this CLSID: it's neither in the registry, nor @@ -38,20 +51,27 @@ 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 -__all__ = ["RegisterInterfaceInGlobal", "RevokeInterfaceFromGlobal", "GetInterfaceFromGlobal"] +__all__ = [ + "RegisterInterfaceInGlobal", + "RevokeInterfaceFromGlobal", + "GetInterfaceFromGlobal" +] + 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/hresult.py b/comtypes/hresult.py index 85f75ceb..e0969bd5 100644 --- a/comtypes/hresult.py +++ b/comtypes/hresult.py @@ -6,52 +6,53 @@ 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 # 0x800020005 +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: @@ -60,12 +61,14 @@ def MAKE_HRESULT(sev, fac, code): 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 diff --git a/comtypes/logutil.py b/comtypes/logutil.py index 6d46e13e..789dc3de 100644 --- a/comtypes/logutil.py +++ b/comtypes/logutil.py @@ -1,37 +1,47 @@ # logutil.py -import logging, ctypes +import logging +import 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") + + 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: - return parser.get(section, option, True) + return parser.get(section, option, True) # NOQA except (configparser.NoOptionError, configparser.NoSectionError): return DEFAULTS[option] levelname = get("logging", "level") - format = get("logging", "format") + format = get("logging", "format") # NOQA handlerclass = get("logging", "handler") # convert level name to level value diff --git a/comtypes/messageloop.py b/comtypes/messageloop.py index 9defb66a..a421017d 100644 --- a/comtypes/messageloop.py +++ b/comtypes/messageloop.py @@ -1,6 +1,8 @@ import ctypes from ctypes import WinDLL, byref, WinError from ctypes.wintypes import MSG + + _user32 = WinDLL("user32") GetMessage = _user32.GetMessageA @@ -33,13 +35,14 @@ 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) def filter_message(self, lpmsg): - return any(list(filter(lpmsg)) for filter in self._filters) + return any(list(flter(lpmsg)) for flter in self._filters) + _messageloop = _MessageLoop() diff --git a/comtypes/patcher.py b/comtypes/patcher.py index 67b02d90..4fff4889 100644 --- a/comtypes/patcher.py +++ b/comtypes/patcher.py @@ -55,11 +55,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) - if no_replace and hasattr(self.target, name): + n_replace = getattr(value, '__no_replace', False) + if n_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 +69,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 3b989a7b..a81bffed 100644 --- a/comtypes/persist.py +++ b/comtypes/persist.py @@ -11,53 +11,69 @@ """ from ctypes import * from ctypes.wintypes import WORD, DWORD, BOOL -from comtypes import GUID, IUnknown, COMMETHOD, HRESULT, dispid +from comtypes import GUID, IUnknown, COMMETHOD, HRESULT from comtypes import IPersist from comtypes.automation import VARIANT, tagEXCEPINFO + # XXX Replace by canonical solution!!! WSTRING = c_wchar_p + class IErrorLog(IUnknown): _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}') _idlflags_ = [] _methods_ = [ - # XXX Note: According to MSDN, pVar and pErrorLog are ['in', 'out'] parameters. + # 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' )), - ] + # 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') + ) + ] + class IPersistPropertyBag(IPersist): _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, '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 @@ -70,6 +86,7 @@ class IPersistPropertyBag(IPersist): PROPBAG2_TYPE_STORAGE = 5 PROPBAG2_TYPE_MONIKER = 6 + class tagPROPBAG2(Structure): _fields_ = [ ('dwType', c_ulong), @@ -78,50 +95,66 @@ class tagPROPBAG2(Structure): ('dwHint', c_ulong), ('pstrName', WSTRING), ('clsid', GUID), - ] + ] + class IPropertyBag2(IUnknown): _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}') _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, '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 @@ -159,28 +192,40 @@ class IPersistPropertyBag2(IPersist): LPOLESTR = LPCOLESTR = c_wchar_p + class IPersistFile(IPersist): _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' )) - ] - - -from comtypes import COMObject -from comtypes.hresult import * + 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 # NOQA +from comtypes.hresult import * # NOQA + + class DictPropertyBag(COMObject): - """An object implementing the IProperty interface on a dictionary. + """ + An object implementing the IProperty interface on a dictionary. Pass named values in the constructor for the client to Read(), or retrieve from the .values instance variable after the client has @@ -192,7 +237,7 @@ def __init__(self, **kw): super(DictPropertyBag, self).__init__() self.values = kw - def Read(self, this, name, pVar, errorlog): + def Read(self, _, name, pVar, __): try: val = self.values[name] except KeyError: @@ -206,7 +251,7 @@ def Read(self, this, name, pVar, errorlog): var.ChangeType(typecode) return S_OK - def Write(self, this, name, var): + def Write(self, _, name, var): val = var[0].value self.values[name] = val return S_OK diff --git a/comtypes/safearray.py b/comtypes/safearray.py index a8a2b2ff..1747bcac 100644 --- a/comtypes/safearray.py +++ b/comtypes/safearray.py @@ -1,8 +1,16 @@ 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 +18,8 @@ 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 +32,7 @@ class _SafeArrayAsNdArrayContextManager(object): >>> type(my_arr) numpy.ndarray - ''' + """ thread_local = threading.local() def __enter__(self): @@ -37,12 +46,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)) - __nonzero__ = __bool__ # for Py2.7 compatibility + __nonzero__ = __bool__ # for Py2.7 compatibility # Global _SafeArrayAsNdArrayContextManager @@ -52,7 +59,8 @@ def __bool__(self): ################################################################ # This is THE PUBLIC function: the gateway to the SAFEARRAY functionality. def _midlSAFEARRAY(itemtype): - """This function mimics the 'SAFEARRAY(aType)' IDL idiom. It + """ + This function mimics the 'SAFEARRAY(aType)' IDL idiom. It returns a subtype of SAFEARRAY, instances will be built with a typecode VT_... corresponding to the aType, which must be one of the supported ctypes. @@ -67,13 +75,21 @@ 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] @@ -81,19 +97,21 @@ def _make_safearray_type(itemtype): except KeyError: if issubclass(itemtype, Structure): try: - guids = itemtype._recordinfo_ + guids = itemtype._recordinfo_ # NOQA except AttributeError: extra = None else: from comtypes.typeinfo import GetRecordInfoFromGuids + extra = GetRecordInfoFromGuids(*guids) + vartype = VT_RECORD elif issubclass(itemtype, POINTER(IDispatch)): vartype = VT_DISPATCH - extra = pointer(itemtype._iid_) + extra = pointer(itemtype._iid_) # NOQA elif issubclass(itemtype, POINTER(IUnknown)): vartype = VT_UNKNOWN - extra = pointer(itemtype._iid_) + extra = pointer(itemtype._iid_) # NOQA else: raise TypeError(itemtype) @@ -105,8 +123,9 @@ class _(object): _needsfree = False @classmethod - def create(cls, value, extra=None): - """Create a POINTER(SAFEARRAY_...) instance of the correct + def create(cls, value, extra=None): # NOQA + """ + Create a POINTER(SAFEARRAY_...) instance of the correct type; value is an object containing the items to store. Python lists, tuples, and array.array instances containing @@ -125,21 +144,28 @@ 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 # to the correct type: pa = cast(pa, cls) # Now, fill the data in: ptr = POINTER(cls._itemtype_)() # container for the values _safearray.SafeArrayAccessData(pa, byref(ptr)) + try: if isinstance(value, array.array): addr, n = value.buffer_info() @@ -153,8 +179,9 @@ def create(cls, value, extra=None): return pa @classmethod - def create_from_ndarray(cls, value, extra, lBound=0): + def create_from_ndarray(cls, value, extra, lBound=0): # NOQA 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: @@ -162,8 +189,13 @@ def create_from_ndarray(cls, value, extra, lBound=0): else: ai = value.__array_interface__ if ai["version"] != 3: - raise TypeError("only __array_interface__ version 3 supported") - if cls._itemtype_ != comtypes.npsupport.typecodes[ai["typestr"]]: + raise TypeError( + "only __array_interface__ version 3 supported" + ) + if ( + cls._itemtype_ != + comtypes.npsupport.typecodes[ai["typestr"]] + ): raise TypeError("Wrong array item type") # SAFEARRAYs have Fortran order; convert the numpy array if needed @@ -181,21 +213,28 @@ 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, # cDims + rgsa, # rgsaBound + extra + ) # 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 # to the correct type: pa = cast(pa, cls) # Now, fill the data in: ptr = POINTER(cls._itemtype_)() # pointer to the item values _safearray.SafeArrayAccessData(pa, byref(ptr)) + try: nbytes = nitems * sizeof(cls._itemtype_) memmove(ptr, value.ctypes.data, nbytes) @@ -218,7 +257,7 @@ def __getitem__(self, index): def __setitem__(self, index, value): # XXX Need this to implement [in, out] safearrays in COM servers! -## print "__setitem__", index, value + # print "__setitem__", index, value raise TypeError("Setting items not allowed") def __ctypes_from_outparam__(self): @@ -230,25 +269,29 @@ def __del__(self, _SafeArrayDestroy=_safearray.SafeArrayDestroy): _SafeArrayDestroy(self) def _get_size(self, dim): - "Return the number of elements for dimension 'dim'" + """Return the number of elements for dimension 'dim'""" ub = _safearray.SafeArrayGetUBound(self, dim) + 1 lb = _safearray.SafeArrayGetLBound(self, dim) return ub - lb def unpack(self): - """Unpack a POINTER(SAFEARRAY_...) into a Python tuple or ndarray.""" + """ + Unpack a POINTER(SAFEARRAY_...) into a Python tuple or ndarray. + """ dim = _safearray.SafeArrayGetDim(self) if dim == 0: if safearray_as_ndarray: return comtypes.npsupport.numpy.array() return tuple() + elif dim == 1: num_elements = self._get_size(1) result = self._get_elements_raw(num_elements) if safearray_as_ndarray: return comtypes.npsupport.numpy.asarray(result) return tuple(result) + elif dim == 2: # get the number of elements in each dimension rows, cols = self._get_size(1), self._get_size(2) @@ -257,23 +300,34 @@ 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) + return row def _get_elements_raw(self, num_elements): - """Returns a flat list or ndarray containing ALL elements in - the safearray.""" + """ + 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 @@ -285,6 +339,7 @@ def _get_elements_raw(self, num_elements): # We have to loop over each item, so we get no # speedup by creating an ndarray here. return [i.value for i in ptr[:num_elements]] + elif issubclass(self._itemtype_, POINTER(IUnknown)): iid = _safearray.SafeArrayGetIID(self) itf = com_interface_registry[str(iid)] @@ -302,6 +357,7 @@ def _get_elements_raw(self, num_elements): # return a NULL-interface pointer. result.append(POINTER(itf)()) return result + else: # If the safearray element are NOT native python # objects, the containing safearray must be kept @@ -311,17 +367,24 @@ 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) @@ -334,8 +397,9 @@ def _get_row(self, dim, indices, lowerbounds, upperbounds): obj = self._itemtype_() pobj = byref(obj) 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? + # 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): indices[dim] = i _safearray.SafeArrayGetElement(self, indices, pobj) @@ -343,12 +407,14 @@ def _get_row(self, dim, indices, lowerbounds, upperbounds): else: 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): + class __(object): # NOQA @classmethod def from_param(cls, value): @@ -361,13 +427,13 @@ def __setitem__(self, index, value): pa = self._type_.create(value, extra) # XXX Must we destroy the currently contained data? # fill it into self - super(POINTER(POINTER(sa_type)), self).__setitem__(index, pa) + super(POINTER(POINTER(sa_type)), self).__setitem__(index, pa) # NOQA return sa_type 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." @@ -399,7 +465,12 @@ def _datetime64_ndarray_to_variant_array(value): 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 = 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/shelllink.py b/comtypes/shelllink.py index 55e531ef..2c776463 100644 --- a/comtypes/shelllink.py +++ b/comtypes/shelllink.py @@ -9,75 +9,112 @@ SLGP_RAWPATH = 0x4 # for SetShowCmd, GetShowCmd -##SW_SHOWNORMAL -##SW_SHOWMAXIMIZED -##SW_SHOWMINNOACTIVE +# SW_SHOWNORMAL +# SW_SHOWMAXIMIZED +# SW_SHOWMINNOACTIVE # for Resolve -##SLR_INVOKE_MSI -##SLR_NOLINKINFO -##SLR_NO_UI -##SLR_NOUPDATE -##SLR_NOSEARCH -##SLR_NOTRACK -##SLR_UPDATE +# SLR_INVOKE_MSI +# SLR_NOLINKINFO +# SLR_NO_UI +# SLR_NOUPDATE +# SLR_NOSEARCH +# SLR_NOTRACK +# SLR_UPDATE # fake these... ITEMIDLIST = c_int LPITEMIDLIST = LPCITEMIDLIST = POINTER(ITEMIDLIST) + class IShellLinkA(IUnknown): _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 +143,94 @@ 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}') _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,6 +259,7 @@ 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}') @@ -193,17 +268,13 @@ class ShellLink(CoClass): if __name__ == "__main__": - import sys - import comtypes from comtypes.client import CreateObject from comtypes.persist import IPersistFile - - shortcut = CreateObject(ShellLink) print(shortcut) - ##help(shortcut) + # help(shortcut) shortcut.SetPath(sys.executable) diff --git a/comtypes/typeinfo.py b/comtypes/typeinfo.py index c591119d..567abfa9 100644 --- a/comtypes/typeinfo.py +++ b/comtypes/typeinfo.py @@ -1,27 +1,52 @@ # XXX Should convert from STDMETHOD to COMMETHOD. # generated by 'xml2py' -# flags '..\tools\windows.xml -m comtypes -m comtypes.automation -w -r .*TypeLibEx -r .*TypeLib -o typeinfo.py' +# flags '..\tools\windows.xml -m comtypes -m comtypes.automation -w -r . +# *TypeLibEx -r .*TypeLib -o typeinfo.py' # then hacked manually -import os import sys import weakref 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, + IID, + IUnknown, + STDMETHOD, + TYPE_CHECKING ) from comtypes.automation import ( - DISPID, DISPPARAMS, EXCEPINFO, LCID, SCODE, VARIANT, VARIANTARG, VARTYPE, - tagVARIANT, + DISPID, + DISPPARAMS, + EXCEPINFO, + LCID, + SCODE, + VARIANT, + VARIANTARG, + VARTYPE, + tagVARIANT as _tagVARIANT, ) + +tagVARIANT = _tagVARIANT +del _tagVARIANT + if TYPE_CHECKING: - from ctypes import _CData, _Pointer + from ctypes import _CData, _Pointer # NOQA 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) @@ -44,20 +69,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 +94,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 +110,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 +125,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 +144,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 +162,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 +178,7 @@ FUNCFLAG_FIMMEDIATEBIND = 4096 FUNCFLAGS = tagFUNCFLAGS -tagVARFLAGS = c_int # enum +tagVARFLAGS = c_int # enum VARFLAG_FREADONLY = 1 VARFLAG_FSOURCE = 2 VARFLAG_FBINDABLE = 4 @@ -178,6 +203,7 @@ PARAMFLAG_FHASDEFAULT = 32 PARAMFLAG_FHASCUSTDATA = 64 + ################################################################ # a helper @@ -192,6 +218,7 @@ def _deref_with_release(ptr, release): # interfaces + class ITypeLib(IUnknown): _iid_ = GUID("{00020402-0000-0000-C000-000000000046}") @@ -202,30 +229,37 @@ 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): @@ -235,7 +269,8 @@ def GetLibAttr(self): def IsName(self, name, lHashVal=0): # type: (str, int) -> Optional[str] - """Check if there is type information for this name. + """ + Check if there is type information for this name. Returns the name with capitalization found in the type library, or None. @@ -255,21 +290,32 @@ def FindName(self, name, lHashVal=0): found = c_ushort(1) tinfo = POINTER(ITypeInfo)() memid = MEMBERID() - self.__com_FindName(name, lHashVal, byref(tinfo), byref(memid), byref(found)) # type: ignore + self.__com_FindName( + name, + lHashVal, + byref(tinfo), + byref(memid), + byref(found) + ) # type: ignore if found.value: 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,6 +323,7 @@ def fix_name(name): return name return name.split("\0")[0] + class ITypeInfo(IUnknown): _iid_ = GUID("{00020401-0000-0000-C000-000000000046}") @@ -285,32 +332,45 @@ 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)]), + # 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.""" + """ + 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] @@ -330,7 +390,10 @@ def GetDocumentation(self, memid): def GetFuncDesc(self, index): """Return FUNCDESC for index""" - return _deref_with_release(self._GetFuncDesc(index), self.ReleaseFuncDesc) + return _deref_with_release( + self._GetFuncDesc(index), + self.ReleaseFuncDesc + ) def GetVarDesc(self, index): """Return VARDESC for index""" @@ -339,7 +402,7 @@ def GetVarDesc(self, index): def GetNames(self, memid, count=1): # type: (int, int) -> List[str] """Return names for memid""" - names = (BSTR * count)() + names = (BSTR * count)() # NOQA cnames = c_uint() self.__com_GetNames(memid, names, count, byref(cnames)) # type: ignore return names[:cnames.value] @@ -352,10 +415,10 @@ def GetIDsOfNames(self, *names): self.__com_GetIDsOfNames(rgsznames, len(names), ids) # type: ignore return ids[:] - def AddressOfMember(self, memid, invkind): + def AddressOfMember(self, memid, invkind): # NOQA """Get the address of a function in a dll""" raise RuntimeError("Check Me") - p = c_void_p() + p = c_void_p() # NOQA self.__com_AddressOfMember(memid, invkind, byref(p)) # XXX Would the default impl return the value of p? return p.value @@ -364,7 +427,9 @@ def CreateInstance(self, punkouter=None, interface=IUnknown, iid=None): # type: (Optional[Type[_Pointer[IUnknown]]], Type[_T_IUnknown], Optional[GUID]) -> _T_IUnknown if iid is None: iid = interface._iid_ - return self._CreateInstance(punkouter, byref(interface._iid_)) # type: ignore + + return self._CreateInstance(punkouter, byref(iid)) # type: ignore + ################ @@ -377,20 +442,37 @@ def Bind(self, name, flags=0, lHashVal=0): bindptr = BINDPTR() desckind = DESCKIND() ti = POINTER(ITypeInfo)() # type: ITypeInfo - self.__com_Bind(name, lHashVal, flags, byref(ti), byref(desckind), byref(bindptr)) # type: ignore + self.__com_Bind( + name, + lHashVal, + flags, + byref(ti), + byref(desckind), + byref(bindptr) + ) # type: ignore 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 + elif kind == DESCKIND_IMPLICITAPPOBJ: raise NotImplementedError + elif kind == DESCKIND_NONE: raise NameError("Name %s not found" % name) @@ -399,7 +481,12 @@ def BindType(self, name, lHashVal=0): """Bind a type, and return both the typeinfo and typecomp for it.""" ti = POINTER(ITypeInfo)() tc = POINTER(ITypeComp)() - self.__com_BindType(name, lHashVal, byref(ti), byref(tc)) # type: ignore + self.__com_BindType( + name, + lHashVal, + byref(ti), + byref(tc) + ) # type: ignore return ti, tc # type: ignore @@ -409,9 +496,11 @@ 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 @@ -425,142 +514,216 @@ 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}") - def GetFieldNames(self, *args): + def GetFieldNames(self, *args): # NOQA # type: (Any) -> List[Optional[str]] count = c_ulong() self.__com_GetFieldNames(count, None) # type: ignore - array = (BSTR * count.value)() + array = (BSTR * count.value)() # NOQA self.__com_GetFieldNames(count, array) # type: ignore result = array[:] # 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, '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'))] - + 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" + """Return an IRecordInfo pointer to the UDT described in tinfo""" ri = POINTER(IRecordInfo)() _oleaut32.GetRecordInfoFromTypeInfo(tinfo, byref(ri)) return ri # type: ignore -def GetRecordInfoFromGuids(rGuidTypeLib, verMajor, verMinor, lcid, rGuidTypeInfo): + +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" + """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): + def LoadTypeLibEx(szFile, regkind=REGKIND_NONE): # NOQA # type: (str, int) -> ITypeLib - "Load, and optionally register a type library file" + """Load, and optionally register a type library file""" ptl = POINTER(ITypeLib)() _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" + """Load and register a type library file""" tlib = POINTER(ITypeLib)() _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) + """Unregister a registered type library""" + 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)) + """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" + """Return a ICreateTypeLib2 pointer""" ctlib = POINTER(ICreateTypeLib2)() _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" + """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 @@ -575,10 +738,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 +773,21 @@ 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 +805,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 +830,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,15 +873,18 @@ 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')), + # 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)]), @@ -686,136 +897,244 @@ class tagARRAYDESC(Structure): ] ICreateTypeLib2._methods_ = [ -# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 2444 + # 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 + # 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))) + 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))), -## STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(LPOLESTR), UINT, POINTER(MEMBERID)]), + # 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 + # 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, + # '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, + 'SetFuncAndParamNames', + [UINT, POINTER(c_wchar_p), UINT] + ), STDMETHOD(HRESULT, 'SetVarName', [UINT, LPOLESTR]), STDMETHOD(HRESULT, 'SetTypeDescAlias', [POINTER(TYPEDESC)]), STDMETHOD(HRESULT, 'DefineFuncAsDllEntry', [UINT, LPOLESTR, LPOLESTR]), @@ -825,29 +1144,37 @@ class tagARRAYDESC(Structure): STDMETHOD(HRESULT, 'SetVarHelpContext', [UINT, DWORD]), STDMETHOD(HRESULT, 'SetMops', [UINT, BSTR]), STDMETHOD(HRESULT, 'SetTypeIdldesc', [POINTER(IDLDESC)]), - STDMETHOD(HRESULT, 'LayOut', []), + 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" ) ) - ] + # Returns the ITypeInfo interface for + # the object's coclass type information. + COMMETHOD( + [], HRESULT, "GetClassInfo", + (['out'], POINTER(POINTER(ITypeInfo)), "ppTI") + ) + ] + class IProvideClassInfo2(IProvideClassInfo): _iid_ = GUID("{A6BC3AC0-DBAA-11CE-9DE3-00AA004BB851}") if TYPE_CHECKING: 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" )) - ] + # 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") + ) + ] ################################################################ @@ -862,18 +1189,23 @@ class IProvideClassInfo2(IProvideClassInfo): ('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), ] + tagTYPEDESC._anonymous_ = ('_',) tagTYPEDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 582 @@ -881,11 +1213,13 @@ class N11tagTYPEDESC5DOLLAR_203E(Union): ('_', N11tagTYPEDESC5DOLLAR_203E), ('vt', VARTYPE), ] + tagIDLDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 633 ('dwReserved', ULONG_PTR), ('wIDLFlags', USHORT), ] + tagTYPEATTR._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 672 ('guid', GUID), @@ -907,38 +1241,50 @@ class N11tagTYPEDESC5DOLLAR_203E(Union): ('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)), ] + + 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_ = [ @@ -953,6 +1299,7 @@ class tagPARAMDESCEX(Structure): ('idldesc', IDLDESC), ('paramdesc', PARAMDESC), ] + tagELEMDESC._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 661 ('tdesc', TYPEDESC), @@ -971,6 +1318,7 @@ class tagPARAMDESCEX(Structure): ('wVarFlags', WORD), ('varkind', VARKIND), ] + tagBINDPTR._fields_ = [ # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 3075 ('lpfuncdesc', POINTER(FUNCDESC)), @@ -1000,6 +1348,7 @@ class tagPARAMDESCEX(Structure): ('varDefaultValue', VARIANTARG), ] + class tagSAFEARRAYBOUND(Structure): # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 226 if TYPE_CHECKING: @@ -1009,6 +1358,8 @@ class tagSAFEARRAYBOUND(Structure): ('cElements', DWORD), ('lLbound', LONG), ] + + SAFEARRAYBOUND = tagSAFEARRAYBOUND tagARRAYDESC._fields_ = [ diff --git a/comtypes/util.py b/comtypes/util.py index 0eaf864d..15fa6983 100644 --- a/comtypes/util.py +++ b/comtypes/util.py @@ -1,8 +1,10 @@ -"""This module defines the funtions byref_at(cobj, offset) +""" +This module defines the funtions byref_at(cobj, offset) and cast_field(struct, fieldname, fieldtype). """ from ctypes import * + def _calc_offset(): # Internal helper function that calculates where the object # returned by a byref() call stores the pointer. @@ -11,30 +13,34 @@ 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"] # additional checks to make sure that everything works as expected - if sizeof(PyCArgObject) != type(byref(c_int())).__basicsize__: + if sizeof(PyCArgObject) != type(byref(c_int())).__basicsize__: # NOQA raise RuntimeError("sizeof(PyCArgObject) invalid") obj = c_int() @@ -42,23 +48,29 @@ 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() - ): - """byref_at(cobj, offset) behaves similar this C code: +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 +80,9 @@ 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,20 +90,27 @@ 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, # NOQA + _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"]