Skip to content

Commit 00cf639

Browse files
committed
1 parent ca14c63 commit 00cf639

File tree

3 files changed

+66
-41
lines changed

3 files changed

+66
-41
lines changed

comtypes/_meta.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ def _coclass_from_param(cls, obj):
3434
# object
3535

3636

37+
_initializing_coclass_meta = False
38+
39+
3740
class _coclass_meta(type):
3841
# metaclass for CoClass
3942
#
@@ -42,28 +45,32 @@ class _coclass_meta(type):
4245
# POINTER(...) type gets a __ctypes_from_outparam__ method which
4346
# will QueryInterface for the default interface: the first one on
4447
# the coclass' _com_interfaces_ list.
45-
def __new__(cls, name, bases, namespace):
46-
self = type.__new__(cls, name, bases, namespace)
48+
def __init__(self, name, bases, namespace):
4749
if bases == (object,):
48-
return self
50+
return
4951
# XXX We should insist that a _reg_clsid_ is present.
5052
if "_reg_clsid_" in namespace:
5153
clsid = namespace["_reg_clsid_"]
5254
comtypes.com_coclass_registry[str(clsid)] = self
53-
PTR = _coclass_pointer_meta(
54-
f"POINTER({self.__name__})",
55-
(self, c_void_p),
56-
{
57-
"__ctypes_from_outparam__": _wrap_coclass,
58-
"from_param": classmethod(_coclass_from_param),
59-
},
60-
)
55+
global _initializing_coclass_meta
56+
if _initializing_coclass_meta:
57+
return
58+
try:
59+
_initializing_coclass_meta = True
60+
PTR = _coclass_pointer_meta(
61+
"POINTER(%s)" % self.__name__,
62+
(self, c_void_p),
63+
{
64+
"__ctypes_from_outparam__": _wrap_coclass,
65+
"from_param": classmethod(_coclass_from_param),
66+
},
67+
)
68+
finally:
69+
_initializing_coclass_meta = False
6170
from ctypes import _pointer_type_cache # type: ignore
6271

6372
_pointer_type_cache[self] = PTR
6473

65-
return self
66-
6774

6875
# will not work if we change the order of the two base classes!
6976
class _coclass_pointer_meta(type(c_void_p), _coclass_meta):

comtypes/_post_coinit/unknwn.py

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ def _shutdown(
5151
# The metaclasses...
5252

5353

54+
_initializing_cominterface_meta = False
55+
56+
5457
class _cominterface_meta(type):
5558
"""Metaclass for COM interfaces. Automatically creates high level
5659
methods from COMMETHOD lists.
@@ -66,35 +69,45 @@ class _cominterface_meta(type):
6669
_com_shutting_down = False
6770

6871
# Creates also a POINTER type for the newly created class.
69-
def __new__(cls, name, bases, namespace):
70-
methods = namespace.pop("_methods_", None)
71-
dispmethods = namespace.pop("_disp_methods_", None)
72-
self = type.__new__(cls, name, bases, namespace)
72+
def __init(self, name, bases, namespace):
73+
methods = namespace.get("_methods_", None)
74+
dispmethods = namespace.get("_disp_methods_", None)
7375

7476
if methods is not None:
75-
self._methods_ = methods
77+
self._make_methods(methods)
78+
self._make_specials()
7679
if dispmethods is not None:
77-
self._disp_methods_ = dispmethods
80+
self._make_dispmethods(dispmethods)
81+
self._make_specials()
7882

79-
# If we sublass a COM interface, for example:
80-
#
81-
# class IDispatch(IUnknown):
82-
# ....
83-
#
84-
# then we need to make sure that POINTER(IDispatch) is a
85-
# subclass of POINTER(IUnknown) because of the way ctypes
86-
# typechecks work.
87-
if bases == (object,):
88-
_ptr_bases = (self, _compointer_base)
89-
else:
90-
_ptr_bases = (self, POINTER(bases[0]))
83+
global _initializing_cominterface_meta
9184

92-
# The interface 'self' is used as a mixin.
93-
p = type(_compointer_base)(
94-
f"POINTER({self.__name__})",
95-
_ptr_bases,
96-
{"__com_interface__": self, "_needs_com_addref_": None},
97-
)
85+
if _initializing_cominterface_meta:
86+
return
87+
88+
try:
89+
_initializing_cominterface_meta = True
90+
# If we sublass a COM interface, for example:
91+
#
92+
# class IDispatch(IUnknown):
93+
# ....
94+
#
95+
# then we need to make sure that POINTER(IDispatch) is a
96+
# subclass of POINTER(IUnknown) because of the way ctypes
97+
# typechecks work.
98+
if bases == (object,):
99+
_ptr_bases = (self, _compointer_base)
100+
else:
101+
_ptr_bases = (self, POINTER(bases[0]))
102+
103+
# The interface 'self' is used as a mixin.
104+
p = type(_compointer_base)(
105+
f"POINTER({self.__name__})",
106+
_ptr_bases,
107+
{"__com_interface__": self, "_needs_com_addref_": None},
108+
)
109+
finally:
110+
_initializing_cominterface_meta = False
98111

99112
from ctypes import _pointer_type_cache # type: ignore
100113

@@ -104,7 +117,14 @@ def __new__(cls, name, bases, namespace):
104117
self._patch_case_insensitive_to_ptr_type(p)
105118
self._patch_reference_fix_to_ptrptr_type(POINTER(p)) # type: ignore
106119

107-
return self
120+
if sys.version_info >= (3, 13):
121+
__init__ = __init
122+
else:
123+
124+
def __new__(cls, name, bases, namespace):
125+
self = type.__new__(cls, name, bases, namespace)
126+
self.__init(name, bases, namespace)
127+
return self
108128

109129
@staticmethod
110130
def _patch_case_insensitive_to_ptr_type(p: Type) -> None:

comtypes/safearray.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ def _make_safearray_type(itemtype):
8181
)
8282

8383
meta = type(_safearray.tagSAFEARRAY)
84-
sa_type = meta.__new__(
85-
meta, "SAFEARRAY_%s" % itemtype.__name__, (_safearray.tagSAFEARRAY,), {}
86-
)
84+
sa_type = meta(f"SAFEARRAY_{itemtype.__name__}", (_safearray.tagSAFEARRAY,), {})
8785

8886
try:
8987
vartype = _ctype_to_vartype[itemtype]

0 commit comments

Comments
 (0)