diff --git a/comtypes/_meta.py b/comtypes/_meta.py index 14ef4c78..5f74109a 100644 --- a/comtypes/_meta.py +++ b/comtypes/_meta.py @@ -45,6 +45,17 @@ class _coclass_meta(type): def __new__(cls, name, bases, namespace): self = type.__new__(cls, name, bases, namespace) if bases == (object,): + # HACK: Could this conditional branch be removed since it is never reached? + # Since definition is `class CoClass(COMObject, metaclass=_coclass_meta)`, + # the `bases` parameter passed to the `_coclass_meta.__new__` would be + # `(COMObject,)`. + # Moreover, since the `COMObject` derives from `object` and does not specify + # a metaclass, `(object,)` will not be passed as the `bases` parameter + # to the `_coclass_meta.__new__`. + # The reason for this implementation might be a remnant of the differences + # in how metaclasses work between Python 3.x and Python 2.x. + # If there are no problems with the versions of Python that `comtypes` + # supports, this removal could make the process flow easier to understand. return self # XXX We should insist that a _reg_clsid_ is present. if "_reg_clsid_" in namespace: @@ -67,4 +78,6 @@ def __new__(cls, name, bases, namespace): # will not work if we change the order of the two base classes! class _coclass_pointer_meta(type(c_void_p), _coclass_meta): - pass + # metaclass for CoClass pointer + + pass # no functionality, but needed to avoid a metaclass conflict diff --git a/comtypes/_post_coinit/unknwn.py b/comtypes/_post_coinit/unknwn.py index 85e23d2f..7d10b47e 100644 --- a/comtypes/_post_coinit/unknwn.py +++ b/comtypes/_post_coinit/unknwn.py @@ -85,11 +85,21 @@ def __new__(cls, name, bases, namespace): # subclass of POINTER(IUnknown) because of the way ctypes # typechecks work. if bases == (object,): + # `self` is the `IUnknown` type. _ptr_bases = (self, _compointer_base) else: + # `self` is an interface type derived from `IUnknown`. _ptr_bases = (self, POINTER(bases[0])) # The interface 'self' is used as a mixin. + # HACK: Could `type(_compointer_base)` be replaced with `_compointer_meta`? + # `type(klass)` returns its metaclass. + # Since this specification, `type(_compointer_base)` will return the + # `_compointer_meta` type as per the class definition. + # The reason for this implementation might be a remnant of the differences in + # how metaclasses work between Python 3.x and Python 2.x. + # If there are no problems with the versions of Python that `comtypes` + # supports, this replacement could make the process flow easier to understand. p = type(_compointer_base)( f"POINTER({self.__name__})", _ptr_bases, @@ -369,10 +379,11 @@ def _make_methods(self, methods: List[_ComMemberSpec]) -> None: ################################################################ +# will not work if we change the order of the two base classes! 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 + pass # no functionality, but needed to avoid a metaclass conflict class _compointer_base(c_void_p, metaclass=_compointer_meta):