comtypes 1.4.8__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 (146) hide show
  1. {comtypes-1.4.8 → comtypes-1.4.9}/CHANGES.txt +21 -0
  2. {comtypes-1.4.8/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +2 -2
  3. {comtypes-1.4.8 → comtypes-1.4.9}/README.md +1 -1
  4. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_memberspec.py +80 -8
  8. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  9. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +1 -1
  10. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +25 -171
  11. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  12. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  13. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  14. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_code_cache.py +4 -4
  15. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  16. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_events.py +1 -1
  17. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_generate.py +4 -8
  18. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -2
  19. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  20. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/git.py +1 -2
  21. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hints.pyi +7 -15
  22. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/safearray.py +10 -0
  23. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  24. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  25. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  26. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/register.py +61 -73
  27. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  28. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/shelllink.py +3 -26
  29. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -11
  30. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  31. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  32. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  33. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  34. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  35. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  36. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -4
  37. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  38. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -12
  39. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  40. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +7 -4
  41. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  42. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  43. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  44. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  45. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  46. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  47. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -17
  48. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  49. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  50. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  51. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  52. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  53. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  54. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +7 -7
  55. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc.py +1 -6
  56. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/typeinfo.py +11 -22
  57. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  58. {comtypes-1.4.8 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +2 -2
  59. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  60. {comtypes-1.4.8 → comtypes-1.4.9}/pyproject.toml +1 -0
  61. comtypes-1.4.8/comtypes/_comobject.py +0 -833
  62. comtypes-1.4.8/comtypes/_idl_stuff.py +0 -67
  63. comtypes-1.4.8/comtypes/server/__init__.py +0 -70
  64. comtypes-1.4.8/comtypes/server/w_getopt.py +0 -75
  65. comtypes-1.4.8/comtypes/test/test_comserver.py +0 -239
  66. comtypes-1.4.8/comtypes/test/test_dispinterface.py +0 -137
  67. comtypes-1.4.8/comtypes/test/test_propputref.py +0 -40
  68. comtypes-1.4.8/comtypes/test/test_server.py +0 -354
  69. {comtypes-1.4.8 → comtypes-1.4.9}/LICENSE.txt +0 -0
  70. {comtypes-1.4.8 → comtypes-1.4.9}/MANIFEST.in +0 -0
  71. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_meta.py +0 -0
  72. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_npsupport.py +0 -0
  73. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +0 -0
  74. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  75. /comtypes-1.4.8/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  76. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  77. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  78. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/__init__.py +0 -0
  79. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  80. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  81. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  82. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  83. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  84. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  85. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/persist.py +0 -0
  86. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  87. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  88. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  89. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  90. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.py +0 -0
  91. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  92. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  93. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +0 -0
  94. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  95. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -0
  96. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  97. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  98. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  99. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  100. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  101. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  102. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  103. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  104. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -0
  105. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  106. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +0 -0
  107. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  108. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  109. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  110. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  111. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  112. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  113. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  114. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  115. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  116. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  117. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  118. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  119. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  120. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  121. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  122. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  123. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  124. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  125. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  126. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +0 -0
  127. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  128. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_stream.py +0 -0
  129. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  130. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +0 -0
  131. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  132. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +0 -0
  133. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  134. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  135. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  136. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  137. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  138. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +0 -0
  139. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +0 -0
  140. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  141. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/util.py +0 -0
  142. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  143. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  144. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  145. {comtypes-1.4.8 → comtypes-1.4.9}/setup.cfg +0 -0
  146. {comtypes-1.4.8 → comtypes-1.4.9}/setup.py +0 -0
@@ -0,0 +1,448 @@
1
+ import logging
2
+ from _ctypes import COMError
3
+ from ctypes import WINFUNCTYPE, Structure, c_void_p
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Callable,
8
+ Dict,
9
+ Iterator,
10
+ List,
11
+ Optional,
12
+ Sequence,
13
+ Tuple,
14
+ Type,
15
+ )
16
+ from typing import Union as _UnionT
17
+
18
+ import comtypes
19
+ from comtypes import GUID, IUnknown, hresult
20
+ from comtypes._memberspec import _encode_idl
21
+ from comtypes.errorinfo import ReportError, ReportException
22
+
23
+ if TYPE_CHECKING:
24
+ from ctypes import _FuncPointer
25
+
26
+ from comtypes import hints # type: ignore
27
+ from comtypes._memberspec import _ArgSpecElmType, _DispMemberSpec, _ParamFlagType
28
+
29
+ logger = logging.getLogger(__name__)
30
+ _debug = logger.debug
31
+ _warning = logger.warning
32
+ _error = logger.error
33
+
34
+ ################################################################
35
+ # COM object implementation
36
+
37
+ # so we don't have to import comtypes.automation
38
+ DISPATCH_METHOD = 1
39
+ DISPATCH_PROPERTYGET = 2
40
+ DISPATCH_PROPERTYPUT = 4
41
+ DISPATCH_PROPERTYPUTREF = 8
42
+
43
+
44
+ class E_NotImplemented(Exception):
45
+ """COM method is not implemented"""
46
+
47
+
48
+ def HRESULT_FROM_WIN32(errcode: Optional[int]) -> int:
49
+ "Convert a Windows error code into a HRESULT value."
50
+ if errcode is None:
51
+ return 0x80000000
52
+ if errcode & 0x80000000:
53
+ return errcode
54
+ return (errcode & 0xFFFF) | 0x80070000
55
+
56
+
57
+ def winerror(exc: Exception) -> int:
58
+ """Return the windows error code from a WindowsError or COMError
59
+ instance."""
60
+ if isinstance(exc, COMError):
61
+ return exc.hresult
62
+ elif isinstance(exc, WindowsError):
63
+ code = exc.winerror
64
+ if isinstance(code, int):
65
+ return code
66
+ # Sometimes, a WindowsError instance has no error code. An access
67
+ # violation raised by ctypes has only text, for example. In this
68
+ # cases we return a generic error code.
69
+ return hresult.E_FAIL
70
+ raise TypeError(
71
+ f"Expected comtypes.COMERROR or WindowsError instance, got {type(exc).__name__}"
72
+ )
73
+
74
+
75
+ def _do_implement(interface_name: str, method_name: str) -> Callable[..., int]:
76
+ def _not_implemented(*args):
77
+ """Return E_NOTIMPL because the method is not implemented."""
78
+ _debug("unimplemented method %s_%s called", interface_name, method_name)
79
+ return hresult.E_NOTIMPL
80
+
81
+ return _not_implemented
82
+
83
+
84
+ def catch_errors(
85
+ obj: "hints.COMObject",
86
+ mth: Callable[..., Any],
87
+ paramflags: Optional[Tuple["_ParamFlagType", ...]],
88
+ interface: Type[IUnknown],
89
+ mthname: str,
90
+ ) -> Callable[..., Any]:
91
+ clsid = getattr(obj, "_reg_clsid_", None)
92
+
93
+ def call_with_this(*args, **kw):
94
+ try:
95
+ result = mth(*args, **kw)
96
+ except comtypes.ReturnHRESULT as err:
97
+ (hr, text) = err.args
98
+ return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hr)
99
+ except (COMError, WindowsError) as details:
100
+ _error(
101
+ "Exception in %s.%s implementation:",
102
+ interface.__name__,
103
+ mthname,
104
+ exc_info=True,
105
+ )
106
+ return HRESULT_FROM_WIN32(winerror(details))
107
+ except E_NotImplemented:
108
+ _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
109
+ return hresult.E_NOTIMPL
110
+ except:
111
+ _error(
112
+ "Exception in %s.%s implementation:",
113
+ interface.__name__,
114
+ mthname,
115
+ exc_info=True,
116
+ )
117
+ return ReportException(hresult.E_FAIL, interface._iid_, clsid=clsid)
118
+ if result is None:
119
+ return hresult.S_OK
120
+ return result
121
+
122
+ if paramflags is None:
123
+ has_outargs = False
124
+ else:
125
+ has_outargs = bool([x[0] for x in paramflags if x[0] & 2])
126
+ call_with_this.has_outargs = has_outargs
127
+ return call_with_this
128
+
129
+
130
+ ################################################################
131
+
132
+
133
+ def hack(
134
+ inst: "hints.COMObject",
135
+ mth: Callable[..., Any],
136
+ paramflags: Optional[Tuple["_ParamFlagType", ...]],
137
+ interface: Type[IUnknown],
138
+ mthname: str,
139
+ ) -> Callable[..., Any]:
140
+ if paramflags is None:
141
+ return catch_errors(inst, mth, paramflags, interface, mthname)
142
+ code = mth.__code__
143
+ if code.co_varnames[1:2] == ("this",):
144
+ return catch_errors(inst, mth, paramflags, interface, mthname)
145
+ dirflags = [f[0] for f in paramflags]
146
+ # An argument is an input arg either if flags are NOT set in the
147
+ # idl file, or if the flags contain 'in'. In other words, the
148
+ # direction flag is either exactly '0' or has the '1' bit set:
149
+ # Output arguments have flag '2'
150
+
151
+ args_out_idx = []
152
+ args_in_idx = []
153
+ for i, a in enumerate(dirflags):
154
+ if a & 2:
155
+ args_out_idx.append(i)
156
+ if a & 1 or a == 0:
157
+ args_in_idx.append(i)
158
+ args_out = len(args_out_idx)
159
+
160
+ ## XXX Remove this:
161
+ # if args_in != code.co_argcount - 1:
162
+ # return catch_errors(inst, mth, interface, mthname)
163
+
164
+ clsid = getattr(inst, "_reg_clsid_", None)
165
+
166
+ def call_without_this(this, *args):
167
+ # Method implementations could check for and return E_POINTER
168
+ # themselves. Or an error will be raised when
169
+ # 'outargs[i][0] = value' is executed.
170
+ # for a in outargs:
171
+ # if not a:
172
+ # return E_POINTER
173
+
174
+ # make argument list for handler by index array built above
175
+ inargs = []
176
+ for a in args_in_idx:
177
+ inargs.append(args[a])
178
+ try:
179
+ result = mth(*inargs)
180
+ if args_out == 1:
181
+ args[args_out_idx[0]][0] = result
182
+ elif args_out != 0:
183
+ if len(result) != args_out:
184
+ msg = f"Method should have returned a {args_out}-tuple"
185
+ raise ValueError(msg)
186
+ for i, value in enumerate(result):
187
+ args[args_out_idx[i]][0] = value
188
+ except comtypes.ReturnHRESULT as err:
189
+ (hr, text) = err.args
190
+ return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hr)
191
+ except COMError as err:
192
+ (hr, text, details) = err.args
193
+ _error(
194
+ "Exception in %s.%s implementation:",
195
+ interface.__name__,
196
+ mthname,
197
+ exc_info=True,
198
+ )
199
+ try:
200
+ descr, source, helpfile, helpcontext, progid = details
201
+ except (ValueError, TypeError):
202
+ msg = str(details)
203
+ else:
204
+ msg = f"{source}: {descr}"
205
+ hr = HRESULT_FROM_WIN32(hr)
206
+ return ReportError(msg, iid=interface._iid_, clsid=clsid, hresult=hr)
207
+ except WindowsError as details:
208
+ _error(
209
+ "Exception in %s.%s implementation:",
210
+ interface.__name__,
211
+ mthname,
212
+ exc_info=True,
213
+ )
214
+ hr = HRESULT_FROM_WIN32(winerror(details))
215
+ return ReportException(hr, interface._iid_, clsid=clsid)
216
+ except E_NotImplemented:
217
+ _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
218
+ return hresult.E_NOTIMPL
219
+ except:
220
+ _error(
221
+ "Exception in %s.%s implementation:",
222
+ interface.__name__,
223
+ mthname,
224
+ exc_info=True,
225
+ )
226
+ return ReportException(hresult.E_FAIL, interface._iid_, clsid=clsid)
227
+ return hresult.S_OK
228
+
229
+ if args_out:
230
+ call_without_this.has_outargs = True
231
+ return call_without_this
232
+
233
+
234
+ class _MethodFinder(object):
235
+ def __init__(self, inst: "hints.COMObject") -> None:
236
+ self.inst = inst
237
+ # map lower case names to names with correct spelling.
238
+ self.names = dict([(n.lower(), n) for n in dir(inst)])
239
+
240
+ def get_impl(
241
+ self,
242
+ interface: Type[IUnknown],
243
+ mthname: str,
244
+ paramflags: Optional[Tuple["_ParamFlagType", ...]],
245
+ idlflags: Tuple[_UnionT[str, int], ...],
246
+ ) -> Callable[..., Any]:
247
+ mth = self.find_impl(interface, mthname, paramflags, idlflags)
248
+ if mth is None:
249
+ return _do_implement(interface.__name__, mthname)
250
+ return hack(self.inst, mth, paramflags, interface, mthname)
251
+
252
+ def find_method(self, fq_name: str, mthname: str) -> Callable[..., Any]:
253
+ # Try to find a method, first with the fully qualified name
254
+ # ('IUnknown_QueryInterface'), if that fails try the simple
255
+ # name ('QueryInterface')
256
+ try:
257
+ return getattr(self.inst, fq_name)
258
+ except AttributeError:
259
+ pass
260
+ return getattr(self.inst, mthname)
261
+
262
+ def find_impl(
263
+ self,
264
+ interface: Type[IUnknown],
265
+ mthname: str,
266
+ paramflags: Optional[Tuple["_ParamFlagType", ...]],
267
+ idlflags: Tuple[_UnionT[str, int], ...],
268
+ ) -> Optional[Callable[..., Any]]:
269
+ fq_name = f"{interface.__name__}_{mthname}"
270
+ if interface._case_insensitive_:
271
+ # simple name, like 'QueryInterface'
272
+ mthname = self.names.get(mthname.lower(), mthname)
273
+ # qualified name, like 'IUnknown_QueryInterface'
274
+ fq_name = self.names.get(fq_name.lower(), fq_name)
275
+
276
+ try:
277
+ return self.find_method(fq_name, mthname)
278
+ except AttributeError:
279
+ pass
280
+ propname = mthname[5:] # strip the '_get_' or '_set' prefix
281
+ if interface._case_insensitive_:
282
+ propname = self.names.get(propname.lower(), propname)
283
+ # propput and propget is done with 'normal' attribute access,
284
+ # but only for COM properties that do not take additional
285
+ # arguments:
286
+
287
+ if "propget" in idlflags and len(paramflags) == 1:
288
+ return self.getter(propname)
289
+ if "propput" in idlflags and len(paramflags) == 1:
290
+ return self.setter(propname)
291
+ _debug("%r: %s.%s not implemented", self.inst, interface.__name__, mthname)
292
+ return None
293
+
294
+ def setter(self, propname: str) -> Callable[[Any], Any]:
295
+ #
296
+ def set(self, value):
297
+ try:
298
+ # XXX this may not be correct is the object implements
299
+ # _get_PropName but not _set_PropName
300
+ setattr(self, propname, value)
301
+ except AttributeError:
302
+ raise E_NotImplemented()
303
+
304
+ return comtypes.instancemethod(set, self.inst, type(self.inst))
305
+
306
+ def getter(self, propname: str) -> Callable[[], Any]:
307
+ def get(self):
308
+ try:
309
+ return getattr(self, propname)
310
+ except AttributeError:
311
+ raise E_NotImplemented()
312
+
313
+ return comtypes.instancemethod(get, self.inst, type(self.inst))
314
+
315
+
316
+ def _create_vtbl_type(
317
+ fields: Tuple[Tuple[str, Type["_FuncPointer"]], ...], itf: Type[IUnknown]
318
+ ) -> Type[Structure]:
319
+ try:
320
+ return _vtbl_types[fields]
321
+ except KeyError:
322
+
323
+ class Vtbl(Structure):
324
+ _fields_ = fields
325
+
326
+ Vtbl.__name__ = f"Vtbl_{itf.__name__}"
327
+ _vtbl_types[fields] = Vtbl
328
+ return Vtbl
329
+
330
+
331
+ # Ugh. Another type cache to avoid leaking types.
332
+ _vtbl_types: Dict[Tuple[Tuple[str, Type["_FuncPointer"]], ...], Type[Structure]] = {}
333
+
334
+ ################################################################
335
+
336
+
337
+ def create_vtbl_mapping(
338
+ itf: Type[IUnknown], finder: _MethodFinder
339
+ ) -> Tuple[Sequence[GUID], Structure]:
340
+ methods: List[Callable[..., Any]] = [] # method implementations
341
+ fields: List[Tuple[str, Type["_FuncPointer"]]] = [] # virtual function table
342
+ iids: List[GUID] = [] # interface identifiers.
343
+ # iterate over interface inheritance in reverse order to build the
344
+ # virtual function table, and leave out the 'object' base class.
345
+ for interface in itf.__mro__[-2::-1]:
346
+ iids.append(interface._iid_)
347
+ for m in interface._methods_:
348
+ restype, mthname, argtypes, paramflags, idlflags, helptext = m
349
+ proto = WINFUNCTYPE(restype, c_void_p, *argtypes)
350
+ fields.append((mthname, proto))
351
+ mth = finder.get_impl(interface, mthname, paramflags, idlflags)
352
+ methods.append(proto(mth))
353
+ Vtbl = _create_vtbl_type(tuple(fields), itf)
354
+ vtbl = Vtbl(*methods)
355
+ return (iids, vtbl)
356
+
357
+
358
+ def create_dispimpl(
359
+ itf: Type[IUnknown], finder: _MethodFinder
360
+ ) -> Dict[Tuple[int, int], Callable[..., Any]]:
361
+ dispimpl: Dict[Tuple[int, int], Callable[..., Any]] = {}
362
+ for m in itf._disp_methods_:
363
+ #################
364
+ # What we have:
365
+ #
366
+ # restypes is a ctypes type or None
367
+ # argspec is seq. of (['in'], paramtype, paramname) tuples (or
368
+ # lists?)
369
+ #################
370
+ # What we need:
371
+ #
372
+ # idlflags must contain 'propget', 'propset' and so on:
373
+ # Must be constructed by converting disptype
374
+ #
375
+ # paramflags must be a sequence
376
+ # of (F_IN|F_OUT|F_RETVAL, paramname[, default-value]) tuples
377
+ #
378
+ # comtypes has this function which helps:
379
+ # def _encode_idl(names):
380
+ # # convert to F_xxx and sum up "in", "out",
381
+ # # "retval" values found in _PARAMFLAGS, ignoring
382
+ # # other stuff.
383
+ # return sum([_PARAMFLAGS.get(n, 0) for n in names])
384
+ #################
385
+
386
+ if m.what == "DISPMETHOD":
387
+ dispimpl.update(_make_dispmthentry(itf, finder, m))
388
+ elif m.what == "DISPPROPERTY":
389
+ dispimpl.update(_make_disppropentry(itf, finder, m))
390
+ return dispimpl
391
+
392
+
393
+ def _make_dispmthentry(
394
+ itf: Type[IUnknown], finder: _MethodFinder, m: "_DispMemberSpec"
395
+ ) -> Iterator[Tuple[Tuple[int, int], Callable[..., Any]]]:
396
+ _, mthname, idlflags, restype, argspec = m
397
+ if "propget" in idlflags:
398
+ invkind = DISPATCH_PROPERTYGET
399
+ mthname = f"_get_{mthname}"
400
+ elif "propput" in idlflags:
401
+ invkind = DISPATCH_PROPERTYPUT
402
+ mthname = f"_set_{mthname}"
403
+ elif "propputref" in idlflags:
404
+ invkind = DISPATCH_PROPERTYPUTREF
405
+ mthname = f"_setref_{mthname}"
406
+ else:
407
+ invkind = DISPATCH_METHOD
408
+ if restype:
409
+ argspec = argspec + ((["out"], restype, ""),)
410
+ yield from _make_dispentry(finder, itf, mthname, idlflags, argspec, invkind)
411
+
412
+
413
+ def _make_disppropentry(
414
+ itf: Type[IUnknown], finder: _MethodFinder, m: "_DispMemberSpec"
415
+ ) -> Iterator[Tuple[Tuple[int, int], Callable[..., Any]]]:
416
+ _, mthname, idlflags, restype, argspec = m
417
+ # DISPPROPERTY have implicit "out"
418
+ if restype:
419
+ argspec += ((["out"], restype, ""),)
420
+ yield from _make_dispentry(
421
+ finder, itf, f"_get_{mthname}", idlflags, argspec, DISPATCH_PROPERTYGET
422
+ )
423
+ if "readonly" not in idlflags:
424
+ yield from _make_dispentry(
425
+ finder, itf, f"_set_{mthname}", idlflags, argspec, DISPATCH_PROPERTYPUT
426
+ )
427
+ # Add DISPATCH_PROPERTYPUTREF also?
428
+
429
+
430
+ def _make_dispentry(
431
+ finder: _MethodFinder,
432
+ interface: Type[IUnknown],
433
+ mthname: str,
434
+ idlflags: Tuple[_UnionT[str, int], ...],
435
+ argspec: Tuple["_ArgSpecElmType", ...],
436
+ invkind: int,
437
+ ) -> Iterator[Tuple[Tuple[int, int], Callable[..., Any]]]:
438
+ # We build a _dispmap_ entry now that maps invkind and dispid to
439
+ # implementations that the finder finds; IDispatch_Invoke will later call it.
440
+ paramflags = tuple(((_encode_idl(x[0]), x[1]) + tuple(x[3:])) for x in argspec)
441
+ # XXX can the dispid be at a different index? Check codegenerator.
442
+ dispid = idlflags[0]
443
+ impl = finder.get_impl(interface, mthname, paramflags, idlflags) # type: ignore
444
+ yield ((dispid, invkind), impl) # type: ignore
445
+ # invkind is really a set of flags; we allow both DISPATCH_METHOD and
446
+ # DISPATCH_PROPERTYGET (win32com uses this, maybe other languages too?)
447
+ if invkind in (DISPATCH_METHOD, DISPATCH_PROPERTYGET):
448
+ yield ((dispid, DISPATCH_METHOD | DISPATCH_PROPERTYGET), impl) # type: ignore
@@ -2,31 +2,26 @@
2
2
  import array
