comtypes 1.4.1__zip → 1.4.3__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.4.1 → comtypes-1.4.3}/CHANGES.txt +24 -1
- {comtypes-1.4.1/comtypes.egg-info → comtypes-1.4.3}/PKG-INFO +29 -1
- {comtypes-1.4.1 → comtypes-1.4.3}/README.md +28 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/__init__.py +6 -8
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/automation.py +26 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_generate.py +105 -80
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hints.pyi +29 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_GUID.py +23 -2
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client.py +14 -4
- comtypes-1.4.3/comtypes/test/test_client_regenerate_modules.py +158 -0
- comtypes-1.4.3/comtypes/test/test_dispifc_records.py +90 -0
- comtypes-1.4.3/comtypes/test/test_findgendir.py +87 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/__init__.py +5 -0
- {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/codegenerator.py +140 -716
- comtypes-1.4.3/comtypes/tools/codegenerator/helpers.py +357 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/modulenamer.py +24 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/namespaces.py +212 -0
- comtypes-1.4.3/comtypes/tools/codegenerator/packing.py +81 -0
- {comtypes-1.4.1/comtypes/tools → comtypes-1.4.3/comtypes/tools/codegenerator}/typeannotator.py +32 -15
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/tlbparser.py +19 -49
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc.py +58 -10
- {comtypes-1.4.1 → comtypes-1.4.3/comtypes.egg-info}/PKG-INFO +29 -1
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/SOURCES.txt +10 -3
- {comtypes-1.4.1 → comtypes-1.4.3}/setup.py +1 -0
- comtypes-1.4.1/comtypes/test/test_findgendir.py +0 -94
- {comtypes-1.4.1 → comtypes-1.4.3}/LICENSE.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/MANIFEST.in +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/GUID.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_comobject.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_memberspec.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_meta.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_npsupport.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/_safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_code_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_constants.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/_events.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/client/lazybind.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/errorinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/git.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/hresult.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/logutil.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/messageloop.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/patcher.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/persist.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/automation.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/inprocserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/localserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/register.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/shelllink.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/find_memleak.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/runtests.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/setup.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_BSTR.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_agilent.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_clear_cache.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_client_dynamic.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_collections.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_comserver.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dict.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ie.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_ienum.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_imfattributes.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_inout_args.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_npsupport.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_outparam.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_propputref.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_safearray.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_server.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_urlhistory.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_variant.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_wmi.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/test/test_word.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/tools/typedesc_base.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/typeinfo.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/util.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes/viewobject.py +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.1 → comtypes-1.4.3}/setup.cfg +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import keyword
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import List, Tuple
|
|
4
|
+
from typing import Iterator
|
|
5
|
+
from typing import Union as _UnionT
|
|
6
|
+
|
|
7
|
+
import comtypes
|
|
8
|
+
from comtypes.tools import typedesc
|
|
9
|
+
from comtypes.tools.codegenerator.modulenamer import name_wrapper_module
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class lcid(object):
|
|
13
|
+
def __repr__(self):
|
|
14
|
+
return "_lcid"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
lcid = lcid()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class dispid(object):
|
|
21
|
+
def __init__(self, memid):
|
|
22
|
+
self.memid = memid
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
return "dispid(%s)" % self.memid
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class helpstring(object):
|
|
29
|
+
def __init__(self, text):
|
|
30
|
+
self.text = text
|
|
31
|
+
|
|
32
|
+
def __repr__(self):
|
|
33
|
+
return "helpstring(%r)" % self.text
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# XXX Should this be in ctypes itself?
|
|
37
|
+
ctypes_names = {
|
|
38
|
+
"unsigned char": "c_ubyte",
|
|
39
|
+
"signed char": "c_byte",
|
|
40
|
+
"char": "c_char",
|
|
41
|
+
"wchar_t": "c_wchar",
|
|
42
|
+
"short unsigned int": "c_ushort",
|
|
43
|
+
"short int": "c_short",
|
|
44
|
+
"long unsigned int": "c_ulong",
|
|
45
|
+
"long int": "c_long",
|
|
46
|
+
"long signed int": "c_long",
|
|
47
|
+
"unsigned int": "c_uint",
|
|
48
|
+
"int": "c_int",
|
|
49
|
+
"long long unsigned int": "c_ulonglong",
|
|
50
|
+
"long long int": "c_longlong",
|
|
51
|
+
"double": "c_double",
|
|
52
|
+
"float": "c_float",
|
|
53
|
+
# Hm...
|
|
54
|
+
"void": "None",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_real_type(tp):
|
|
59
|
+
if type(tp) is typedesc.Typedef:
|
|
60
|
+
return get_real_type(tp.typ)
|
|
61
|
+
elif isinstance(tp, typedesc.CvQualifiedType):
|
|
62
|
+
return get_real_type(tp.typ)
|
|
63
|
+
return tp
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
ASSUME_STRINGS = True
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
################################################################
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
_DefValType = _UnionT["lcid", Any, None]
|
|
73
|
+
_IdlFlagType = _UnionT[str, dispid, helpstring]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _to_arg_definition(
|
|
77
|
+
type_name: str,
|
|
78
|
+
arg_name: str,
|
|
79
|
+
idlflags: List[str],
|
|
80
|
+
default: _DefValType,
|
|
81
|
+
) -> str:
|
|
82
|
+
if default is not None:
|
|
83
|
+
code = f" ({idlflags!r}, {type_name}, '{arg_name}', {default!r})"
|
|
84
|
+
if len(code) > 80:
|
|
85
|
+
code = (
|
|
86
|
+
" (\n"
|
|
87
|
+
f" {idlflags!r},\n"
|
|
88
|
+
f" {type_name},\n"
|
|
89
|
+
f" '{arg_name}',\n"
|
|
90
|
+
f" {default!r}\n"
|
|
91
|
+
" )"
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
code = f" ({idlflags!r}, {type_name}, '{arg_name}')"
|
|
95
|
+
if len(code) > 80:
|
|
96
|
+
code = (
|
|
97
|
+
" (\n"
|
|
98
|
+
f" {idlflags!r},\n"
|
|
99
|
+
f" {type_name},\n"
|
|
100
|
+
f" '{arg_name}',\n"
|
|
101
|
+
" )"
|
|
102
|
+
)
|
|
103
|
+
return code
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ComMethodGenerator(object):
|
|
107
|
+
def __init__(self, m: typedesc.ComMethod, isdual: bool) -> None:
|
|
108
|
+
self._m = m
|
|
109
|
+
self._isdual = isdual
|
|
110
|
+
self.data: List[str] = []
|
|
111
|
+
self._to_type_name = TypeNamer()
|
|
112
|
+
|
|
113
|
+
def generate(self) -> str:
|
|
114
|
+
if not self._m.arguments:
|
|
115
|
+
self._make_noargs()
|
|
116
|
+
else:
|
|
117
|
+
self._make_withargs()
|
|
118
|
+
return "\n".join(self.data)
|
|
119
|
+
|
|
120
|
+
def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
|
|
121
|
+
idlflags: List[_IdlFlagType] = []
|
|
122
|
+
if self._isdual:
|
|
123
|
+
idlflags.append(dispid(self._m.memid))
|
|
124
|
+
idlflags.extend(self._m.idlflags)
|
|
125
|
+
else: # We don't include the dispid for non-dispatch COM interfaces
|
|
126
|
+
idlflags.extend(self._m.idlflags)
|
|
127
|
+
if __debug__ and self._m.doc:
|
|
128
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
129
|
+
type_name = self._to_type_name(self._m.returns)
|
|
130
|
+
return (idlflags, type_name, self._m.name)
|
|
131
|
+
|
|
132
|
+
def _make_noargs(self) -> None:
|
|
133
|
+
flags, type_name, member_name = self._get_common_elms()
|
|
134
|
+
code = f" COMMETHOD({flags!r}, {type_name}, '{member_name}'),"
|
|
135
|
+
if len(code) > 80:
|
|
136
|
+
code = (
|
|
137
|
+
" COMMETHOD(\n"
|
|
138
|
+
f" {flags!r},\n"
|
|
139
|
+
f" {type_name},\n"
|
|
140
|
+
f" '{member_name}',\n"
|
|
141
|
+
" ),"
|
|
142
|
+
)
|
|
143
|
+
self.data.append(code)
|
|
144
|
+
|
|
145
|
+
def _make_withargs(self) -> None:
|
|
146
|
+
flags, type_name, member_name = self._get_common_elms()
|
|
147
|
+
code = (
|
|
148
|
+
" COMMETHOD(\n"
|
|
149
|
+
f" {flags!r},\n"
|
|
150
|
+
f" {type_name},\n"
|
|
151
|
+
f" '{member_name}',"
|
|
152
|
+
)
|
|
153
|
+
self.data.append(code)
|
|
154
|
+
arglist = [_to_arg_definition(*i) for i in self._iter_args()]
|
|
155
|
+
self.data.append(",\n".join(arglist))
|
|
156
|
+
self.data.append(" ),")
|
|
157
|
+
|
|
158
|
+
def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
|
|
159
|
+
for typ, arg_name, _f, _defval in self._m.arguments:
|
|
160
|
+
###########################################################
|
|
161
|
+
# IDL files that contain 'open arrays' or 'conformant
|
|
162
|
+
# varying arrays' method parameters are strange.
|
|
163
|
+
# These arrays have both a 'size_is()' and
|
|
164
|
+
# 'length_is()' attribute, like this example from
|
|
165
|
+
# dia2.idl (in the DIA SDK):
|
|
166
|
+
#
|
|
167
|
+
# interface IDiaSymbol: IUnknown {
|
|
168
|
+
# ...
|
|
169
|
+
# HRESULT get_dataBytes(
|
|
170
|
+
# [in] DWORD cbData,
|
|
171
|
+
# [out] DWORD *pcbData,
|
|
172
|
+
# [out, size_is(cbData),
|
|
173
|
+
# length_is(*pcbData)] BYTE data[]
|
|
174
|
+
# );
|
|
175
|
+
#
|
|
176
|
+
# The really strange thing is that the decompiled type
|
|
177
|
+
# library then contains this declaration, which declares
|
|
178
|
+
# the interface itself as [out] method parameter:
|
|
179
|
+
#
|
|
180
|
+
# interface IDiaSymbol: IUnknown {
|
|
181
|
+
# ...
|
|
182
|
+
# HRESULT _stdcall get_dataBytes(
|
|
183
|
+
# [in] unsigned long cbData,
|
|
184
|
+
# [out] unsigned long* pcbData,
|
|
185
|
+
# [out] IDiaSymbol data);
|
|
186
|
+
#
|
|
187
|
+
# Of course, comtypes does not accept a COM interface
|
|
188
|
+
# as method parameter; so replace the parameter type
|
|
189
|
+
# with the comtypes spelling of 'unsigned char *', and
|
|
190
|
+
# mark the parameter as [in, out], so the IDL
|
|
191
|
+
# equivalent would be like this:
|
|
192
|
+
#
|
|
193
|
+
# interface IDiaSymbol: IUnknown {
|
|
194
|
+
# ...
|
|
195
|
+
# HRESULT _stdcall get_dataBytes(
|
|
196
|
+
# [in] unsigned long cbData,
|
|
197
|
+
# [out] unsigned long* pcbData,
|
|
198
|
+
# [in, out] BYTE data[]);
|
|
199
|
+
###########################################################
|
|
200
|
+
idlflags = list(_f) # shallow copy to avoid side effects
|
|
201
|
+
if isinstance(typ, typedesc.ComInterface):
|
|
202
|
+
type_name = "OPENARRAY"
|
|
203
|
+
if "in" not in idlflags:
|
|
204
|
+
idlflags.append("in")
|
|
205
|
+
else:
|
|
206
|
+
type_name = self._to_type_name(typ)
|
|
207
|
+
if "lcid" in idlflags: # and 'in' in idlflags:
|
|
208
|
+
default = lcid
|
|
209
|
+
else:
|
|
210
|
+
default = _defval
|
|
211
|
+
yield (type_name, arg_name, idlflags, default)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class DispMethodGenerator(object):
|
|
215
|
+
def __init__(self, m: typedesc.DispMethod) -> None:
|
|
216
|
+
self._m = m
|
|
217
|
+
self.data: List[str] = []
|
|
218
|
+
self._to_type_name = TypeNamer()
|
|
219
|
+
|
|
220
|
+
def generate(self) -> str:
|
|
221
|
+
if not self._m.arguments:
|
|
222
|
+
self._make_noargs()
|
|
223
|
+
else:
|
|
224
|
+
self._make_withargs()
|
|
225
|
+
return "\n".join(self.data)
|
|
226
|
+
|
|
227
|
+
def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
|
|
228
|
+
idlflags: List[_IdlFlagType] = []
|
|
229
|
+
idlflags.append(dispid(self._m.dispid))
|
|
230
|
+
idlflags.extend(self._m.idlflags)
|
|
231
|
+
if __debug__ and self._m.doc:
|
|
232
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
233
|
+
type_name = self._to_type_name(self._m.returns)
|
|
234
|
+
return (idlflags, type_name, self._m.name)
|
|
235
|
+
|
|
236
|
+
def _make_noargs(self) -> None:
|
|
237
|
+
flags, type_name, member_name = self._get_common_elms()
|
|
238
|
+
code = f" DISPMETHOD({flags!r}, {type_name}, '{member_name}'),"
|
|
239
|
+
if len(code) > 80:
|
|
240
|
+
code = (
|
|
241
|
+
" DISPMETHOD(\n"
|
|
242
|
+
f" {flags!r},\n"
|
|
243
|
+
f" {type_name},\n"
|
|
244
|
+
f" '{member_name}',\n"
|
|
245
|
+
" ),"
|
|
246
|
+
)
|
|
247
|
+
self.data.append(code)
|
|
248
|
+
|
|
249
|
+
def _make_withargs(self) -> None:
|
|
250
|
+
flags, type_name, member_name = self._get_common_elms()
|
|
251
|
+
code = (
|
|
252
|
+
" DISPMETHOD(\n"
|
|
253
|
+
f" {flags!r},\n"
|
|
254
|
+
f" {type_name},\n"
|
|
255
|
+
f" '{member_name}',"
|
|
256
|
+
)
|
|
257
|
+
self.data.append(code)
|
|
258
|
+
arglist = [_to_arg_definition(*i) for i in self._iter_args()]
|
|
259
|
+
self.data.append(",\n".join(arglist))
|
|
260
|
+
self.data.append(" ),")
|
|
261
|
+
|
|
262
|
+
def _iter_args(self) -> Iterator[Tuple[str, str, List[str], _DefValType]]:
|
|
263
|
+
for typ, arg_name, idlflags, default in self._m.arguments:
|
|
264
|
+
type_name = self._to_type_name(typ)
|
|
265
|
+
yield (type_name, arg_name, idlflags, default)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class DispPropertyGenerator(object):
|
|
269
|
+
def __init__(self, m: typedesc.DispProperty) -> None:
|
|
270
|
+
self._m = m
|
|
271
|
+
self._to_type_name = TypeNamer()
|
|
272
|
+
|
|
273
|
+
def generate(self) -> str:
|
|
274
|
+
flags, type_name, member_name = self._get_common_elms()
|
|
275
|
+
code = f" DISPPROPERTY({flags!r}, {type_name}, '{member_name}'),"
|
|
276
|
+
if len(code) > 80:
|
|
277
|
+
code = (
|
|
278
|
+
" DISPPROPERTY(\n"
|
|
279
|
+
f" {flags!r},\n"
|
|
280
|
+
f" {type_name},\n"
|
|
281
|
+
f" '{member_name}'\n"
|
|
282
|
+
" ),"
|
|
283
|
+
)
|
|
284
|
+
return code
|
|
285
|
+
|
|
286
|
+
def _get_common_elms(self) -> Tuple[List[_IdlFlagType], str, str]:
|
|
287
|
+
idlflags: List[_IdlFlagType] = []
|
|
288
|
+
idlflags.append(dispid(self._m.dispid))
|
|
289
|
+
idlflags.extend(self._m.idlflags)
|
|
290
|
+
if __debug__ and self._m.doc:
|
|
291
|
+
idlflags.insert(1, helpstring(self._m.doc))
|
|
292
|
+
type_name = self._to_type_name(self._m.typ)
|
|
293
|
+
return (idlflags, type_name, self._m.name)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class TypeNamer(object):
|
|
297
|
+
def __call__(self, t: Any) -> str:
|
|
298
|
+
# Return a string, containing an expression which can be used
|
|
299
|
+
# to refer to the type. Assumes the 'from ctypes import *'
|
|
300
|
+
# namespace is available.
|
|
301
|
+
if isinstance(t, typedesc.SAFEARRAYType):
|
|
302
|
+
return "_midlSAFEARRAY(%s)" % self(t.typ)
|
|
303
|
+
# if isinstance(t, typedesc.CoClass):
|
|
304
|
+
# return "%s._com_interfaces_[0]" % t.name
|
|
305
|
+
if isinstance(t, typedesc.Typedef):
|
|
306
|
+
return t.name
|
|
307
|
+
if isinstance(t, typedesc.PointerType):
|
|
308
|
+
_t, pcnt = self._inspect_PointerType(t)
|
|
309
|
+
return "%s%s%s" % ("POINTER(" * pcnt, self(_t), ")" * pcnt)
|
|
310
|
+
elif isinstance(t, typedesc.ArrayType):
|
|
311
|
+
return "%s * %s" % (self(t.typ), int(t.max) + 1)
|
|
312
|
+
elif isinstance(t, typedesc.FunctionType):
|
|
313
|
+
args = [self(x) for x in [t.returns] + list(t.iterArgTypes())]
|
|
314
|
+
if "__stdcall__" in t.attributes:
|
|
315
|
+
return "WINFUNCTYPE(%s)" % ", ".join(args)
|
|
316
|
+
else:
|
|
317
|
+
return "CFUNCTYPE(%s)" % ", ".join(args)
|
|
318
|
+
elif isinstance(t, typedesc.CvQualifiedType):
|
|
319
|
+
# const and volatile are ignored
|
|
320
|
+
return "%s" % self(t.typ)
|
|
321
|
+
elif isinstance(t, typedesc.FundamentalType):
|
|
322
|
+
return ctypes_names[t.name]
|
|
323
|
+
elif isinstance(t, typedesc.Structure):
|
|
324
|
+
return t.name
|
|
325
|
+
elif isinstance(t, typedesc.Enumeration):
|
|
326
|
+
if t.name:
|
|
327
|
+
return t.name
|
|
328
|
+
return "c_int" # enums are integers
|
|
329
|
+
elif isinstance(t, typedesc.EnumValue):
|
|
330
|
+
if keyword.iskeyword(t.name):
|
|
331
|
+
return t.name + "_"
|
|
332
|
+
return t.name
|
|
333
|
+
elif isinstance(t, typedesc.External):
|
|
334
|
+
# t.symbol_name - symbol to generate
|
|
335
|
+
# t.tlib - the ITypeLib pointer to the typelibrary containing the symbols definition
|
|
336
|
+
modname = name_wrapper_module(t.tlib)
|
|
337
|
+
return "%s.%s" % (modname, t.symbol_name)
|
|
338
|
+
return t.name
|
|
339
|
+
|
|
340
|
+
def _inspect_PointerType(
|
|
341
|
+
self, t: typedesc.PointerType, count: int = 0
|
|
342
|
+
) -> Tuple[Any, int]:
|
|
343
|
+
if ASSUME_STRINGS:
|
|
344
|
+
x = get_real_type(t.typ)
|
|
345
|
+
if isinstance(x, typedesc.FundamentalType):
|
|
346
|
+
if x.name == "char":
|
|
347
|
+
return typedesc.Typedef("STRING", x), count
|
|
348
|
+
elif x.name == "wchar_t":
|
|
349
|
+
return typedesc.Typedef("WSTRING", x), count
|
|
350
|
+
if isinstance(t.typ, typedesc.FunctionType):
|
|
351
|
+
return t.typ, count
|
|
352
|
+
if isinstance(t.typ, typedesc.FundamentalType):
|
|
353
|
+
if t.typ.name == "void":
|
|
354
|
+
return typedesc.Typedef("c_void_p", t.typ), count
|
|
355
|
+
if isinstance(t.typ, typedesc.PointerType):
|
|
356
|
+
return self._inspect_PointerType(t.typ, count + 1)
|
|
357
|
+
return t.typ, count + 1
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import comtypes
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def name_wrapper_module(tlib):
|
|
5
|
+
"""Determine the name of a typelib wrapper module"""
|
|
6
|
+
libattr = tlib.GetLibAttr()
|
|
7
|
+
modname = "_%s_%s_%s_%s" % (
|
|
8
|
+
str(libattr.guid)[1:-1].replace("-", "_"),
|
|
9
|
+
libattr.lcid,
|
|
10
|
+
libattr.wMajorVerNum,
|
|
11
|
+
libattr.wMinorVerNum,
|
|
12
|
+
)
|
|
13
|
+
return "comtypes.gen.%s" % modname
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def name_friendly_module(tlib):
|
|
17
|
+
"""Determine the friendly-name of a typelib module.
|
|
18
|
+
If cannot get friendly-name from typelib, returns `None`.
|
|
19
|
+
"""
|
|
20
|
+
try:
|
|
21
|
+
modulename = tlib.GetDocumentation(-1)[0]
|
|
22
|
+
except comtypes.COMError:
|
|
23
|
+
return
|
|
24
|
+
return "comtypes.gen.%s" % modulename
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import textwrap
|
|
2
|
+
from typing import Dict, List, Set, Tuple
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ImportedNamespaces(object):
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.data = {}
|
|
8
|
+
|
|
9
|
+
def add(self, name1, name2=None, symbols=None):
|
|
10
|
+
"""Adds a namespace will be imported.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
>>> imports = ImportedNamespaces()
|
|
14
|
+
>>> imports.add('datetime')
|
|
15
|
+
>>> imports.add('ctypes', '*')
|
|
16
|
+
>>> imports.add('decimal', 'Decimal')
|
|
17
|
+
>>> imports.add('GUID', symbols={'GUID': 'comtypes'})
|
|
18
|
+
>>> for name in ('COMMETHOD', 'DISPMETHOD', 'IUnknown', 'dispid',
|
|
19
|
+
... 'CoClass', 'BSTR', 'DISPPROPERTY'):
|
|
20
|
+
... imports.add('comtypes', name)
|
|
21
|
+
>>> imports.add('ctypes.wintypes')
|
|
22
|
+
>>> print(imports.getvalue())
|
|
23
|
+
from ctypes import *
|
|
24
|
+
import datetime
|
|
25
|
+
from decimal import Decimal
|
|
26
|
+
from comtypes import (
|
|
27
|
+
BSTR, CoClass, COMMETHOD, dispid, DISPMETHOD, DISPPROPERTY, GUID,
|
|
28
|
+
IUnknown
|
|
29
|
+
)
|
|
30
|
+
import ctypes.wintypes
|
|
31
|
+
>>> assert imports.get_symbols() == {
|
|
32
|
+
... 'Decimal', 'GUID', 'COMMETHOD', 'DISPMETHOD', 'IUnknown',
|
|
33
|
+
... 'dispid', 'CoClass', 'BSTR', 'DISPPROPERTY'
|
|
34
|
+
... }
|
|
35
|
+
"""
|
|
36
|
+
if name2 is None:
|
|
37
|
+
import_ = name1
|
|
38
|
+
if not symbols:
|
|
39
|
+
self.data[import_] = None
|
|
40
|
+
return
|
|
41
|
+
from_ = symbols[import_]
|
|
42
|
+
else:
|
|
43
|
+
from_, import_ = name1, name2
|
|
44
|
+
self.data[import_] = from_
|
|
45
|
+
|
|
46
|
+
def __contains__(self, item):
|
|
47
|
+
"""Returns item has already added.
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
>>> imports = ImportedNamespaces()
|
|
51
|
+
>>> imports.add('datetime')
|
|
52
|
+
>>> imports.add('ctypes', '*')
|
|
53
|
+
>>> 'datetime' in imports
|
|
54
|
+
True
|
|
55
|
+
>>> ('ctypes', '*') in imports
|
|
56
|
+
True
|
|
57
|
+
>>> 'os' in imports
|
|
58
|
+
False
|
|
59
|
+
>>> 'ctypes' in imports
|
|
60
|
+
False
|
|
61
|
+
>>> ('ctypes', 'c_int') in imports
|
|
62
|
+
False
|
|
63
|
+
"""
|
|
64
|
+
if isinstance(item, tuple):
|
|
65
|
+
from_, import_ = item
|
|
66
|
+
else:
|
|
67
|
+
from_, import_ = None, item
|
|
68
|
+
if import_ in self.data:
|
|
69
|
+
return self.data[import_] == from_
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
def get_symbols(self) -> Set[str]:
|
|
73
|
+
names = set()
|
|
74
|
+
for key, val in self.data.items():
|
|
75
|
+
if val is None or key == "*":
|
|
76
|
+
continue
|
|
77
|
+
names.add(key)
|
|
78
|
+
return names
|
|
79
|
+
|
|
80
|
+
def _make_line(self, from_, imports):
|
|
81
|
+
import_ = ", ".join(imports)
|
|
82
|
+
code = "from %s import %s" % (from_, import_)
|
|
83
|
+
if len(code) <= 80:
|
|
84
|
+
return code
|
|
85
|
+
wrapper = textwrap.TextWrapper(
|
|
86
|
+
subsequent_indent=" ", initial_indent=" ", break_long_words=False
|
|
87
|
+
)
|
|
88
|
+
import_ = "\n".join(wrapper.wrap(import_))
|
|
89
|
+
code = "from %s import (\n%s\n)" % (from_, import_)
|
|
90
|
+
return code
|
|
91
|
+
|
|
92
|
+
def getvalue(self):
|
|
93
|
+
ns = {}
|
|
94
|
+
lines = []
|
|
95
|
+
for key, val in self.data.items():
|
|
96
|
+
if val is None:
|
|
97
|
+
ns[key] = val
|
|
98
|
+
elif key == "*":
|
|
99
|
+
lines.append("from %s import *" % val)
|
|
100
|
+
else:
|
|
101
|
+
ns.setdefault(val, set()).add(key)
|
|
102
|
+
for key, val in ns.items():
|
|
103
|
+
if val is None:
|
|
104
|
+
lines.append("import %s" % key)
|
|
105
|
+
else:
|
|
106
|
+
names = sorted(val, key=lambda s: s.lower())
|
|
107
|
+
lines.append(self._make_line(key, names))
|
|
108
|
+
return "\n".join(lines)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DeclaredNamespaces(object):
|
|
112
|
+
def __init__(self):
|
|
113
|
+
self.data = {}
|
|
114
|
+
|
|
115
|
+
def add(self, alias, definition, comment=None):
|
|
116
|
+
"""Adds a namespace will be declared.
|
|
117
|
+
|
|
118
|
+
Examples:
|
|
119
|
+
>>> declarations = DeclaredNamespaces()
|
|
120
|
+
>>> declarations.add('STRING', 'c_char_p')
|
|
121
|
+
>>> declarations.add('_lcid', '0', 'change this if required')
|
|
122
|
+
>>> print(declarations.getvalue())
|
|
123
|
+
STRING = c_char_p
|
|
124
|
+
_lcid = 0 # change this if required
|
|
125
|
+
>>> assert declarations.get_symbols() == {
|
|
126
|
+
... 'STRING', '_lcid'
|
|
127
|
+
... }
|
|
128
|
+
"""
|
|
129
|
+
self.data[(alias, definition)] = comment
|
|
130
|
+
|
|
131
|
+
def get_symbols(self) -> Set[str]:
|
|
132
|
+
names = set()
|
|
133
|
+
for alias, _ in self.data.keys():
|
|
134
|
+
names.add(alias)
|
|
135
|
+
return names
|
|
136
|
+
|
|
137
|
+
def getvalue(self):
|
|
138
|
+
lines = []
|
|
139
|
+
for (alias, definition), comment in self.data.items():
|
|
140
|
+
code = "%s = %s" % (alias, definition)
|
|
141
|
+
if comment:
|
|
142
|
+
code = code + " # %s" % comment
|
|
143
|
+
lines.append(code)
|
|
144
|
+
return "\n".join(lines)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class EnumerationNamespaces(object):
|
|
148
|
+
def __init__(self):
|
|
149
|
+
self.data: Dict[str, List[Tuple[str, int]]] = {}
|
|
150
|
+
|
|
151
|
+
def add(self, enum_name: str, member_name: str, value: int) -> None:
|
|
152
|
+
"""Adds a namespace will be enumeration and its member.
|
|
153
|
+
|
|
154
|
+
Examples:
|
|
155
|
+
<BLANKLINE> is necessary for doctest
|
|
156
|
+
>>> enums = EnumerationNamespaces()
|
|
157
|
+
>>> assert not enums
|
|
158
|
+
>>> enums.add('Foo', 'ham', 1)
|
|
159
|
+
>>> assert enums
|
|
160
|
+
>>> enums.add('Foo', 'spam', 2)
|
|
161
|
+
>>> enums.add('Bar', 'bacon', 3)
|
|
162
|
+
>>> assert 'Foo' in enums
|
|
163
|
+
>>> assert 'Baz' not in enums
|
|
164
|
+
>>> print(enums.to_intflags())
|
|
165
|
+
class Foo(IntFlag):
|
|
166
|
+
ham = 1
|
|
167
|
+
spam = 2
|
|
168
|
+
<BLANKLINE>
|
|
169
|
+
<BLANKLINE>
|
|
170
|
+
class Bar(IntFlag):
|
|
171
|
+
bacon = 3
|
|
172
|
+
>>> print(enums.to_constants())
|
|
173
|
+
# values for enumeration 'Foo'
|
|
174
|
+
ham = 1
|
|
175
|
+
spam = 2
|
|
176
|
+
Foo = c_int # enum
|
|
177
|
+
<BLANKLINE>
|
|
178
|
+
# values for enumeration 'Bar'
|
|
179
|
+
bacon = 3
|
|
180
|
+
Bar = c_int # enum
|
|
181
|
+
"""
|
|
182
|
+
self.data.setdefault(enum_name, []).append((member_name, value))
|
|
183
|
+
|
|
184
|
+
def __contains__(self, item: str) -> bool:
|
|
185
|
+
return item in self.data
|
|
186
|
+
|
|
187
|
+
def __bool__(self) -> bool:
|
|
188
|
+
return bool(self.data)
|
|
189
|
+
|
|
190
|
+
def get_symbols(self) -> Set[str]:
|
|
191
|
+
return set(self.data)
|
|
192
|
+
|
|
193
|
+
def to_constants(self) -> str:
|
|
194
|
+
blocks = []
|
|
195
|
+
for enum_name, enum_members in self.data.items():
|
|
196
|
+
lines = []
|
|
197
|
+
lines.append(f"# values for enumeration '{enum_name}'")
|
|
198
|
+
for n, v in enum_members:
|
|
199
|
+
lines.append(f"{n} = {v}")
|
|
200
|
+
lines.append(f"{enum_name} = c_int # enum")
|
|
201
|
+
blocks.append("\n".join(lines))
|
|
202
|
+
return "\n\n".join(blocks)
|
|
203
|
+
|
|
204
|
+
def to_intflags(self) -> str:
|
|
205
|
+
blocks = []
|
|
206
|
+
for enum_name, enum_members in self.data.items():
|
|
207
|
+
lines = []
|
|
208
|
+
lines.append(f"class {enum_name}(IntFlag):")
|
|
209
|
+
for member_name, value in enum_members:
|
|
210
|
+
lines.append(f" {member_name} = {value}")
|
|
211
|
+
blocks.append("\n".join(lines))
|
|
212
|
+
return "\n\n\n".join(blocks)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from comtypes.tools import typedesc
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _calc_packing(struct, fields, pack, isStruct):
|
|
5
|
+
# Try a certain packing, raise PackingError if field offsets,
|
|
6
|
+
# total size ot total alignment is wrong.
|
|
7
|
+
if struct.size is None: # incomplete struct
|
|
8
|
+
return -1
|
|
9
|
+
if struct.name in dont_assert_size:
|
|
10
|
+
return None
|
|
11
|
+
if struct.bases:
|
|
12
|
+
size = struct.bases[0].size
|
|
13
|
+
total_align = struct.bases[0].align
|
|
14
|
+
else:
|
|
15
|
+
size = 0
|
|
16
|
+
total_align = 8 # in bits
|
|
17
|
+
for i, f in enumerate(fields):
|
|
18
|
+
if f.bits: # this code cannot handle bit field sizes.
|
|
19
|
+
# print "##XXX FIXME"
|
|
20
|
+
return -2 # XXX FIXME
|
|
21
|
+
s, a = storage(f.typ)
|
|
22
|
+
if pack is not None:
|
|
23
|
+
a = min(pack, a)
|
|
24
|
+
if size % a:
|
|
25
|
+
size += a - size % a
|
|
26
|
+
if isStruct:
|
|
27
|
+
if size != f.offset:
|
|
28
|
+
raise PackingError("field %s offset (%s/%s)" % (f.name, size, f.offset))
|
|
29
|
+
size += s
|
|
30
|
+
else:
|
|
31
|
+
size = max(size, s)
|
|
32
|
+
total_align = max(total_align, a)
|
|
33
|
+
if total_align != struct.align:
|
|
34
|
+
raise PackingError("total alignment (%s/%s)" % (total_align, struct.align))
|
|
35
|
+
a = total_align
|
|
36
|
+
if pack is not None:
|
|
37
|
+
a = min(pack, a)
|
|
38
|
+
if size % a:
|
|
39
|
+
size += a - size % a
|
|
40
|
+
if size != struct.size:
|
|
41
|
+
raise PackingError("total size (%s/%s)" % (size, struct.size))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def calc_packing(struct, fields):
|
|
45
|
+
# try several packings, starting with unspecified packing
|
|
46
|
+
isStruct = isinstance(struct, typedesc.Structure)
|
|
47
|
+
for pack in [None, 16 * 8, 8 * 8, 4 * 8, 2 * 8, 1 * 8]:
|
|
48
|
+
try:
|
|
49
|
+
_calc_packing(struct, fields, pack, isStruct)
|
|
50
|
+
except PackingError as details:
|
|
51
|
+
continue
|
|
52
|
+
else:
|
|
53
|
+
if pack is None:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
return int(pack / 8)
|
|
57
|
+
|
|
58
|
+
raise PackingError("PACKING FAILED: %s" % details)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class PackingError(Exception):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# XXX These should be filtered out in gccxmlparser.
|
|
66
|
+
dont_assert_size = set(
|
|
67
|
+
[
|
|
68
|
+
"__si_class_type_info_pseudo",
|
|
69
|
+
"__class_type_info_pseudo",
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def storage(t):
|
|
75
|
+
# return the size and alignment of a type
|
|
76
|
+
if isinstance(t, typedesc.Typedef):
|
|
77
|
+
return storage(t.typ)
|
|
78
|
+
elif isinstance(t, typedesc.ArrayType):
|
|
79
|
+
s, a = storage(t.typ)
|
|
80
|
+
return s * (int(t.max) - int(t.min) + 1), a
|
|
81
|
+
return int(t.size), int(t.align)
|