comtypes 1.4.4__zip → 1.4.5__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. {comtypes-1.4.4 → comtypes-1.4.5}/CHANGES.txt +12 -0
  2. {comtypes-1.4.4/comtypes.egg-info → comtypes-1.4.5}/PKG-INFO +1 -1
  3. comtypes-1.4.5/comtypes/__init__.py +268 -0
  4. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_comobject.py +2 -1
  5. comtypes-1.4.5/comtypes/_idl_stuff.py +67 -0
  6. comtypes-1.4.5/comtypes/_post_coinit/__init__.py +15 -0
  7. comtypes-1.4.5/comtypes/_post_coinit/bstr.py +30 -0
  8. comtypes-1.4.5/comtypes/_post_coinit/misc.py +385 -0
  9. comtypes-1.4.5/comtypes/_post_coinit/unknwn.py +537 -0
  10. comtypes-1.4.5/comtypes/_py_instance_method.py +13 -0
  11. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_safearray.py +3 -2
  12. comtypes-1.4.5/comtypes/_tlib_version_checker.py +18 -0
  13. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/automation.py +22 -6
  14. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_generate.py +2 -1
  15. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/hints.pyi +34 -0
  16. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/safearray.py +11 -4
  17. comtypes-1.4.5/comtypes/stream.py +65 -0
  18. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client.py +11 -0
  19. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dispifc_records.py +1 -1
  20. comtypes-1.4.5/comtypes/test/test_dispifc_safearrays.py +89 -0
  21. comtypes-1.4.5/comtypes/test/test_istream.py +53 -0
  22. comtypes-1.4.5/comtypes/test/test_midl_safearray_create.py +100 -0
  23. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_wmi.py +11 -18
  24. {comtypes-1.4.4 → comtypes-1.4.5/comtypes.egg-info}/PKG-INFO +1 -1
  25. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/SOURCES.txt +11 -0
  26. {comtypes-1.4.4 → comtypes-1.4.5}/setup.cfg +1 -0
  27. comtypes-1.4.4/comtypes/__init__.py +0 -1229
  28. {comtypes-1.4.4 → comtypes-1.4.5}/LICENSE.txt +0 -0
  29. {comtypes-1.4.4 → comtypes-1.4.5}/MANIFEST.in +0 -0
  30. {comtypes-1.4.4 → comtypes-1.4.5}/README.md +0 -0
  31. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/GUID.py +0 -0
  32. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_memberspec.py +0 -0
  33. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_meta.py +0 -0
  34. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_npsupport.py +0 -0
  35. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/clear_cache.py +0 -0
  36. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/__init__.py +0 -0
  37. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_code_cache.py +0 -0
  38. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_constants.py +0 -0
  39. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_events.py +0 -0
  40. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/dynamic.py +0 -0
  41. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/lazybind.py +0 -0
  42. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/connectionpoints.py +0 -0
  43. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/errorinfo.py +0 -0
  44. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/git.py +0 -0
  45. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/hresult.py +0 -0
  46. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/logutil.py +0 -0
  47. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/messageloop.py +0 -0
  48. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/patcher.py +0 -0
  49. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/persist.py +0 -0
  50. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/__init__.py +0 -0
  51. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/automation.py +0 -0
  52. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/connectionpoints.py +0 -0
  53. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/inprocserver.py +0 -0
  54. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/localserver.py +0 -0
  55. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/register.py +0 -0
  56. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/w_getopt.py +0 -0
  57. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/shelllink.py +0 -0
  58. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.idl +0 -0
  59. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.py +0 -0
  60. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.tlb +0 -0
  61. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.idl +0 -0
  62. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.py +0 -0
  63. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.tlb +0 -0
  64. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/__init__.py +0 -0
  65. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/find_memleak.py +0 -0
  66. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mylib.idl +0 -0
  67. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mylib.tlb +0 -0
  68. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mytypelib.idl +0 -0
  69. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/runtests.py +0 -0
  70. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/setup.py +0 -0
  71. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_BSTR.py +0 -0
  72. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_DISPPARAMS.py +0 -0
  73. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_GUID.py +0 -0
  74. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_QueryService.py +0 -0
  75. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_agilent.py +0 -0
  76. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_avmc.py +0 -0
  77. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_basic.py +0 -0
  78. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_casesensitivity.py +0 -0
  79. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_clear_cache.py +0 -0
  80. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client_dynamic.py +0 -0
  81. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client_regenerate_modules.py +0 -0
  82. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_collections.py +0 -0
  83. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_comserver.py +0 -0
  84. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_createwrappers.py +0 -0
  85. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dict.py +0 -0
  86. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dispinterface.py +0 -0
  87. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dyndispatch.py +0 -0
  88. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_excel.py +0 -0
  89. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_findgendir.py +0 -0
  90. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_getactiveobj.py +0 -0
  91. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_ie.py +0 -0
  92. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_ienum.py +0 -0
  93. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_imfattributes.py +0 -0
  94. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_inout_args.py +0 -0
  95. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_jscript.js +0 -0
  96. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_msscript.py +0 -0
  97. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_npsupport.py +0 -0
  98. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_outparam.py +0 -0
  99. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_propputref.py +0 -0
  100. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_pump_events.py +0 -0
  101. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_safearray.py +0 -0
  102. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_sapi.py +0 -0
  103. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_server.py +0 -0
  104. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_showevents.py +0 -0
  105. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_subinterface.py +0 -0
  106. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_typeinfo.py +0 -0
  107. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_urlhistory.py +0 -0
  108. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_variant.py +0 -0
  109. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_win32com_interop.py +0 -0
  110. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_word.py +0 -0
  111. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/urlhist.tlb +0 -0
  112. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/__init__.py +0 -0
  113. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/__init__.py +0 -0
  114. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/codegenerator.py +0 -0
  115. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/helpers.py +0 -0
  116. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  117. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/namespaces.py +0 -0
  118. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/packing.py +0 -0
  119. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/typeannotator.py +0 -0
  120. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/tlbparser.py +0 -0
  121. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/typedesc.py +0 -0
  122. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/typedesc_base.py +0 -0
  123. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/typeinfo.py +0 -0
  124. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/util.py +0 -0
  125. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/viewobject.py +0 -0
  126. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/dependency_links.txt +0 -0
  127. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/entry_points.txt +0 -0
  128. {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/top_level.txt +0 -0
  129. {comtypes-1.4.4 → comtypes-1.4.5}/pyproject.toml +0 -0
  130. {comtypes-1.4.4 → comtypes-1.4.5}/setup.py +0 -0
@@ -0,0 +1,537 @@
1
+ # https://learn.microsoft.com/en-us/windows/win32/api/unknwn/
2
+
3
+ from ctypes import byref, c_ulong, c_void_p, HRESULT, POINTER
4
+ from _ctypes import COMError
5
+
6
+ import logging
7
+ import sys
8
+ import types
9
+ from typing import ClassVar, TYPE_CHECKING, TypeVar
10
+ from typing import Optional
11
+ from typing import List, Type
12
+
13
+ from comtypes import GUID, patcher, _ole32_nohresult, com_interface_registry
14
+ from comtypes._idl_stuff import STDMETHOD
15
+ from comtypes._memberspec import ComMemberGenerator, DispMemberGenerator
16
+ from comtypes._memberspec import _ComMemberSpec, _DispMemberSpec
17
+ from comtypes._py_instance_method import instancemethod
18
+
19
+
20
+ _all_slice = slice(None, None, None)
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def _shutdown(
26
+ func=_ole32_nohresult.CoUninitialize,
27
+ _debug=logger.debug,
28
+ _exc_clear=getattr(sys, "exc_clear", lambda: None),
29
+ ):
30
+ # Make sure no COM pointers stay in exception frames.
31
+ _exc_clear()
32
+ # Sometimes, CoUninitialize, running at Python shutdown,
33
+ # raises an exception. We suppress this when __debug__ is
34
+ # False.
35
+ _debug("Calling CoUninitialize()")
36
+ if __debug__:
37
+ func()
38
+ else:
39
+ try:
40
+ func()
41
+ except WindowsError:
42
+ pass
43
+ # Set the flag which means that calling obj.Release() is no longer
44
+ # needed.
45
+ if _cominterface_meta is not None:
46
+ _cominterface_meta._com_shutting_down = True
47
+ _debug("CoUninitialize() done.")
48
+
49
+
50
+ ################################################################
51
+ # The metaclasses...
52
+
53
+
54
+ class _cominterface_meta(type):
55
+ """Metaclass for COM interfaces. Automatically creates high level
56
+ methods from COMMETHOD lists.
57
+ """
58
+
59
+ _case_insensitive_: bool
60
+ _iid_: GUID
61
+ _methods_: List[_ComMemberSpec]
62
+ _disp_methods_: List[_DispMemberSpec]
63
+
64
+ # This flag is set to True by the atexit handler which calls
65
+ # CoUninitialize.
66
+ _com_shutting_down = False
67
+
68
+ # 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
+ new_cls = type.__new__(cls, name, bases, namespace)
73
+
74
+ if methods is not None:
75
+ new_cls._methods_ = methods
76
+ if dispmethods is not None:
77
+ new_cls._disp_methods_ = dispmethods
78
+
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 = (new_cls, _compointer_base)
89
+ else:
90
+ _ptr_bases = (new_cls, POINTER(bases[0]))
91
+
92
+ # The interface 'new_cls' is used as a mixin.
93
+ p = type(_compointer_base)(
94
+ "POINTER(%s)" % new_cls.__name__,
95
+ _ptr_bases,
96
+ {"__com_interface__": new_cls, "_needs_com_addref_": None},
97
+ )
98
+
99
+ from ctypes import _pointer_type_cache
100
+
101
+ _pointer_type_cache[new_cls] = p
102
+
103
+ if new_cls._case_insensitive_:
104
+
105
+ @patcher.Patch(p)
106
+ class CaseInsensitive(object):
107
+ # case insensitive attributes for COM methods and properties
108
+ def __getattr__(self, name):
109
+ """Implement case insensitive access to methods and properties"""
110
+ try:
111
+ fixed_name = self.__map_case__[name.lower()]
112
+ except KeyError:
113
+ raise AttributeError(name)
114
+ if fixed_name != name: # prevent unbounded recursion
115
+ return getattr(self, fixed_name)
116
+ raise AttributeError(name)
117
+
118
+ # __setattr__ is pretty heavy-weight, because it is called for
119
+ # EVERY attribute assignment. Settings a non-com attribute
120
+ # through this function takes 8.6 usec, while without this
121
+ # function it takes 0.7 sec - 12 times slower.
122
+ #
123
+ # How much faster would this be if implemented in C?
124
+ def __setattr__(self, name, value):
125
+ """Implement case insensitive access to methods and properties"""
126
+ object.__setattr__(
127
+ self, self.__map_case__.get(name.lower(), name), value
128
+ )
129
+
130
+ @patcher.Patch(POINTER(p))
131
+ class ReferenceFix(object):
132
+ def __setitem__(self, index, value):
133
+ # We override the __setitem__ method of the
134
+ # POINTER(POINTER(interface)) type, so that the COM
135
+ # reference count is managed correctly.
136
+ #
137
+ # This is so that we can implement COM methods that have to
138
+ # return COM pointers more easily and consistent. Instead of
139
+ # using CopyComPointer in the method implementation, we can
140
+ # simply do:
141
+ #
142
+ # def GetTypeInfo(self, this, ..., pptinfo):
143
+ # if not pptinfo: return E_POINTER
144
+ # pptinfo[0] = a_com_interface_pointer
145
+ # return S_OK
146
+ if index != 0:
147
+ # CopyComPointer, which is in _ctypes, does only
148
+ # handle an index of 0. This code does what
149
+ # CopyComPointer should do if index != 0.
150
+ if bool(value):
151
+ value.AddRef()
152
+ super(POINTER(p), self).__setitem__(index, value)
153
+ return
154
+ from _ctypes import CopyComPointer
155
+
156
+ CopyComPointer(value, self)
157
+
158
+ return new_cls
159
+
160
+ def __setattr__(self, name, value):
161
+ if name == "_methods_":
162
+ # XXX I'm no longer sure why the code generator generates
163
+ # "_methods_ = []" in the interface definition, and later
164
+ # overrides this by "Interface._methods_ = [...]
165
+ # assert self.__dict__.get("_methods_", None) is None
166
+ self._make_methods(value)
167
+ self._make_specials()
168
+ elif name == "_disp_methods_":
169
+ assert self.__dict__.get("_disp_methods_", None) is None
170
+ self._make_dispmethods(value)
171
+ self._make_specials()
172
+ type.__setattr__(self, name, value)
173
+
174
+ def _make_specials(self):
175
+ # This call installs methods that forward the Python protocols
176
+ # to COM protocols.
177
+
178
+ def has_name(name):
179
+ # Determine whether a property or method named 'name'
180
+ # exists
181
+ if self._case_insensitive_:
182
+ return name.lower() in self.__map_case__
183
+ return hasattr(self, name)
184
+
185
+ # XXX These special methods should be generated by the code generator.
186
+ if has_name("Count"):
187
+
188
+ @patcher.Patch(self)
189
+ class _(object):
190
+ def __len__(self):
191
+ "Return the the 'self.Count' property."
192
+ return self.Count
193
+
194
+ if has_name("Item"):
195
+
196
+ @patcher.Patch(self)
197
+ class _(object):
198
+ # 'Item' is the 'default' value. Make it available by
199
+ # calling the instance (Not sure this makes sense, but
200
+ # win32com does this also).
201
+ def __call__(self, *args, **kw):
202
+ "Return 'self.Item(*args, **kw)'"
203
+ return self.Item(*args, **kw)
204
+
205
+ # does this make sense? It seems that all standard typelibs I've
206
+ # seen so far that support .Item also support ._NewEnum
207
+ @patcher.no_replace
208
+ def __getitem__(self, index):
209
+ "Return 'self.Item(index)'"
210
+ # Handle tuples and all-slice
211
+ if isinstance(index, tuple):
212
+ args = index
213
+ elif index == _all_slice:
214
+ args = ()
215
+ else:
216
+ args = (index,)
217
+
218
+ try:
219
+ result = self.Item(*args)
220
+ except COMError as err:
221
+ (hresult, text, details) = err.args
222
+ if hresult == -2147352565: # DISP_E_BADINDEX
223
+ raise IndexError("invalid index")
224
+ else:
225
+ raise
226
+
227
+ # Note that result may be NULL COM pointer. There is no way
228
+ # to interpret this properly, so it is returned as-is.
229
+
230
+ # Hm, should we call __ctypes_from_outparam__ on the
231
+ # result?
232
+ return result
233
+
234
+ @patcher.no_replace
235
+ def __setitem__(self, index, value):
236
+ "Attempt 'self.Item[index] = value'"
237
+ try:
238
+ self.Item[index] = value
239
+ except COMError as err:
240
+ (hresult, text, details) = err.args
241
+ if hresult == -2147352565: # DISP_E_BADINDEX
242
+ raise IndexError("invalid index")
243
+ else:
244
+ raise
245
+ except TypeError:
246
+ msg = "%r object does not support item assignment"
247
+ raise TypeError(msg % type(self))
248
+
249
+ if has_name("_NewEnum"):
250
+
251
+ @patcher.Patch(self)
252
+ class _(object):
253
+ def __iter__(self):
254
+ "Return an iterator over the _NewEnum collection."
255
+ # This method returns a pointer to _some_ _NewEnum interface.
256
+ # It relies on the fact that the code generator creates next()
257
+ # methods for them automatically.
258
+ #
259
+ # Better would maybe to return an object that
260
+ # implements the Python iterator protocol, and
261
+ # forwards the calls to the COM interface.
262
+ enum = self._NewEnum
263
+ if isinstance(enum, types.MethodType):
264
+ # _NewEnum should be a propget property, with dispid -4.
265
+ #
266
+ # Sometimes, however, it is a method.
267
+ enum = enum()
268
+ if hasattr(enum, "Next"):
269
+ return enum
270
+ # _NewEnum returns an IUnknown pointer, QueryInterface() it to
271
+ # IEnumVARIANT
272
+ from comtypes.automation import IEnumVARIANT
273
+
274
+ return enum.QueryInterface(IEnumVARIANT)
275
+
276
+ def _make_case_insensitive(self):
277
+ # The __map_case__ dictionary maps lower case names to the
278
+ # names in the original spelling to enable case insensitive
279
+ # method and attribute access.
280
+ try:
281
+ self.__dict__["__map_case__"]
282
+ except KeyError:
283
+ d = {}
284
+ d.update(getattr(self, "__map_case__", {}))
285
+ self.__map_case__ = d
286
+
287
+ def _make_dispmethods(self, methods: List[_DispMemberSpec]) -> None:
288
+ if self._case_insensitive_:
289
+ self._make_case_insensitive()
290
+ # create dispinterface methods and properties on the interface 'self'
291
+ member_gen = DispMemberGenerator(self.__name__)
292
+ for m in methods:
293
+ member_gen.add(m)
294
+ for name, func_or_prop, is_prop in member_gen.items():
295
+ setattr(self, name, func_or_prop)
296
+ # COM is case insensitive.
297
+ # For a method, this is the real name. For a property,
298
+ # this is the name WITHOUT the _set_ or _get_ prefix.
299
+ if self._case_insensitive_:
300
+ self.__map_case__[name.lower()] = name
301
+ if is_prop:
302
+ self.__map_case__[name[5:].lower()] = name[5:]
303
+ for name, accessor in member_gen.properties():
304
+ setattr(self, name, accessor)
305
+ # COM is case insensitive
306
+ if self._case_insensitive_:
307
+ self.__map_case__[name.lower()] = name
308
+
309
+ def __get_baseinterface_methodcount(self):
310
+ "Return the number of com methods in the base interfaces"
311
+ try:
312
+ result = 0
313
+ for itf in self.mro()[1:-1]:
314
+ result += len(itf.__dict__["_methods_"])
315
+ return result
316
+ except KeyError as err:
317
+ (name,) = err.args
318
+ if name == "_methods_":
319
+ raise TypeError("baseinterface '%s' has no _methods_" % itf.__name__)
320
+ raise
321
+
322
+ def _make_methods(self, methods: List[_ComMemberSpec]) -> None:
323
+ if self._case_insensitive_:
324
+ self._make_case_insensitive()
325
+ # register com interface. we insist on an _iid_ in THIS class!
326
+ try:
327
+ iid = self.__dict__["_iid_"]
328
+ except KeyError:
329
+ raise AttributeError("this class must define an _iid_")
330
+ else:
331
+ com_interface_registry[str(iid)] = self
332
+ # create members
333
+ vtbl_offset = self.__get_baseinterface_methodcount()
334
+ member_gen = ComMemberGenerator(self.__name__, vtbl_offset, self._iid_)
335
+ # create private low level, and public high level methods
336
+ for m in methods:
337
+ member_gen.add(m)
338
+ for name, func, raw_func, is_prop in member_gen.methods():
339
+ raw_mth = instancemethod(raw_func, None, self)
340
+ setattr(self, "_%s__com_%s" % (self.__name__, name), raw_mth)
341
+ mth = instancemethod(func, None, self)
342
+ if not is_prop:
343
+ # We install the method in the class, except when it's a property.
344
+ # And we make sure we don't overwrite a property that's already present.
345
+ mthname = name if not hasattr(self, name) else ("_%s" % name)
346
+ setattr(self, mthname, mth)
347
+ # For a method, this is the real name.
348
+ # For a property, this is the name WITHOUT the _set_ or _get_ prefix.
349
+ if self._case_insensitive_:
350
+ self.__map_case__[name.lower()] = name
351
+ if is_prop:
352
+ self.__map_case__[name[5:].lower()] = name[5:]
353
+ # create public properties / attribute accessors
354
+ for name, accessor in member_gen.properties():
355
+ # Again, we should not overwrite class attributes that are already present.
356
+ propname = name if not hasattr(self, name) else ("_%s" % name)
357
+ setattr(self, propname, accessor)
358
+ # COM is case insensitive
359
+ if self._case_insensitive_:
360
+ self.__map_case__[name.lower()] = name
361
+
362
+
363
+ ################################################################
364
+
365
+
366
+ class _compointer_meta(type(c_void_p), _cominterface_meta):
367
+ "metaclass for COM interface pointer classes"
368
+ # no functionality, but needed to avoid a metaclass conflict
369
+
370
+
371
+ class _compointer_base(c_void_p, metaclass=_compointer_meta):
372
+ "base class for COM interface pointer classes"
373
+
374
+ def __del__(self, _debug=logger.debug):
375
+ "Release the COM refcount we own."
376
+ if self:
377
+ # comtypes calls CoUninitialize() when the atexit handlers
378
+ # runs. CoUninitialize() cleans up the COM objects that
379
+ # are still alive. Python COM pointers may still be
380
+ # present but we can no longer call Release() on them -
381
+ # this may give a protection fault. So we need the
382
+ # _com_shutting_down flag.
383
+ #
384
+ if not type(self)._com_shutting_down:
385
+ _debug("Release %s", self)
386
+ self.Release()
387
+
388
+ def __cmp__(self, other):
389
+ """Compare pointers to COM interfaces."""
390
+ # COM identity rule
391
+ #
392
+ # XXX To compare COM interface pointers, should we
393
+ # automatically QueryInterface for IUnknown on both items, and
394
+ # compare the pointer values?
395
+ if not isinstance(other, _compointer_base):
396
+ return 1
397
+
398
+ # get the value property of the c_void_p baseclass, this is the pointer value
399
+ return cmp(
400
+ super(_compointer_base, self).value, super(_compointer_base, other).value
401
+ )
402
+
403
+ def __eq__(self, other):
404
+ if not isinstance(other, _compointer_base):
405
+ return False
406
+ # get the value property of the c_void_p baseclass, this is the pointer value
407
+ return (
408
+ super(_compointer_base, self).value == super(_compointer_base, other).value
409
+ )
410
+
411
+ def __hash__(self):
412
+ """Return the hash value of the pointer."""
413
+ # hash the pointer values
414
+ return hash(super(_compointer_base, self).value)
415
+
416
+ # redefine the .value property; return the object itself.
417
+ def __get_value(self):
418
+ return self
419
+
420
+ value = property(__get_value, doc="""Return self.""")
421
+
422
+ def __repr__(self):
423
+ ptr = super(_compointer_base, self).value
424
+ return "<%s ptr=0x%x at %x>" % (self.__class__.__name__, ptr or 0, id(self))
425
+
426
+ # This fixes the problem when there are multiple python interface types
427
+ # wrapping the same COM interface. This could happen because some interfaces
428
+ # are contained in multiple typelibs.
429
+ #
430
+ # It also allows to pass a CoClass instance to an api
431
+ # expecting a COM interface.
432
+ @classmethod
433
+ def from_param(cls, value):
434
+ """Convert 'value' into a COM pointer to the interface.
435
+
436
+ This method accepts a COM pointer, or a CoClass instance
437
+ which is QueryInterface()d."""
438
+ if value is None:
439
+ return None
440
+ # CLF: 2013-01-18
441
+ # A default value of 0, meaning null, can pass through to here.
442
+ if value == 0:
443
+ return None
444
+ if isinstance(value, cls):
445
+ return value
446
+ # multiple python interface types for the same COM interface.
447
+ # Do we need more checks here?
448
+ if cls._iid_ == getattr(value, "_iid_", None):
449
+ return value
450
+ # Accept an CoClass instance which exposes the interface required.
451
+ try:
452
+ table = value._com_pointers_
453
+ except AttributeError:
454
+ pass
455
+ else:
456
+ try:
457
+ # a kind of QueryInterface
458
+ return table[cls._iid_]
459
+ except KeyError:
460
+ raise TypeError("Interface %s not supported" % cls._iid_)
461
+ return value.QueryInterface(cls.__com_interface__)
462
+
463
+
464
+ ################################################################
465
+ # IUnknown, the root of all evil...
466
+
467
+ _T_IUnknown = TypeVar("_T_IUnknown", bound="IUnknown")
468
+
469
+ if TYPE_CHECKING:
470
+
471
+ class _IUnknown_Base(c_void_p, metaclass=_cominterface_meta): # type: ignore
472
+ """This is workaround to avoid false-positive of static type checking.
473
+
474
+ `IUnknown` behaves as a ctypes type, and `POINTER` can take it.
475
+ This behavior is defined by some metaclasses in runtime.
476
+
477
+ In runtime, this symbol in the namespace is just alias for
478
+ `builtins.object`.
479
+ """
480
+
481
+ ...
482
+
483
+ else:
484
+ _IUnknown_Base = object
485
+
486
+
487
+ class IUnknown(_IUnknown_Base, metaclass=_cominterface_meta):
488
+ """The most basic COM interface.
489
+
490
+ Each subclasses of IUnknown must define these class attributes:
491
+
492
+ _iid_ - a GUID instance defining the identifier of this interface
493
+
494
+ _methods_ - a list of methods for this interface.
495
+
496
+ The _methods_ list must in VTable order. Methods are specified
497
+ with STDMETHOD or COMMETHOD calls.
498
+ """
499
+
500
+ _case_insensitive_: ClassVar[bool] = False
501
+ _iid_: ClassVar[GUID] = GUID("{00000000-0000-0000-C000-000000000046}")
502
+ _methods_: ClassVar[List[_ComMemberSpec]] = [
503
+ STDMETHOD(HRESULT, "QueryInterface", [POINTER(GUID), POINTER(c_void_p)]),
504
+ STDMETHOD(c_ulong, "AddRef"),
505
+ STDMETHOD(c_ulong, "Release"),
506
+ ]
507
+
508
+ # NOTE: Why not `QueryInterface(T) -> _Pointer[T]`?
509
+ # Any static type checkers is not able to provide members of `T` from `_Pointer[T]`,
510
+ # regardless of the pointer is able to access members of contents in runtime.
511
+ # And if `isinstance(p, POINTER(T))` is `True`, then `isinstance(p, T)` is also `True`.
512
+ # So returning `T` is not a lie, and good way to know what members the class has.
513
+ def QueryInterface(
514
+ self, interface: Type[_T_IUnknown], iid: Optional[GUID] = None
515
+ ) -> _T_IUnknown:
516
+ """QueryInterface(interface) -> instance"""
517
+ p = POINTER(interface)()
518
+ if iid is None:
519
+ iid = interface._iid_
520
+ self.__com_QueryInterface(byref(iid), byref(p)) # type: ignore
521
+ clsid = self.__dict__.get("__clsid")
522
+ if clsid is not None:
523
+ p.__dict__["__clsid"] = clsid
524
+ return p # type: ignore
525
+
526
+ # these are only so that they get a docstring.
527
+ # XXX There should be other ways to install a docstring.
528
+ def AddRef(self) -> int:
529
+ """Increase the internal refcount by one and return it."""
530
+ return self.__com_AddRef() # type: ignore
531
+
532
+ def Release(self) -> int:
533
+ """Decrease the internal refcount by one and return it."""
534
+ return self.__com_Release() # type: ignore
535
+
536
+
537
+ ################################################################
@@ -0,0 +1,13 @@
1
+ from ctypes import pythonapi, py_object
2
+
3
+
4
+ pythonapi.PyInstanceMethod_New.argtypes = [py_object]
5
+ pythonapi.PyInstanceMethod_New.restype = py_object
6
+ PyInstanceMethod_Type = type(pythonapi.PyInstanceMethod_New(id))
7
+
8
+
9
+ def instancemethod(func, inst, cls):
10
+ mth = PyInstanceMethod_Type(func)
11
+ if inst is None:
12
+ return mth
13
+ return mth.__get__(inst)
@@ -1,7 +1,8 @@
1
1
  """SAFEARRAY api functions, data types, and constants."""
2
2
 
3
- from ctypes import *
4
- from ctypes.wintypes import *
3
+ from ctypes import c_uint, c_ushort, c_void_p, POINTER, Structure, WinDLL
4
+ from ctypes.wintypes import DWORD, LONG, UINT
5
+
5
6
  from comtypes import HRESULT, GUID
6
7
 
7
8
  ################################################################
@@ -0,0 +1,18 @@
1
+ import os
2
+ import sys
3
+
4
+
5
+ def _check_version(actual, tlib_cached_mtime=None):
6
+ from comtypes.tools.codegenerator import version as required
7
+
8
+ if actual != required:
9
+ raise ImportError("Wrong version")
10
+ if not hasattr(sys, "frozen"):
11
+ g = sys._getframe(1).f_globals
12
+ tlb_path = g.get("typelib_path")
13
+ try:
14
+ tlib_curr_mtime = os.stat(tlb_path).st_mtime
15
+ except (OSError, TypeError):
16
+ return
17
+ if not tlib_cached_mtime or abs(tlib_curr_mtime - tlib_cached_mtime) >= 1:
18
+ raise ImportError("Typelib different than module")
@@ -20,18 +20,20 @@ from typing import (
20
20
 
21
21
  from comtypes import BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD
22
22
  from comtypes.hresult import *
23
+ from comtypes._memberspec import _DispMemberSpec
23
24
  import comtypes.patcher
24
25
  import comtypes
25
26
 
26
27
  if TYPE_CHECKING:
27
28
  from comtypes import hints # type: ignore
28
-
29
- try:
30
29
  from comtypes import _safearray
31
- except (ImportError, AttributeError):
30
+ else:
31
+ try:
32
+ from comtypes import _safearray
33
+ except (ImportError, AttributeError):
32
34
 
33
- class _safearray(object):
34
- tagSAFEARRAY = None
35
+ class _safearray(object):
36
+ tagSAFEARRAY = None
35
37
 
36
38
 
37
39
  LCID = DWORD
@@ -404,6 +406,11 @@ class tagVARIANT(Structure):
404
406
  ri.AddRef()
405
407
  self._.pRecInfo = ri
406
408
  self._.pvRecord = cast(value, c_void_p)
409
+ elif isinstance(ref, _Pointer) and isinstance(
410
+ ref.contents, _safearray.tagSAFEARRAY
411
+ ):
412
+ self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
413
+ self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
407
414
  else:
408
415
  self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
409
416
  elif isinstance(value, _Pointer):
@@ -421,6 +428,15 @@ class tagVARIANT(Structure):
421
428
  ri.AddRef()
422
429
  self._.pRecInfo = ri
423
430
  self._.pvRecord = cast(value, c_void_p)
431
+ elif isinstance(ref, _safearray.tagSAFEARRAY):
432
+ obj = _midlSAFEARRAY(value._itemtype_).create(value.unpack())
433
+ memmove(byref(self._), byref(obj), sizeof(obj))
434
+ self.vt = VT_ARRAY | obj._vartype_
435
+ elif isinstance(ref, _Pointer) and isinstance(
436
+ ref.contents, _safearray.tagSAFEARRAY
437
+ ):
438
+ self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
439
+ self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
424
440
  else:
425
441
  self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
426
442
  else:
@@ -791,7 +807,7 @@ RawInvokeFunc = Callable[
791
807
 
792
808
 
793
809
  class IDispatch(IUnknown):
794
- _disp_methods_: ClassVar[List[comtypes._DispMemberSpec]]
810
+ _disp_methods_: ClassVar[List[_DispMemberSpec]]
795
811
  _GetTypeInfo: Callable[[int, int], IUnknown]
796
812
  __com_GetIDsOfNames: RawGetIDsOfNamesFunc
797
813
  __com_Invoke: RawInvokeFunc
@@ -262,7 +262,7 @@ def _get_known_namespaces() -> Tuple[
262
262
  Note:
263
263
  The interfaces that should be included in `__known_symbols__` should be limited
264
264
  to those that can be said to be bound to the design concept of COM, such as
265
- `IUnknown`, and those defined in `objidl` and `oaidl`.
265
+ `IUnknown`, `IDispatch` and `ITypeInfo`.
266
266
  `comtypes` does NOT aim to statically define all COM object interfaces in
267
267
  its repository.
268
268
  """
@@ -272,6 +272,7 @@ def _get_known_namespaces() -> Tuple[
272
272
  "comtypes.persist",
273
273
  "comtypes.typeinfo",
274
274
  "comtypes.automation",
275
+ "comtypes.stream",
275
276
  "comtypes",
276
277
  "ctypes.wintypes",
277
278
  "ctypes",