comtypes 1.4.7__zip → 1.4.9__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 (149) hide show
  1. {comtypes-1.4.7 → comtypes-1.4.9}/CHANGES.txt +39 -0
  2. {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +6 -4
  3. {comtypes-1.4.7 → comtypes-1.4.9}/README.md +5 -3
  4. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_memberspec.py +81 -9
  8. comtypes-1.4.9/comtypes/_meta.py +95 -0
  9. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_npsupport.py +2 -1
  10. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +1 -0
  11. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  12. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +21 -40
  13. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +88 -209
  14. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  15. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  16. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  17. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/__init__.py +21 -31
  18. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_code_cache.py +5 -4
  19. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  20. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_events.py +1 -2
  21. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_generate.py +9 -13
  22. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -7
  23. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  24. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/git.py +2 -2
  25. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hints.pyi +11 -19
  26. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/persist.py +7 -7
  27. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/safearray.py +12 -6
  28. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  29. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  30. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  31. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/register.py +62 -73
  32. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  33. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/shelllink.py +49 -67
  34. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.py +1 -1
  35. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +1 -1
  36. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -12
  37. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -1
  38. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  39. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -1
  40. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  41. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  42. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +1 -0
  43. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  44. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  45. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  46. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -6
  47. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  48. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -13
  49. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  50. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +8 -5
  51. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  52. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  53. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  54. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  55. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  56. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +10 -14
  57. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  58. comtypes-1.4.9/comtypes/test/test_stream.py +131 -0
  59. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +1 -1
  60. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +1 -0
  61. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -19
  62. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  63. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  64. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  65. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  66. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  67. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +97 -27
  68. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  69. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +9 -11
  70. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +33 -32
  71. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc.py +3 -8
  72. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/typeinfo.py +32 -47
  73. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/util.py +1 -0
  74. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  75. {comtypes-1.4.7 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +6 -4
  76. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  77. comtypes-1.4.9/pyproject.toml +55 -0
  78. comtypes-1.4.7/comtypes/_comobject.py +0 -834
  79. comtypes-1.4.7/comtypes/_idl_stuff.py +0 -67
  80. comtypes-1.4.7/comtypes/_meta.py +0 -70
  81. comtypes-1.4.7/comtypes/server/__init__.py +0 -69
  82. comtypes-1.4.7/comtypes/server/w_getopt.py +0 -75
  83. comtypes-1.4.7/comtypes/test/test_comserver.py +0 -239
  84. comtypes-1.4.7/comtypes/test/test_dispinterface.py +0 -138
  85. comtypes-1.4.7/comtypes/test/test_propputref.py +0 -40
  86. comtypes-1.4.7/comtypes/test/test_server.py +0 -348
  87. comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
  88. comtypes-1.4.7/pyproject.toml +0 -3
  89. {comtypes-1.4.7 → comtypes-1.4.9}/LICENSE.txt +0 -0
  90. {comtypes-1.4.7 → comtypes-1.4.9}/MANIFEST.in +0 -0
  91. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  92. /comtypes-1.4.7/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  93. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  94. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  95. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  96. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  97. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  98. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  99. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  100. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  101. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  102. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  103. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  104. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  105. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  106. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  107. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  108. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  109. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  110. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  111. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  112. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  113. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  114. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  115. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  116. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  117. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  118. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  119. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  120. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  121. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  122. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  123. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  124. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  125. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  126. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  127. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  128. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  129. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  130. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  131. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  132. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  133. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  134. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  135. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  136. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  137. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  138. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  139. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  140. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  141. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  142. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  143. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  144. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  145. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  146. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  147. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  148. {comtypes-1.4.7 → comtypes-1.4.9}/setup.cfg +0 -0
  149. {comtypes-1.4.7 → comtypes-1.4.9}/setup.py +0 -0
@@ -0,0 +1,507 @@
1
+ import logging
2
+ import queue
3
+ from _ctypes import COMError, CopyComPointer
4
+ from ctypes import (
5
+ POINTER,
6
+ FormatError,
7
+ Structure,
8
+ byref,
9
+ c_long,
10
+ c_void_p,
11
+ oledll,
12
+ pointer,
13
+ windll,
14
+ )
15
+ from typing import (
16
+ TYPE_CHECKING,
17
+ Any,
18
+ Callable,
19
+ ClassVar,
20
+ Dict,
21
+ List,
22
+ Optional,
23
+ Sequence,
24
+ Tuple,
25
+ Type,
26
+ TypeVar,
27
+ )
28
+ from typing import Union as _UnionT
29
+
30
+ from comtypes import GUID, IPersist, IUnknown, hresult
31
+ from comtypes._vtbl import _MethodFinder, create_dispimpl, create_vtbl_mapping
32
+ from comtypes.errorinfo import ISupportErrorInfo
33
+ from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2, ITypeInfo
34
+
35
+ if TYPE_CHECKING:
36
+ from ctypes import _CArgObject, _Pointer
37
+
38
+ from comtypes import hints # type: ignore
39
+
40
+ logger = logging.getLogger(__name__)
41
+ _debug = logger.debug
42
+
43
+ ################################################################
44
+ # COM object implementation
45
+
46
+ # so we don't have to import comtypes.automation
47
+ DISPATCH_METHOD = 1
48
+ DISPATCH_PROPERTYGET = 2
49
+ DISPATCH_PROPERTYPUT = 4
50
+ DISPATCH_PROPERTYPUTREF = 8
51
+
52
+ ################################################################
53
+
54
+ try:
55
+ _InterlockedIncrement = windll.kernel32.InterlockedIncrement
56
+ _InterlockedDecrement = windll.kernel32.InterlockedDecrement
57
+ except AttributeError:
58
+ import threading
59
+
60
+ _lock = threading.Lock()
61
+ _acquire = _lock.acquire
62
+ _release = _lock.release
63
+ # win 64 doesn't have these functions
64
+
65
+ def _InterlockedIncrement(ob: c_long) -> int:
66
+ _acquire()
67
+ refcnt = ob.value + 1
68
+ ob.value = refcnt
69
+ _release()
70
+ return refcnt
71
+
72
+ def _InterlockedDecrement(ob: c_long) -> int:
73
+ _acquire()
74
+ refcnt = ob.value - 1
75
+ ob.value = refcnt
76
+ _release()
77
+ return refcnt
78
+
79
+ else:
80
+ _InterlockedIncrement.argtypes = [POINTER(c_long)]
81
+ _InterlockedDecrement.argtypes = [POINTER(c_long)]
82
+ _InterlockedIncrement.restype = c_long
83
+ _InterlockedDecrement.restype = c_long
84
+
85
+
86
+ class LocalServer(object):
87
+ _queue: Optional[queue.Queue] = None
88
+
89
+ def run(self, classobjects: Sequence["hints.localserver.ClassFactory"]) -> None:
90
+ # Use windll instead of oledll so that we don't get an
91
+ # exception on a FAILED hresult:
92
+ hr = windll.ole32.CoInitialize(None)
93
+ if hresult.RPC_E_CHANGED_MODE == hr:
94
+ # we're running in MTA: no message pump needed
95
+ _debug("Server running in MTA")
96
+ self.run_mta()
97
+ else:
98
+ # we're running in STA: need a message pump
99
+ _debug("Server running in STA")
100
+ if hr >= 0:
101
+ # we need a matching CoUninitialize() call for a successful
102
+ # CoInitialize().
103
+ windll.ole32.CoUninitialize()
104
+ self.run_sta()
105
+
106
+ for obj in classobjects:
107
+ obj._revoke_class()
108
+
109
+ def run_sta(self) -> None:
110
+ from comtypes import messageloop
111
+
112
+ messageloop.run()
113
+
114
+ def run_mta(self) -> None:
115
+ self._queue = queue.Queue()
116
+ self._queue.get()
117
+
118
+ def Lock(self) -> None:
119
+ oledll.ole32.CoAddRefServerProcess()
120
+
121
+ def Unlock(self) -> None:
122
+ rc = oledll.ole32.CoReleaseServerProcess()
123
+ if rc == 0:
124
+ if self._queue:
125
+ self._queue.put(42)
126
+ else:
127
+ windll.user32.PostQuitMessage(0)
128
+
129
+
130
+ class InprocServer(object):
131
+ def __init__(self) -> None:
132
+ self.locks = c_long(0)
133
+
134
+ def Lock(self) -> None:
135
+ _InterlockedIncrement(self.locks)
136
+
137
+ def Unlock(self) -> None:
138
+ _InterlockedDecrement(self.locks)
139
+
140
+ def DllCanUnloadNow(self) -> int:
141
+ if self.locks.value:
142
+ return hresult.S_FALSE
143
+ if COMObject._instances_:
144
+ return hresult.S_FALSE
145
+ return hresult.S_OK
146
+
147
+
148
+ _T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown)
149
+
150
+
151
+ class COMObject(object):
152
+ _com_interfaces_: ClassVar[List[Type[IUnknown]]]
153
+ _outgoing_interfaces_: ClassVar[List[Type["hints.IDispatch"]]]
154
+ _instances_: ClassVar[Dict["COMObject", None]] = {}
155
+ _reg_clsid_: ClassVar[GUID]
156
+ _reg_typelib_: ClassVar[Tuple[str, int, int]]
157
+ __typelib: "hints.ITypeLib"
158
+ _com_pointers_: Dict[GUID, "_Pointer[_Pointer[Structure]]"]
159
+ _dispimpl_: Dict[Tuple[int, int], Callable[..., Any]]
160
+
161
+ def __new__(cls, *args, **kw):
162
+ self = super(COMObject, cls).__new__(cls)
163
+ if isinstance(self, c_void_p):
164
+ # We build the VTables only for direct instances of
165
+ # CoClass, not for POINTERs to CoClass.
166
+ return self
167
+ if hasattr(self, "_com_interfaces_"):
168
+ self.__prepare_comobject()
169
+ return self
170
+
171
+ def __prepare_comobject(self) -> None:
172
+ # When a CoClass instance is created, COM pointers to all
173
+ # interfaces are created. Also, the CoClass must be kept alive as
174
+ # until the COM reference count drops to zero, even if no Python
175
+ # code keeps a reference to the object.
176
+ #
177
+ # The _com_pointers_ instance variable maps string interface iids
178
+ # to C compatible COM pointers.
179
+ self._com_pointers_ = {}
180
+ # COM refcount starts at zero.
181
+ self._refcnt = c_long(0)
182
+
183
+ # Some interfaces have a default implementation in COMObject:
184
+ # - ISupportErrorInfo
185
+ # - IPersist (if the subclass has a _reg_clsid_ attribute)
186
+ # - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
187
+ # - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_
188
+ # attribute)
189
+ #
190
+ # Add these if they are not listed in _com_interfaces_.
191
+ interfaces = tuple(self._com_interfaces_)
192
+ if ISupportErrorInfo not in interfaces:
193
+ interfaces += (ISupportErrorInfo,)
194
+ if hasattr(self, "_reg_typelib_"):
195
+ from comtypes.typeinfo import LoadRegTypeLib
196
+
197
+ self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
198
+ if hasattr(self, "_reg_clsid_"):
199
+ if IProvideClassInfo not in interfaces:
200
+ interfaces += (IProvideClassInfo,)
201
+ if (
202
+ hasattr(self, "_outgoing_interfaces_")
203
+ and IProvideClassInfo2 not in interfaces
204
+ ):
205
+ interfaces += (IProvideClassInfo2,)
206
+ if hasattr(self, "_reg_clsid_"):
207
+ if IPersist not in interfaces:
208
+ interfaces += (IPersist,)
209
+ for itf in interfaces[::-1]:
210
+ self.__make_interface_pointer(itf)
211
+
212
+ def __make_interface_pointer(self, itf: Type[IUnknown]) -> None:
213
+ finder = self._get_method_finder_(itf)
214
+ iids, vtbl = create_vtbl_mapping(itf, finder)
215
+ for iid in iids:
216
+ self._com_pointers_[iid] = pointer(pointer(vtbl))
217
+ if hasattr(itf, "_disp_methods_"):
218
+ self._dispimpl_ = create_dispimpl(itf, finder)
219
+
220
+ def _get_method_finder_(self, itf: Type[IUnknown]) -> _MethodFinder:
221
+ # This method can be overridden to customize how methods are found.
222
+ return _MethodFinder(self)
223
+
224
+ ################################################################
225
+ # LocalServer / InprocServer stuff
226
+ __server__: _UnionT[None, InprocServer, LocalServer] = None
227
+
228
+ @staticmethod
229
+ def __run_inprocserver__() -> None:
230
+ if COMObject.__server__ is None:
231
+ COMObject.__server__ = InprocServer()
232
+ elif isinstance(COMObject.__server__, InprocServer):
233
+ pass
234
+ else:
235
+ raise RuntimeError("Wrong server type")
236
+
237
+ @staticmethod
238
+ def __run_localserver__(
239
+ classobjects: Sequence["hints.localserver.ClassFactory"],
240
+ ) -> None:
241
+ assert COMObject.__server__ is None
242
+ # XXX Decide whether we are in STA or MTA
243
+ server = COMObject.__server__ = LocalServer()
244
+ server.run(classobjects)
245
+ COMObject.__server__ = None
246
+
247
+ @staticmethod
248
+ def __keep__(obj: "COMObject") -> None:
249
+ COMObject._instances_[obj] = None
250
+ _debug("%d active COM objects: Added %r", len(COMObject._instances_), obj)
251
+ if COMObject.__server__:
252
+ COMObject.__server__.Lock()
253
+
254
+ @staticmethod
255
+ def __unkeep__(obj: "COMObject") -> None:
256
+ try:
257
+ del COMObject._instances_[obj]
258
+ except AttributeError:
259
+ _debug("? active COM objects: Removed %r", obj)
260
+ else:
261
+ _debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj)
262
+ _debug("Remaining: %s", list(COMObject._instances_.keys()))
263
+ if COMObject.__server__:
264
+ COMObject.__server__.Unlock()
265
+
266
+ #
267
+ ################################################################
268
+
269
+ #########################################################
270
+ # IUnknown methods implementations
271
+ def IUnknown_AddRef(
272
+ self,
273
+ this: Any,
274
+ __InterlockedIncrement: Callable[[c_long], int] = _InterlockedIncrement,
275
+ _debug=_debug,
276
+ ) -> int:
277
+ result = __InterlockedIncrement(self._refcnt)
278
+ if result == 1:
279
+ self.__keep__(self)
280
+ _debug("%r.AddRef() -> %s", self, result)
281
+ return result
282
+
283
+ def _final_release_(self) -> None:
284
+ """This method may be overridden in subclasses
285
+ to free allocated resources or so."""
286
+ pass
287
+
288
+ def IUnknown_Release(
289
+ self,
290
+ this: Any,
291
+ __InterlockedDecrement: Callable[[c_long], int] = _InterlockedDecrement,
292
+ _debug=_debug,
293
+ ) -> int:
294
+ # If this is called at COM shutdown, _InterlockedDecrement()
295
+ # must still be available, although module level variables may
296
+ # have been deleted already - so we supply it as default
297
+ # argument.
298
+ result = __InterlockedDecrement(self._refcnt)
299
+ _debug("%r.Release() -> %s", self, result)
300
+ if result == 0:
301
+ self._final_release_()
302
+ self.__unkeep__(self)
303
+ # Hm, why isn't this cleaned up by the cycle gc?
304
+ self._com_pointers_ = {}
305
+ return result
306
+
307
+ def IUnknown_QueryInterface(
308
+ self,
309
+ this: Any,
310
+ riid: "_Pointer[GUID]",
311
+ ppvObj: _UnionT[c_void_p, "_CArgObject"],
312
+ _debug=_debug,
313
+ ) -> int:
314
+ # XXX This is probably too slow.
315
+ # riid[0].hashcode() alone takes 33 us!
316
+ iid = riid[0]
317
+ ptr = self._com_pointers_.get(iid, None)
318
+ if ptr is not None:
319
+ # CopyComPointer(src, dst) calls AddRef!
320
+ _debug("%r.QueryInterface(%s) -> S_OK", self, iid)
321
+ return CopyComPointer(ptr, ppvObj)
322
+ _debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
323
+ return hresult.E_NOINTERFACE
324
+
325
+ def QueryInterface(self, interface: Type[_T_IUnknown]) -> _T_IUnknown:
326
+ "Query the object for an interface pointer"
327
+ # This method is NOT the implementation of
328
+ # IUnknown::QueryInterface, instead it is supposed to be
329
+ # called on an COMObject by user code. It allows to get COM
330
+ # interface pointers from COMObject instances.
331
+ ptr = self._com_pointers_.get(interface._iid_, None)
332
+ if ptr is None:
333
+ raise COMError(
334
+ hresult.E_NOINTERFACE,
335
+ FormatError(hresult.E_NOINTERFACE),
336
+ (None, None, None, 0, None),
337
+ )
338
+ # CopyComPointer(src, dst) calls AddRef!
339
+ result = POINTER(interface)()
340
+ CopyComPointer(ptr, byref(result))
341
+ return result # type: ignore
342
+
343
+ ################################################################
344
+ # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
345
+ def ISupportErrorInfo_InterfaceSupportsErrorInfo(
346
+ self, this: Any, riid: "_Pointer[GUID]"
347
+ ) -> int:
348
+ if riid[0] in self._com_pointers_:
349
+ return hresult.S_OK
350
+ return hresult.S_FALSE
351
+
352
+ ################################################################
353
+ # IProvideClassInfo::GetClassInfo implementation
354
+ def IProvideClassInfo_GetClassInfo(self) -> ITypeInfo:
355
+ try:
356
+ self.__typelib
357
+ except AttributeError:
358
+ raise WindowsError(hresult.E_NOTIMPL)
359
+ return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
360
+
361
+ ################################################################
362
+ # IProvideClassInfo2::GetGUID implementation
363
+
364
+ def IProvideClassInfo2_GetGUID(self, dwGuidKind: int) -> GUID:
365
+ # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
366
+ if dwGuidKind != 1:
367
+ raise WindowsError(hresult.E_INVALIDARG)
368
+ return self._outgoing_interfaces_[0]._iid_
369
+
370
+ ################################################################
371
+ # IDispatch methods
372
+ @property
373
+ def __typeinfo(self):
374
+ # XXX Looks like this better be a static property, set by the
375
+ # code that sets __typelib also...
376
+ iid = self._com_interfaces_[0]._iid_
377
+ return self.__typelib.GetTypeInfoOfGuid(iid)
378
+
379
+ def IDispatch_GetTypeInfoCount(self):
380
+ try:
381
+ self.__typelib
382
+ except AttributeError:
383
+ return 0
384
+ else:
385
+ return 1
386
+
387
+ def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo):
388
+ if itinfo != 0:
389
+ return hresult.DISP_E_BADINDEX
390
+ try:
391
+ ptinfo[0] = self.__typeinfo
392
+ return hresult.S_OK
393
+ except AttributeError:
394
+ return hresult.E_NOTIMPL
395
+
396
+ def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
397
+ # This call uses windll instead of oledll so that a failed
398
+ # call to DispGetIDsOfNames will return a HRESULT instead of
399
+ # raising an error.
400
+ try:
401
+ tinfo = self.__typeinfo
402
+ except AttributeError:
403
+ return hresult.E_NOTIMPL
404
+ return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId)
405
+
406
+ def IDispatch_Invoke(
407
+ self,
408
+ this,
409
+ dispIdMember,
410
+ riid,
411
+ lcid,
412
+ wFlags,
413
+ pDispParams,
414
+ pVarResult,
415
+ pExcepInfo,
416
+ puArgErr,
417
+ ):
418
+ try:
419
+ self._dispimpl_
420
+ except AttributeError:
421
+ try:
422
+ tinfo = self.__typeinfo
423
+ except AttributeError:
424
+ # Hm, we pretend to implement IDispatch, but have no
425
+ # typeinfo, and so cannot fulfill the contract. Should we
426
+ # better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
427
+ # clients call IDispatch_Invoke with 'known' DISPID_...'
428
+ # values, without going through GetIDsOfNames first.
429
+ return hresult.DISP_E_MEMBERNOTFOUND
430
+ # This call uses windll instead of oledll so that a failed
431
+ # call to DispInvoke will return a HRESULT instead of raising
432
+ # an error.
433
+ interface = self._com_interfaces_[0]
434
+ ptr = self._com_pointers_[interface._iid_]
435
+ return windll.oleaut32.DispInvoke(
436
+ ptr,
437
+ tinfo,
438
+ dispIdMember,
439
+ wFlags,
440
+ pDispParams,
441
+ pVarResult,
442
+ pExcepInfo,
443
+ puArgErr,
444
+ )
445
+
446
+ try:
447
+ # XXX Hm, wFlags should be considered a SET of flags...
448
+ mth = self._dispimpl_[(dispIdMember, wFlags)]
449
+ except KeyError:
450
+ return hresult.DISP_E_MEMBERNOTFOUND
451
+
452
+ # Unpack the parameters: It would be great if we could use the
453
+ # DispGetParam function - but we cannot since it requires that
454
+ # we pass a VARTYPE for each argument and we do not know that.
455
+ #
456
+ # Seems that n arguments have dispids (0, 1, ..., n-1).
457
+ # Unnamed arguments are packed into the DISPPARAMS array in
458
+ # reverse order (starting with the highest dispid), named
459
+ # arguments are packed in the order specified by the
460
+ # rgdispidNamedArgs array.
461
+ #
462
+ params = pDispParams[0]
463
+
464
+ if wFlags & (4 | 8):
465
+ # DISPATCH_PROPERTYPUT
466
+ # DISPATCH_PROPERTYPUTREF
467
+ #
468
+ # How are the parameters unpacked for propertyput
469
+ # operations with additional parameters? Can propput
470
+ # have additional args?
471
+ args = [
472
+ params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs)))
473
+ ]
474
+ # MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or
475
+ # DISPATCH_PROPERTYPUTREF is specified.
476
+ return mth(this, *args)
477
+
478
+ else:
479
+ # DISPATCH_METHOD
480
+ # DISPATCH_PROPERTYGET
481
+ # the positions of named arguments
482
+ #
483
+ # 2to3 has problems to translate 'range(...)[::-1]'
484
+ # correctly, so use 'list(range)[::-1]' instead (will be
485
+ # fixed in Python 3.1, probably):
486
+ named_indexes = [
487
+ params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs)
488
+ ]
489
+ # the positions of unnamed arguments
490
+ num_unnamed = params.cArgs - params.cNamedArgs
491
+ unnamed_indexes = list(reversed(list(range(num_unnamed))))
492
+ # It seems that this code calculates the indexes of the
493
+ # parameters in the params.rgvarg array correctly.
494
+ indexes = named_indexes + unnamed_indexes
495
+ args = [params.rgvarg[i].value for i in indexes]
496
+
497
+ if pVarResult and getattr(mth, "has_outargs", False):
498
+ args.append(pVarResult)
499
+ return mth(this, *args)
500
+
501
+ ################################################################
502
+ # IPersist interface
503
+ def IPersist_GetClassID(self) -> GUID:
504
+ return self._reg_clsid_
505
+
506
+
507
+ __all__ = ["COMObject"]
@@ -1,5 +1,5 @@
1
1
  import ctypes
