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,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:
@@ -580,23 +575,29 @@ class tagVARIANT(Structure):
580
575
  VARIANT = tagVARIANT
581
576
  VARIANTARG = VARIANT
582
577
 
578
+ _oleaut32_nohresult = WinDLL("oleaut32")
579
+
580
+ _SysAllocStringLen = _oleaut32_nohresult.SysAllocStringLen
581
+ _SysAllocStringLen.argtypes = c_wchar_p, c_uint
582
+ _SysAllocStringLen.restype = c_void_p
583
+
583
584
  _oleaut32 = OleDLL("oleaut32")
584
585
 
585
586
  _VariantChangeType = _oleaut32.VariantChangeType
586
587
  _VariantChangeType.argtypes = (POINTER(VARIANT), POINTER(VARIANT), c_ushort, VARTYPE)
588
+ _VariantChangeType.restype = HRESULT
587
589
 
588
590
  _VariantClear = _oleaut32.VariantClear
589
591
  _VariantClear.argtypes = (POINTER(VARIANT),)
590
-
591
- _SysAllocStringLen = windll.oleaut32.SysAllocStringLen
592
- _SysAllocStringLen.argtypes = c_wchar_p, c_uint
593
- _SysAllocStringLen.restype = c_void_p
592
+ _VariantClear.restype = HRESULT
594
593
 
595
594
  _VariantCopy = _oleaut32.VariantCopy
596
595
  _VariantCopy.argtypes = POINTER(VARIANT), POINTER(VARIANT)
596
+ _VariantCopy.restype = HRESULT
597
597
 
598
598
  _VariantCopyInd = _oleaut32.VariantCopyInd
599
599
  _VariantCopyInd.argtypes = POINTER(VARIANT), POINTER(VARIANT)
600
+ _VariantCopyInd.restype = HRESULT
600
601
 
601
602
  # some commonly used VARIANT instances
602
603
  VARIANT.null = VARIANT(None)
@@ -714,17 +715,16 @@ class tagEXCEPINFO(Structure):
714
715
  scode: int
715
716
 
716
717
  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
- ),
718
+ info = (
719
+ self.wCode,
720
+ self.bstrSource,
721
+ self.bstrDescription,
722
+ self.bstrHelpFile,
723
+ self.dwHelpContext,
724
+ self.pfnDeferredFillIn,
725
+ self.scode,
727
726
  )
727
+ return f"<EXCEPINFO {info}>"
728
728
 
729
729
 
730
730
  tagEXCEPINFO._fields_ = [
@@ -775,7 +775,7 @@ DISPID_COLLECT = -8
775
775
 
776
776
 
777
777
  class IDispatch(IUnknown):
778
- _disp_methods_: ClassVar[List[_DispMemberSpec]]
778
+ _disp_methods_: ClassVar[List["_DispMemberSpec"]]
779
779
 
780
780
  _iid_ = GUID("{00020400-0000-0000-C000-000000000046}")
781
781
  _methods_ = [
@@ -812,6 +812,10 @@ class IDispatch(IUnknown):
812
812
  ),
813
813
  ]
814
814
 
815
+ if TYPE_CHECKING:
816
+
817
+ def GetTypeInfoCount(self) -> int: ...
818
+
815
819
  def GetTypeInfo(self, index: int, lcid: int = 0) -> "hints.ITypeInfo":
816
820
  """Return type information. Index 0 specifies typeinfo for IDispatch"""
817
821
  import comtypes.typeinfo
@@ -894,8 +898,8 @@ class IDispatch(IUnknown):
894
898
  byref(argerr),
895
899
  )
896
900
  except COMError as err:
897
- (hresult, text, details) = err.args
898
- if hresult == DISP_E_EXCEPTION:
901
+ (hr, text, details) = err.args
902
+ if hr == hresult.DISP_E_EXCEPTION:
899
903
  details = (
900
904
  excepinfo.bstrDescription,
901
905
  excepinfo.bstrSource,
@@ -903,24 +907,22 @@ class IDispatch(IUnknown):
903
907
  excepinfo.dwHelpContext,
904
908
  excepinfo.scode,
905
909
  )
906
- raise COMError(hresult, text, details)
907
- elif hresult == DISP_E_PARAMNOTFOUND:
910
+ raise COMError(hr, text, details)
911
+ elif hr == hresult.DISP_E_PARAMNOTFOUND:
908
912
  # MSDN says: You get the error DISP_E_PARAMNOTFOUND
909
913
  # when you try to set a property and you have not
910
914
  # initialized the cNamedArgs and rgdispidNamedArgs
911
915
  # elements of your DISPPARAMS structure.
912
916
  #
913
917
  # So, this looks like a bug.
914
- raise COMError(hresult, text, argerr.value)
915
- elif hresult == DISP_E_TYPEMISMATCH:
918
+ raise COMError(hr, text, argerr.value)
919
+ elif hr == hresult.DISP_E_TYPEMISMATCH:
916
920
  # MSDN: One or more of the arguments could not be
917
921
  # coerced.
918
922
  #
919
923
  # Hm, should we raise TypeError, or COMError?
920
924
  raise COMError(
921
- hresult,
922
- text,
923
- ("TypeError: Parameter %s" % (argerr.value + 1), args),
925
+ hr, text, (f"TypeError: Parameter {argerr.value + 1}", args)
924
926
  )
925
927
  raise
926
928
  return result._get_value(dynamic=True)
@@ -960,6 +962,7 @@ _ctype_to_vartype: Dict[Type[_CData], int] = {
960
962
  c_ulonglong: VT_UI8,
961
963
  VARIANT_BOOL: VT_BOOL,
962
964
  BSTR: VT_BSTR,
965
+ HRESULT: VT_HRESULT,
963
966
  VARIANT: VT_VARIANT,
964
967
  # SAFEARRAY(VARIANT *)
965
968
  #
@@ -991,12 +994,6 @@ _vartype_to_ctype[VT_UINT] = _vartype_to_ctype[VT_UI4]
991
994
  _ctype_to_vartype[c_char] = VT_UI1
992
995
 
993
996
 
994
- try:
995
- from comtypes.safearray import _midlSAFEARRAY
996
- except (ImportError, AttributeError):
997
- pass
998
-
999
-
1000
997
  # fmt: off
1001
998
  __known_symbols__ = [
1002
999
  "CURRENCY", "CY", "tagCY", "DECIMAL", "tagDEC", "DISPATCH_METHOD",