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