2
- from typing import Any, NamedTuple
2
+ from typing import Any, Literal, NamedTuple
3
3
  from typing import Dict, List, Tuple, Type
4
4
  from typing import Optional, Union as _UnionT
5
5
  from typing import Callable, Iterator
@@ -43,7 +43,7 @@ def _unpack_argspec(
43
43
 
44
44
 
45
45
  def _resolve_argspec(
46
- items: Tuple[_ArgSpecElmType, ...]
46
+ items: Tuple[_ArgSpecElmType, ...],
47
47
  ) -> Tuple[Tuple[_ParamFlagType, ...], Tuple[Type[_CData], ...]]:
48
48
  """Unpacks and converts from argspec to paramflags and argtypes.
49
49
 
@@ -64,7 +64,7 @@ def _resolve_argspec(
64
64
  elif typ is ctypes.POINTER(VARIANT):
65
65
  defval = ctypes.pointer(VARIANT.missing)
66
66
  else:
67
- # msg = ("'optional' only allowed for VARIANT and VARIANT*, not for %s" % typ.__name__)
67
+ # msg = f"'optional' only allowed for VARIANT and VARIANT*, not for {typ.__name__}"
68
68
  # warnings.warn(msg, IDLWarning, stacklevel=2)
69
69
  defval = typ()
70
70
  if defval is _NOTHING:
@@ -92,7 +92,7 @@ class _ComMemberSpec(NamedTuple):
92
92
  class _DispMemberSpec(NamedTuple):
93
93
  """Specifier for a slot of dispinterface method or property."""
94
94
 
95
- what: str
95
+ what: Literal["DISPMETHOD", "DISPPROPERTY"]
96
96
  name: str
97
97
  idlflags: Tuple[_UnionT[str, int], ...]
98
98
  restype: Optional[Type[_CData]]
@@ -118,6 +118,78 @@ def _is_spec_prop(m: _MemberSpec):
118
118
  return any(f in ("propget", "propput", "propputref") for f in m.idlflags)
119
119
 
120
120
 
121
+ ################################################################
122
+ # IDL stuff
123
+
124
+
125
+ class helpstring(str):
126
+ "Specifies the helpstring for a COM method or property."
127
+
128
+
129
+ class defaultvalue(object):
130
+ "Specifies the default value for parameters marked optional."
131
+
132
+ def __init__(self, value):
133
+ self.value = value
134
+
135
+
136
+ class dispid(int):
137
+ "Specifies the DISPID of a method or property."
138
+
139
+
140
+ # XXX STDMETHOD, COMMETHOD, DISPMETHOD, and DISPPROPERTY should return
141
+ # instances with more methods or properties, and should not behave as an unpackable.
142
+
143
+
144
+ def STDMETHOD(restype, name, argtypes=()) -> _ComMemberSpec:
145
+ "Specifies a COM method slot without idlflags"
146
+ return _ComMemberSpec(restype, name, argtypes, None, (), None)
147
+
148
+
149
+ def DISPMETHOD(idlflags, restype, name, *argspec) -> _DispMemberSpec:
150
+ "Specifies a method of a dispinterface"
151
+ return _DispMemberSpec("DISPMETHOD", name, tuple(idlflags), restype, argspec)
152
+
153
+
154
+ def DISPPROPERTY(idlflags, proptype, name) -> _DispMemberSpec:
155
+ "Specifies a property of a dispinterface"
156
+ return _DispMemberSpec("DISPPROPERTY", name, tuple(idlflags), proptype, ())
157
+
158
+
159
+ # tuple(idlflags) is for the method itself: (dispid, 'readonly')
160
+
161
+ # sample generated code:
162
+ # DISPPROPERTY([5, 'readonly'], OLE_YSIZE_HIMETRIC, 'Height'),
163
+ # DISPMETHOD(
164
+ # [6], None, 'Render', ([], c_int, 'hdc'), ([], c_int, 'x'), ([], c_int, 'y')
165
+ # )
166
+
167
+
168
+ def COMMETHOD(idlflags, restype, methodname, *argspec) -> _ComMemberSpec:
169
+ """Specifies a COM method slot with idlflags.
170
+
171
+ XXX should explain the sematics of the arguments.
172
+ """
173
+ # collect all helpstring instances
174
+ # We should suppress docstrings when Python is started with -OO
175
+ # join them together(does this make sense?) and replace by None if empty.
176
+ helptext = "".join(t for t in idlflags if isinstance(t, helpstring)) or None
177
+ paramflags, argtypes = _resolve_argspec(argspec)
178
+ if "propget" in idlflags:
179
+ name = f"_get_{methodname}"
180
+ elif "propput" in idlflags:
181
+ name = f"_set_{methodname}"
182
+ elif "propputref" in idlflags:
183
+ name = f"_setref_{methodname}"
184
+ else:
185
+ name = methodname
186
+ return _ComMemberSpec(
187
+ restype, name, argtypes, paramflags, tuple(idlflags), helptext
188
+ )
189
+
190
+
191
+ ################################################################
192
+
121
193
  _PropFunc = Optional[Callable[..., Any]]
122
194
  _DocType = Optional[str]
123
195
 
@@ -310,7 +382,7 @@ class PropertyGenerator(object):
310
382
  # Hm, must be a descriptor where the __get__ method
311
383
  # returns a bound object having __getitem__ and
312
384
  # __setitem__ methods.
313
- prop = named_property("%s.%s" % (self._cls_name, name), fget, fset, doc)
385
+ prop = named_property(f"{self._cls_name}.{name}", fget, fset, doc)
314
386
  yield (name, prop)
315
387
 
316
388
  def to_propget_keys(self, m: _MemberSpec) -> Tuple[str, _DocType, int]:
@@ -360,7 +432,7 @@ class DispPropertyGenerator(PropertyGenerator):
360
432
 
361
433
 
362
434
  class ComMemberGenerator(object):
363
- def __init__(self, cls_name: str, vtbl_offset: int, iid: comtypes.GUID) -> None:
435
+ def __init__(self, cls_name: str, vtbl_offset: int, iid: "comtypes.GUID") -> None:
364
436
  self._vtbl_offset = vtbl_offset
365
437
  self._iid = iid
366
438
  self._props = ComPropertyGenerator(cls_name)
@@ -533,11 +605,11 @@ class bound_named_property(object):
533
605
  self.fset(self.instance, index, value)
534
606
 
535
607
  def __repr__(self):
536
- return "<bound_named_property %r at %x>" % (self.name, id(self))
608
+ return f"<bound_named_property {self.name!r} at {id(self):x}>"
537
609
 
538
610
  def __iter__(self):
539
611
  """Explicitly disallow iteration."""
540
- msg = "%r is not iterable" % self.name
612
+ msg = f"{self.name!r} is not iterable"
541
613
  raise TypeError(msg)
542
614
 
543
615
 
@@ -558,4 +630,4 @@ class named_property(object):
558
630
  raise AttributeError("Unsettable attribute")
559
631
 
560
632
  def __repr__(self):
561
- return "<named_property %r at %x>" % (self.name, id(self))
633
+ return f"<named_property {self.name!r} at {id(self):x}>"