3
3
  import datetime
4
4
  import decimal
5
- import sys
5
+ from _ctypes import COMError, CopyComPointer
6
6
  from ctypes import *
7
- from ctypes import _Pointer, Array as _CArrayType
8
- from _ctypes import CopyComPointer
7
+ from ctypes import Array as _CArrayType
8
+ from ctypes import _Pointer
9
9
  from ctypes.wintypes import DWORD, LONG, UINT, VARIANT_BOOL, WCHAR, WORD
10
- from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Type
10
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Type
11
11
 
12
- from comtypes import _CData, BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD
13
- from comtypes.hresult import *
14
- from comtypes._memberspec import _DispMemberSpec
15
- import comtypes.patcher
16
12
  import comtypes
13
+ import comtypes.patcher
14
+ from comtypes import BSTR, COMMETHOD, GUID, IID, STDMETHOD, IUnknown, _CData, _safearray
15
+ from comtypes import hresult as hresult
16
+ from comtypes.safearray import _midlSAFEARRAY
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from ctypes import _CArgObject
20
+
20
21
  from comtypes import hints # type: ignore
21
- from comtypes import _safearray
22
+ from comtypes._memberspec import _DispMemberSpec
22
23
  else:
23
24
  _CArgObject = type(byref(c_int()))
24
- try:
25
- from comtypes import _safearray
26
- except (ImportError, AttributeError):
27
-
28
- class _safearray(object):
29
- tagSAFEARRAY = None
30
25
 
