comtypes 1.4.7__zip → 1.4.9__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. {comtypes-1.4.7 → comtypes-1.4.9}/CHANGES.txt +39 -0
  2. {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +6 -4
  3. {comtypes-1.4.7 → comtypes-1.4.9}/README.md +5 -3
  4. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_memberspec.py +81 -9
  8. comtypes-1.4.9/comtypes/_meta.py +95 -0
  9. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_npsupport.py +2 -1
  10. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +1 -0
  11. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  12. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +21 -40
  13. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +88 -209
  14. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  15. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  16. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  17. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/__init__.py +21 -31
  18. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_code_cache.py +5 -4
  19. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  20. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_events.py +1 -2
  21. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_generate.py +9 -13
  22. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -7
  23. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  24. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/git.py +2 -2
  25. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hints.pyi +11 -19
  26. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/persist.py +7 -7
  27. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/safearray.py +12 -6
  28. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  29. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  30. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  31. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/register.py +62 -73
  32. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  33. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/shelllink.py +49 -67
  34. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.py +1 -1
  35. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +1 -1
  36. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -12
  37. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -1
  38. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  39. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -1
  40. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  41. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  42. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +1 -0
  43. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  44. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  45. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  46. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -6
  47. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  48. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -13
  49. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  50. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +8 -5
  51. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  52. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  53. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  54. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  55. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  56. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +10 -14
  57. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  58. comtypes-1.4.9/comtypes/test/test_stream.py +131 -0
  59. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +1 -1
  60. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +1 -0
  61. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -19
  62. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  63. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  64. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  65. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  66. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  67. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +97 -27
  68. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  69. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +9 -11
  70. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +33 -32
  71. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc.py +3 -8
  72. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/typeinfo.py +32 -47
  73. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/util.py +1 -0
  74. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  75. {comtypes-1.4.7 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +6 -4
  76. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  77. comtypes-1.4.9/pyproject.toml +55 -0
  78. comtypes-1.4.7/comtypes/_comobject.py +0 -834
  79. comtypes-1.4.7/comtypes/_idl_stuff.py +0 -67
  80. comtypes-1.4.7/comtypes/_meta.py +0 -70
  81. comtypes-1.4.7/comtypes/server/__init__.py +0 -69
  82. comtypes-1.4.7/comtypes/server/w_getopt.py +0 -75
  83. comtypes-1.4.7/comtypes/test/test_comserver.py +0 -239
  84. comtypes-1.4.7/comtypes/test/test_dispinterface.py +0 -138
  85. comtypes-1.4.7/comtypes/test/test_propputref.py +0 -40
  86. comtypes-1.4.7/comtypes/test/test_server.py +0 -348
  87. comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
  88. comtypes-1.4.7/pyproject.toml +0 -3
  89. {comtypes-1.4.7 → comtypes-1.4.9}/LICENSE.txt +0 -0
  90. {comtypes-1.4.7 → comtypes-1.4.9}/MANIFEST.in +0 -0
  91. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  92. /comtypes-1.4.7/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  93. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  94. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  95. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  96. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  97. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  98. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  99. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  100. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  101. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  102. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  103. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  104. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  105. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  106. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  107. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  108. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  109. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  110. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  111. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  112. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  113. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  114. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  115. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  116. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  117. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  118. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  119. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  120. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  121. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  122. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  123. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  124. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  125. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  126. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  127. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  128. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  129. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  130. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  131. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  132. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  133. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  134. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  135. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  136. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  137. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  138. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  139. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  140. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  141. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  142. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  143. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  144. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  145. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  146. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  147. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  148. {comtypes-1.4.7 → comtypes-1.4.9}/setup.cfg +0 -0
  149. {comtypes-1.4.7 → comtypes-1.4.9}/setup.py +0 -0
@@ -1,834 +0,0 @@
1
- from ctypes import (
2
- FormatError,
3
- POINTER,
4
- Structure,
5
- WINFUNCTYPE,
6
- byref,
7
- c_long,
8
- c_void_p,
9
- oledll,
10
- pointer,
11
- windll,
12
- )
13
- from _ctypes import CopyComPointer
14
- import logging
15
- import os
16
- import queue
17
- import sys
18
-
19
- from comtypes import COMError, ReturnHRESULT, instancemethod
20
- from comtypes._memberspec import _encode_idl
21
- from comtypes.errorinfo import ISupportErrorInfo, ReportException, ReportError
22
- from comtypes import IPersist
23
- from comtypes.hresult import (
24
- DISP_E_BADINDEX,
25
- DISP_E_MEMBERNOTFOUND,
26
- E_FAIL,
27
- E_NOINTERFACE,
28
- E_INVALIDARG,
29
- E_NOTIMPL,
30
- RPC_E_CHANGED_MODE,
31
- S_FALSE,
32
- S_OK,
33
- )
34
- from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2
35
-
36
-
37
- logger = logging.getLogger(__name__)
38
- _debug = logger.debug
39
- _warning = logger.warning
40
- _error = logger.error
41
-
42
- ################################################################
43
- # COM object implementation
44
-
45
- # so we don't have to import comtypes.automation
46
- DISPATCH_METHOD = 1
47
- DISPATCH_PROPERTYGET = 2
48
- DISPATCH_PROPERTYPUT = 4
49
- DISPATCH_PROPERTYPUTREF = 8
50
-
51
-
52
- class E_NotImplemented(Exception):
53
- """COM method is not implemented"""
54
-
55
-
56
- def HRESULT_FROM_WIN32(errcode):
57
- "Convert a Windows error code into a HRESULT value."
58
- if errcode is None:
59
- return 0x80000000
60
- if errcode & 0x80000000:
61
- return errcode
62
- return (errcode & 0xFFFF) | 0x80070000
63
-
64
-
65
- def winerror(exc):
66
- """Return the windows error code from a WindowsError or COMError
67
- instance."""
68
- if isinstance(exc, COMError):
69
- return exc.hresult
70
- elif isinstance(exc, WindowsError):
71
- code = exc.winerror
72
- if isinstance(code, int):
73
- return code
74
- # Sometimes, a WindowsError instance has no error code. An access
75
- # violation raised by ctypes has only text, for example. In this
76
- # cases we return a generic error code.
77
- return E_FAIL
78
- raise TypeError(
79
- "Expected comtypes.COMERROR or WindowsError instance, got %s"
80
- % type(exc).__name__
81
- )
82
-
83
-
84
- def _do_implement(interface_name, method_name):
85
- def _not_implemented(*args):
86
- """Return E_NOTIMPL because the method is not implemented."""
87
- _debug("unimplemented method %s_%s called", interface_name, method_name)
88
- return E_NOTIMPL
89
-
90
- return _not_implemented
91
-
92
-
93
- def catch_errors(obj, mth, paramflags, interface, mthname):
94
- clsid = getattr(obj, "_reg_clsid_", None)
95
-
96
- def call_with_this(*args, **kw):
97
- try:
98
- result = mth(*args, **kw)
99
- except ReturnHRESULT as err:
100
- (hresult, text) = err.args
101
- return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult)
102
- except (COMError, WindowsError) as details:
103
- _error(
104
- "Exception in %s.%s implementation:",
105
- interface.__name__,
106
- mthname,
107
- exc_info=True,
108
- )
109
- return HRESULT_FROM_WIN32(winerror(details))
110
- except E_NotImplemented:
111
- _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
112
- return E_NOTIMPL
113
- except:
114
- _error(
115
- "Exception in %s.%s implementation:",
116
- interface.__name__,
117
- mthname,
118
- exc_info=True,
119
- )
120
- return ReportException(E_FAIL, interface._iid_, clsid=clsid)
121
- if result is None:
122
- return S_OK
123
- return result
124
-
125
- if paramflags is None:
126
- has_outargs = False
127
- else:
128
- has_outargs = bool([x[0] for x in paramflags if x[0] & 2])
129
- call_with_this.has_outargs = has_outargs
130
- return call_with_this
131
-
132
-
133
- ################################################################
134
-
135
-
136
- def hack(inst, mth, paramflags, interface, mthname):
137
- if paramflags is None:
138
- return catch_errors(inst, mth, paramflags, interface, mthname)
139
- code = mth.__code__
140
- if code.co_varnames[1:2] == ("this",):
141
- return catch_errors(inst, mth, paramflags, interface, mthname)
142
- dirflags = [f[0] for f in paramflags]
143
- # An argument is an input arg either if flags are NOT set in the
144
- # idl file, or if the flags contain 'in'. In other words, the
145
- # direction flag is either exactly '0' or has the '1' bit set:
146
- # Output arguments have flag '2'
147
-
148
- args_out_idx = []
149
- args_in_idx = []
150
- for i, a in enumerate(dirflags):
151
- if a & 2:
152
- args_out_idx.append(i)
153
- if a & 1 or a == 0:
154
- args_in_idx.append(i)
155
- args_out = len(args_out_idx)
156
-
157
- ## XXX Remove this:
158
- # if args_in != code.co_argcount - 1:
159
- # return catch_errors(inst, mth, interface, mthname)
160
-
161
- clsid = getattr(inst, "_reg_clsid_", None)
162
-
163
- def call_without_this(this, *args):
164
- # Method implementations could check for and return E_POINTER
165
- # themselves. Or an error will be raised when
166
- # 'outargs[i][0] = value' is executed.
167
- # for a in outargs:
168
- # if not a:
169
- # return E_POINTER
170
-
171
- # make argument list for handler by index array built above
172
- inargs = []
173
- for a in args_in_idx:
174
- inargs.append(args[a])
175
- try:
176
- result = mth(*inargs)
177
- if args_out == 1:
178
- args[args_out_idx[0]][0] = result
179
- elif args_out != 0:
180
- if len(result) != args_out:
181
- msg = "Method should have returned a %s-tuple" % args_out
182
- raise ValueError(msg)
183
- for i, value in enumerate(result):
184
- args[args_out_idx[i]][0] = value
185
- except ReturnHRESULT as err:
186
- (hresult, text) = err.args
187
- return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult)
188
- except COMError as err:
189
- (hr, text, details) = err.args
190
- _error(
191
- "Exception in %s.%s implementation:",
192
- interface.__name__,
193
- mthname,
194
- exc_info=True,
195
- )
196
- try:
197
- descr, source, helpfile, helpcontext, progid = details
198
- except (ValueError, TypeError):
199
- msg = str(details)
200
- else:
201
- msg = "%s: %s" % (source, descr)
202
- hr = HRESULT_FROM_WIN32(hr)
203
- return ReportError(msg, iid=interface._iid_, clsid=clsid, hresult=hr)
204
- except WindowsError as details:
205
- _error(
206
- "Exception in %s.%s implementation:",
207
- interface.__name__,
208
- mthname,
209
- exc_info=True,
210
- )
211
- hr = HRESULT_FROM_WIN32(winerror(details))
212
- return ReportException(hr, interface._iid_, clsid=clsid)
213
- except E_NotImplemented:
214
- _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
215
- return E_NOTIMPL
216
- except:
217
- _error(
218
- "Exception in %s.%s implementation:",
219
- interface.__name__,
220
- mthname,
221
- exc_info=True,
222
- )
223
- return ReportException(E_FAIL, interface._iid_, clsid=clsid)
224
- return S_OK
225
-
226
- if args_out:
227
- call_without_this.has_outargs = True
228
- return call_without_this
229
-
230
-
231
- class _MethodFinder(object):
232
- def __init__(self, inst):
233
- self.inst = inst
234
- # map lower case names to names with correct spelling.
235
- self.names = dict([(n.lower(), n) for n in dir(inst)])
236
-
237
- def get_impl(self, interface, mthname, paramflags, idlflags):
238
- mth = self.find_impl(interface, mthname, paramflags, idlflags)
239
- if mth is None:
240
- return _do_implement(interface.__name__, mthname)
241
- return hack(self.inst, mth, paramflags, interface, mthname)
242
-
243
- def find_method(self, fq_name, mthname):
244
- # Try to find a method, first with the fully qualified name
245
- # ('IUnknown_QueryInterface'), if that fails try the simple
246
- # name ('QueryInterface')
247
- try:
248
- return getattr(self.inst, fq_name)
249
- except AttributeError:
250
- pass
251
- return getattr(self.inst, mthname)
252
-
253
- def find_impl(self, interface, mthname, paramflags, idlflags):
254
- fq_name = "%s_%s" % (interface.__name__, mthname)
255
- if interface._case_insensitive_:
256
- # simple name, like 'QueryInterface'
257
- mthname = self.names.get(mthname.lower(), mthname)
258
- # qualified name, like 'IUnknown_QueryInterface'
259
- fq_name = self.names.get(fq_name.lower(), fq_name)
260
-
261
- try:
262
- return self.find_method(fq_name, mthname)
263
- except AttributeError:
264
- pass
265
- propname = mthname[5:] # strip the '_get_' or '_set' prefix
266
- if interface._case_insensitive_:
267
- propname = self.names.get(propname.lower(), propname)
268
- # propput and propget is done with 'normal' attribute access,
269
- # but only for COM properties that do not take additional
270
- # arguments:
271
-
272
- if "propget" in idlflags and len(paramflags) == 1:
273
- return self.getter(propname)
274
- if "propput" in idlflags and len(paramflags) == 1:
275
- return self.setter(propname)
276
- _debug("%r: %s.%s not implemented", self.inst, interface.__name__, mthname)
277
- return None
278
-
279
- def setter(self, propname):
280
- #
281
- def set(self, value):
282
- try:
283
- # XXX this may not be correct is the object implements
284
- # _get_PropName but not _set_PropName
285
- setattr(self, propname, value)
286
- except AttributeError:
287
- raise E_NotImplemented()
288
-
289
- return instancemethod(set, self.inst, type(self.inst))
290
-
291
- def getter(self, propname):
292
- def get(self):
293
- try:
294
- return getattr(self, propname)
295
- except AttributeError:
296
- raise E_NotImplemented()
297
-
298
- return instancemethod(get, self.inst, type(self.inst))
299
-
300
-
301
- def _create_vtbl_type(fields, itf):
302
- try:
303
- return _vtbl_types[fields]
304
- except KeyError:
305
-
306
- class Vtbl(Structure):
307
- _fields_ = fields
308
-
309
- Vtbl.__name__ = "Vtbl_%s" % itf.__name__
310
- _vtbl_types[fields] = Vtbl
311
- return Vtbl
312
-
313
-
314
- # Ugh. Another type cache to avoid leaking types.
315
- _vtbl_types = {}
316
-
317
- ################################################################
318
-
319
- try:
320
- _InterlockedIncrement = windll.kernel32.InterlockedIncrement
321
- _InterlockedDecrement = windll.kernel32.InterlockedDecrement
322
- except AttributeError:
323
- import threading
324
-
325
- _lock = threading.Lock()
326
- _acquire = _lock.acquire
327
- _release = _lock.release
328
- # win 64 doesn't have these functions
329
-
330
- def _InterlockedIncrement(ob):
331
- _acquire()
332
- refcnt = ob.value + 1
333
- ob.value = refcnt
334
- _release()
335
- return refcnt
336
-
337
- def _InterlockedDecrement(ob):
338
- _acquire()
339
- refcnt = ob.value - 1
340
- ob.value = refcnt
341
- _release()
342
- return refcnt
343
-
344
- else:
345
- _InterlockedIncrement.argtypes = [POINTER(c_long)]
346
- _InterlockedDecrement.argtypes = [POINTER(c_long)]
347
- _InterlockedIncrement.restype = c_long
348
- _InterlockedDecrement.restype = c_long
349
-
350
-
351
- class LocalServer(object):
352
-
353
- _queue = None
354
-
355
- def run(self, classobjects):
356
- # Use windll instead of oledll so that we don't get an
357
- # exception on a FAILED hresult:
358
- result = windll.ole32.CoInitialize(None)
359
- if RPC_E_CHANGED_MODE == result:
360
- # we're running in MTA: no message pump needed
361
- _debug("Server running in MTA")
362
- self.run_mta()
363
- else:
364
- # we're running in STA: need a message pump
365
- _debug("Server running in STA")
366
- if result >= 0:
367
- # we need a matching CoUninitialize() call for a successful
368
- # CoInitialize().
369
- windll.ole32.CoUninitialize()
370
- self.run_sta()
371
-
372
- for obj in classobjects:
373
- obj._revoke_class()
374
-
375
- def run_sta(self):
376
- from comtypes import messageloop
377
-
378
- messageloop.run()
379
-
380
- def run_mta(self):
381
- self._queue = queue.Queue()
382
- self._queue.get()
383
-
384
- def Lock(self):
385
- oledll.ole32.CoAddRefServerProcess()
386
-
387
- def Unlock(self):
388
- rc = oledll.ole32.CoReleaseServerProcess()
389
- if rc == 0:
390
- if self._queue:
391
- self._queue.put(42)
392
- else:
393
- windll.user32.PostQuitMessage(0)
394
-
395
-
396
- class InprocServer(object):
397
- def __init__(self):
398
- self.locks = c_long(0)
399
-
400
- def Lock(self):
401
- _InterlockedIncrement(self.locks)
402
-
403
- def Unlock(self):
404
- _InterlockedDecrement(self.locks)
405
-
406
- def DllCanUnloadNow(self):
407
- if self.locks.value:
408
- return S_FALSE
409
- if COMObject._instances_:
410
- return S_FALSE
411
- return S_OK
412
-
413
-
414
- class COMObject(object):
415
- _instances_ = {}
416
-
417
- def __new__(cls, *args, **kw):
418
- self = super(COMObject, cls).__new__(cls)
419
- if isinstance(self, c_void_p):
420
- # We build the VTables only for direct instances of
421
- # CoClass, not for POINTERs to CoClass.
422
- return self
423
- if hasattr(self, "_com_interfaces_"):
424
- self.__prepare_comobject()
425
- return self
426
-
427
- def __prepare_comobject(self):
428
- # When a CoClass instance is created, COM pointers to all
429
- # interfaces are created. Also, the CoClass must be kept alive as
430
- # until the COM reference count drops to zero, even if no Python
431
- # code keeps a reference to the object.
432
- #
433
- # The _com_pointers_ instance variable maps string interface iids
434
- # to C compatible COM pointers.
435
- self._com_pointers_ = {}
436
- # COM refcount starts at zero.
437
- self._refcnt = c_long(0)
438
-
439
- # Some interfaces have a default implementation in COMObject:
440
- # - ISupportErrorInfo
441
- # - IPersist (if the subclass has a _reg_clsid_ attribute)
442
- # - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
443
- # - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_
444
- # attribute)
445
- #
446
- # Add these if they are not listed in _com_interfaces_.
447
- interfaces = tuple(self._com_interfaces_)
448
- if ISupportErrorInfo not in interfaces:
449
- interfaces += (ISupportErrorInfo,)
450
- if hasattr(self, "_reg_typelib_"):
451
- from comtypes.typeinfo import LoadRegTypeLib
452
-
453
- self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
454
- if hasattr(self, "_reg_clsid_"):
455
- if IProvideClassInfo not in interfaces:
456
- interfaces += (IProvideClassInfo,)
457
- if (
458
- hasattr(self, "_outgoing_interfaces_")
459
- and IProvideClassInfo2 not in interfaces
460
- ):
461
- interfaces += (IProvideClassInfo2,)
462
- if hasattr(self, "_reg_clsid_"):
463
- if IPersist not in interfaces:
464
- interfaces += (IPersist,)
465
- for itf in interfaces[::-1]:
466
- self.__make_interface_pointer(itf)
467
-
468
- def __make_interface_pointer(self, itf):
469
- methods = [] # method implementations
470
- fields = [] # (name, prototype) for virtual function table
471
- iids = [] # interface identifiers.
472
- # iterate over interface inheritance in reverse order to build the
473
- # virtual function table, and leave out the 'object' base class.
474
- finder = self._get_method_finder_(itf)
475
- for interface in itf.__mro__[-2::-1]:
476
- iids.append(interface._iid_)
477
- for m in interface._methods_:
478
- restype, mthname, argtypes, paramflags, idlflags, helptext = m
479
- proto = WINFUNCTYPE(restype, c_void_p, *argtypes)
480
- fields.append((mthname, proto))
481
- mth = finder.get_impl(interface, mthname, paramflags, idlflags)
482
- methods.append(proto(mth))
483
- Vtbl = _create_vtbl_type(tuple(fields), itf)
484
- vtbl = Vtbl(*methods)
485
- for iid in iids:
486
- self._com_pointers_[iid] = pointer(pointer(vtbl))
487
- if hasattr(itf, "_disp_methods_"):
488
- self._dispimpl_ = {}
489
- for m in itf._disp_methods_:
490
- what, mthname, idlflags, restype, argspec = m
491
- #################
492
- # What we have:
493
- #
494
- # restypes is a ctypes type or None
495
- # argspec is seq. of (['in'], paramtype, paramname) tuples (or
496
- # lists?)
497
- #################
498
- # What we need:
499
- #
500
- # idlflags must contain 'propget', 'propset' and so on:
501
- # Must be constructed by converting disptype
502
- #
503
- # paramflags must be a sequence
504
- # of (F_IN|F_OUT|F_RETVAL, paramname[, default-value]) tuples
505
- #
506
- # comtypes has this function which helps:
507
- # def _encode_idl(names):
508
- # # convert to F_xxx and sum up "in", "out",
509
- # # "retval" values found in _PARAMFLAGS, ignoring
510
- # # other stuff.
511
- # return sum([_PARAMFLAGS.get(n, 0) for n in names])
512
- #################
513
-
514
- if what == "DISPMETHOD":
515
- if "propget" in idlflags:
516
- invkind = 2 # DISPATCH_PROPERTYGET
517
- mthname = "_get_" + mthname
518
- elif "propput" in idlflags:
519
- invkind = 4 # DISPATCH_PROPERTYPUT
520
- mthname = "_set_" + mthname
521
- elif "propputref" in idlflags:
522
- invkind = 8 # DISPATCH_PROPERTYPUTREF
523
- mthname = "_setref_" + mthname
524
- else:
525
- invkind = 1 # DISPATCH_METHOD
526
- if restype:
527
- argspec = argspec + ((["out"], restype, ""),)
528
- self.__make_dispentry(
529
- finder, interface, mthname, idlflags, argspec, invkind
530
- )
531
- elif what == "DISPPROPERTY":
532
- # DISPPROPERTY have implicit "out"
533
- if restype:
534
- argspec += ((["out"], restype, ""),)
535
- self.__make_dispentry(
536
- finder,
537
- interface,
538
- "_get_" + mthname,
539
- idlflags,
540
- argspec,
541
- 2, # DISPATCH_PROPERTYGET
542
- )
543
- if not "readonly" in idlflags:
544
- self.__make_dispentry(
545
- finder, interface, "_set_" + mthname, idlflags, argspec, 4
546
- ) # DISPATCH_PROPERTYPUT
547
- # Add DISPATCH_PROPERTYPUTREF also?
548
-
549
- def __make_dispentry(self, finder, interface, mthname, idlflags, argspec, invkind):
550
- # We build a _dispmap_ entry now that maps invkind and
551
- # dispid to implementations that the finder finds;
552
- # IDispatch_Invoke will later call it.
553
- paramflags = [((_encode_idl(x[0]), x[1]) + tuple(x[3:])) for x in argspec]
554
- # XXX can the dispid be at a different index? Check codegenerator.
555
- dispid = idlflags[0]
556
- impl = finder.get_impl(interface, mthname, paramflags, idlflags)
557
- self._dispimpl_[(dispid, invkind)] = impl
558
- # invkind is really a set of flags; we allow both
559
- # DISPATCH_METHOD and DISPATCH_PROPERTYGET (win32com uses
560
- # this, maybe other languages too?)
561
- if invkind in (1, 2):
562
- self._dispimpl_[(dispid, 3)] = impl
563
-
564
- def _get_method_finder_(self, itf):
565
- # This method can be overridden to customize how methods are
566
- # found.
567
- return _MethodFinder(self)
568
-
569
- ################################################################
570
- # LocalServer / InprocServer stuff
571
- __server__ = None
572
-
573
- @staticmethod
574
- def __run_inprocserver__():
575
- if COMObject.__server__ is None:
576
- COMObject.__server__ = InprocServer()
577
- elif isinstance(COMObject.__server__, InprocServer):
578
- pass
579
- else:
580
- raise RuntimeError("Wrong server type")
581
-
582
- @staticmethod
583
- def __run_localserver__(classobjects):
584
- assert COMObject.__server__ is None
585
- # XXX Decide whether we are in STA or MTA
586
- server = COMObject.__server__ = LocalServer()
587
- server.run(classobjects)
588
- COMObject.__server__ = None
589
-
590
- @staticmethod
591
- def __keep__(obj):
592
- COMObject._instances_[obj] = None
593
- _debug("%d active COM objects: Added %r", len(COMObject._instances_), obj)
594
- if COMObject.__server__:
595
- COMObject.__server__.Lock()
596
-
597
- @staticmethod
598
- def __unkeep__(obj):
599
- try:
600
- del COMObject._instances_[obj]
601
- except AttributeError:
602
- _debug("? active COM objects: Removed %r", obj)
603
- else:
604
- _debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj)
605
- _debug("Remaining: %s", list(COMObject._instances_.keys()))
606
- if COMObject.__server__:
607
- COMObject.__server__.Unlock()
608
-
609
- #
610
- ################################################################
611
-
612
- #########################################################
613
- # IUnknown methods implementations
614
- def IUnknown_AddRef(
615
- self, this, __InterlockedIncrement=_InterlockedIncrement, _debug=_debug
616
- ):
617
- result = __InterlockedIncrement(self._refcnt)
618
- if result == 1:
619
- self.__keep__(self)
620
- _debug("%r.AddRef() -> %s", self, result)
621
- return result
622
-
623
- def _final_release_(self):
624
- """This method may be overridden in subclasses
625
- to free allocated resources or so."""
626
- pass
627
-
628
- def IUnknown_Release(
629
- self, this, __InterlockedDecrement=_InterlockedDecrement, _debug=_debug
630
- ):
631
- # If this is called at COM shutdown, _InterlockedDecrement()
632
- # must still be available, although module level variables may
633
- # have been deleted already - so we supply it as default
634
- # argument.
635
- result = __InterlockedDecrement(self._refcnt)
636
- _debug("%r.Release() -> %s", self, result)
637
- if result == 0:
638
- self._final_release_()
639
- self.__unkeep__(self)
640
- # Hm, why isn't this cleaned up by the cycle gc?
641
- self._com_pointers_ = {}
642
- return result
643
-
644
- def IUnknown_QueryInterface(self, this, riid, ppvObj, _debug=_debug):
645
- # XXX This is probably too slow.
646
- # riid[0].hashcode() alone takes 33 us!
647
- iid = riid[0]
648
- ptr = self._com_pointers_.get(iid, None)
649
- if ptr is not None:
650
- # CopyComPointer(src, dst) calls AddRef!
651
- _debug("%r.QueryInterface(%s) -> S_OK", self, iid)
652
- return CopyComPointer(ptr, ppvObj)
653
- _debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
654
- return E_NOINTERFACE
655
-
656
- def QueryInterface(self, interface):
657
- "Query the object for an interface pointer"
658
- # This method is NOT the implementation of
659
- # IUnknown::QueryInterface, instead it is supposed to be
660
- # called on an COMObject by user code. It allows to get COM
661
- # interface pointers from COMObject instances.
662
- ptr = self._com_pointers_.get(interface._iid_, None)
663
- if ptr is None:
664
- raise COMError(
665
- E_NOINTERFACE, FormatError(E_NOINTERFACE), (None, None, 0, None, None)
666
- )
667
- # CopyComPointer(src, dst) calls AddRef!
668
- result = POINTER(interface)()
669
- CopyComPointer(ptr, byref(result))
670
- return result
671
-
672
- ################################################################
673
- # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
674
- def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, this, riid):
675
- if riid[0] in self._com_pointers_:
676
- return S_OK
677
- return S_FALSE
678
-
679
- ################################################################
680
- # IProvideClassInfo::GetClassInfo implementation
681
- def IProvideClassInfo_GetClassInfo(self):
682
- try:
683
- self.__typelib
684
- except AttributeError:
685
- raise WindowsError(E_NOTIMPL)
686
- return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
687
-
688
- ################################################################
689
- # IProvideClassInfo2::GetGUID implementation
690
-
691
- def IProvideClassInfo2_GetGUID(self, dwGuidKind):
692
- # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
693
- if dwGuidKind != 1:
694
- raise WindowsError(E_INVALIDARG)
695
- return self._outgoing_interfaces_[0]._iid_
696
-
697
- ################################################################
698
- # IDispatch methods
699
- @property
700
- def __typeinfo(self):
701
- # XXX Looks like this better be a static property, set by the
702
- # code that sets __typelib also...
703
- iid = self._com_interfaces_[0]._iid_
704
- return self.__typelib.GetTypeInfoOfGuid(iid)
705
-
706
- def IDispatch_GetTypeInfoCount(self):
707
- try:
708
- self.__typelib
709
- except AttributeError:
710
- return 0
711
- else:
712
- return 1
713
-
714
- def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo):
715
- if itinfo != 0:
716
- return DISP_E_BADINDEX
717
- try:
718
- ptinfo[0] = self.__typeinfo
719
- return S_OK
720
- except AttributeError:
721
- return E_NOTIMPL
722
-
723
- def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
724
- # This call uses windll instead of oledll so that a failed
725
- # call to DispGetIDsOfNames will return a HRESULT instead of
726
- # raising an error.
727
- try:
728
- tinfo = self.__typeinfo
729
- except AttributeError:
730
- return E_NOTIMPL
731
- return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId)
732
-
733
- def IDispatch_Invoke(
734
- self,
735
- this,
736
- dispIdMember,
737
- riid,
738
- lcid,
739
- wFlags,
740
- pDispParams,
741
- pVarResult,
742
- pExcepInfo,
743
- puArgErr,
744
- ):
745
- try:
746
- self._dispimpl_
747
- except AttributeError:
748
- try:
749
- tinfo = self.__typeinfo
750
- except AttributeError:
751
- # Hm, we pretend to implement IDispatch, but have no
752
- # typeinfo, and so cannot fulfill the contract. Should we
753
- # better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
754
- # clients call IDispatch_Invoke with 'known' DISPID_...'
755
- # values, without going through GetIDsOfNames first.
756
- return DISP_E_MEMBERNOTFOUND
757
- # This call uses windll instead of oledll so that a failed
758
- # call to DispInvoke will return a HRESULT instead of raising
759
- # an error.
760
- interface = self._com_interfaces_[0]
761
- ptr = self._com_pointers_[interface._iid_]
762
- return windll.oleaut32.DispInvoke(
763
- ptr,
764
- tinfo,
765
- dispIdMember,
766
- wFlags,
767
- pDispParams,
768
- pVarResult,
769
- pExcepInfo,
770
- puArgErr,
771
- )
772
-
773
- try:
774
- # XXX Hm, wFlags should be considered a SET of flags...
775
- mth = self._dispimpl_[(dispIdMember, wFlags)]
776
- except KeyError:
777
- return DISP_E_MEMBERNOTFOUND
778
-
779
- # Unpack the parameters: It would be great if we could use the
780
- # DispGetParam function - but we cannot since it requires that
781
- # we pass a VARTYPE for each argument and we do not know that.
782
- #
783
- # Seems that n arguments have dispids (0, 1, ..., n-1).
784
- # Unnamed arguments are packed into the DISPPARAMS array in
785
- # reverse order (starting with the highest dispid), named
786
- # arguments are packed in the order specified by the
787
- # rgdispidNamedArgs array.
788
- #
789
- params = pDispParams[0]
790
-
791
- if wFlags & (4 | 8):
792
- # DISPATCH_PROPERTYPUT
793
- # DISPATCH_PROPERTYPUTREF
794
- #
795
- # How are the parameters unpacked for propertyput
796
- # operations with additional parameters? Can propput
797
- # have additional args?
798
- args = [
799
- params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs)))
800
- ]
801
- # MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or
802
- # DISPATCH_PROPERTYPUTREF is specified.
803
- return mth(this, *args)
804
-
805
- else:
806
- # DISPATCH_METHOD
807
- # DISPATCH_PROPERTYGET
808
- # the positions of named arguments
809
- #
810
- # 2to3 has problems to translate 'range(...)[::-1]'
811
- # correctly, so use 'list(range)[::-1]' instead (will be
812
- # fixed in Python 3.1, probably):
813
- named_indexes = [
814
- params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs)
815
- ]
816
- # the positions of unnamed arguments
817
- num_unnamed = params.cArgs - params.cNamedArgs
818
- unnamed_indexes = list(reversed(list(range(num_unnamed))))
819
- # It seems that this code calculates the indexes of the
820
- # parameters in the params.rgvarg array correctly.
821
- indexes = named_indexes + unnamed_indexes
822
- args = [params.rgvarg[i].value for i in indexes]
823
-
824
- if pVarResult and getattr(mth, "has_outargs", False):
825
- args.append(pVarResult)
826
- return mth(this, *args)
827
-
828
- ################################################################
829
- # IPersist interface
830
- def IPersist_GetClassID(self):
831
- return self._reg_clsid_
832
-
833
-
834
- __all__ = ["COMObject"]