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
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
import ctypes
|
|
3
|
+
import importlib
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import types
|
|
8
|
+
if sys.version_info >= (3, 0):
|
|
9
|
+
base_text_type = str
|
|
10
|
+
import winreg
|
|
11
|
+
else:
|
|
12
|
+
base_text_type = basestring
|
|
13
|
+
import _winreg as winreg
|
|
14
|
+
|
|
15
|
+
from comtypes import GUID, TYPE_CHECKING, typeinfo
|
|
16
|
+
import comtypes.client
|
|
17
|
+
from comtypes.tools import codegenerator, tlbparser
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from typing import Any, Tuple, List, Optional, Dict, Union as _UnionT
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
PATH = os.environ["PATH"].split(os.pathsep)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _my_import(fullname):
|
|
29
|
+
# type: (str) -> types.ModuleType
|
|
30
|
+
"""helper function to import dotted modules"""
|
|
31
|
+
import comtypes.gen as g
|
|
32
|
+
if comtypes.client.gen_dir and comtypes.client.gen_dir not in g.__path__:
|
|
33
|
+
g.__path__.append(comtypes.client.gen_dir) # type: ignore
|
|
34
|
+
return importlib.import_module(fullname)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _resolve_filename(tlib_string, dirpath):
|
|
38
|
+
# type: (str, str) -> Tuple[str, bool]
|
|
39
|
+
"""Tries to make sense of a type library specified as a string.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
tlib_string: type library designator
|
|
43
|
+
dirpath: a directory to relativize the location
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
(abspath, True) or (relpath, False):
|
|
47
|
+
where relpath is an unresolved path.
|
|
48
|
+
"""
|
|
49
|
+
assert isinstance(tlib_string, base_text_type)
|
|
50
|
+
# pathname of type library
|
|
51
|
+
if os.path.isabs(tlib_string):
|
|
52
|
+
# a specific location
|
|
53
|
+
return tlib_string, True
|
|
54
|
+
elif dirpath:
|
|
55
|
+
abspath = os.path.normpath(os.path.join(dirpath, tlib_string))
|
|
56
|
+
if os.path.exists(abspath):
|
|
57
|
+
return abspath, True
|
|
58
|
+
# try with respect to cwd (if _getmodule executed from command line)
|
|
59
|
+
abspath = os.path.abspath(tlib_string)
|
|
60
|
+
if os.path.exists(abspath):
|
|
61
|
+
return abspath, True
|
|
62
|
+
# Otherwise it may still be that the file is on Windows search
|
|
63
|
+
# path for typelibs, and we leave the pathname alone.
|
|
64
|
+
return tlib_string, False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def GetModule(tlib):
|
|
68
|
+
# type: (_UnionT[Any, typeinfo.ITypeLib]) -> types.ModuleType
|
|
69
|
+
"""Create a module wrapping a COM typelibrary on demand.
|
|
70
|
+
|
|
71
|
+
'tlib' must be ...
|
|
72
|
+
- an `ITypeLib` COM pointer instance
|
|
73
|
+
- an absolute pathname of a type library
|
|
74
|
+
- a relative pathname of a type library
|
|
75
|
+
- interpreted as relative to the callers `__file__`, if this exists
|
|
76
|
+
- a COM CLSID `GUID`
|
|
77
|
+
- a `tuple`/`list` specifying the typelib
|
|
78
|
+
- `List[_UnionT[str, int]]`
|
|
79
|
+
- `(libid: str[, wMajorVerNum: int, wMinorVerNum: int[, lcid: int]])`
|
|
80
|
+
- an object with `_reg_libid_: str` and `_reg_version_: Iterable[int]`
|
|
81
|
+
|
|
82
|
+
This function determines the module name from the typelib
|
|
83
|
+
attributes, then tries to import it. If that fails because the
|
|
84
|
+
module doesn't exist, the module is generated into the
|
|
85
|
+
`comtypes.gen` package.
|
|
86
|
+
|
|
87
|
+
It is possible to delete the whole `comtypes/gen` directory to
|
|
88
|
+
remove all generated modules, the directory and the `__init__.py`
|
|
89
|
+
file in it will be recreated when needed.
|
|
90
|
+
|
|
91
|
+
If `comtypes.gen.__path__` is not a directory (in a frozen
|
|
92
|
+
executable it lives in a zip archive), generated modules are only
|
|
93
|
+
created in memory without writing them to the file system.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
GetModule("UIAutomationCore.dll")
|
|
97
|
+
|
|
98
|
+
would create modules named
|
|
99
|
+
|
|
100
|
+
`comtypes.gen._944DE083_8FB8_45CF_BCB7_C477ACB2F897_L_M_m`
|
|
101
|
+
- typelib wrapper module
|
|
102
|
+
- where L, M, m are numbers of Lcid, Major-ver, minor-ver
|
|
103
|
+
`comtypes.gen.UIAutomationClient`
|
|
104
|
+
- friendly named module
|
|
105
|
+
|
|
106
|
+
containing the Python wrapper code for the type library used by
|
|
107
|
+
UIAutomation. The former module contains all the code, the
|
|
108
|
+
latter is a short stub loading the former.
|
|
109
|
+
"""
|
|
110
|
+
if isinstance(tlib, base_text_type):
|
|
111
|
+
tlib_string = tlib
|
|
112
|
+
# if a relative pathname is used, we try to interpret it relative to
|
|
113
|
+
# the directory of the calling module (if not from command line)
|
|
114
|
+
frame = sys._getframe(1)
|
|
115
|
+
_file_ = frame.f_globals.get("__file__", None) # type: str
|
|
116
|
+
pathname, is_abs = _resolve_filename(tlib_string, _file_ and os.path.dirname(_file_))
|
|
117
|
+
logger.debug("GetModule(%s), resolved: %s", pathname, is_abs)
|
|
118
|
+
tlib = _load_tlib(pathname) # don't register
|
|
119
|
+
if not is_abs:
|
|
120
|
+
# try to get path after loading, but this only works if already registered
|
|
121
|
+
pathname = tlbparser.get_tlib_filename(tlib)
|
|
122
|
+
if pathname is None:
|
|
123
|
+
logger.info("GetModule(%s): could not resolve to a filename", tlib)
|
|
124
|
+
pathname = tlib_string
|
|
125
|
+
# if above path torture resulted in an absolute path, then the file exists (at this point)!
|
|
126
|
+
assert not(os.path.isabs(pathname)) or os.path.exists(pathname)
|
|
127
|
+
else:
|
|
128
|
+
pathname = None
|
|
129
|
+
tlib = _load_tlib(tlib)
|
|
130
|
+
logger.debug("GetModule(%s)", tlib.GetLibAttr())
|
|
131
|
+
# create and import the real typelib wrapper module
|
|
132
|
+
mod = _create_wrapper_module(tlib, pathname)
|
|
133
|
+
# try to get the friendly-name, if not, returns the real typelib wrapper module
|
|
134
|
+
modulename = codegenerator.name_friendly_module(tlib)
|
|
135
|
+
if modulename is None:
|
|
136
|
+
return mod
|
|
137
|
+
if sys.version_info < (3, 0):
|
|
138
|
+
modulename = modulename.encode("mbcs")
|
|
139
|
+
# create and import the friendly-named module
|
|
140
|
+
return _create_friendly_module(tlib, modulename)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _load_tlib(obj):
|
|
144
|
+
# type: (Any) -> typeinfo.ITypeLib
|
|
145
|
+
"""Load a pointer of ITypeLib on demand."""
|
|
146
|
+
# obj is a filepath or a ProgID
|
|
147
|
+
if isinstance(obj, base_text_type):
|
|
148
|
+
# in any case, attempt to load and if tlib_string is not valid, then raise
|
|
149
|
+
# as "OSError: [WinError -2147312566] Error loading type library/DLL"
|
|
150
|
+
return typeinfo.LoadTypeLibEx(obj)
|
|
151
|
+
# obj is a tlib GUID contain a clsid
|
|
152
|
+
elif isinstance(obj, GUID):
|
|
153
|
+
clsid = str(obj)
|
|
154
|
+
# lookup associated typelib in registry
|
|
155
|
+
with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\TypeLib" % clsid) as key:
|
|
156
|
+
libid = winreg.EnumValue(key, 0)[1]
|
|
157
|
+
with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Version" % clsid) as key:
|
|
158
|
+
ver = winreg.EnumValue(key, 0)[1].split(".")
|
|
159
|
+
return typeinfo.LoadRegTypeLib(GUID(libid), int(ver[0]), int(ver[1]), 0)
|
|
160
|
+
# obj is a sequence containing libid
|
|
161
|
+
elif isinstance(obj, (tuple, list)):
|
|
162
|
+
libid, ver = obj[0], obj[1:]
|
|
163
|
+
if not ver: # case of version numbers are not containing
|
|
164
|
+
with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"TypeLib\%s" % libid) as key:
|
|
165
|
+
ver = [int(v, base=16) for v in winreg.EnumKey(key, 0).split(".")]
|
|
166
|
+
return typeinfo.LoadRegTypeLib(GUID(libid), *ver)
|
|
167
|
+
# obj is a COMObject implementation
|
|
168
|
+
elif hasattr(obj, "_reg_libid_"):
|
|
169
|
+
return typeinfo.LoadRegTypeLib(GUID(obj._reg_libid_), *obj._reg_version_)
|
|
170
|
+
# obj is a pointer of ITypeLib
|
|
171
|
+
elif isinstance(obj, ctypes.POINTER(typeinfo.ITypeLib)):
|
|
172
|
+
return obj # type: ignore
|
|
173
|
+
raise TypeError("'%r' is not supported type for loading typelib" % obj)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _create_module_in_file(modulename, code):
|
|
177
|
+
# type: (str, str) -> types.ModuleType
|
|
178
|
+
"""create module in file system, and import it"""
|
|
179
|
+
# `modulename` is 'comtypes.gen.xxx'
|
|
180
|
+
filename = "%s.py" % modulename.split(".")[-1]
|
|
181
|
+
with open(os.path.join(comtypes.client.gen_dir, filename), "w") as ofi:
|
|
182
|
+
print(code, file=ofi)
|
|
183
|
+
# clear the import cache to make sure Python sees newly created modules
|
|
184
|
+
if hasattr(importlib, "invalidate_caches"):
|
|
185
|
+
importlib.invalidate_caches()
|
|
186
|
+
return _my_import(modulename)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _create_module_in_memory(modulename, code):
|
|
190
|
+
# type: (str, str) -> types.ModuleType
|
|
191
|
+
"""create module in memory system, and import it"""
|
|
192
|
+
# `modulename` is 'comtypes.gen.xxx'
|
|
193
|
+
import comtypes.gen as g
|
|
194
|
+
mod = types.ModuleType(modulename)
|
|
195
|
+
abs_gen_path = os.path.abspath(g.__path__[0]) # type: ignore
|
|
196
|
+
mod.__file__ = os.path.join(abs_gen_path, "<memory>")
|
|
197
|
+
exec(code, mod.__dict__)
|
|
198
|
+
sys.modules[modulename] = mod
|
|
199
|
+
setattr(g, modulename.split(".")[-1], mod)
|
|
200
|
+
return mod
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _create_friendly_module(tlib, modulename):
|
|
204
|
+
# type: (typeinfo.ITypeLib, str) -> types.ModuleType
|
|
205
|
+
"""helper which creates and imports the friendly-named module."""
|
|
206
|
+
try:
|
|
207
|
+
mod = _my_import(modulename)
|
|
208
|
+
except Exception as details:
|
|
209
|
+
logger.info("Could not import %s: %s", modulename, details)
|
|
210
|
+
else:
|
|
211
|
+
return mod
|
|
212
|
+
# the module is always regenerated if the import fails
|
|
213
|
+
logger.info("# Generating %s", modulename)
|
|
214
|
+
# determine the Python module name
|
|
215
|
+
modname = codegenerator.name_wrapper_module(tlib).split(".")[-1]
|
|
216
|
+
code = "from comtypes.gen import %s\n" % modname
|
|
217
|
+
code += "globals().update(%s.__dict__)\n" % modname
|
|
218
|
+
code += "__name__ = '%s'" % modulename
|
|
219
|
+
if comtypes.client.gen_dir is None:
|
|
220
|
+
return _create_module_in_memory(modulename, code)
|
|
221
|
+
return _create_module_in_file(modulename, code)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _create_wrapper_module(tlib, pathname):
|
|
225
|
+
# type: (typeinfo.ITypeLib, Optional[str]) -> types.ModuleType
|
|
226
|
+
"""helper which creates and imports the real typelib wrapper module."""
|
|
227
|
+
modulename = codegenerator.name_wrapper_module(tlib)
|
|
228
|
+
if modulename in sys.modules:
|
|
229
|
+
return sys.modules[modulename]
|
|
230
|
+
try:
|
|
231
|
+
return _my_import(modulename)
|
|
232
|
+
except Exception as details:
|
|
233
|
+
logger.info("Could not import %s: %s", modulename, details)
|
|
234
|
+
# generate the module since it doesn't exist or is out of date
|
|
235
|
+
logger.info("# Generating %s", modulename)
|
|
236
|
+
p = tlbparser.TypeLibParser(tlib)
|
|
237
|
+
if pathname is None:
|
|
238
|
+
pathname = tlbparser.get_tlib_filename(tlib)
|
|
239
|
+
items = list(p.parse().values())
|
|
240
|
+
codegen = codegenerator.CodeGenerator(_get_known_symbols())
|
|
241
|
+
code = codegen.generate_code(items, filename=pathname)
|
|
242
|
+
for ext_tlib in codegen.externals: # generates dependency COM-lib modules
|
|
243
|
+
GetModule(ext_tlib)
|
|
244
|
+
if comtypes.client.gen_dir is None:
|
|
245
|
+
return _create_module_in_memory(modulename, code)
|
|
246
|
+
return _create_module_in_file(modulename, code)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _get_known_symbols():
|
|
250
|
+
# type: () -> Dict[str, str]
|
|
251
|
+
known_symbols = {} # type: Dict[str, str]
|
|
252
|
+
for mod_name in (
|
|
253
|
+
"comtypes.persist",
|
|
254
|
+
"comtypes.typeinfo",
|
|
255
|
+
"comtypes.automation",
|
|
256
|
+
"comtypes",
|
|
257
|
+
"ctypes.wintypes",
|
|
258
|
+
"ctypes"
|
|
259
|
+
):
|
|
260
|
+
mod = importlib.import_module(mod_name)
|
|
261
|
+
if hasattr(mod, "__known_symbols__"):
|
|
262
|
+
names = mod.__known_symbols__ # type: List[str]
|
|
263
|
+
else:
|
|
264
|
+
names = list(mod.__dict__)
|
|
265
|
+
for name in names:
|
|
266
|
+
known_symbols[name] = mod.__name__
|
|
267
|
+
return known_symbols
|
|
268
|
+
|
|
269
|
+
################################################################
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
if __name__ == "__main__":
|
|
273
|
+
# When started as script, generate typelib wrapper from .tlb file.
|
|
274
|
+
GetModule(sys.argv[1])
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any, Callable, Generic, NoReturn, Optional, overload, SupportsIndex,
|
|
3
|
+
Type, TypeVar, Union as _UnionT,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
# symbols those what might occur recursive imports in runtime.
|
|
7
|
+
from comtypes.automation import IDispatch as IDispatch, VARIANT as VARIANT
|
|
8
|
+
from comtypes.server import IClassFactory as IClassFactory
|
|
9
|
+
from comtypes.typeinfo import ITypeInfo as ITypeInfo
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def AnnoField() -> Any:
|
|
13
|
+
"""**THIS IS `TYPE_CHECKING` ONLY SYMBOL.
|
|
14
|
+
|
|
15
|
+
This is workaround for class field type annotations for old
|
|
16
|
+
python versions.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
# instead of class field annotation, like below
|
|
20
|
+
|
|
21
|
+
class Foo:
|
|
22
|
+
# spam: int # <- not available in old versions.
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
spam = AnnoField() # type: int # <- available in old versions.
|
|
25
|
+
"""
|
|
26
|
+
...
|
|
@@ -210,3 +210,17 @@ class DictPropertyBag(COMObject):
|
|
|
210
210
|
val = var[0].value
|
|
211
211
|
self.values[name] = val
|
|
212
212
|
return S_OK
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
__known_symbols__ = [
|
|
216
|
+
'CLIPFORMAT', 'DictPropertyBag', 'IErrorLog', 'IPersistFile',
|
|
217
|
+
'IPersistPropertyBag', 'IPersistPropertyBag2', 'IPropertyBag',
|
|
218
|
+
'IPropertyBag2', 'tagPROPBAG2', 'PROPBAG2_TYPE_DATA',
|
|
219
|
+
'PROPBAG2_TYPE_MONIKER', 'PROPBAG2_TYPE_OBJECT', 'PROPBAG2_TYPE_STORAGE',
|
|
220
|
+
'PROPBAG2_TYPE_STREAM', 'PROPBAG2_TYPE_UNDEFINED', 'PROPBAG2_TYPE_URL',
|
|
221
|
+
'STGM_CONVERT', 'STGM_CREATE', 'STGM_DELETEONRELEASE', 'STGM_DIRECT',
|
|
222
|
+
'STGM_DIRECT_SWMR', 'STGM_FAILIFTHERE', 'STGM_NOSCRATCH',
|
|
223
|
+
'STGM_NOSNAPSHOT', 'STGM_PRIORITY', 'STGM_READ', 'STGM_READWRITE',
|
|
224
|
+
'STGM_SHARE_DENY_NONE', 'STGM_SHARE_DENY_READ', 'STGM_SHARE_DENY_WRITE',
|
|
225
|
+
'STGM_SHARE_EXCLUSIVE', 'STGM_SIMPLE', 'STGM_TRANSACTED', 'STGM_WRITE',
|
|
226
|
+
]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
import array
|
|
3
|
+
import comtypes
|
|
3
4
|
from ctypes import (POINTER, Structure, byref, cast, c_long, memmove, pointer,
|
|
4
5
|
sizeof)
|
|
5
|
-
from comtypes import _safearray, IUnknown, com_interface_registry
|
|
6
|
+
from comtypes import _safearray, IUnknown, com_interface_registry
|
|
6
7
|
from comtypes.patcher import Patch
|
|
7
8
|
|
|
8
|
-
numpy = npsupport.numpy
|
|
9
9
|
_safearray_type_cache = {}
|
|
10
10
|
|
|
11
11
|
|
|
@@ -27,6 +27,7 @@ class _SafeArrayAsNdArrayContextManager(object):
|
|
|
27
27
|
thread_local = threading.local()
|
|
28
28
|
|
|
29
29
|
def __enter__(self):
|
|
30
|
+
comtypes.npsupport.enable()
|
|
30
31
|
try:
|
|
31
32
|
self.thread_local.count += 1
|
|
32
33
|
except AttributeError:
|
|
@@ -113,7 +114,7 @@ def _make_safearray_type(itemtype):
|
|
|
113
114
|
one-dimensional arrays. To create multidimensional arrys,
|
|
114
115
|
numpy arrays must be passed.
|
|
115
116
|
"""
|
|
116
|
-
if npsupport.isndarray(value):
|
|
117
|
+
if comtypes.npsupport.isndarray(value):
|
|
117
118
|
return cls.create_from_ndarray(value, extra)
|
|
118
119
|
|
|
119
120
|
# For VT_UNKNOWN or VT_DISPATCH, extra must be a pointer to
|
|
@@ -156,18 +157,18 @@ def _make_safearray_type(itemtype):
|
|
|
156
157
|
from comtypes.automation import VARIANT
|
|
157
158
|
# If processing VARIANT, makes sure the array type is correct.
|
|
158
159
|
if cls._itemtype_ is VARIANT:
|
|
159
|
-
if value.dtype != npsupport.VARIANT_dtype:
|
|
160
|
+
if value.dtype != comtypes.npsupport.VARIANT_dtype:
|
|
160
161
|
value = _ndarray_to_variant_array(value)
|
|
161
162
|
else:
|
|
162
163
|
ai = value.__array_interface__
|
|
163
164
|
if ai["version"] != 3:
|
|
164
165
|
raise TypeError("only __array_interface__ version 3 supported")
|
|
165
|
-
if cls._itemtype_ != npsupport.typecodes[ai["typestr"]]:
|
|
166
|
+
if cls._itemtype_ != comtypes.npsupport.typecodes[ai["typestr"]]:
|
|
166
167
|
raise TypeError("Wrong array item type")
|
|
167
168
|
|
|
168
169
|
# SAFEARRAYs have Fortran order; convert the numpy array if needed
|
|
169
170
|
if not value.flags.f_contiguous:
|
|
170
|
-
value = numpy.array(value, order="F")
|
|
171
|
+
value = comtypes.npsupport.numpy.array(value, order="F")
|
|
171
172
|
|
|
172
173
|
# For VT_UNKNOWN or VT_DISPATCH, extra must be a pointer to
|
|
173
174
|
# the GUID of the interface.
|
|
@@ -240,15 +241,13 @@ def _make_safearray_type(itemtype):
|
|
|
240
241
|
|
|
241
242
|
if dim == 0:
|
|
242
243
|
if safearray_as_ndarray:
|
|
243
|
-
|
|
244
|
-
return numpy.array()
|
|
244
|
+
return comtypes.npsupport.numpy.array()
|
|
245
245
|
return tuple()
|
|
246
246
|
elif dim == 1:
|
|
247
247
|
num_elements = self._get_size(1)
|
|
248
248
|
result = self._get_elements_raw(num_elements)
|
|
249
249
|
if safearray_as_ndarray:
|
|
250
|
-
|
|
251
|
-
return numpy.asarray(result)
|
|
250
|
+
return comtypes.npsupport.numpy.asarray(result)
|
|
252
251
|
return tuple(result)
|
|
253
252
|
elif dim == 2:
|
|
254
253
|
# get the number of elements in each dimension
|
|
@@ -258,8 +257,7 @@ def _make_safearray_type(itemtype):
|
|
|
258
257
|
# this must be reshaped and transposed because it is
|
|
259
258
|
# flat, and in VB order
|
|
260
259
|
if safearray_as_ndarray:
|
|
261
|
-
|
|
262
|
-
return numpy.asarray(result).reshape((cols, rows)).T
|
|
260
|
+
return comtypes.npsupport.numpy.asarray(result).reshape((cols, rows)).T
|
|
263
261
|
result = [tuple(result[r::rows]) for r in range(rows)]
|
|
264
262
|
return tuple(result)
|
|
265
263
|
else:
|
|
@@ -270,8 +268,7 @@ def _make_safearray_type(itemtype):
|
|
|
270
268
|
for d in range(1, dim+1)]
|
|
271
269
|
row = self._get_row(0, indexes, lowerbounds, upperbounds)
|
|
272
270
|
if safearray_as_ndarray:
|
|
273
|
-
|
|
274
|
-
return numpy.asarray(row)
|
|
271
|
+
return comtypes.npsupport.numpy.asarray(row)
|
|
275
272
|
return row
|
|
276
273
|
|
|
277
274
|
def _get_elements_raw(self, num_elements):
|
|
@@ -315,8 +312,8 @@ def _make_safearray_type(itemtype):
|
|
|
315
312
|
# XXX Only try to convert types known to
|
|
316
313
|
# numpy.ctypeslib.
|
|
317
314
|
if (safearray_as_ndarray and self._itemtype_ in
|
|
318
|
-
list(npsupport.typecodes.keys())):
|
|
319
|
-
arr = numpy.ctypeslib.as_array(ptr,
|
|
315
|
+
list(comtypes.npsupport.typecodes.keys())):
|
|
316
|
+
arr = comtypes.npsupport.numpy.ctypeslib.as_array(ptr,
|
|
320
317
|
(num_elements,))
|
|
321
318
|
return arr.copy()
|
|
322
319
|
return ptr[:num_elements]
|
|
@@ -372,17 +369,20 @@ def _make_safearray_type(itemtype):
|
|
|
372
369
|
def _ndarray_to_variant_array(value):
|
|
373
370
|
""" Convert an ndarray to VARIANT_dtype array """
|
|
374
371
|
# Check that variant arrays are supported
|
|
375
|
-
if npsupport.VARIANT_dtype is None:
|
|
372
|
+
if comtypes.npsupport.interop.VARIANT_dtype is None:
|
|
376
373
|
msg = "VARIANT ndarrays require NumPy 1.7 or newer."
|
|
377
374
|
raise RuntimeError(msg)
|
|
375
|
+
numpy = comtypes.npsupport.interop.numpy
|
|
378
376
|
|
|
379
377
|
# special cases
|
|
380
|
-
if numpy.issubdtype(value.dtype, npsupport.datetime64):
|
|
378
|
+
if numpy.issubdtype(value.dtype, comtypes.npsupport.interop.datetime64):
|
|
381
379
|
return _datetime64_ndarray_to_variant_array(value)
|
|
382
380
|
|
|
383
381
|
from comtypes.automation import VARIANT
|
|
384
382
|
# Empty array
|
|
385
|
-
varr = numpy.zeros(
|
|
383
|
+
varr = numpy.zeros(
|
|
384
|
+
value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F'
|
|
385
|
+
)
|
|
386
386
|
# Convert each value to a variant and put it in the array.
|
|
387
387
|
varr.flat = [VARIANT(v) for v in value.flat]
|
|
388
388
|
return varr
|
|
@@ -394,11 +394,12 @@ def _datetime64_ndarray_to_variant_array(value):
|
|
|
394
394
|
# since midnight 30 December 1899. Hours and minutes are represented as
|
|
395
395
|
# fractional days.
|
|
396
396
|
from comtypes.automation import VT_DATE
|
|
397
|
+
numpy = comtypes.npsupport.interop.numpy
|
|
397
398
|
value = numpy.array(value, "datetime64[ns]")
|
|
398
|
-
value = value - npsupport.com_null_date64
|
|
399
|
+
value = value - comtypes.npsupport.interop.com_null_date64
|
|
399
400
|
# Convert to days
|
|
400
401
|
value = value / numpy.timedelta64(1, 'D')
|
|
401
|
-
varr = numpy.zeros(value.shape, npsupport.VARIANT_dtype, order='F')
|
|
402
|
+
varr = numpy.zeros(value.shape, comtypes.npsupport.interop.VARIANT_dtype, order='F')
|
|
402
403
|
varr['vt'] = VT_DATE
|
|
403
404
|
varr['_']['VT_R8'].flat = value.flat
|
|
404
405
|
return varr
|
|
@@ -10,13 +10,6 @@ import unittest
|
|
|
10
10
|
|
|
11
11
|
use_resources = ["*"]
|
|
12
12
|
|
|
13
|
-
def get_numpy():
|
|
14
|
-
'''Get numpy if it is available.'''
|
|
15
|
-
try:
|
|
16
|
-
import numpy
|
|
17
|
-
return numpy
|
|
18
|
-
except ImportError:
|
|
19
|
-
return None
|
|
20
13
|
|
|
21
14
|
def register_server(source_dir):
|
|
22
15
|
""" Register testing server appropriate for the python architecture.
|
|
@@ -69,6 +69,11 @@ class Test_GetModule(ut.TestCase):
|
|
|
69
69
|
mod = comtypes.client.GetModule(clsid)
|
|
70
70
|
self.assertEqual(mod.MediaPlayer._reg_clsid_, clsid)
|
|
71
71
|
|
|
72
|
+
def test_ptr_itypelib(self):
|
|
73
|
+
from comtypes import typeinfo
|
|
74
|
+
mod = comtypes.client.GetModule(typeinfo.LoadTypeLibEx("scrrun.dll"))
|
|
75
|
+
self.assertIs(mod, Scripting)
|
|
76
|
+
|
|
72
77
|
def test_imports_IEnumVARIANT_from_other_generated_modules(self):
|
|
73
78
|
# NOTE: `codegenerator` generates code that contains unused imports,
|
|
74
79
|
# but removing them are attracting wierd bugs in library-wrappers
|
|
@@ -84,6 +89,36 @@ class Test_GetModule(ut.TestCase):
|
|
|
84
89
|
# NOTE: `WindowsInstaller`, which has `Patch` definition in dll.
|
|
85
90
|
comtypes.client.GetModule("msi.dll")
|
|
86
91
|
|
|
92
|
+
def test_raises_typerror_if_takes_unsupported(self):
|
|
93
|
+
with self.assertRaises(TypeError):
|
|
94
|
+
comtypes.client.GetModule(object())
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Test_KnownSymbols(ut.TestCase):
|
|
98
|
+
# It is guaranteed that each element of `__known_symbols__` is in
|
|
99
|
+
# each module's namespace.
|
|
100
|
+
# If this test fails, `ImportError` or `AttributeError` may be raised
|
|
101
|
+
# when generating a `comtypes.gen._xxx...` in runtime.
|
|
102
|
+
def _doit(self, mod):
|
|
103
|
+
for s in mod.__known_symbols__:
|
|
104
|
+
self.assertTrue(hasattr(mod, s))
|
|
105
|
+
|
|
106
|
+
def test_symbols_in_comtypes(self):
|
|
107
|
+
import comtypes
|
|
108
|
+
self._doit(comtypes)
|
|
109
|
+
|
|
110
|
+
def test_symbols_in_comtypes_automation(self):
|
|
111
|
+
import comtypes.automation
|
|
112
|
+
self._doit(comtypes.automation)
|
|
113
|
+
|
|
114
|
+
def test_symbols_in_comtypes_typeinfo(self):
|
|
115
|
+
import comtypes.typeinfo
|
|
116
|
+
self._doit(comtypes.typeinfo)
|
|
117
|
+
|
|
118
|
+
def test_symbols_in_comtypes_persist(self):
|
|
119
|
+
import comtypes.persist
|
|
120
|
+
self._doit(comtypes.persist)
|
|
121
|
+
|
|
87
122
|
|
|
88
123
|
class Test_CreateObject(ut.TestCase):
|
|
89
124
|
def test_progid(self):
|
|
@@ -7,10 +7,6 @@ from comtypes.client import CreateObject
|
|
|
7
7
|
from comtypes.client.lazybind import Dispatch
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def setUpModule():
|
|
11
|
-
raise unittest.SkipTest("Depends on `comtypes.safearray` which depends on numpy which isn't "
|
|
12
|
-
"listed in project dependencies.")
|
|
13
|
-
|
|
14
10
|
class Test(unittest.TestCase):
|
|
15
11
|
def test_dict(self):
|
|
16
12
|
d = CreateObject("Scripting.Dictionary", dynamic=True)
|