31
26
 
32
27
  LCID = DWORD
@@ -212,14 +207,14 @@ class tagVARIANT(Structure):
212
207
 
213
208
  def __repr__(self):
214
209
  if self.vt & VT_BYREF:
215
- return "VARIANT(vt=0x%x, byref(%r))" % (self.vt, self[0])
210
+ return f"VARIANT(vt=0x{self.vt:x}, byref({self[0]!r}))"
216
211
  elif self is type(self).null:
217
212
  return "VARIANT.null"
218
213
  elif self is type(self).empty:
219
214
  return "VARIANT.empty"
220
215
  elif self is type(self).missing:
221
216
  return "VARIANT.missing"
222
- return "VARIANT(vt=0x%x, %r)" % (self.vt, self.value)
217
+ return f"VARIANT(vt=0x{self.vt:x}, {self.value!r})"
223
218
 
224
219
  @classmethod
225
220
  def from_param(cls, value):
@@ -428,7 +423,7 @@ class tagVARIANT(Structure):
428
423
  else:
429
424
  self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
430
425
  else:
431
- raise TypeError("Cannot put %r in VARIANT" % value)
426
+ raise TypeError(f"Cannot put {value!r} in VARIANT")
432
427
  # buffer -> SAFEARRAY of VT_UI1 ?
