comtypes 1.4.4__zip → 1.4.5__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.4 → comtypes-1.4.5}/CHANGES.txt +12 -0
- {comtypes-1.4.4/comtypes.egg-info → comtypes-1.4.5}/PKG-INFO +1 -1
- comtypes-1.4.5/comtypes/__init__.py +268 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_comobject.py +2 -1
- comtypes-1.4.5/comtypes/_idl_stuff.py +67 -0
- comtypes-1.4.5/comtypes/_post_coinit/__init__.py +15 -0
- comtypes-1.4.5/comtypes/_post_coinit/bstr.py +30 -0
- comtypes-1.4.5/comtypes/_post_coinit/misc.py +385 -0
- comtypes-1.4.5/comtypes/_post_coinit/unknwn.py +537 -0
- comtypes-1.4.5/comtypes/_py_instance_method.py +13 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_safearray.py +3 -2
- comtypes-1.4.5/comtypes/_tlib_version_checker.py +18 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/automation.py +22 -6
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_generate.py +2 -1
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/hints.pyi +34 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/safearray.py +11 -4
- comtypes-1.4.5/comtypes/stream.py +65 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client.py +11 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dispifc_records.py +1 -1
- comtypes-1.4.5/comtypes/test/test_dispifc_safearrays.py +89 -0
- comtypes-1.4.5/comtypes/test/test_istream.py +53 -0
- comtypes-1.4.5/comtypes/test/test_midl_safearray_create.py +100 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_wmi.py +11 -18
- {comtypes-1.4.4 → comtypes-1.4.5/comtypes.egg-info}/PKG-INFO +1 -1
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/SOURCES.txt +11 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/setup.cfg +1 -0
- comtypes-1.4.4/comtypes/__init__.py +0 -1229
- {comtypes-1.4.4 → comtypes-1.4.5}/LICENSE.txt +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/MANIFEST.in +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/README.md +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/GUID.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_memberspec.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_meta.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/_npsupport.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/__init__.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_code_cache.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_constants.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/_events.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/client/lazybind.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/errorinfo.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/git.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/hresult.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/logutil.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/messageloop.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/patcher.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/persist.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/__init__.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/automation.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/inprocserver.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/localserver.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/register.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/shelllink.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/__init__.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/find_memleak.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mylib.tlb +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/runtests.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/setup.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_BSTR.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_GUID.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_agilent.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_clear_cache.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client_dynamic.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_client_regenerate_modules.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_collections.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_comserver.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dict.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_findgendir.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_ie.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_ienum.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_imfattributes.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_inout_args.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_npsupport.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_outparam.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_propputref.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_safearray.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_server.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_urlhistory.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_variant.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/test_word.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/test/urlhist.tlb +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/__init__.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/codegenerator.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/helpers.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/modulenamer.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/namespaces.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/packing.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/codegenerator/typeannotator.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/tlbparser.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/typedesc.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/tools/typedesc_base.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/typeinfo.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/util.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes/viewobject.py +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/pyproject.toml +0 -0
- {comtypes-1.4.4 → comtypes-1.4.5}/setup.py +0 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# https://learn.microsoft.com/en-us/windows/win32/api/unknwn/
|
|
2
|
+
|
|
3
|
+
from ctypes import byref, c_ulong, c_void_p, HRESULT, POINTER
|
|
4
|
+
from _ctypes import COMError
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import sys
|
|
8
|
+
import types
|
|
9
|
+
from typing import ClassVar, TYPE_CHECKING, TypeVar
|
|
10
|
+
from typing import Optional
|
|
11
|
+
from typing import List, Type
|
|
12
|
+
|
|
13
|
+
from comtypes import GUID, patcher, _ole32_nohresult, com_interface_registry
|
|
14
|
+
from comtypes._idl_stuff import STDMETHOD
|
|
15
|
+
from comtypes._memberspec import ComMemberGenerator, DispMemberGenerator
|
|
16
|
+
from comtypes._memberspec import _ComMemberSpec, _DispMemberSpec
|
|
17
|
+
from comtypes._py_instance_method import instancemethod
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_all_slice = slice(None, None, None)
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _shutdown(
|
|
26
|
+
func=_ole32_nohresult.CoUninitialize,
|
|
27
|
+
_debug=logger.debug,
|
|
28
|
+
_exc_clear=getattr(sys, "exc_clear", lambda: None),
|
|
29
|
+
):
|
|
30
|
+
# Make sure no COM pointers stay in exception frames.
|
|
31
|
+
_exc_clear()
|
|
32
|
+
# Sometimes, CoUninitialize, running at Python shutdown,
|
|
33
|
+
# raises an exception. We suppress this when __debug__ is
|
|
34
|
+
# False.
|
|
35
|
+
_debug("Calling CoUninitialize()")
|
|
36
|
+
if __debug__:
|
|
37
|
+
func()
|
|
38
|
+
else:
|
|
39
|
+
try:
|
|
40
|
+
func()
|
|
41
|
+
except WindowsError:
|
|
42
|
+
pass
|
|
43
|
+
# Set the flag which means that calling obj.Release() is no longer
|
|
44
|
+
# needed.
|
|
45
|
+
if _cominterface_meta is not None:
|
|
46
|
+
_cominterface_meta._com_shutting_down = True
|
|
47
|
+
_debug("CoUninitialize() done.")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
################################################################
|
|
51
|
+
# The metaclasses...
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _cominterface_meta(type):
|
|
55
|
+
"""Metaclass for COM interfaces. Automatically creates high level
|
|
56
|
+
methods from COMMETHOD lists.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
_case_insensitive_: bool
|
|
60
|
+
_iid_: GUID
|
|
61
|
+
_methods_: List[_ComMemberSpec]
|
|
62
|
+
_disp_methods_: List[_DispMemberSpec]
|
|
63
|
+
|
|
64
|
+
# This flag is set to True by the atexit handler which calls
|
|
65
|
+
# CoUninitialize.
|
|
66
|
+
_com_shutting_down = False
|
|
67
|
+
|
|
68
|
+
# Creates also a POINTER type for the newly created class.
|
|
69
|
+
def __new__(cls, name, bases, namespace):
|
|
70
|
+
methods = namespace.pop("_methods_", None)
|
|
71
|
+
dispmethods = namespace.pop("_disp_methods_", None)
|
|
72
|
+
new_cls = type.__new__(cls, name, bases, namespace)
|
|
73
|
+
|
|
74
|
+
if methods is not None:
|
|
75
|
+
new_cls._methods_ = methods
|
|
76
|
+
if dispmethods is not None:
|
|
77
|
+
new_cls._disp_methods_ = dispmethods
|
|
78
|
+
|
|
79
|
+
# If we sublass a COM interface, for example:
|
|
80
|
+
#
|
|
81
|
+
# class IDispatch(IUnknown):
|
|
82
|
+
# ....
|
|
83
|
+
#
|
|
84
|
+
# then we need to make sure that POINTER(IDispatch) is a
|
|
85
|
+
# subclass of POINTER(IUnknown) because of the way ctypes
|
|
86
|
+
# typechecks work.
|
|
87
|
+
if bases == (object,):
|
|
88
|
+
_ptr_bases = (new_cls, _compointer_base)
|
|
89
|
+
else:
|
|
90
|
+
_ptr_bases = (new_cls, POINTER(bases[0]))
|
|
91
|
+
|
|
92
|
+
# The interface 'new_cls' is used as a mixin.
|
|
93
|
+
p = type(_compointer_base)(
|
|
94
|
+
"POINTER(%s)" % new_cls.__name__,
|
|
95
|
+
_ptr_bases,
|
|
96
|
+
{"__com_interface__": new_cls, "_needs_com_addref_": None},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
from ctypes import _pointer_type_cache
|
|
100
|
+
|
|
101
|
+
_pointer_type_cache[new_cls] = p
|
|
102
|
+
|
|
103
|
+
if new_cls._case_insensitive_:
|
|
104
|
+
|
|
105
|
+
@patcher.Patch(p)
|
|
106
|
+
class CaseInsensitive(object):
|
|
107
|
+
# case insensitive attributes for COM methods and properties
|
|
108
|
+
def __getattr__(self, name):
|
|
109
|
+
"""Implement case insensitive access to methods and properties"""
|
|
110
|
+
try:
|
|
111
|
+
fixed_name = self.__map_case__[name.lower()]
|
|
112
|
+
except KeyError:
|
|
113
|
+
raise AttributeError(name)
|
|
114
|
+
if fixed_name != name: # prevent unbounded recursion
|
|
115
|
+
return getattr(self, fixed_name)
|
|
116
|
+
raise AttributeError(name)
|
|
117
|
+
|
|
118
|
+
# __setattr__ is pretty heavy-weight, because it is called for
|
|
119
|
+
# EVERY attribute assignment. Settings a non-com attribute
|
|
120
|
+
# through this function takes 8.6 usec, while without this
|
|
121
|
+
# function it takes 0.7 sec - 12 times slower.
|
|
122
|
+
#
|
|
123
|
+
# How much faster would this be if implemented in C?
|
|
124
|
+
def __setattr__(self, name, value):
|
|
125
|
+
"""Implement case insensitive access to methods and properties"""
|
|
126
|
+
object.__setattr__(
|
|
127
|
+
self, self.__map_case__.get(name.lower(), name), value
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@patcher.Patch(POINTER(p))
|
|
131
|
+
class ReferenceFix(object):
|
|
132
|
+
def __setitem__(self, index, value):
|
|
133
|
+
# We override the __setitem__ method of the
|
|
134
|
+
# POINTER(POINTER(interface)) type, so that the COM
|
|
135
|
+
# reference count is managed correctly.
|
|
136
|
+
#
|
|
137
|
+
# This is so that we can implement COM methods that have to
|
|
138
|
+
# return COM pointers more easily and consistent. Instead of
|
|
139
|
+
# using CopyComPointer in the method implementation, we can
|
|
140
|
+
# simply do:
|
|
141
|
+
#
|
|
142
|
+
# def GetTypeInfo(self, this, ..., pptinfo):
|
|
143
|
+
# if not pptinfo: return E_POINTER
|
|
144
|
+
# pptinfo[0] = a_com_interface_pointer
|
|
145
|
+
# return S_OK
|
|
146
|
+
if index != 0:
|
|
147
|
+
# CopyComPointer, which is in _ctypes, does only
|
|
148
|
+
# handle an index of 0. This code does what
|
|
149
|
+
# CopyComPointer should do if index != 0.
|
|
150
|
+
if bool(value):
|
|
151
|
+
value.AddRef()
|
|
152
|
+
super(POINTER(p), self).__setitem__(index, value)
|
|
153
|
+
return
|
|
154
|
+
from _ctypes import CopyComPointer
|
|
155
|
+
|
|
156
|
+
CopyComPointer(value, self)
|
|
157
|
+
|
|
158
|
+
return new_cls
|
|
159
|
+
|
|
160
|
+
def __setattr__(self, name, value):
|
|
161
|
+
if name == "_methods_":
|
|
162
|
+
# XXX I'm no longer sure why the code generator generates
|
|
163
|
+
# "_methods_ = []" in the interface definition, and later
|
|
164
|
+
# overrides this by "Interface._methods_ = [...]
|
|
165
|
+
# assert self.__dict__.get("_methods_", None) is None
|
|
166
|
+
self._make_methods(value)
|
|
167
|
+
self._make_specials()
|
|
168
|
+
elif name == "_disp_methods_":
|
|
169
|
+
assert self.__dict__.get("_disp_methods_", None) is None
|
|
170
|
+
self._make_dispmethods(value)
|
|
171
|
+
self._make_specials()
|
|
172
|
+
type.__setattr__(self, name, value)
|
|
173
|
+
|
|
174
|
+
def _make_specials(self):
|
|
175
|
+
# This call installs methods that forward the Python protocols
|
|
176
|
+
# to COM protocols.
|
|
177
|
+
|
|
178
|
+
def has_name(name):
|
|
179
|
+
# Determine whether a property or method named 'name'
|
|
180
|
+
# exists
|
|
181
|
+
if self._case_insensitive_:
|
|
182
|
+
return name.lower() in self.__map_case__
|
|
183
|
+
return hasattr(self, name)
|
|
184
|
+
|
|
185
|
+
# XXX These special methods should be generated by the code generator.
|
|
186
|
+
if has_name("Count"):
|
|
187
|
+
|
|
188
|
+
@patcher.Patch(self)
|
|
189
|
+
class _(object):
|
|
190
|
+
def __len__(self):
|
|
191
|
+
"Return the the 'self.Count' property."
|
|
192
|
+
return self.Count
|
|
193
|
+
|
|
194
|
+
if has_name("Item"):
|
|
195
|
+
|
|
196
|
+
@patcher.Patch(self)
|
|
197
|
+
class _(object):
|
|
198
|
+
# 'Item' is the 'default' value. Make it available by
|
|
199
|
+
# calling the instance (Not sure this makes sense, but
|
|
200
|
+
# win32com does this also).
|
|
201
|
+
def __call__(self, *args, **kw):
|
|
202
|
+
"Return 'self.Item(*args, **kw)'"
|
|
203
|
+
return self.Item(*args, **kw)
|
|
204
|
+
|
|
205
|
+
# does this make sense? It seems that all standard typelibs I've
|
|
206
|
+
# seen so far that support .Item also support ._NewEnum
|
|
207
|
+
@patcher.no_replace
|
|
208
|
+
def __getitem__(self, index):
|
|
209
|
+
"Return 'self.Item(index)'"
|
|
210
|
+
# Handle tuples and all-slice
|
|
211
|
+
if isinstance(index, tuple):
|
|
212
|
+
args = index
|
|
213
|
+
elif index == _all_slice:
|
|
214
|
+
args = ()
|
|
215
|
+
else:
|
|
216
|
+
args = (index,)
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
result = self.Item(*args)
|
|
220
|
+
except COMError as err:
|
|
221
|
+
(hresult, text, details) = err.args
|
|
222
|
+
if hresult == -2147352565: # DISP_E_BADINDEX
|
|
223
|
+
raise IndexError("invalid index")
|
|
224
|
+
else:
|
|
225
|
+
raise
|
|
226
|
+
|
|
227
|
+
# Note that result may be NULL COM pointer. There is no way
|
|
228
|
+
# to interpret this properly, so it is returned as-is.
|
|
229
|
+
|
|
230
|
+
# Hm, should we call __ctypes_from_outparam__ on the
|
|
231
|
+
# result?
|
|
232
|
+
return result
|
|
233
|
+
|
|
234
|
+
@patcher.no_replace
|
|
235
|
+
def __setitem__(self, index, value):
|
|
236
|
+
"Attempt 'self.Item[index] = value'"
|
|
237
|
+
try:
|
|
238
|
+
self.Item[index] = value
|
|
239
|
+
except COMError as err:
|
|
240
|
+
(hresult, text, details) = err.args
|
|
241
|
+
if hresult == -2147352565: # DISP_E_BADINDEX
|
|
242
|
+
raise IndexError("invalid index")
|
|
243
|
+
else:
|
|
244
|
+
raise
|
|
245
|
+
except TypeError:
|
|
246
|
+
msg = "%r object does not support item assignment"
|
|
247
|
+
raise TypeError(msg % type(self))
|
|
248
|
+
|
|
249
|
+
if has_name("_NewEnum"):
|
|
250
|
+
|
|
251
|
+
@patcher.Patch(self)
|
|
252
|
+
class _(object):
|
|
253
|
+
def __iter__(self):
|
|
254
|
+
"Return an iterator over the _NewEnum collection."
|
|
255
|
+
# This method returns a pointer to _some_ _NewEnum interface.
|
|
256
|
+
# It relies on the fact that the code generator creates next()
|
|
257
|
+
# methods for them automatically.
|
|
258
|
+
#
|
|
259
|
+
# Better would maybe to return an object that
|
|
260
|
+
# implements the Python iterator protocol, and
|
|
261
|
+
# forwards the calls to the COM interface.
|
|
262
|
+
enum = self._NewEnum
|
|
263
|
+
if isinstance(enum, types.MethodType):
|
|
264
|
+
# _NewEnum should be a propget property, with dispid -4.
|
|
265
|
+
#
|
|
266
|
+
# Sometimes, however, it is a method.
|
|
267
|
+
enum = enum()
|
|
268
|
+
if hasattr(enum, "Next"):
|
|
269
|
+
return enum
|
|
270
|
+
# _NewEnum returns an IUnknown pointer, QueryInterface() it to
|
|
271
|
+
# IEnumVARIANT
|
|
272
|
+
from comtypes.automation import IEnumVARIANT
|
|
273
|
+
|
|
274
|
+
return enum.QueryInterface(IEnumVARIANT)
|
|
275
|
+
|
|
276
|
+
def _make_case_insensitive(self):
|
|
277
|
+
# The __map_case__ dictionary maps lower case names to the
|
|
278
|
+
# names in the original spelling to enable case insensitive
|
|
279
|
+
# method and attribute access.
|
|
280
|
+
try:
|
|
281
|
+
self.__dict__["__map_case__"]
|
|
282
|
+
except KeyError:
|
|
283
|
+
d = {}
|
|
284
|
+
d.update(getattr(self, "__map_case__", {}))
|
|
285
|
+
self.__map_case__ = d
|
|
286
|
+
|
|
287
|
+
def _make_dispmethods(self, methods: List[_DispMemberSpec]) -> None:
|
|
288
|
+
if self._case_insensitive_:
|
|
289
|
+
self._make_case_insensitive()
|
|
290
|
+
# create dispinterface methods and properties on the interface 'self'
|
|
291
|
+
member_gen = DispMemberGenerator(self.__name__)
|
|
292
|
+
for m in methods:
|
|
293
|
+
member_gen.add(m)
|
|
294
|
+
for name, func_or_prop, is_prop in member_gen.items():
|
|
295
|
+
setattr(self, name, func_or_prop)
|
|
296
|
+
# COM is case insensitive.
|
|
297
|
+
# For a method, this is the real name. For a property,
|
|
298
|
+
# this is the name WITHOUT the _set_ or _get_ prefix.
|
|
299
|
+
if self._case_insensitive_:
|
|
300
|
+
self.__map_case__[name.lower()] = name
|
|
301
|
+
if is_prop:
|
|
302
|
+
self.__map_case__[name[5:].lower()] = name[5:]
|
|
303
|
+
for name, accessor in member_gen.properties():
|
|
304
|
+
setattr(self, name, accessor)
|
|
305
|
+
# COM is case insensitive
|
|
306
|
+
if self._case_insensitive_:
|
|
307
|
+
self.__map_case__[name.lower()] = name
|
|
308
|
+
|
|
309
|
+
def __get_baseinterface_methodcount(self):
|
|
310
|
+
"Return the number of com methods in the base interfaces"
|
|
311
|
+
try:
|
|
312
|
+
result = 0
|
|
313
|
+
for itf in self.mro()[1:-1]:
|
|
314
|
+
result += len(itf.__dict__["_methods_"])
|
|
315
|
+
return result
|
|
316
|
+
except KeyError as err:
|
|
317
|
+
(name,) = err.args
|
|
318
|
+
if name == "_methods_":
|
|
319
|
+
raise TypeError("baseinterface '%s' has no _methods_" % itf.__name__)
|
|
320
|
+
raise
|
|
321
|
+
|
|
322
|
+
def _make_methods(self, methods: List[_ComMemberSpec]) -> None:
|
|
323
|
+
if self._case_insensitive_:
|
|
324
|
+
self._make_case_insensitive()
|
|
325
|
+
# register com interface. we insist on an _iid_ in THIS class!
|
|
326
|
+
try:
|
|
327
|
+
iid = self.__dict__["_iid_"]
|
|
328
|
+
except KeyError:
|
|
329
|
+
raise AttributeError("this class must define an _iid_")
|
|
330
|
+
else:
|
|
331
|
+
com_interface_registry[str(iid)] = self
|
|
332
|
+
# create members
|
|
333
|
+
vtbl_offset = self.__get_baseinterface_methodcount()
|
|
334
|
+
member_gen = ComMemberGenerator(self.__name__, vtbl_offset, self._iid_)
|
|
335
|
+
# create private low level, and public high level methods
|
|
336
|
+
for m in methods:
|
|
337
|
+
member_gen.add(m)
|
|
338
|
+
for name, func, raw_func, is_prop in member_gen.methods():
|
|
339
|
+
raw_mth = instancemethod(raw_func, None, self)
|
|
340
|
+
setattr(self, "_%s__com_%s" % (self.__name__, name), raw_mth)
|
|
341
|
+
mth = instancemethod(func, None, self)
|
|
342
|
+
if not is_prop:
|
|
343
|
+
# We install the method in the class, except when it's a property.
|
|
344
|
+
# And we make sure we don't overwrite a property that's already present.
|
|
345
|
+
mthname = name if not hasattr(self, name) else ("_%s" % name)
|
|
346
|
+
setattr(self, mthname, mth)
|
|
347
|
+
# For a method, this is the real name.
|
|
348
|
+
# For a property, this is the name WITHOUT the _set_ or _get_ prefix.
|
|
349
|
+
if self._case_insensitive_:
|
|
350
|
+
self.__map_case__[name.lower()] = name
|
|
351
|
+
if is_prop:
|
|
352
|
+
self.__map_case__[name[5:].lower()] = name[5:]
|
|
353
|
+
# create public properties / attribute accessors
|
|
354
|
+
for name, accessor in member_gen.properties():
|
|
355
|
+
# Again, we should not overwrite class attributes that are already present.
|
|
356
|
+
propname = name if not hasattr(self, name) else ("_%s" % name)
|
|
357
|
+
setattr(self, propname, accessor)
|
|
358
|
+
# COM is case insensitive
|
|
359
|
+
if self._case_insensitive_:
|
|
360
|
+
self.__map_case__[name.lower()] = name
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
################################################################
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class _compointer_meta(type(c_void_p), _cominterface_meta):
|
|
367
|
+
"metaclass for COM interface pointer classes"
|
|
368
|
+
# no functionality, but needed to avoid a metaclass conflict
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class _compointer_base(c_void_p, metaclass=_compointer_meta):
|
|
372
|
+
"base class for COM interface pointer classes"
|
|
373
|
+
|
|
374
|
+
def __del__(self, _debug=logger.debug):
|
|
375
|
+
"Release the COM refcount we own."
|
|
376
|
+
if self:
|
|
377
|
+
# comtypes calls CoUninitialize() when the atexit handlers
|
|
378
|
+
# runs. CoUninitialize() cleans up the COM objects that
|
|
379
|
+
# are still alive. Python COM pointers may still be
|
|
380
|
+
# present but we can no longer call Release() on them -
|
|
381
|
+
# this may give a protection fault. So we need the
|
|
382
|
+
# _com_shutting_down flag.
|
|
383
|
+
#
|
|
384
|
+
if not type(self)._com_shutting_down:
|
|
385
|
+
_debug("Release %s", self)
|
|
386
|
+
self.Release()
|
|
387
|
+
|
|
388
|
+
def __cmp__(self, other):
|
|
389
|
+
"""Compare pointers to COM interfaces."""
|
|
390
|
+
# COM identity rule
|
|
391
|
+
#
|
|
392
|
+
# XXX To compare COM interface pointers, should we
|
|
393
|
+
# automatically QueryInterface for IUnknown on both items, and
|
|
394
|
+
# compare the pointer values?
|
|
395
|
+
if not isinstance(other, _compointer_base):
|
|
396
|
+
return 1
|
|
397
|
+
|
|
398
|
+
# get the value property of the c_void_p baseclass, this is the pointer value
|
|
399
|
+
return cmp(
|
|
400
|
+
super(_compointer_base, self).value, super(_compointer_base, other).value
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
def __eq__(self, other):
|
|
404
|
+
if not isinstance(other, _compointer_base):
|
|
405
|
+
return False
|
|
406
|
+
# get the value property of the c_void_p baseclass, this is the pointer value
|
|
407
|
+
return (
|
|
408
|
+
super(_compointer_base, self).value == super(_compointer_base, other).value
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def __hash__(self):
|
|
412
|
+
"""Return the hash value of the pointer."""
|
|
413
|
+
# hash the pointer values
|
|
414
|
+
return hash(super(_compointer_base, self).value)
|
|
415
|
+
|
|
416
|
+
# redefine the .value property; return the object itself.
|
|
417
|
+
def __get_value(self):
|
|
418
|
+
return self
|
|
419
|
+
|
|
420
|
+
value = property(__get_value, doc="""Return self.""")
|
|
421
|
+
|
|
422
|
+
def __repr__(self):
|
|
423
|
+
ptr = super(_compointer_base, self).value
|
|
424
|
+
return "<%s ptr=0x%x at %x>" % (self.__class__.__name__, ptr or 0, id(self))
|
|
425
|
+
|
|
426
|
+
# This fixes the problem when there are multiple python interface types
|
|
427
|
+
# wrapping the same COM interface. This could happen because some interfaces
|
|
428
|
+
# are contained in multiple typelibs.
|
|
429
|
+
#
|
|
430
|
+
# It also allows to pass a CoClass instance to an api
|
|
431
|
+
# expecting a COM interface.
|
|
432
|
+
@classmethod
|
|
433
|
+
def from_param(cls, value):
|
|
434
|
+
"""Convert 'value' into a COM pointer to the interface.
|
|
435
|
+
|
|
436
|
+
This method accepts a COM pointer, or a CoClass instance
|
|
437
|
+
which is QueryInterface()d."""
|
|
438
|
+
if value is None:
|
|
439
|
+
return None
|
|
440
|
+
# CLF: 2013-01-18
|
|
441
|
+
# A default value of 0, meaning null, can pass through to here.
|
|
442
|
+
if value == 0:
|
|
443
|
+
return None
|
|
444
|
+
if isinstance(value, cls):
|
|
445
|
+
return value
|
|
446
|
+
# multiple python interface types for the same COM interface.
|
|
447
|
+
# Do we need more checks here?
|
|
448
|
+
if cls._iid_ == getattr(value, "_iid_", None):
|
|
449
|
+
return value
|
|
450
|
+
# Accept an CoClass instance which exposes the interface required.
|
|
451
|
+
try:
|
|
452
|
+
table = value._com_pointers_
|
|
453
|
+
except AttributeError:
|
|
454
|
+
pass
|
|
455
|
+
else:
|
|
456
|
+
try:
|
|
457
|
+
# a kind of QueryInterface
|
|
458
|
+
return table[cls._iid_]
|
|
459
|
+
except KeyError:
|
|
460
|
+
raise TypeError("Interface %s not supported" % cls._iid_)
|
|
461
|
+
return value.QueryInterface(cls.__com_interface__)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
################################################################
|
|
465
|
+
# IUnknown, the root of all evil...
|
|
466
|
+
|
|
467
|
+
_T_IUnknown = TypeVar("_T_IUnknown", bound="IUnknown")
|
|
468
|
+
|
|
469
|
+
if TYPE_CHECKING:
|
|
470
|
+
|
|
471
|
+
class _IUnknown_Base(c_void_p, metaclass=_cominterface_meta): # type: ignore
|
|
472
|
+
"""This is workaround to avoid false-positive of static type checking.
|
|
473
|
+
|
|
474
|
+
`IUnknown` behaves as a ctypes type, and `POINTER` can take it.
|
|
475
|
+
This behavior is defined by some metaclasses in runtime.
|
|
476
|
+
|
|
477
|
+
In runtime, this symbol in the namespace is just alias for
|
|
478
|
+
`builtins.object`.
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
...
|
|
482
|
+
|
|
483
|
+
else:
|
|
484
|
+
_IUnknown_Base = object
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
class IUnknown(_IUnknown_Base, metaclass=_cominterface_meta):
|
|
488
|
+
"""The most basic COM interface.
|
|
489
|
+
|
|
490
|
+
Each subclasses of IUnknown must define these class attributes:
|
|
491
|
+
|
|
492
|
+
_iid_ - a GUID instance defining the identifier of this interface
|
|
493
|
+
|
|
494
|
+
_methods_ - a list of methods for this interface.
|
|
495
|
+
|
|
496
|
+
The _methods_ list must in VTable order. Methods are specified
|
|
497
|
+
with STDMETHOD or COMMETHOD calls.
|
|
498
|
+
"""
|
|
499
|
+
|
|
500
|
+
_case_insensitive_: ClassVar[bool] = False
|
|
501
|
+
_iid_: ClassVar[GUID] = GUID("{00000000-0000-0000-C000-000000000046}")
|
|
502
|
+
_methods_: ClassVar[List[_ComMemberSpec]] = [
|
|
503
|
+
STDMETHOD(HRESULT, "QueryInterface", [POINTER(GUID), POINTER(c_void_p)]),
|
|
504
|
+
STDMETHOD(c_ulong, "AddRef"),
|
|
505
|
+
STDMETHOD(c_ulong, "Release"),
|
|
506
|
+
]
|
|
507
|
+
|
|
508
|
+
# NOTE: Why not `QueryInterface(T) -> _Pointer[T]`?
|
|
509
|
+
# Any static type checkers is not able to provide members of `T` from `_Pointer[T]`,
|
|
510
|
+
# regardless of the pointer is able to access members of contents in runtime.
|
|
511
|
+
# And if `isinstance(p, POINTER(T))` is `True`, then `isinstance(p, T)` is also `True`.
|
|
512
|
+
# So returning `T` is not a lie, and good way to know what members the class has.
|
|
513
|
+
def QueryInterface(
|
|
514
|
+
self, interface: Type[_T_IUnknown], iid: Optional[GUID] = None
|
|
515
|
+
) -> _T_IUnknown:
|
|
516
|
+
"""QueryInterface(interface) -> instance"""
|
|
517
|
+
p = POINTER(interface)()
|
|
518
|
+
if iid is None:
|
|
519
|
+
iid = interface._iid_
|
|
520
|
+
self.__com_QueryInterface(byref(iid), byref(p)) # type: ignore
|
|
521
|
+
clsid = self.__dict__.get("__clsid")
|
|
522
|
+
if clsid is not None:
|
|
523
|
+
p.__dict__["__clsid"] = clsid
|
|
524
|
+
return p # type: ignore
|
|
525
|
+
|
|
526
|
+
# these are only so that they get a docstring.
|
|
527
|
+
# XXX There should be other ways to install a docstring.
|
|
528
|
+
def AddRef(self) -> int:
|
|
529
|
+
"""Increase the internal refcount by one and return it."""
|
|
530
|
+
return self.__com_AddRef() # type: ignore
|
|
531
|
+
|
|
532
|
+
def Release(self) -> int:
|
|
533
|
+
"""Decrease the internal refcount by one and return it."""
|
|
534
|
+
return self.__com_Release() # type: ignore
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
################################################################
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from ctypes import pythonapi, py_object
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
pythonapi.PyInstanceMethod_New.argtypes = [py_object]
|
|
5
|
+
pythonapi.PyInstanceMethod_New.restype = py_object
|
|
6
|
+
PyInstanceMethod_Type = type(pythonapi.PyInstanceMethod_New(id))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def instancemethod(func, inst, cls):
|
|
10
|
+
mth = PyInstanceMethod_Type(func)
|
|
11
|
+
if inst is None:
|
|
12
|
+
return mth
|
|
13
|
+
return mth.__get__(inst)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""SAFEARRAY api functions, data types, and constants."""
|
|
2
2
|
|
|
3
|
-
from ctypes import
|
|
4
|
-
from ctypes.wintypes import
|
|
3
|
+
from ctypes import c_uint, c_ushort, c_void_p, POINTER, Structure, WinDLL
|
|
4
|
+
from ctypes.wintypes import DWORD, LONG, UINT
|
|
5
|
+
|
|
5
6
|
from comtypes import HRESULT, GUID
|
|
6
7
|
|
|
7
8
|
################################################################
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _check_version(actual, tlib_cached_mtime=None):
|
|
6
|
+
from comtypes.tools.codegenerator import version as required
|
|
7
|
+
|
|
8
|
+
if actual != required:
|
|
9
|
+
raise ImportError("Wrong version")
|
|
10
|
+
if not hasattr(sys, "frozen"):
|
|
11
|
+
g = sys._getframe(1).f_globals
|
|
12
|
+
tlb_path = g.get("typelib_path")
|
|
13
|
+
try:
|
|
14
|
+
tlib_curr_mtime = os.stat(tlb_path).st_mtime
|
|
15
|
+
except (OSError, TypeError):
|
|
16
|
+
return
|
|
17
|
+
if not tlib_cached_mtime or abs(tlib_curr_mtime - tlib_cached_mtime) >= 1:
|
|
18
|
+
raise ImportError("Typelib different than module")
|
|
@@ -20,18 +20,20 @@ from typing import (
|
|
|
20
20
|
|
|
21
21
|
from comtypes import BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD
|
|
22
22
|
from comtypes.hresult import *
|
|
23
|
+
from comtypes._memberspec import _DispMemberSpec
|
|
23
24
|
import comtypes.patcher
|
|
24
25
|
import comtypes
|
|
25
26
|
|
|
26
27
|
if TYPE_CHECKING:
|
|
27
28
|
from comtypes import hints # type: ignore
|
|
28
|
-
|
|
29
|
-
try:
|
|
30
29
|
from comtypes import _safearray
|
|
31
|
-
|
|
30
|
+
else:
|
|
31
|
+
try:
|
|
32
|
+
from comtypes import _safearray
|
|
33
|
+
except (ImportError, AttributeError):
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
class _safearray(object):
|
|
36
|
+
tagSAFEARRAY = None
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
LCID = DWORD
|
|
@@ -404,6 +406,11 @@ class tagVARIANT(Structure):
|
|
|
404
406
|
ri.AddRef()
|
|
405
407
|
self._.pRecInfo = ri
|
|
406
408
|
self._.pvRecord = cast(value, c_void_p)
|
|
409
|
+
elif isinstance(ref, _Pointer) and isinstance(
|
|
410
|
+
ref.contents, _safearray.tagSAFEARRAY
|
|
411
|
+
):
|
|
412
|
+
self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
|
|
413
|
+
self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
|
|
407
414
|
else:
|
|
408
415
|
self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
|
|
409
416
|
elif isinstance(value, _Pointer):
|
|
@@ -421,6 +428,15 @@ class tagVARIANT(Structure):
|
|
|
421
428
|
ri.AddRef()
|
|
422
429
|
self._.pRecInfo = ri
|
|
423
430
|
self._.pvRecord = cast(value, c_void_p)
|
|
431
|
+
elif isinstance(ref, _safearray.tagSAFEARRAY):
|
|
432
|
+
obj = _midlSAFEARRAY(value._itemtype_).create(value.unpack())
|
|
433
|
+
memmove(byref(self._), byref(obj), sizeof(obj))
|
|
434
|
+
self.vt = VT_ARRAY | obj._vartype_
|
|
435
|
+
elif isinstance(ref, _Pointer) and isinstance(
|
|
436
|
+
ref.contents, _safearray.tagSAFEARRAY
|
|
437
|
+
):
|
|
438
|
+
self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
|
|
439
|
+
self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
|
|
424
440
|
else:
|
|
425
441
|
self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
|
|
426
442
|
else:
|
|
@@ -791,7 +807,7 @@ RawInvokeFunc = Callable[
|
|
|
791
807
|
|
|
792
808
|
|
|
793
809
|
class IDispatch(IUnknown):
|
|
794
|
-
_disp_methods_: ClassVar[List[
|
|
810
|
+
_disp_methods_: ClassVar[List[_DispMemberSpec]]
|
|
795
811
|
_GetTypeInfo: Callable[[int, int], IUnknown]
|
|
796
812
|
__com_GetIDsOfNames: RawGetIDsOfNamesFunc
|
|
797
813
|
__com_Invoke: RawInvokeFunc
|
|
@@ -262,7 +262,7 @@ def _get_known_namespaces() -> Tuple[
|
|
|
262
262
|
Note:
|
|
263
263
|
The interfaces that should be included in `__known_symbols__` should be limited
|
|
264
264
|
to those that can be said to be bound to the design concept of COM, such as
|
|
265
|
-
`IUnknown`,
|
|
265
|
+
`IUnknown`, `IDispatch` and `ITypeInfo`.
|
|
266
266
|
`comtypes` does NOT aim to statically define all COM object interfaces in
|
|
267
267
|
its repository.
|
|
268
268
|
"""
|
|
@@ -272,6 +272,7 @@ def _get_known_namespaces() -> Tuple[
|
|
|
272
272
|
"comtypes.persist",
|
|
273
273
|
"comtypes.typeinfo",
|
|
274
274
|
"comtypes.automation",
|
|
275
|
+
"comtypes.stream",
|
|
275
276
|
"comtypes",
|
|
276
277
|
"ctypes.wintypes",
|
|
277
278
|
"ctypes",
|