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
@@ -1,833 +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
- _queue = None
353
-
354
- def run(self, classobjects):
355
- # Use windll instead of oledll so that we don't get an
356
- # exception on a FAILED hresult:
357
- result = windll.ole32.CoInitialize(None)
358
- if RPC_E_CHANGED_MODE == result:
359
- # we're running in MTA: no message pump needed
360
- _debug("Server running in MTA")
361
- self.run_mta()
362
- else:
363
- # we're running in STA: need a message pump
364
- _debug("Server running in STA")
365
- if result >= 0:
366
- # we need a matching CoUninitialize() call for a successful
367
- # CoInitialize().
368
- windll.ole32.CoUninitialize()
369
- self.run_sta()
370
-
371
- for obj in classobjects:
372
- obj._revoke_class()
373
-
374
- def run_sta(self):
375
- from comtypes import messageloop
376
-
377
- messageloop.run()
378
-
379
- def run_mta(self):
380
- self._queue = queue.Queue()
381
- self._queue.get()
382
-
383
- def Lock(self):
384
- oledll.ole32.CoAddRefServerProcess()
385
-
386
- def Unlock(self):
387
- rc = oledll.ole32.CoReleaseServerProcess()
388
- if rc == 0:
389
- if self._queue:
390
- self._queue.put(42)
391
- else:
392
- windll.user32.PostQuitMessage(0)
393
-
394
-
395
- class InprocServer(object):
396
- def __init__(self):
397
- self.locks = c_long(0)
398
-
399
- def Lock(self):
400
- _InterlockedIncrement(self.locks)
401
-
402
- def Unlock(self):
403
- _InterlockedDecrement(self.locks)
404
-
405
- def DllCanUnloadNow(self):
406
- if self.locks.value:
407
- return S_FALSE
408
- if COMObject._instances_:
409
- return S_FALSE
410
- return S_OK
411
-
412
-
413
- class COMObject(object):
414
- _instances_ = {}
415
-
416
- def __new__(cls, *args, **kw):
417
- self = super(COMObject, cls).__new__(cls)
418
- if isinstance(self, c_void_p):
419
- # We build the VTables only for direct instances of
420
- # CoClass, not for POINTERs to CoClass.
421
- return self
422
- if hasattr(self, "_com_interfaces_"):
423
- self.__prepare_comobject()
424
- return self
425
-
426
- def __prepare_comobject(self):
427
- # When a CoClass instance is created, COM pointers to all
428
- # interfaces are created. Also, the CoClass must be kept alive as
429
- # until the COM reference count drops to zero, even if no Python
430
- # code keeps a reference to the object.
431
- #
432
- # The _com_pointers_ instance variable maps string interface iids
433
- # to C compatible COM pointers.
434
- self._com_pointers_ = {}
435
- # COM refcount starts at zero.
436
- self._refcnt = c_long(0)
437
-
438
- # Some interfaces have a default implementation in COMObject:
439
- # - ISupportErrorInfo
440
- # - IPersist (if the subclass has a _reg_clsid_ attribute)
441
- # - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
442
- # - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_
443
- # attribute)
444
- #
445
- # Add these if they are not listed in _com_interfaces_.
446
- interfaces = tuple(self._com_interfaces_)
447
- if ISupportErrorInfo not in interfaces:
448
- interfaces += (ISupportErrorInfo,)
449
- if hasattr(self, "_reg_typelib_"):
450
- from comtypes.typeinfo import LoadRegTypeLib
451
-
452
- self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
453
- if hasattr(self, "_reg_clsid_"):
454
- if IProvideClassInfo not in interfaces:
455
- interfaces += (IProvideClassInfo,)
456
- if (
457
- hasattr(self, "_outgoing_interfaces_")
458
- and IProvideClassInfo2 not in interfaces
459
- ):
460
- interfaces += (IProvideClassInfo2,)
461
- if hasattr(self, "_reg_clsid_"):
462
- if IPersist not in interfaces:
463
- interfaces += (IPersist,)
464
- for itf in interfaces[::-1]:
465
- self.__make_interface_pointer(itf)
466
-
467
- def __make_interface_pointer(self, itf):
468
- methods = [] # method implementations
469
- fields = [] # (name, prototype) for virtual function table
470
- iids = [] # interface identifiers.
471
- # iterate over interface inheritance in reverse order to build the
472
- # virtual function table, and leave out the 'object' base class.
473
- finder = self._get_method_finder_(itf)
474
- for interface in itf.__mro__[-2::-1]:
475
- iids.append(interface._iid_)
476
- for m in interface._methods_:
477
- restype, mthname, argtypes, paramflags, idlflags, helptext = m
478
- proto = WINFUNCTYPE(restype, c_void_p, *argtypes)
479
- fields.append((mthname, proto))
480
- mth = finder.get_impl(interface, mthname, paramflags, idlflags)
481
- methods.append(proto(mth))
482
- Vtbl = _create_vtbl_type(tuple(fields), itf)
483
- vtbl = Vtbl(*methods)
484
- for iid in iids:
485
- self._com_pointers_[iid] = pointer(pointer(vtbl))
486
- if hasattr(itf, "_disp_methods_"):
487
- self._dispimpl_ = {}
488
- for m in itf._disp_methods_:
489
- what, mthname, idlflags, restype, argspec = m
490
- #################
491
- # What we have:
492
- #
493
- # restypes is a ctypes type or None
494
- # argspec is seq. of (['in'], paramtype, paramname) tuples (or
495
- # lists?)
496
- #################
497
- # What we need:
498
- #
499
- # idlflags must contain 'propget', 'propset' and so on:
500
- # Must be constructed by converting disptype
501
- #
502
- # paramflags must be a sequence
503
- # of (F_IN|F_OUT|F_RETVAL, paramname[, default-value]) tuples
504
- #
505
- # comtypes has this function which helps:
506
- # def _encode_idl(names):
507
- # # convert to F_xxx and sum up "in", "out",
508
- # # "retval" values found in _PARAMFLAGS, ignoring
509
- # # other stuff.
510
- # return sum([_PARAMFLAGS.get(n, 0) for n in names])
511
- #################
512
-
513
- if what == "DISPMETHOD":
514
- if "propget" in idlflags:
515
- invkind = 2 # DISPATCH_PROPERTYGET
516
- mthname = "_get_" + mthname
517
- elif "propput" in idlflags:
518
- invkind = 4 # DISPATCH_PROPERTYPUT
519
- mthname = "_set_" + mthname
520
- elif "propputref" in idlflags:
521
- invkind = 8 # DISPATCH_PROPERTYPUTREF
522
- mthname = "_setref_" + mthname
523
- else:
524
- invkind = 1 # DISPATCH_METHOD
525
- if restype:
526
- argspec = argspec + ((["out"], restype, ""),)
527
- self.__make_dispentry(
528
- finder, interface, mthname, idlflags, argspec, invkind
529
- )
530
- elif what == "DISPPROPERTY":
531
- # DISPPROPERTY have implicit "out"
532
- if restype:
533
- argspec += ((["out"], restype, ""),)
534
- self.__make_dispentry(
535
- finder,
536
- interface,
537
- "_get_" + mthname,
538
- idlflags,
539
- argspec,
540
- 2, # DISPATCH_PROPERTYGET
541
- )
542
- if not "readonly" in idlflags:
543
- self.__make_dispentry(
544
- finder, interface, "_set_" + mthname, idlflags, argspec, 4
545
- ) # DISPATCH_PROPERTYPUT
546
- # Add DISPATCH_PROPERTYPUTREF also?
547
-
548
- def __make_dispentry(self, finder, interface, mthname, idlflags, argspec, invkind):
549
- # We build a _dispmap_ entry now that maps invkind and
550
- # dispid to implementations that the finder finds;
551
- # IDispatch_Invoke will later call it.
552
- paramflags = [((_encode_idl(x[0]), x[1]) + tuple(x[3:])) for x in argspec]
553
- # XXX can the dispid be at a different index? Check codegenerator.
554
- dispid = idlflags[0]
555
- impl = finder.get_impl(interface, mthname, paramflags, idlflags)
556
- self._dispimpl_[(dispid, invkind)] = impl
557
- # invkind is really a set of flags; we allow both
558
- # DISPATCH_METHOD and DISPATCH_PROPERTYGET (win32com uses
559
- # this, maybe other languages too?)
560
- if invkind in (1, 2):
561
- self._dispimpl_[(dispid, 3)] = impl
562
-
563
- def _get_method_finder_(self, itf):
564
- # This method can be overridden to customize how methods are
565
- # found.
566
- return _MethodFinder(self)
567
-
568
- ################################################################
569
- # LocalServer / InprocServer stuff
570
- __server__ = None
571
-
572
- @staticmethod
573
- def __run_inprocserver__():
574
- if COMObject.__server__ is None:
575
- COMObject.__server__ = InprocServer()
576
- elif isinstance(COMObject.__server__, InprocServer):
577
- pass
578
- else:
579
- raise RuntimeError("Wrong server type")
580
-
581
- @staticmethod
582
- def __run_localserver__(classobjects):
583
- assert COMObject.__server__ is None
584
- # XXX Decide whether we are in STA or MTA
585
- server = COMObject.__server__ = LocalServer()
586
- server.run(classobjects)
587
- COMObject.__server__ = None
588
-
589
- @staticmethod
590
- def __keep__(obj):
591
- COMObject._instances_[obj] = None
592
- _debug("%d active COM objects: Added %r", len(COMObject._instances_), obj)
593
- if COMObject.__server__:
594
- COMObject.__server__.Lock()
595
-
596
- @staticmethod
597
- def __unkeep__(obj):
598
- try:
599
- del COMObject._instances_[obj]
600
- except AttributeError:
601
- _debug("? active COM objects: Removed %r", obj)
602
- else:
603
- _debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj)
604
- _debug("Remaining: %s", list(COMObject._instances_.keys()))
605
- if COMObject.__server__:
606
- COMObject.__server__.Unlock()
607
-
608
- #
609
- ################################################################
610
-
611
- #########################################################
612
- # IUnknown methods implementations
613
- def IUnknown_AddRef(
614
- self, this, __InterlockedIncrement=_InterlockedIncrement, _debug=_debug
615
- ):
616
- result = __InterlockedIncrement(self._refcnt)
617
- if result == 1:
618
- self.__keep__(self)
619
- _debug("%r.AddRef() -> %s", self, result)
620
- return result
621
-
622
- def _final_release_(self):
623
- """This method may be overridden in subclasses
624
- to free allocated resources or so."""
625
- pass
626
-
627
- def IUnknown_Release(
628
- self, this, __InterlockedDecrement=_InterlockedDecrement, _debug=_debug
629
- ):
630
- # If this is called at COM shutdown, _InterlockedDecrement()
631
- # must still be available, although module level variables may
632
- # have been deleted already - so we supply it as default
633
- # argument.
634
- result = __InterlockedDecrement(self._refcnt)
635
- _debug("%r.Release() -> %s", self, result)
636
- if result == 0:
637
- self._final_release_()
638
- self.__unkeep__(self)
639
- # Hm, why isn't this cleaned up by the cycle gc?
640
- self._com_pointers_ = {}
641
- return result
642
-
643
- def IUnknown_QueryInterface(self, this, riid, ppvObj, _debug=_debug):
644
- # XXX This is probably too slow.
645
- # riid[0].hashcode() alone takes 33 us!
646
- iid = riid[0]
647
- ptr = self._com_pointers_.get(iid, None)
648
- if ptr is not None:
649
- # CopyComPointer(src, dst) calls AddRef!
650
- _debug("%r.QueryInterface(%s) -> S_OK", self, iid)
651
- return CopyComPointer(ptr, ppvObj)
652
- _debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
653
- return E_NOINTERFACE
654
-
655
- def QueryInterface(self, interface):
656
- "Query the object for an interface pointer"
657
- # This method is NOT the implementation of
658
- # IUnknown::QueryInterface, instead it is supposed to be
659
- # called on an COMObject by user code. It allows to get COM
660
- # interface pointers from COMObject instances.
661
- ptr = self._com_pointers_.get(interface._iid_, None)
662
- if ptr is None:
663
- raise COMError(
664
- E_NOINTERFACE, FormatError(E_NOINTERFACE), (None, None, 0, None, None)
665
- )
666
- # CopyComPointer(src, dst) calls AddRef!
667
- result = POINTER(interface)()
668
- CopyComPointer(ptr, byref(result))
669
- return result
670
-
671
- ################################################################
672
- # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
673
- def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, this, riid):
674
- if riid[0] in self._com_pointers_:
675
- return S_OK
676
- return S_FALSE
677
-
678
- ################################################################
679
- # IProvideClassInfo::GetClassInfo implementation
680
- def IProvideClassInfo_GetClassInfo(self):
681
- try:
682
- self.__typelib
683
- except AttributeError:
684
- raise WindowsError(E_NOTIMPL)
685
- return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
686
-
687
- ################################################################
688
- # IProvideClassInfo2::GetGUID implementation
689
-
690
- def IProvideClassInfo2_GetGUID(self, dwGuidKind):
691
- # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
692
- if dwGuidKind != 1:
693
- raise WindowsError(E_INVALIDARG)
694
- return self._outgoing_interfaces_[0]._iid_
695
-
696
- ################################################################
697
- # IDispatch methods
698
- @property
699
- def __typeinfo(self):
700
- # XXX Looks like this better be a static property, set by the
701
- # code that sets __typelib also...
702
- iid = self._com_interfaces_[0]._iid_
703
- return self.__typelib.GetTypeInfoOfGuid(iid)
704
-
705
- def IDispatch_GetTypeInfoCount(self):
706
- try:
707
- self.__typelib
708
- except AttributeError:
709
- return 0
710
- else:
711
- return 1
712
-
713
- def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo):
714
- if itinfo != 0:
715
- return DISP_E_BADINDEX
716
- try:
717
- ptinfo[0] = self.__typeinfo
718
- return S_OK
719
- except AttributeError:
720
- return E_NOTIMPL
721
-
722
- def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
723
- # This call uses windll instead of oledll so that a failed
724
- # call to DispGetIDsOfNames will return a HRESULT instead of
725
- # raising an error.
726
- try:
727
- tinfo = self.__typeinfo
728
- except AttributeError:
729
- return E_NOTIMPL
730
- return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId)
731
-
732
- def IDispatch_Invoke(
733
- self,
734
- this,
735
- dispIdMember,
736
- riid,
737
- lcid,
738
- wFlags,
739
- pDispParams,
740
- pVarResult,
741
- pExcepInfo,
742
- puArgErr,
743
- ):
744
- try:
745
- self._dispimpl_
746
- except AttributeError:
747
- try:
748
- tinfo = self.__typeinfo
749
- except AttributeError:
750
- # Hm, we pretend to implement IDispatch, but have no
751
- # typeinfo, and so cannot fulfill the contract. Should we
752
- # better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
753
- # clients call IDispatch_Invoke with 'known' DISPID_...'
754
- # values, without going through GetIDsOfNames first.
755
- return DISP_E_MEMBERNOTFOUND
756
- # This call uses windll instead of oledll so that a failed
757
- # call to DispInvoke will return a HRESULT instead of raising
758
- # an error.
759
- interface = self._com_interfaces_[0]
760
- ptr = self._com_pointers_[interface._iid_]
761
- return windll.oleaut32.DispInvoke(
762
- ptr,
763
- tinfo,
764
- dispIdMember,
765
- wFlags,
766
- pDispParams,
767
- pVarResult,
768
- pExcepInfo,
769
- puArgErr,
770
- )
771
-
772
- try:
773
- # XXX Hm, wFlags should be considered a SET of flags...
774
- mth = self._dispimpl_[(dispIdMember, wFlags)]
775
- except KeyError:
776
- return DISP_E_MEMBERNOTFOUND
777
-
778
- # Unpack the parameters: It would be great if we could use the
779
- # DispGetParam function - but we cannot since it requires that
780
- # we pass a VARTYPE for each argument and we do not know that.
781
- #
782
- # Seems that n arguments have dispids (0, 1, ..., n-1).
783
- # Unnamed arguments are packed into the DISPPARAMS array in
784
- # reverse order (starting with the highest dispid), named
785
- # arguments are packed in the order specified by the
786
- # rgdispidNamedArgs array.
787
- #
788
- params = pDispParams[0]
789
-
790
- if wFlags & (4 | 8):
791
- # DISPATCH_PROPERTYPUT
792
- # DISPATCH_PROPERTYPUTREF
793
- #
794
- # How are the parameters unpacked for propertyput
795
- # operations with additional parameters? Can propput
796
- # have additional args?
797
- args = [
798
- params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs)))
799
- ]
800
- # MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or
801
- # DISPATCH_PROPERTYPUTREF is specified.
802
- return mth(this, *args)
803
-
804
- else:
805
- # DISPATCH_METHOD
806
- # DISPATCH_PROPERTYGET
807
- # the positions of named arguments
808
- #
809
- # 2to3 has problems to translate 'range(...)[::-1]'
810
- # correctly, so use 'list(range)[::-1]' instead (will be
811
- # fixed in Python 3.1, probably):
812
- named_indexes = [
813
- params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs)
814
- ]
815
- # the positions of unnamed arguments
816
- num_unnamed = params.cArgs - params.cNamedArgs
817
- unnamed_indexes = list(reversed(list(range(num_unnamed))))
818
- # It seems that this code calculates the indexes of the
819
- # parameters in the params.rgvarg array correctly.
820
- indexes = named_indexes + unnamed_indexes
821
- args = [params.rgvarg[i].value for i in indexes]
822
-
823
- if pVarResult and getattr(mth, "has_outargs", False):
824
- args.append(pVarResult)
825
- return mth(this, *args)
826
-
827
- ################################################################
828
- # IPersist interface
829
- def IPersist_GetClassID(self):
830
- return self._reg_clsid_
831
-
832
-
833
- __all__ = ["COMObject"]