433
428
 
434
429
  # c:/sf/pywin32/com/win32com/src/oleargs.cpp 197
@@ -524,7 +519,7 @@ class tagVARIANT(Structure):
524
519
  typ = _vartype_to_ctype[self.vt & ~VT_ARRAY]
525
520
  return cast(self._.pparray, _midlSAFEARRAY(typ)).unpack()
526
521
  else:
527
- raise NotImplementedError("typecode %d = 0x%x)" % (vt, vt))
522
+ raise NotImplementedError(f"typecode {vt} = 0x{vt:x})")
528
523
 
529
524
  def __getitem__(self, index):
530
525
  if index != 0:
@@ -714,17 +709,16 @@ class tagEXCEPINFO(Structure):
714
709
  scode: int
715
710
 
716
711
  def __repr__(self):
717
- return "<EXCEPINFO %s>" % (
718
- (
719
- self.wCode,
720
- self.bstrSource,
721
- self.bstrDescription,
722
- self.bstrHelpFile,
723
- self.dwHelpContext,
724
- self.pfnDeferredFillIn,
725
- self.scode,
726
- ),
712
+ info = (
713
+ self.wCode,
714
+ self.bstrSource,
715
+ self.bstrDescription,
716
+ self.bstrHelpFile,
717
+ self.dwHelpContext,
718
+ self.pfnDeferredFillIn,
719
+ self.scode,
727
720
  )
721
+ return f"<EXCEPINFO {info}>"
728
722
 
729
723
 
730
724
  tagEXCEPINFO._fields_ = [
@@ -775,7 +769,7 @@ DISPID_COLLECT = -8
775
769
 
776
770
 
777
771
  class IDispatch(IUnknown):
778
- _disp_methods_: ClassVar[List[_DispMemberSpec]]
772
+ _disp_methods_: ClassVar[List["_DispMemberSpec"]]
779
773
 
780
774
  _iid_ = GUID("{00020400-0000-0000-C000-000000000046}")
781
775
  _methods_ = [
@@ -812,6 +806,10 @@ class IDispatch(IUnknown):
812
806
  ),
813
807
  ]
814
808
 
809
+ if TYPE_CHECKING:
810
+
811
+ def GetTypeInfoCount(self) -> int: ...
812
+
815
813
  def GetTypeInfo(self, index: int, lcid: int = 0) -> "hints.ITypeInfo":
816
814
  """Return type information. Index 0 specifies typeinfo for IDispatch"""
817
815
  import comtypes.typeinfo
@@ -894,8 +892,8 @@ class IDispatch(IUnknown):
894
892
  byref(argerr),
895
893
  )
