comtypes 1.1.14__zip → 1.2.1__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.
- {comtypes-1.1.14 → comtypes-1.2.1}/CHANGES.txt +37 -0
- comtypes-1.2.1/PKG-INFO +79 -0
- comtypes-1.2.1/README.md +59 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/__init__.py +302 -555
- comtypes-1.2.1/comtypes/_memberspec.py +520 -0
- comtypes-1.2.1/comtypes/_npsupport.py +143 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/automation.py +99 -11
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/__init__.py +80 -26
- comtypes-1.2.1/comtypes/client/_generate.py +274 -0
- comtypes-1.2.1/comtypes/hints.pyi +26 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/persist.py +14 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/safearray.py +22 -21
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/__init__.py +0 -7
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_client.py +35 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dict.py +0 -4
- comtypes-1.2.1/comtypes/test/test_npsupport.py +343 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_safearray.py +2 -235
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_variant.py +6 -59
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/codegenerator.py +454 -337
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/tlbparser.py +56 -75
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc.py +31 -3
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/typedesc_base.py +28 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/typeinfo.py +291 -121
- comtypes-1.2.1/comtypes.egg-info/PKG-INFO +79 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/SOURCES.txt +4 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/setup.cfg +0 -1
- {comtypes-1.1.14 → comtypes-1.2.1}/setup.py +15 -8
- comtypes-1.1.14/PKG-INFO +0 -50
- comtypes-1.1.14/README.md +0 -31
- comtypes-1.1.14/comtypes/client/_generate.py +0 -257
- comtypes-1.1.14/comtypes/npsupport.py +0 -125
- comtypes-1.1.14/comtypes.egg-info/PKG-INFO +0 -50
- {comtypes-1.1.14 → comtypes-1.2.1}/LICENSE.txt +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/MANIFEST.in +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/clear_comtypes_cache.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/GUID.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_comobject.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_meta.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/_safearray.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_code_cache.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_constants.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/_events.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/client/lazybind.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/errorinfo.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/git.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/hresult.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/logutil.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/messageloop.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/patcher.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/__init__.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/automation.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/inprocserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/localserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/register.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/shelllink.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/find_memleak.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/runtests.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/setup.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_BSTR.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_GUID.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_agilent.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_collections.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_comserver.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_findgendir.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_ie.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_outparam.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_propputref.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_server.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_urlhistory.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_wmi.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/test/test_word.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/util.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes/viewobject.py +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.1.14 → comtypes-1.2.1}/comtypes.egg-info/top_level.txt +0 -0
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
# Code generator to generate code for everything contained in COM type
|
|
2
2
|
# libraries.
|
|
3
3
|
from __future__ import print_function
|
|
4
|
+
import ctypes
|
|
5
|
+
import keyword
|
|
6
|
+
import logging
|
|
4
7
|
import os
|
|
5
8
|
import sys
|
|
9
|
+
import textwrap
|
|
6
10
|
if sys.version_info >= (3, 0):
|
|
7
11
|
import io
|
|
8
12
|
else:
|
|
9
13
|
import cStringIO as io
|
|
10
|
-
import keyword
|
|
11
|
-
import ctypes
|
|
12
|
-
import textwrap
|
|
13
14
|
|
|
14
|
-
from comtypes.tools import typedesc
|
|
15
15
|
import comtypes
|
|
16
|
-
import
|
|
17
|
-
|
|
16
|
+
from comtypes import TYPE_CHECKING, typeinfo
|
|
17
|
+
from comtypes.tools import tlbparser, typedesc
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from typing import (
|
|
21
|
+
Any, Dict, Iterator, List, Optional, Tuple, Union as _UnionT,
|
|
22
|
+
)
|
|
23
|
+
|
|
18
24
|
|
|
19
25
|
version = comtypes.__version__
|
|
20
26
|
|
|
21
|
-
import logging
|
|
22
27
|
logger = logging.getLogger(__name__)
|
|
23
28
|
|
|
24
29
|
__warn_on_munge__ = __debug__
|
|
@@ -158,17 +163,273 @@ def storage(t):
|
|
|
158
163
|
|
|
159
164
|
################################################################
|
|
160
165
|
|
|
161
|
-
|
|
166
|
+
def name_wrapper_module(tlib):
|
|
167
|
+
"""Determine the name of a typelib wrapper module"""
|
|
168
|
+
libattr = tlib.GetLibAttr()
|
|
169
|
+
modname = "_%s_%s_%s_%s" % \
|
|
170
|
+
(str(libattr.guid)[1:-1].replace("-", "_"),
|
|
171
|
+
libattr.lcid,
|
|
172
|
+
libattr.wMajorVerNum,
|
|
173
|
+
libattr.wMinorVerNum)
|
|
174
|
+
return "comtypes.gen.%s" % modname
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def name_friendly_module(tlib):
|
|
178
|
+
"""Determine the friendly-name of a typelib module.
|
|
179
|
+
If cannot get friendly-name from typelib, returns `None`.
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
modulename = tlib.GetDocumentation(-1)[0]
|
|
183
|
+
except comtypes.COMError:
|
|
184
|
+
return
|
|
185
|
+
return "comtypes.gen.%s" % modulename
|
|
186
|
+
|
|
187
|
+
################################################################
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _to_arg_definition(type_name, arg_name, idlflags, default):
|
|
191
|
+
# type: (str, str, List[str], _UnionT[lcid, Any, None]) -> str
|
|
192
|
+
if default is not None:
|
|
193
|
+
elms = (idlflags, type_name, arg_name, default)
|
|
194
|
+
code = " (%r, %s, '%s', %r)" % elms
|
|
195
|
+
if len(code) > 80:
|
|
196
|
+
code = (
|
|
197
|
+
" (\n"
|
|
198
|
+
" %r,\n"
|
|
199
|
+
" %s,\n"
|
|
200
|
+
" '%s',\n"
|
|
201
|
+
" %r\n"
|
|
202
|
+
" )"
|
|
203
|
+
) % elms
|
|
204
|
+
else:
|
|
205
|
+
elms = (idlflags, type_name, arg_name)
|
|
206
|
+
code = " (%r, %s, '%s')" % elms
|
|
207
|
+
if len(code) > 80:
|
|
208
|
+
code = (
|
|
209
|
+
" (\n"
|
|
210
|
+
" %r,\n"
|
|
211
|
+
" %s,\n"
|
|
212
|
+
" '%s',\n"
|
|
213
|
+
" )"
|
|
214
|
+
) % elms
|
|
215
|
+
return code
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class ComMethodGenerator(object):
|
|
219
|
+
def __init__(self, m, isdual):
|
|
220
|
+
# type: (typedesc.ComMethod, bool) -> None
|
|
221
|
+
self._m = m
|
|
222
|
+
self._isdual = isdual
|
|
223
|
+
self._stream = io.StringIO()
|
|
224
|
+
self._to_type_name = TypeNamer()
|
|
225
|
+
|
|
226
|
+
def generate(self):
|
|
227
|
+
# () -> str
|
|
228
|
+
if not self._m.arguments:
|
|
229
|
+
self._make_noargs()
|
|
230
|
+
else:
|
|
231
|
+
self._make_withargs()
|
|
232
|
+
return self._stream.getvalue()
|
|
233
|
+
|
|
234
|
+
def _get_common_elms(self):
|
|
235
|
+
# type: () -> Tuple[List[_UnionT[str, dispid, helpstring]], str, str]
|
|
236
|
+
idlflags = [] # type: List[_UnionT[str, dispid, helpstring]]
|
|
237
|
+
if self._isdual:
|
|
238
|
+
idlflags.append(dispid(self._m.memid))
|
|
239
|
+
idlflags.extend(self._m.idlflags)
|
|
240
|
+
else: # We don't include the dispid for non-dispatch COM interfaces
|
|
241
|
+
idlflags.extend(self._m.idlflags)
|
|
242
|
+
if __debug__ and self._m.doc:
|
|
243
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
244
|
+
type_name = self._to_type_name(self._m.returns)
|
|
245
|
+
return (idlflags, type_name, self._m.name)
|
|
246
|
+
|
|
247
|
+
def _make_noargs(self):
|
|
248
|
+
# type: () -> None
|
|
249
|
+
elms = self._get_common_elms()
|
|
250
|
+
code = " COMMETHOD(%r, %s, '%s')," % elms
|
|
251
|
+
if len(code) > 80:
|
|
252
|
+
code = (
|
|
253
|
+
" COMMETHOD(\n"
|
|
254
|
+
" %r,\n"
|
|
255
|
+
" %s,\n"
|
|
256
|
+
" '%s',\n"
|
|
257
|
+
" ),"
|
|
258
|
+
) % elms
|
|
259
|
+
print(code, file=self._stream)
|
|
260
|
+
|
|
261
|
+
def _make_withargs(self):
|
|
262
|
+
# type: () -> None
|
|
263
|
+
code = (
|
|
264
|
+
" COMMETHOD(\n"
|
|
265
|
+
" %r,\n"
|
|
266
|
+
" %s,\n"
|
|
267
|
+
" '%s',"
|
|
268
|
+
) % self._get_common_elms()
|
|
269
|
+
print(code, file=self._stream)
|
|
270
|
+
arglist = [_to_arg_definition(*i) for i in self._iter_args()]
|
|
271
|
+
print(",\n".join(arglist), file=self._stream)
|
|
272
|
+
print(" ),", file=self._stream)
|
|
273
|
+
|
|
274
|
+
def _iter_args(self):
|
|
275
|
+
# type: () -> Iterator[Tuple[str, str, List[str], _UnionT[lcid, Any, None]]]
|
|
276
|
+
for typ, arg_name, _f, _defval in self._m.arguments:
|
|
277
|
+
###########################################################
|
|
278
|
+
# IDL files that contain 'open arrays' or 'conformant
|
|
279
|
+
# varying arrays' method parameters are strange.
|
|
280
|
+
# These arrays have both a 'size_is()' and
|
|
281
|
+
# 'length_is()' attribute, like this example from
|
|
282
|
+
# dia2.idl (in the DIA SDK):
|
|
283
|
+
#
|
|
284
|
+
# interface IDiaSymbol: IUnknown {
|
|
285
|
+
# ...
|
|
286
|
+
# HRESULT get_dataBytes(
|
|
287
|
+
# [in] DWORD cbData,
|
|
288
|
+
# [out] DWORD *pcbData,
|
|
289
|
+
# [out, size_is(cbData),
|
|
290
|
+
# length_is(*pcbData)] BYTE data[]
|
|
291
|
+
# );
|
|
292
|
+
#
|
|
293
|
+
# The really strange thing is that the decompiled type
|
|
294
|
+
# library then contains this declaration, which declares
|
|
295
|
+
# the interface itself as [out] method parameter:
|
|
296
|
+
#
|
|
297
|
+
# interface IDiaSymbol: IUnknown {
|
|
298
|
+
# ...
|
|
299
|
+
# HRESULT _stdcall get_dataBytes(
|
|
300
|
+
# [in] unsigned long cbData,
|
|
301
|
+
# [out] unsigned long* pcbData,
|
|
302
|
+
# [out] IDiaSymbol data);
|
|
303
|
+
#
|
|
304
|
+
# Of course, comtypes does not accept a COM interface
|
|
305
|
+
# as method parameter; so replace the parameter type
|
|
306
|
+
# with the comtypes spelling of 'unsigned char *', and
|
|
307
|
+
# mark the parameter as [in, out], so the IDL
|
|
308
|
+
# equivalent would be like this:
|
|
309
|
+
#
|
|
310
|
+
# interface IDiaSymbol: IUnknown {
|
|
311
|
+
# ...
|
|
312
|
+
# HRESULT _stdcall get_dataBytes(
|
|
313
|
+
# [in] unsigned long cbData,
|
|
314
|
+
# [out] unsigned long* pcbData,
|
|
315
|
+
# [in, out] BYTE data[]);
|
|
316
|
+
###########################################################
|
|
317
|
+
idlflags = list(_f) # shallow copy to avoid side effects
|
|
318
|
+
if isinstance(typ, typedesc.ComInterface):
|
|
319
|
+
type_name = "OPENARRAY"
|
|
320
|
+
if 'in' not in idlflags:
|
|
321
|
+
idlflags.append('in')
|
|
322
|
+
else:
|
|
323
|
+
type_name = self._to_type_name(typ)
|
|
324
|
+
if 'lcid' in idlflags:# and 'in' in idlflags:
|
|
325
|
+
default = lcid
|
|
326
|
+
else:
|
|
327
|
+
default = _defval
|
|
328
|
+
yield (type_name, arg_name, idlflags, default)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class DispMethodGenerator(object):
|
|
332
|
+
def __init__(self, m):
|
|
333
|
+
# type: (typedesc.DispMethod) -> None
|
|
334
|
+
self._m = m
|
|
335
|
+
self._stream = io.StringIO()
|
|
336
|
+
self._to_type_name = TypeNamer()
|
|
162
337
|
|
|
163
|
-
def
|
|
164
|
-
|
|
338
|
+
def generate(self):
|
|
339
|
+
# () -> str
|
|
340
|
+
if not self._m.arguments:
|
|
341
|
+
self._make_noargs()
|
|
342
|
+
else:
|
|
343
|
+
self._make_withargs()
|
|
344
|
+
return self._stream.getvalue()
|
|
345
|
+
|
|
346
|
+
def _get_common_elms(self):
|
|
347
|
+
# type: () -> Tuple[List[_UnionT[str, dispid, helpstring]], str, str]
|
|
348
|
+
idlflags = [] # type: List[_UnionT[str, dispid, helpstring]]
|
|
349
|
+
idlflags.append(dispid(self._m.dispid))
|
|
350
|
+
idlflags.extend(self._m.idlflags)
|
|
351
|
+
if __debug__ and self._m.doc:
|
|
352
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
353
|
+
type_name = self._to_type_name(self._m.returns)
|
|
354
|
+
return (idlflags, type_name, self._m.name)
|
|
355
|
+
|
|
356
|
+
def _make_noargs(self):
|
|
357
|
+
# type: () -> None
|
|
358
|
+
elms = self._get_common_elms()
|
|
359
|
+
code = " DISPMETHOD(%r, %s, '%s')," % elms
|
|
360
|
+
if len(code) > 80:
|
|
361
|
+
code = (
|
|
362
|
+
" DISPMETHOD(\n"
|
|
363
|
+
" %r,\n"
|
|
364
|
+
" %s,\n"
|
|
365
|
+
" '%s',\n"
|
|
366
|
+
" ),"
|
|
367
|
+
) % elms
|
|
368
|
+
print(code, file=self._stream)
|
|
369
|
+
|
|
370
|
+
def _make_withargs(self):
|
|
371
|
+
# type: () -> None
|
|
372
|
+
code = (
|
|
373
|
+
" DISPMETHOD(\n"
|
|
374
|
+
" %r,\n"
|
|
375
|
+
" %s,\n"
|
|
376
|
+
" '%s',"
|
|
377
|
+
) % self._get_common_elms()
|
|
378
|
+
print(code, file=self._stream)
|
|
379
|
+
arglist = [_to_arg_definition(*i) for i in self._iter_args()]
|
|
380
|
+
print(",\n".join(arglist), file=self._stream)
|
|
381
|
+
print(" ),", file=self._stream)
|
|
382
|
+
|
|
383
|
+
def _iter_args(self):
|
|
384
|
+
# type: () -> Iterator[Tuple[str, str, List[str], _UnionT[lcid, Any, None]]]
|
|
385
|
+
for typ, arg_name, idlflags, default in self._m.arguments:
|
|
386
|
+
type_name = self._to_type_name(typ)
|
|
387
|
+
yield (type_name, arg_name, idlflags, default)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class DispPropertyGenerator(object):
|
|
391
|
+
def __init__(self, m):
|
|
392
|
+
# type: (typedesc.DispProperty) -> None
|
|
393
|
+
self._m = m
|
|
394
|
+
self._to_type_name = TypeNamer()
|
|
395
|
+
|
|
396
|
+
def generate(self):
|
|
397
|
+
# () -> str
|
|
398
|
+
elms = self._get_common_elms()
|
|
399
|
+
code = " DISPPROPERTY(%r, %s, '%s')," % elms
|
|
400
|
+
if len(code) > 80:
|
|
401
|
+
code = (
|
|
402
|
+
" DISPPROPERTY(\n"
|
|
403
|
+
" %r,\n"
|
|
404
|
+
" %s,\n"
|
|
405
|
+
" '%s'\n"
|
|
406
|
+
" ),"
|
|
407
|
+
) % elms
|
|
408
|
+
return code + "\n"
|
|
409
|
+
|
|
410
|
+
def _get_common_elms(self):
|
|
411
|
+
# type: () -> Tuple[List[_UnionT[str, dispid, helpstring]], str, str]
|
|
412
|
+
idlflags = [] # type: List[_UnionT[str, dispid, helpstring]]
|
|
413
|
+
idlflags.append(dispid(self._m.dispid))
|
|
414
|
+
idlflags.extend(self._m.idlflags)
|
|
415
|
+
if __debug__ and self._m.doc:
|
|
416
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
417
|
+
type_name = self._to_type_name(self._m.typ)
|
|
418
|
+
return (idlflags, type_name, self._m.name)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class CodeGenerator(object):
|
|
422
|
+
|
|
423
|
+
def __init__(self, known_symbols=None):
|
|
165
424
|
self.stream = io.StringIO()
|
|
166
425
|
self.imports = ImportedNamespaces()
|
|
167
426
|
self.declarations = DeclaredNamespaces()
|
|
427
|
+
self._to_type_name = TypeNamer()
|
|
168
428
|
self.known_symbols = known_symbols or {}
|
|
169
429
|
|
|
170
430
|
self.done = set() # type descriptions that have been generated
|
|
171
431
|
self.names = set() # names that have been generated
|
|
432
|
+
self.externals = [] # typelibs imported to generated module
|
|
172
433
|
self.last_item_class = False
|
|
173
434
|
|
|
174
435
|
def generate(self, item):
|
|
@@ -248,8 +509,8 @@ class Generator(object):
|
|
|
248
509
|
|
|
249
510
|
if filename is not None:
|
|
250
511
|
# get full path to DLL first (os.stat can't work with relative DLL paths properly)
|
|
251
|
-
loaded_typelib =
|
|
252
|
-
full_filename =
|
|
512
|
+
loaded_typelib = typeinfo.LoadTypeLib(filename)
|
|
513
|
+
full_filename = tlbparser.get_tlib_filename(
|
|
253
514
|
loaded_typelib)
|
|
254
515
|
|
|
255
516
|
while full_filename and not os.path.exists(full_filename):
|
|
@@ -281,88 +542,29 @@ class Generator(object):
|
|
|
281
542
|
if tlib_mtime is not None:
|
|
282
543
|
logger.debug("filename: \"%s\": tlib_mtime: %s", filename, tlib_mtime)
|
|
283
544
|
self.imports.add('comtypes', '_check_version')
|
|
284
|
-
|
|
545
|
+
output = io.StringIO()
|
|
285
546
|
if filename is not None:
|
|
286
547
|
# Hm, what is the CORRECT encoding?
|
|
287
|
-
print("# -*- coding: mbcs -*-", file=
|
|
288
|
-
print(file=
|
|
289
|
-
print(self.imports.getvalue(), file=
|
|
290
|
-
print(file=
|
|
291
|
-
print(self.declarations.getvalue(), file=
|
|
292
|
-
print(file=
|
|
293
|
-
print(self.stream.getvalue(), file=
|
|
294
|
-
|
|
548
|
+
print("# -*- coding: mbcs -*-", file=output)
|
|
549
|
+
print(file=output)
|
|
550
|
+
print(self.imports.getvalue(), file=output)
|
|
551
|
+
print(file=output)
|
|
552
|
+
print(self.declarations.getvalue(), file=output)
|
|
553
|
+
print(file=output)
|
|
554
|
+
print(self.stream.getvalue(), file=output)
|
|
555
|
+
names = ", ".join(repr(str(n)) for n in self.names)
|
|
556
|
+
dunder_all = "__all__ = [%s]" % names
|
|
295
557
|
if len(dunder_all) > 80:
|
|
296
558
|
wrapper = textwrap.TextWrapper(subsequent_indent=" ",
|
|
297
559
|
initial_indent=" ",
|
|
298
560
|
break_long_words=False)
|
|
299
|
-
names = ", ".join(repr(str(n)) for n in self.names)
|
|
300
561
|
dunder_all = "__all__ = [\n%s\n]" % "\n".join(wrapper.wrap(names))
|
|
301
|
-
print(dunder_all, file=
|
|
302
|
-
print(file=
|
|
562
|
+
print(dunder_all, file=output)
|
|
563
|
+
print(file=output)
|
|
303
564
|
if tlib_mtime is not None:
|
|
304
565
|
print("_check_version(%r, %f)" % (version, tlib_mtime),
|
|
305
|
-
file=
|
|
306
|
-
|
|
307
|
-
return loops
|
|
308
|
-
|
|
309
|
-
def type_name(self, t):
|
|
310
|
-
# Return a string, containing an expression which can be used
|
|
311
|
-
# to refer to the type. Assumes the 'from ctypes import *'
|
|
312
|
-
# namespace is available.
|
|
313
|
-
if isinstance(t, typedesc.SAFEARRAYType):
|
|
314
|
-
return "_midlSAFEARRAY(%s)" % self.type_name(t.typ)
|
|
315
|
-
# if isinstance(t, typedesc.CoClass):
|
|
316
|
-
# return "%s._com_interfaces_[0]" % t.name
|
|
317
|
-
if isinstance(t, typedesc.Typedef):
|
|
318
|
-
return t.name
|
|
319
|
-
if isinstance(t, typedesc.PointerType):
|
|
320
|
-
if ASSUME_STRINGS:
|
|
321
|
-
x = get_real_type(t.typ)
|
|
322
|
-
if isinstance(x, typedesc.FundamentalType):
|
|
323
|
-
if x.name == "char":
|
|
324
|
-
return "STRING"
|
|
325
|
-
elif x.name == "wchar_t":
|
|
326
|
-
return "WSTRING"
|
|
327
|
-
|
|
328
|
-
result = "POINTER(%s)" % self.type_name(t.typ)
|
|
329
|
-
# XXX Better to inspect t.typ!
|
|
330
|
-
if result.startswith("POINTER(WINFUNCTYPE"):
|
|
331
|
-
return result[len("POINTER("):-1]
|
|
332
|
-
if result.startswith("POINTER(CFUNCTYPE"):
|
|
333
|
-
return result[len("POINTER("):-1]
|
|
334
|
-
elif result == "POINTER(None)":
|
|
335
|
-
return "c_void_p"
|
|
336
|
-
return result
|
|
337
|
-
elif isinstance(t, typedesc.ArrayType):
|
|
338
|
-
return "%s * %s" % (self.type_name(t.typ), int(t.max)+1)
|
|
339
|
-
elif isinstance(t, typedesc.FunctionType):
|
|
340
|
-
args = [self.type_name(x) for x in [t.returns] + list(t.iterArgTypes())]
|
|
341
|
-
if "__stdcall__" in t.attributes:
|
|
342
|
-
return "WINFUNCTYPE(%s)" % ", ".join(args)
|
|
343
|
-
else:
|
|
344
|
-
return "CFUNCTYPE(%s)" % ", ".join(args)
|
|
345
|
-
elif isinstance(t, typedesc.CvQualifiedType):
|
|
346
|
-
# const and volatile are ignored
|
|
347
|
-
return "%s" % self.type_name(t.typ)
|
|
348
|
-
elif isinstance(t, typedesc.FundamentalType):
|
|
349
|
-
return ctypes_names[t.name]
|
|
350
|
-
elif isinstance(t, typedesc.Structure):
|
|
351
|
-
return t.name
|
|
352
|
-
elif isinstance(t, typedesc.Enumeration):
|
|
353
|
-
if t.name:
|
|
354
|
-
return t.name
|
|
355
|
-
return "c_int" # enums are integers
|
|
356
|
-
elif isinstance(t, typedesc.EnumValue):
|
|
357
|
-
if keyword.iskeyword(t.name):
|
|
358
|
-
return t.name + "_"
|
|
359
|
-
return t.name
|
|
360
|
-
elif isinstance(t, typedesc.External):
|
|
361
|
-
# t.symbol_name - symbol to generate
|
|
362
|
-
# t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
|
|
363
|
-
modname = comtypes.client._generate._name_module(t.tlib)
|
|
364
|
-
return "%s.%s" % (modname, t.symbol_name)
|
|
365
|
-
return t.name
|
|
566
|
+
file=output)
|
|
567
|
+
return output.getvalue()
|
|
366
568
|
|
|
367
569
|
def need_VARIANT_imports(self, value):
|
|
368
570
|
text = repr(value)
|
|
@@ -371,10 +573,6 @@ class Generator(object):
|
|
|
371
573
|
if "datetime.datetime(" in text:
|
|
372
574
|
self.imports.add("datetime")
|
|
373
575
|
|
|
374
|
-
def need_GUID(self):
|
|
375
|
-
if "GUID" in self.known_symbols:
|
|
376
|
-
self.imports.add("GUID", symbols=self.known_symbols)
|
|
377
|
-
|
|
378
576
|
def _to_docstring(self, orig, depth=1):
|
|
379
577
|
# type: (str, int) -> str
|
|
380
578
|
# increasing `depth` by one increases indentation by one
|
|
@@ -383,28 +581,25 @@ class Generator(object):
|
|
|
383
581
|
repled = orig.replace("\\", r"\\").replace("\"", r"'")
|
|
384
582
|
return '%s"""%s"""' % (indent, repled)
|
|
385
583
|
|
|
386
|
-
_arraytypes = 0
|
|
387
584
|
def ArrayType(self, tp):
|
|
388
|
-
|
|
585
|
+
# type: (typedesc.ArrayType) -> None
|
|
389
586
|
self.generate(get_real_type(tp.typ))
|
|
390
587
|
self.generate(tp.typ)
|
|
391
588
|
|
|
392
|
-
_enumvalues = 0
|
|
393
589
|
def EnumValue(self, tp):
|
|
590
|
+
# type: (typedesc.EnumValue) -> None
|
|
394
591
|
self.last_item_class = False
|
|
395
592
|
value = int(tp.value)
|
|
396
593
|
if keyword.iskeyword(tp.name):
|
|
397
594
|
# XXX use logging!
|
|
398
595
|
if __warn_on_munge__:
|
|
399
596
|
print("# Fixing keyword as EnumValue for %s" % tp.name)
|
|
400
|
-
tp_name = self.
|
|
597
|
+
tp_name = self._to_type_name(tp)
|
|
401
598
|
print("%s = %d" % (tp_name, value), file=self.stream)
|
|
402
599
|
self.names.add(tp_name)
|
|
403
|
-
self._enumvalues += 1
|
|
404
600
|
|
|
405
|
-
_enumtypes = 0
|
|
406
601
|
def Enumeration(self, tp):
|
|
407
|
-
|
|
602
|
+
# type: (typedesc.Enumeration) -> None
|
|
408
603
|
self.last_item_class = False
|
|
409
604
|
if tp.name:
|
|
410
605
|
print("# values for enumeration '%s'" % tp.name, file=self.stream)
|
|
@@ -420,15 +615,14 @@ class Generator(object):
|
|
|
420
615
|
print("%s = c_int # enum" % tp.name, file=self.stream)
|
|
421
616
|
self.names.add(tp.name)
|
|
422
617
|
|
|
423
|
-
_typedefs = 0
|
|
424
618
|
def Typedef(self, tp):
|
|
425
|
-
|
|
426
|
-
if
|
|
619
|
+
# type: (typedesc.Typedef) -> None
|
|
620
|
+
if isinstance(tp.typ, (typedesc.Structure, typedesc.Union)):
|
|
427
621
|
self.generate(tp.typ.get_head())
|
|
428
622
|
self.more.add(tp.typ)
|
|
429
623
|
else:
|
|
430
624
|
self.generate(tp.typ)
|
|
431
|
-
definition = self.
|
|
625
|
+
definition = self._to_type_name(tp.typ)
|
|
432
626
|
if tp.name != definition:
|
|
433
627
|
if definition in self.known_symbols:
|
|
434
628
|
self.declarations.add(tp.name, definition)
|
|
@@ -438,18 +632,20 @@ class Generator(object):
|
|
|
438
632
|
self.names.add(tp.name)
|
|
439
633
|
|
|
440
634
|
def FundamentalType(self, item):
|
|
635
|
+
# type: (typedesc.FundamentalType) -> None
|
|
441
636
|
pass # we should check if this is known somewhere
|
|
442
637
|
|
|
443
638
|
def StructureHead(self, head):
|
|
639
|
+
# type: (typedesc.StructureHead) -> None
|
|
444
640
|
for struct in head.struct.bases:
|
|
445
641
|
self.generate(struct.get_head())
|
|
446
642
|
self.more.add(struct)
|
|
447
643
|
if head.struct.location:
|
|
448
644
|
self.last_item_class = False
|
|
449
645
|
print("# %s %s" % head.struct.location, file=self.stream)
|
|
450
|
-
basenames = [self.
|
|
646
|
+
basenames = [self._to_type_name(b) for b in head.struct.bases]
|
|
451
647
|
if basenames:
|
|
452
|
-
self.
|
|
648
|
+
self.imports.add("comtypes", "GUID")
|
|
453
649
|
|
|
454
650
|
if not self.last_item_class:
|
|
455
651
|
print(file=self.stream)
|
|
@@ -519,17 +715,20 @@ class Generator(object):
|
|
|
519
715
|
print(file=self.stream)
|
|
520
716
|
self.names.add(head.struct.name)
|
|
521
717
|
|
|
522
|
-
_structures = 0
|
|
523
718
|
def Structure(self, struct):
|
|
524
|
-
|
|
719
|
+
# type: (typedesc.Structure) -> None
|
|
525
720
|
self.generate(struct.get_head())
|
|
526
721
|
self.generate(struct.get_body())
|
|
527
722
|
|
|
528
|
-
Union
|
|
723
|
+
def Union(self, union):
|
|
724
|
+
# type: (typedesc.Union) -> None
|
|
725
|
+
self.generate(union.get_head())
|
|
726
|
+
self.generate(union.get_body())
|
|
529
727
|
|
|
530
728
|
def StructureBody(self, body):
|
|
531
|
-
|
|
532
|
-
|
|
729
|
+
# type: (typedesc.StructureBody) -> None
|
|
730
|
+
fields = [] # type: List[typedesc.Field]
|
|
731
|
+
methods = [] # type: List[typedesc.Method]
|
|
533
732
|
for m in body.struct.members:
|
|
534
733
|
if type(m) is typedesc.Field:
|
|
535
734
|
fields.append(m)
|
|
@@ -563,11 +762,6 @@ class Generator(object):
|
|
|
563
762
|
if body.struct.bases:
|
|
564
763
|
assert len(body.struct.bases) == 1
|
|
565
764
|
self.generate(body.struct.bases[0].get_body())
|
|
566
|
-
# field definition normally span several lines.
|
|
567
|
-
# Before we generate them, we need to 'import' everything they need.
|
|
568
|
-
# So, call type_name for each field once,
|
|
569
|
-
for f in fields:
|
|
570
|
-
self.type_name(f.typ)
|
|
571
765
|
|
|
572
766
|
if not self.last_item_class:
|
|
573
767
|
print(file=self.stream)
|
|
@@ -590,9 +784,9 @@ class Generator(object):
|
|
|
590
784
|
else:
|
|
591
785
|
fieldname = f.name
|
|
592
786
|
if f.bits is None:
|
|
593
|
-
print(" ('%s', %s)," % (fieldname, self.
|
|
787
|
+
print(" ('%s', %s)," % (fieldname, self._to_type_name(f.typ)), file=self.stream)
|
|
594
788
|
else:
|
|
595
|
-
print(" ('%s', %s, %s)," % (fieldname, self.
|
|
789
|
+
print(" ('%s', %s, %s)," % (fieldname, self._to_type_name(f.typ), f.bits), file=self.stream)
|
|
596
790
|
print("]", file=self.stream)
|
|
597
791
|
|
|
598
792
|
if body.struct.size is None:
|
|
@@ -611,13 +805,6 @@ class Generator(object):
|
|
|
611
805
|
|
|
612
806
|
if methods:
|
|
613
807
|
self.imports.add("comtypes", "COMMETHOD")
|
|
614
|
-
# method definitions normally span several lines.
|
|
615
|
-
# Before we generate them, we need to 'import' everything they need.
|
|
616
|
-
# So, call type_name for each field once,
|
|
617
|
-
for m in methods:
|
|
618
|
-
self.type_name(m.returns)
|
|
619
|
-
for a in m.iterArgTypes():
|
|
620
|
-
self.type_name(a)
|
|
621
808
|
|
|
622
809
|
if not self.last_item_class:
|
|
623
810
|
print(file=self.stream)
|
|
@@ -636,11 +823,11 @@ class Generator(object):
|
|
|
636
823
|
" [], \n"
|
|
637
824
|
" %s,\n"
|
|
638
825
|
" '%s',\n"
|
|
639
|
-
) % (self.
|
|
826
|
+
) % (self._to_type_name(m.returns), m.name),
|
|
640
827
|
file=self.stream
|
|
641
828
|
)
|
|
642
829
|
for a in m.iterArgTypes():
|
|
643
|
-
print(" ([], %s),\n" % self.
|
|
830
|
+
print(" ([], %s),\n" % self._to_type_name(a), file=self.stream)
|
|
644
831
|
print(" ),", file=self.stream)
|
|
645
832
|
print("]", file=self.stream)
|
|
646
833
|
|
|
@@ -648,8 +835,7 @@ class Generator(object):
|
|
|
648
835
|
# top-level typedesc generators
|
|
649
836
|
#
|
|
650
837
|
def TypeLib(self, lib):
|
|
651
|
-
#
|
|
652
|
-
|
|
838
|
+
# type: (typedesc.TypeLib) -> None
|
|
653
839
|
# Hm, in user code we have to write:
|
|
654
840
|
# class MyServer(COMObject, ...):
|
|
655
841
|
# _com_interfaces_ = [MyTypeLib.IInterface]
|
|
@@ -676,25 +862,27 @@ class Generator(object):
|
|
|
676
862
|
print(file=self.stream)
|
|
677
863
|
|
|
678
864
|
def External(self, ext):
|
|
679
|
-
|
|
865
|
+
# type: (typedesc.External) -> None
|
|
866
|
+
modname = name_wrapper_module(ext.tlib)
|
|
680
867
|
if modname not in self.imports:
|
|
681
|
-
|
|
868
|
+
self.externals.append(ext.tlib)
|
|
682
869
|
self.imports.add(modname)
|
|
683
870
|
|
|
684
871
|
def Constant(self, tp):
|
|
872
|
+
# type: (typedesc.Constant) -> None
|
|
685
873
|
self.last_item_class = False
|
|
686
874
|
print("%s = %r # Constant %s" % (tp.name,
|
|
687
875
|
tp.value,
|
|
688
|
-
self.
|
|
876
|
+
self._to_type_name(tp.typ)), file=self.stream)
|
|
689
877
|
self.names.add(tp.name)
|
|
690
878
|
|
|
691
879
|
def SAFEARRAYType(self, sa):
|
|
880
|
+
# type: (typedesc.SAFEARRAYType) -> None
|
|
692
881
|
self.generate(sa.typ)
|
|
693
882
|
self.imports.add("comtypes.automation", "_midlSAFEARRAY")
|
|
694
883
|
|
|
695
|
-
_pointertypes = 0
|
|
696
884
|
def PointerType(self, tp):
|
|
697
|
-
|
|
885
|
+
# type: (typedesc.PointerType) -> None
|
|
698
886
|
if type(tp.typ) is typedesc.ComInterface:
|
|
699
887
|
# this defines the class
|
|
700
888
|
self.generate(tp.typ.get_head())
|
|
@@ -719,7 +907,8 @@ class Generator(object):
|
|
|
719
907
|
self.declarations.add("WSTRING", "c_wchar_p")
|
|
720
908
|
|
|
721
909
|
def CoClass(self, coclass):
|
|
722
|
-
|
|
910
|
+
# type: (typedesc.CoClass) -> None
|
|
911
|
+
self.imports.add("comtypes", "GUID")
|
|
723
912
|
self.imports.add("comtypes", "CoClass")
|
|
724
913
|
if not self.last_item_class:
|
|
725
914
|
print(file=self.stream)
|
|
@@ -757,9 +946,9 @@ class Generator(object):
|
|
|
757
946
|
where = implemented
|
|
758
947
|
if item[1] & 1: # IMPLTYPEFLAG_FDEAULT
|
|
759
948
|
# The default interface should be the first item on the list
|
|
760
|
-
where.insert(0, self.
|
|
949
|
+
where.insert(0, self._to_type_name(item[0]))
|
|
761
950
|
else:
|
|
762
|
-
where.append(self.
|
|
951
|
+
where.append(self._to_type_name(item[0]))
|
|
763
952
|
|
|
764
953
|
if implemented:
|
|
765
954
|
self.last_item_class = False
|
|
@@ -771,11 +960,13 @@ class Generator(object):
|
|
|
771
960
|
self.names.add(coclass.name)
|
|
772
961
|
|
|
773
962
|
def ComInterface(self, itf):
|
|
963
|
+
# type: (typedesc.ComInterface) -> None
|
|
774
964
|
self.generate(itf.get_head())
|
|
775
965
|
self.generate(itf.get_body())
|
|
776
966
|
self.names.add(itf.name)
|
|
777
967
|
|
|
778
968
|
def _is_enuminterface(self, itf):
|
|
969
|
+
# type: (typedesc.ComInterface) -> bool
|
|
779
970
|
# Check if this is an IEnumXXX interface
|
|
780
971
|
if not itf.name.startswith("IEnum"):
|
|
781
972
|
return False
|
|
@@ -786,6 +977,7 @@ class Generator(object):
|
|
|
786
977
|
return True
|
|
787
978
|
|
|
788
979
|
def ComInterfaceHead(self, head):
|
|
980
|
+
# type: (typedesc.ComInterfaceHead) -> None
|
|
789
981
|
if head.itf.name in self.known_symbols:
|
|
790
982
|
return
|
|
791
983
|
base = head.itf.base
|
|
@@ -794,9 +986,9 @@ class Generator(object):
|
|
|
794
986
|
return
|
|
795
987
|
self.generate(base.get_head())
|
|
796
988
|
self.more.add(base)
|
|
797
|
-
basename = self.
|
|
989
|
+
basename = self._to_type_name(head.itf.base)
|
|
798
990
|
|
|
799
|
-
self.
|
|
991
|
+
self.imports.add("comtypes", "GUID")
|
|
800
992
|
|
|
801
993
|
if not self.last_item_class:
|
|
802
994
|
print(file=self.stream)
|
|
@@ -838,6 +1030,7 @@ class Generator(object):
|
|
|
838
1030
|
print(file=self.stream)
|
|
839
1031
|
|
|
840
1032
|
def ComInterfaceBody(self, body):
|
|
1033
|
+
# type: (typedesc.ComInterfaceBody) -> None
|
|
841
1034
|
# The base class must be fully generated, including the
|
|
842
1035
|
# _methods_ list.
|
|
843
1036
|
self.generate(body.itf.base)
|
|
@@ -908,15 +1101,17 @@ class Generator(object):
|
|
|
908
1101
|
print("#", file=self.stream)
|
|
909
1102
|
|
|
910
1103
|
def DispInterface(self, itf):
|
|
1104
|
+
# type: (typedesc.DispInterface) -> None
|
|
911
1105
|
self.generate(itf.get_head())
|
|
912
1106
|
self.generate(itf.get_body())
|
|
913
1107
|
self.names.add(itf.name)
|
|
914
1108
|
|
|
915
1109
|
def DispInterfaceHead(self, head):
|
|
1110
|
+
# type: (typedesc.DispInterfaceHead) -> None
|
|
916
1111
|
self.generate(head.itf.base)
|
|
917
|
-
basename = self.
|
|
1112
|
+
basename = self._to_type_name(head.itf.base)
|
|
918
1113
|
|
|
919
|
-
self.
|
|
1114
|
+
self.imports.add("comtypes", "GUID")
|
|
920
1115
|
if not self.last_item_class:
|
|
921
1116
|
print(file=self.stream)
|
|
922
1117
|
print(file=self.stream)
|
|
@@ -924,10 +1119,10 @@ class Generator(object):
|
|
|
924
1119
|
self.last_item_class = True
|
|
925
1120
|
|
|
926
1121
|
print("class %s(%s):" % (head.itf.name, basename), file=self.stream)
|
|
927
|
-
print(" _case_insensitive_ = True", file=self.stream)
|
|
928
1122
|
doc = getattr(head.itf, "doc", None)
|
|
929
1123
|
if doc:
|
|
930
|
-
print(
|
|
1124
|
+
print(self._to_docstring(doc), file=self.stream)
|
|
1125
|
+
print(" _case_insensitive_ = True", file=self.stream)
|
|
931
1126
|
print(" _iid_ = GUID(%r)" % head.itf.iid, file=self.stream)
|
|
932
1127
|
print(" _idlflags_ = %s" % head.itf.idlflags, file=self.stream)
|
|
933
1128
|
print(" _methods_ = []", file=self.stream)
|
|
@@ -935,6 +1130,7 @@ class Generator(object):
|
|
|
935
1130
|
print(file=self.stream)
|
|
936
1131
|
|
|
937
1132
|
def DispInterfaceBody(self, body):
|
|
1133
|
+
# type: (typedesc.DispInterfaceBody) -> None
|
|
938
1134
|
# make sure we can generate the body
|
|
939
1135
|
for m in body.itf.members:
|
|
940
1136
|
if isinstance(m, typedesc.DispMethod):
|
|
@@ -965,206 +1161,108 @@ class Generator(object):
|
|
|
965
1161
|
# non-toplevel method generators
|
|
966
1162
|
#
|
|
967
1163
|
def make_ComMethod(self, m, isdual):
|
|
1164
|
+
# type: (typedesc.ComMethod, bool) -> None
|
|
968
1165
|
self.imports.add("comtypes", "COMMETHOD")
|
|
969
|
-
# typ, name, idlflags, default
|
|
970
1166
|
if isdual:
|
|
971
1167
|
self.imports.add("comtypes", "dispid")
|
|
972
|
-
idlflags = [dispid(m.memid)] + m.idlflags
|
|
973
|
-
else:
|
|
974
|
-
# We don't include the dispid for non-dispatch COM interfaces
|
|
975
|
-
idlflags = m.idlflags
|
|
976
1168
|
if __debug__ and m.doc:
|
|
977
1169
|
self.imports.add("comtypes", "helpstring")
|
|
978
|
-
|
|
979
|
-
|
|
1170
|
+
gen = ComMethodGenerator(m, isdual)
|
|
1171
|
+
print(gen.generate(), file=self.stream, end="")
|
|
980
1172
|
self.last_item_class = False
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
" %s,\n"
|
|
988
|
-
" '%s',\n"
|
|
989
|
-
" ),"
|
|
990
|
-
) % (idlflags, self.type_name(m.returns), m.name)
|
|
991
|
-
|
|
992
|
-
print(code, file=self.stream)
|
|
993
|
-
else:
|
|
994
|
-
code = (
|
|
995
|
-
" COMMETHOD(\n"
|
|
996
|
-
" %r,\n"
|
|
997
|
-
" %s,\n"
|
|
998
|
-
" '%s',"
|
|
999
|
-
) % (idlflags, self.type_name(m.returns), m.name)
|
|
1000
|
-
print(code, file=self.stream)
|
|
1001
|
-
arglist = []
|
|
1002
|
-
for typ, name, idlflags, default in m.arguments:
|
|
1003
|
-
type_name = self.type_name(typ)
|
|
1004
|
-
###########################################################
|
|
1005
|
-
# IDL files that contain 'open arrays' or 'conformant
|
|
1006
|
-
# varying arrays' method parameters are strange.
|
|
1007
|
-
# These arrays have both a 'size_is()' and
|
|
1008
|
-
# 'length_is()' attribute, like this example from
|
|
1009
|
-
# dia2.idl (in the DIA SDK):
|
|
1010
|
-
#
|
|
1011
|
-
# interface IDiaSymbol: IUnknown {
|
|
1012
|
-
# ...
|
|
1013
|
-
# HRESULT get_dataBytes(
|
|
1014
|
-
# [in] DWORD cbData,
|
|
1015
|
-
# [out] DWORD *pcbData,
|
|
1016
|
-
# [out, size_is(cbData),
|
|
1017
|
-
# length_is(*pcbData)] BYTE data[]
|
|
1018
|
-
# );
|
|
1019
|
-
#
|
|
1020
|
-
# The really strange thing is that the decompiled type
|
|
1021
|
-
# library then contains this declaration, which declares
|
|
1022
|
-
# the interface itself as [out] method parameter:
|
|
1023
|
-
#
|
|
1024
|
-
# interface IDiaSymbol: IUnknown {
|
|
1025
|
-
# ...
|
|
1026
|
-
# HRESULT _stdcall get_dataBytes(
|
|
1027
|
-
# [in] unsigned long cbData,
|
|
1028
|
-
# [out] unsigned long* pcbData,
|
|
1029
|
-
# [out] IDiaSymbol data);
|
|
1030
|
-
#
|
|
1031
|
-
# Of course, comtypes does not accept a COM interface
|
|
1032
|
-
# as method parameter; so replace the parameter type
|
|
1033
|
-
# with the comtypes spelling of 'unsigned char *', and
|
|
1034
|
-
# mark the parameter as [in, out], so the IDL
|
|
1035
|
-
# equivalent would be like this:
|
|
1036
|
-
#
|
|
1037
|
-
# interface IDiaSymbol: IUnknown {
|
|
1038
|
-
# ...
|
|
1039
|
-
# HRESULT _stdcall get_dataBytes(
|
|
1040
|
-
# [in] unsigned long cbData,
|
|
1041
|
-
# [out] unsigned long* pcbData,
|
|
1042
|
-
# [in, out] BYTE data[]);
|
|
1043
|
-
###########################################################
|
|
1044
|
-
if isinstance(typ, typedesc.ComInterface):
|
|
1045
|
-
self.declarations.add("OPENARRAY", "POINTER(c_ubyte)",
|
|
1046
|
-
"hack, see comtypes/tools/codegenerator.py")
|
|
1047
|
-
type_name = "OPENARRAY"
|
|
1048
|
-
if 'in' not in idlflags:
|
|
1049
|
-
idlflags.append('in')
|
|
1050
|
-
if 'lcid' in idlflags:# and 'in' in idlflags:
|
|
1051
|
-
default = lcid
|
|
1052
|
-
if default is not None:
|
|
1053
|
-
self.need_VARIANT_imports(default)
|
|
1054
|
-
|
|
1055
|
-
code = " (%r, %s, '%s', %r)" % (idlflags, type_name, name, default)
|
|
1056
|
-
|
|
1057
|
-
if len(code) > 80:
|
|
1058
|
-
code = (
|
|
1059
|
-
" (\n"
|
|
1060
|
-
" %r,\n"
|
|
1061
|
-
" %s,\n"
|
|
1062
|
-
" '%s',\n"
|
|
1063
|
-
" %r\n"
|
|
1064
|
-
" )"
|
|
1065
|
-
) % (idlflags, type_name, name, default)
|
|
1066
|
-
else:
|
|
1067
|
-
code = " (%r, %s, '%s')" % (idlflags, type_name, name)
|
|
1068
|
-
if len(code) > 80:
|
|
1069
|
-
code = (
|
|
1070
|
-
" (\n"
|
|
1071
|
-
" %r,\n"
|
|
1072
|
-
" %s,\n"
|
|
1073
|
-
" '%s',\n"
|
|
1074
|
-
" )"
|
|
1075
|
-
) % (idlflags, type_name, name)
|
|
1076
|
-
|
|
1077
|
-
arglist.append(code)
|
|
1078
|
-
|
|
1079
|
-
print(",\n".join(arglist), file=self.stream)
|
|
1080
|
-
print(" ),", file=self.stream)
|
|
1173
|
+
for typ, _, _, default in m.arguments:
|
|
1174
|
+
if isinstance(typ, typedesc.ComInterface):
|
|
1175
|
+
self.declarations.add("OPENARRAY", "POINTER(c_ubyte)",
|
|
1176
|
+
"hack, see comtypes/tools/codegenerator.py")
|
|
1177
|
+
if default is not None:
|
|
1178
|
+
self.need_VARIANT_imports(default)
|
|
1081
1179
|
|
|
1082
1180
|
def make_DispMethod(self, m):
|
|
1181
|
+
# type: (typedesc.DispMethod) -> None
|
|
1083
1182
|
self.imports.add("comtypes", "DISPMETHOD")
|
|
1084
1183
|
self.imports.add("comtypes", "dispid")
|
|
1085
|
-
idlflags = [dispid(m.dispid)] + m.idlflags
|
|
1086
1184
|
if __debug__ and m.doc:
|
|
1087
1185
|
self.imports.add("comtypes", "helpstring")
|
|
1088
|
-
|
|
1089
|
-
|
|
1186
|
+
gen = DispMethodGenerator(m)
|
|
1187
|
+
print(gen.generate(), file=self.stream, end="")
|
|
1090
1188
|
self.last_item_class = False
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
if not m.arguments:
|
|
1094
|
-
code = " DISPMETHOD(%r, %s, '%s')," % (idlflags, self.type_name(m.returns), m.name)
|
|
1095
|
-
if len(code) > 80:
|
|
1096
|
-
code = (
|
|
1097
|
-
" DISPMETHOD(\n"
|
|
1098
|
-
" %r,\n"
|
|
1099
|
-
" %s,\n"
|
|
1100
|
-
" '%s'\n"
|
|
1101
|
-
" ),"
|
|
1102
|
-
) % (idlflags, self.type_name(m.returns), m.name)
|
|
1103
|
-
|
|
1104
|
-
print(code, file=self.stream)
|
|
1105
|
-
else:
|
|
1106
|
-
code = (
|
|
1107
|
-
" DISPMETHOD(\n"
|
|
1108
|
-
" %r,\n"
|
|
1109
|
-
" %s,\n"
|
|
1110
|
-
" '%s',"
|
|
1111
|
-
) % (idlflags, self.type_name(m.returns), m.name)
|
|
1112
|
-
|
|
1113
|
-
print(code, file=self.stream)
|
|
1114
|
-
|
|
1115
|
-
arglist = []
|
|
1116
|
-
for typ, name, idlflags, default in m.arguments:
|
|
1189
|
+
for _, _, _, default in m.arguments:
|
|
1190
|
+
if default is not None:
|
|
1117
1191
|
self.need_VARIANT_imports(default)
|
|
1118
|
-
if default is not None:
|
|
1119
|
-
code = " (%r, %s, '%s', %r)" % (idlflags, self.type_name(typ), name, default)
|
|
1120
|
-
if len(code) > 80:
|
|
1121
|
-
code = (
|
|
1122
|
-
" (\n"
|
|
1123
|
-
" %r,\n"
|
|
1124
|
-
" %s,\n"
|
|
1125
|
-
" '%s',\n"
|
|
1126
|
-
" %r\n"
|
|
1127
|
-
" )"
|
|
1128
|
-
) % (idlflags, self.type_name(typ), name, default)
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
else:
|
|
1132
|
-
code = " (%r, %s, '%s')" % (idlflags, self.type_name(typ), name)
|
|
1133
|
-
|
|
1134
|
-
if len(code) > 80:
|
|
1135
|
-
code = (
|
|
1136
|
-
" (\n"
|
|
1137
|
-
" %r,\n"
|
|
1138
|
-
" %s,\n"
|
|
1139
|
-
" '%s'\n"
|
|
1140
|
-
" )"
|
|
1141
|
-
) % (idlflags, self.type_name(typ), name)
|
|
1142
|
-
|
|
1143
|
-
arglist.append(code)
|
|
1144
|
-
|
|
1145
|
-
print(",\n".join(arglist), file=self.stream)
|
|
1146
|
-
print(" ),", file=self.stream)
|
|
1147
1192
|
|
|
1148
1193
|
def make_DispProperty(self, prop):
|
|
1194
|
+
# type: (typedesc.DispProperty) -> None
|
|
1149
1195
|
self.imports.add("comtypes", "DISPPROPERTY")
|
|
1150
1196
|
self.imports.add("comtypes", "dispid")
|
|
1151
|
-
idlflags = [dispid(prop.dispid)] + prop.idlflags
|
|
1152
1197
|
if __debug__ and prop.doc:
|
|
1153
1198
|
self.imports.add("comtypes", "helpstring")
|
|
1154
|
-
|
|
1155
|
-
|
|
1199
|
+
gen = DispPropertyGenerator(prop)
|
|
1200
|
+
print(gen.generate(), file=self.stream, end="")
|
|
1156
1201
|
self.last_item_class = False
|
|
1157
|
-
code = " DISPPROPERTY(%r, %s, '%s')," % (idlflags, self.type_name(prop.typ), prop.name)
|
|
1158
|
-
if len(code) > 80:
|
|
1159
|
-
code = (
|
|
1160
|
-
" DISPPROPERTY(\n"
|
|
1161
|
-
" %r,\n"
|
|
1162
|
-
" %s,\n"
|
|
1163
|
-
" '%s'\n"
|
|
1164
|
-
" ),"
|
|
1165
|
-
) % (idlflags, self.type_name(prop.typ), prop.name)
|
|
1166
1202
|
|
|
1167
|
-
|
|
1203
|
+
|
|
1204
|
+
class TypeNamer(object):
|
|
1205
|
+
def __call__(self, t):
|
|
1206
|
+
# type: (Any) -> str
|
|
1207
|
+
# Return a string, containing an expression which can be used
|
|
1208
|
+
# to refer to the type. Assumes the 'from ctypes import *'
|
|
1209
|
+
# namespace is available.
|
|
1210
|
+
if isinstance(t, typedesc.SAFEARRAYType):
|
|
1211
|
+
return "_midlSAFEARRAY(%s)" % self(t.typ)
|
|
1212
|
+
# if isinstance(t, typedesc.CoClass):
|
|
1213
|
+
# return "%s._com_interfaces_[0]" % t.name
|
|
1214
|
+
if isinstance(t, typedesc.Typedef):
|
|
1215
|
+
return t.name
|
|
1216
|
+
if isinstance(t, typedesc.PointerType):
|
|
1217
|
+
_t, pcnt = self._inspect_PointerType(t)
|
|
1218
|
+
return "%s%s%s" % ("POINTER("*pcnt, self(_t), ")"*pcnt)
|
|
1219
|
+
elif isinstance(t, typedesc.ArrayType):
|
|
1220
|
+
return "%s * %s" % (self(t.typ), int(t.max)+1)
|
|
1221
|
+
elif isinstance(t, typedesc.FunctionType):
|
|
1222
|
+
args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
|
|
1223
|
+
if "__stdcall__" in t.attributes:
|
|
1224
|
+
return "WINFUNCTYPE(%s)" % ", ".join(args)
|
|
1225
|
+
else:
|
|
1226
|
+
return "CFUNCTYPE(%s)" % ", ".join(args)
|
|
1227
|
+
elif isinstance(t, typedesc.CvQualifiedType):
|
|
1228
|
+
# const and volatile are ignored
|
|
1229
|
+
return "%s" % self(t.typ)
|
|
1230
|
+
elif isinstance(t, typedesc.FundamentalType):
|
|
1231
|
+
return ctypes_names[t.name]
|
|
1232
|
+
elif isinstance(t, typedesc.Structure):
|
|
1233
|
+
return t.name
|
|
1234
|
+
elif isinstance(t, typedesc.Enumeration):
|
|
1235
|
+
if t.name:
|
|
1236
|
+
return t.name
|
|
1237
|
+
return "c_int" # enums are integers
|
|
1238
|
+
elif isinstance(t, typedesc.EnumValue):
|
|
1239
|
+
if keyword.iskeyword(t.name):
|
|
1240
|
+
return t.name + "_"
|
|
1241
|
+
return t.name
|
|
1242
|
+
elif isinstance(t, typedesc.External):
|
|
1243
|
+
# t.symbol_name - symbol to generate
|
|
1244
|
+
# t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
|
|
1245
|
+
modname = name_wrapper_module(t.tlib)
|
|
1246
|
+
return "%s.%s" % (modname, t.symbol_name)
|
|
1247
|
+
return t.name
|
|
1248
|
+
|
|
1249
|
+
def _inspect_PointerType(self, t, count=0):
|
|
1250
|
+
# type: (typedesc.PointerType, int) -> Tuple[Any, int]
|
|
1251
|
+
if ASSUME_STRINGS:
|
|
1252
|
+
x = get_real_type(t.typ)
|
|
1253
|
+
if isinstance(x, typedesc.FundamentalType):
|
|
1254
|
+
if x.name == "char":
|
|
1255
|
+
return typedesc.Typedef("STRING", x), count
|
|
1256
|
+
elif x.name == "wchar_t":
|
|
1257
|
+
return typedesc.Typedef("WSTRING", x), count
|
|
1258
|
+
if isinstance(t.typ, typedesc.FunctionType):
|
|
1259
|
+
return t.typ, count
|
|
1260
|
+
if isinstance(t.typ, typedesc.FundamentalType):
|
|
1261
|
+
if t.typ.name == "void":
|
|
1262
|
+
return typedesc.Typedef("c_void_p", t.typ), count
|
|
1263
|
+
if isinstance(t.typ, typedesc.PointerType):
|
|
1264
|
+
return self._inspect_PointerType(t.typ, count + 1)
|
|
1265
|
+
return t.typ, count + 1
|
|
1168
1266
|
|
|
1169
1267
|
|
|
1170
1268
|
class ImportedNamespaces(object):
|
|
@@ -1184,16 +1282,33 @@ class ImportedNamespaces(object):
|
|
|
1184
1282
|
>>> imports.add('ctypes', '*')
|
|
1185
1283
|
>>> imports.add('decimal', 'Decimal')
|
|
1186
1284
|
>>> imports.add('GUID', symbols={'GUID': 'comtypes'})
|
|
1187
|
-
>>> for name in ('COMMETHOD', '
|
|
1188
|
-
... 'BSTR', 'DISPPROPERTY'):
|
|
1285
|
+
>>> for name in ('COMMETHOD', 'DISPMETHOD', 'IUnknown', 'dispid',
|
|
1286
|
+
... 'CoClass', 'BSTR', 'DISPPROPERTY'):
|
|
1189
1287
|
... imports.add('comtypes', name)
|
|
1190
1288
|
>>> imports.add('ctypes.wintypes')
|
|
1191
1289
|
>>> print(imports.getvalue())
|
|
1192
1290
|
from ctypes import *
|
|
1193
1291
|
import datetime
|
|
1194
1292
|
from decimal import Decimal
|
|
1195
|
-
from comtypes import
|
|
1196
|
-
GUID,
|
|
1293
|
+
from comtypes import (
|
|
1294
|
+
BSTR, CoClass, COMMETHOD, dispid, DISPMETHOD, DISPPROPERTY, GUID,
|
|
1295
|
+
IUnknown
|
|
1296
|
+
)
|
|
1297
|
+
import ctypes.wintypes
|
|
1298
|
+
>>> print(imports.getvalue(for_stub=True))
|
|
1299
|
+
from ctypes import *
|
|
1300
|
+
import datetime
|
|
1301
|
+
from decimal import Decimal as Decimal
|
|
1302
|
+
from comtypes import (
|
|
1303
|
+
BSTR as BSTR,
|
|
1304
|
+
CoClass as CoClass,
|
|
1305
|
+
COMMETHOD as COMMETHOD,
|
|
1306
|
+
dispid as dispid,
|
|
1307
|
+
DISPMETHOD as DISPMETHOD,
|
|
1308
|
+
DISPPROPERTY as DISPPROPERTY,
|
|
1309
|
+
GUID as GUID,
|
|
1310
|
+
IUnknown as IUnknown,
|
|
1311
|
+
)
|
|
1197
1312
|
import ctypes.wintypes
|
|
1198
1313
|
"""
|
|
1199
1314
|
if name2 is None:
|
|
@@ -1232,32 +1347,40 @@ class ImportedNamespaces(object):
|
|
|
1232
1347
|
return self.data[import_] == from_
|
|
1233
1348
|
return False
|
|
1234
1349
|
|
|
1235
|
-
def _make_line(self,
|
|
1236
|
-
if
|
|
1237
|
-
|
|
1350
|
+
def _make_line(self, from_, imports, for_stub):
|
|
1351
|
+
if for_stub:
|
|
1352
|
+
import_ = ", ".join("%s as %s" % (n, n) for n in imports)
|
|
1353
|
+
else:
|
|
1354
|
+
import_ = ", ".join(imports)
|
|
1238
1355
|
code = "from %s import %s" % (from_, import_)
|
|
1239
|
-
if len(code)
|
|
1356
|
+
if len(code) <= 80:
|
|
1357
|
+
return code
|
|
1358
|
+
if for_stub:
|
|
1359
|
+
import_ = "\n".join(" %s as %s," % (n, n) for n in imports)
|
|
1360
|
+
else:
|
|
1240
1361
|
wrapper = textwrap.TextWrapper(subsequent_indent=" ",
|
|
1362
|
+
initial_indent=" ",
|
|
1241
1363
|
break_long_words=False)
|
|
1242
|
-
|
|
1364
|
+
import_ = "\n".join(wrapper.wrap(import_))
|
|
1365
|
+
code = "from %s import (\n%s\n)" % (from_, import_)
|
|
1243
1366
|
return code
|
|
1244
1367
|
|
|
1245
|
-
def getvalue(self):
|
|
1368
|
+
def getvalue(self, for_stub=False):
|
|
1246
1369
|
ns = {}
|
|
1247
1370
|
lines = []
|
|
1248
1371
|
for key, val in self.data.items():
|
|
1249
1372
|
if val is None:
|
|
1250
1373
|
ns[key] = val
|
|
1251
1374
|
elif key == "*":
|
|
1252
|
-
lines.append(
|
|
1375
|
+
lines.append("from %s import *" % val)
|
|
1253
1376
|
else:
|
|
1254
1377
|
ns.setdefault(val, set()).add(key)
|
|
1255
1378
|
for key, val in ns.items():
|
|
1256
1379
|
if val is None:
|
|
1257
|
-
lines.append(
|
|
1380
|
+
lines.append("import %s" % key)
|
|
1258
1381
|
else:
|
|
1259
|
-
names =
|
|
1260
|
-
lines.append(self._make_line(names,
|
|
1382
|
+
names = sorted(val, key=lambda s: s.lower())
|
|
1383
|
+
lines.append(self._make_line(key, names, for_stub=for_stub))
|
|
1261
1384
|
return "\n".join(lines)
|
|
1262
1385
|
|
|
1263
1386
|
|
|
@@ -1290,9 +1413,3 @@ class DeclaredNamespaces(object):
|
|
|
1290
1413
|
code = code + " # %s" % comment
|
|
1291
1414
|
lines.append(code)
|
|
1292
1415
|
return "\n".join(lines)
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
# shortcut for development
|
|
1296
|
-
if __name__ == "__main__":
|
|
1297
|
-
from . import tlbparser
|
|
1298
|
-
tlbparser.main()
|