896
894
  except COMError as err:
897
- (hresult, text, details) = err.args
898
- if hresult == DISP_E_EXCEPTION:
895
+ (hr, text, details) = err.args
896
+ if hr == hresult.DISP_E_EXCEPTION:
899
897
  details = (
900
898
  excepinfo.bstrDescription,
901
899
  excepinfo.bstrSource,
@@ -903,24 +901,22 @@ class IDispatch(IUnknown):
903
901
  excepinfo.dwHelpContext,
904
902
  excepinfo.scode,
905
903
  )
906
- raise COMError(hresult, text, details)
907
- elif hresult == DISP_E_PARAMNOTFOUND:
904
+ raise COMError(hr, text, details)
905
+ elif hr == hresult.DISP_E_PARAMNOTFOUND:
908
906
  # MSDN says: You get the error DISP_E_PARAMNOTFOUND
909
907
  # when you try to set a property and you have not
910
908
  # initialized the cNamedArgs and rgdispidNamedArgs
911
909
  # elements of your DISPPARAMS structure.
912
910
  #
913
911
  # So, this looks like a bug.
914
- raise COMError(hresult, text, argerr.value)
915
- elif hresult == DISP_E_TYPEMISMATCH:
912
+ raise COMError(hr, text, argerr.value)
913
+ elif hr == hresult.DISP_E_TYPEMISMATCH:
916
914
  # MSDN: One or more of the arguments could not be
917
915
  # coerced.
918
916
  #
919
917
  # Hm, should we raise TypeError, or COMError?
920
918
  raise COMError(
921
- hresult,
922
- text,
923
- ("TypeError: Parameter %s" % (argerr.value + 1), args),
919
+ hr, text, (f"TypeError: Parameter {argerr.value + 1}", args)
924
920
  )
925
921
  raise
926
922
  return result._get_value(dynamic=True)
@@ -960,6 +956,7 @@ _ctype_to_vartype: Dict[Type[_CData], int] = {
960
956
  c_ulonglong: VT_UI8,
961
957
  VARIANT_BOOL: VT_BOOL,
962
958
  BSTR: VT_BSTR,
959
+ HRESULT: VT_HRESULT,
963
960
  VARIANT: VT_VARIANT,
964
961
  # SAFEARRAY(VARIANT *)
965
962
  #
@@ -991,12 +988,6 @@ _vartype_to_ctype[VT_UINT] = _vartype_to_ctype[VT_UI4]
991
988
  _ctype_to_vartype[c_char] = VT_UI1
992
989
 
993
990
 
994
- try:
995
- from comtypes.safearray import _midlSAFEARRAY
996
- except (ImportError, AttributeError):
997
- pass
998
-
999
-
1000
991
  # fmt: off
1001
992
  __known_symbols__ = [
1002
993
  "CURRENCY", "CY", "tagCY", "DECIMAL", "tagDEC", "DISPATCH_METHOD",
@@ -48,23 +48,23 @@ def _find_gen_dir():
48
48
  # check type of executable image to determine a subdirectory
49
49
  # where generated modules are placed.
50
50
  ftype = getattr(sys, "frozen", None)
51
- version_str = "%d%d" % sys.version_info[:2]
51
+ pymaj, pymin = sys.version_info[:2]
52
52
  if ftype == None:
53
53
  # Python script
54
- subdir = r"Python\Python%s\comtypes_cache" % version_str
54
+ subdir = rf"Python\Python{pymaj:d}{pymin:d}\comtypes_cache"
55
55
  basedir = _get_appdata_dir()
56
56
 
57
57
  elif ftype == "dll":
58
58
  # dll created with py2exe
59
59
  path = _get_module_filename(sys.frozendllhandle)
60
60
  base = os.path.splitext(os.path.basename(path))[0]
61
- subdir = r"comtypes_cache\%s-%s" % (base, version_str)
61
+ subdir = rf"comtypes_cache\{base}-{pymaj:d}{pymin:d}"
62
62
  basedir = tempfile.gettempdir()
63
63
 
64
64
  else: # ftype in ('windows_exe', 'console_exe')
65
65
  # exe created by py2exe
66
66
  base = os.path.splitext(os.path.basename(sys.executable))[0]
67
- subdir = r"comtypes_cache\%s-%s" % (base, version_str)
67
+ subdir = rf"comtypes_cache\{base}-{pymaj:d}{pymin:d}"
68
68
  basedir = tempfile.gettempdir()
69
69
 
70
70
  gen_dir = os.path.join(basedir, subdir)
@@ -118,7 +118,7 @@ class Constants(object):
118
118
  # XXX is necessary warning? should use logging?
119
119
  # import comtypes.tools
120
120
  # if comtypes.tools.__warn_on_munge__:
121
- # print("# Fixing keyword as VAR_CONST for %s" % name)
121
+ # print(f"# Fixing keyword as VAR_CONST for {name}")
122
122
  name += "_"
123
123
  members[name] = vdesc._.lpvarValue[0].value
124
124
  return _frozen_attr_dict(members)
@@ -227,7 +227,7 @@ class EventDumper(object):
227
227
  def handler(self, this, *args, **kw):
228
228
  # XXX handler is called with 'this'. Should we really print "None" instead?
229
229
  args = (None,) + args
230
- print("Event %s(%s)" % (name, ", ".join([repr(a) for a in args])))
230
+ print(f"Event {name}({', '.join([repr(a) for a in args])})")
231
231
 
232
232
  return comtypes.instancemethod(handler, self, EventDumper)
233
233