comtypes 1.4.7__zip → 1.4.9__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {comtypes-1.4.7 → comtypes-1.4.9}/CHANGES.txt +39 -0
- {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +6 -4
- {comtypes-1.4.7 → comtypes-1.4.9}/README.md +5 -3
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
- comtypes-1.4.9/comtypes/_comobject.py +507 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_memberspec.py +81 -9
- comtypes-1.4.9/comtypes/_meta.py +95 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_npsupport.py +2 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +1 -0
- comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +21 -40
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +88 -209
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
- comtypes-1.4.9/comtypes/_vtbl.py +448 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/automation.py +36 -45
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/__init__.py +21 -31
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_code_cache.py +5 -4
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_events.py +1 -2
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_generate.py +9 -13
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -7
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/git.py +2 -2
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hints.pyi +11 -19
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/persist.py +7 -7
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/safearray.py +12 -6
- comtypes-1.4.9/comtypes/server/__init__.py +86 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/register.py +62 -73
- comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/shelllink.py +49 -67
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.py +1 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +1 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -12
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +1 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
- comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
- comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -6
- comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -13
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +8 -5
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
- comtypes-1.4.9/comtypes/test/test_server.py +350 -0
- comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +10 -14
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
- comtypes-1.4.9/comtypes/test/test_stream.py +131 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +1 -1
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +1 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -19
- comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +97 -27
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +9 -11
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +33 -32
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc.py +3 -8
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/typeinfo.py +32 -47
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/util.py +1 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
- {comtypes-1.4.7 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +6 -4
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
- comtypes-1.4.9/pyproject.toml +55 -0
- comtypes-1.4.7/comtypes/_comobject.py +0 -834
- comtypes-1.4.7/comtypes/_idl_stuff.py +0 -67
- comtypes-1.4.7/comtypes/_meta.py +0 -70
- comtypes-1.4.7/comtypes/server/__init__.py +0 -69
- comtypes-1.4.7/comtypes/server/w_getopt.py +0 -75
- comtypes-1.4.7/comtypes/test/test_comserver.py +0 -239
- comtypes-1.4.7/comtypes/test/test_dispinterface.py +0 -138
- comtypes-1.4.7/comtypes/test/test_propputref.py +0 -40
- comtypes-1.4.7/comtypes/test/test_server.py +0 -348
- comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
- comtypes-1.4.7/pyproject.toml +0 -3
- {comtypes-1.4.7 → comtypes-1.4.9}/LICENSE.txt +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/MANIFEST.in +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
- /comtypes-1.4.7/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/stream.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/setup.cfg +0 -0
- {comtypes-1.4.7 → comtypes-1.4.9}/setup.py +0 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import queue
|
|
3
|
+
from _ctypes import COMError, CopyComPointer
|
|
4
|
+
from ctypes import (
|
|
5
|
+
POINTER,
|
|
6
|
+
FormatError,
|
|
7
|
+
Structure,
|
|
8
|
+
byref,
|
|
9
|
+
c_long,
|
|
10
|
+
c_void_p,
|
|
11
|
+
oledll,
|
|
12
|
+
pointer,
|
|
13
|
+
windll,
|
|
14
|
+
)
|
|
15
|
+
from typing import (
|
|
16
|
+
TYPE_CHECKING,
|
|
17
|
+
Any,
|
|
18
|
+
Callable,
|
|
19
|
+
ClassVar,
|
|
20
|
+
Dict,
|
|
21
|
+
List,
|
|
22
|
+
Optional,
|
|
23
|
+
Sequence,
|
|
24
|
+
Tuple,
|
|
25
|
+
Type,
|
|
26
|
+
TypeVar,
|
|
27
|
+
)
|
|
28
|
+
from typing import Union as _UnionT
|
|
29
|
+
|
|
30
|
+
from comtypes import GUID, IPersist, IUnknown, hresult
|
|
31
|
+
from comtypes._vtbl import _MethodFinder, create_dispimpl, create_vtbl_mapping
|
|
32
|
+
from comtypes.errorinfo import ISupportErrorInfo
|
|
33
|
+
from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2, ITypeInfo
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from ctypes import _CArgObject, _Pointer
|
|
37
|
+
|
|
38
|
+
from comtypes import hints # type: ignore
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
_debug = logger.debug
|
|
42
|
+
|
|
43
|
+
################################################################
|
|
44
|
+
# COM object implementation
|
|
45
|
+
|
|
46
|
+
# so we don't have to import comtypes.automation
|
|
47
|
+
DISPATCH_METHOD = 1
|
|
48
|
+
DISPATCH_PROPERTYGET = 2
|
|
49
|
+
DISPATCH_PROPERTYPUT = 4
|
|
50
|
+
DISPATCH_PROPERTYPUTREF = 8
|
|
51
|
+
|
|
52
|
+
################################################################
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
_InterlockedIncrement = windll.kernel32.InterlockedIncrement
|
|
56
|
+
_InterlockedDecrement = windll.kernel32.InterlockedDecrement
|
|
57
|
+
except AttributeError:
|
|
58
|
+
import threading
|
|
59
|
+
|
|
60
|
+
_lock = threading.Lock()
|
|
61
|
+
_acquire = _lock.acquire
|
|
62
|
+
_release = _lock.release
|
|
63
|
+
# win 64 doesn't have these functions
|
|
64
|
+
|
|
65
|
+
def _InterlockedIncrement(ob: c_long) -> int:
|
|
66
|
+
_acquire()
|
|
67
|
+
refcnt = ob.value + 1
|
|
68
|
+
ob.value = refcnt
|
|
69
|
+
_release()
|
|
70
|
+
return refcnt
|
|
71
|
+
|
|
72
|
+
def _InterlockedDecrement(ob: c_long) -> int:
|
|
73
|
+
_acquire()
|
|
74
|
+
refcnt = ob.value - 1
|
|
75
|
+
ob.value = refcnt
|
|
76
|
+
_release()
|
|
77
|
+
return refcnt
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
_InterlockedIncrement.argtypes = [POINTER(c_long)]
|
|
81
|
+
_InterlockedDecrement.argtypes = [POINTER(c_long)]
|
|
82
|
+
_InterlockedIncrement.restype = c_long
|
|
83
|
+
_InterlockedDecrement.restype = c_long
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class LocalServer(object):
|
|
87
|
+
_queue: Optional[queue.Queue] = None
|
|
88
|
+
|
|
89
|
+
def run(self, classobjects: Sequence["hints.localserver.ClassFactory"]) -> None:
|
|
90
|
+
# Use windll instead of oledll so that we don't get an
|
|
91
|
+
# exception on a FAILED hresult:
|
|
92
|
+
hr = windll.ole32.CoInitialize(None)
|
|
93
|
+
if hresult.RPC_E_CHANGED_MODE == hr:
|
|
94
|
+
# we're running in MTA: no message pump needed
|
|
95
|
+
_debug("Server running in MTA")
|
|
96
|
+
self.run_mta()
|
|
97
|
+
else:
|
|
98
|
+
# we're running in STA: need a message pump
|
|
99
|
+
_debug("Server running in STA")
|
|
100
|
+
if hr >= 0:
|
|
101
|
+
# we need a matching CoUninitialize() call for a successful
|
|
102
|
+
# CoInitialize().
|
|
103
|
+
windll.ole32.CoUninitialize()
|
|
104
|
+
self.run_sta()
|
|
105
|
+
|
|
106
|
+
for obj in classobjects:
|
|
107
|
+
obj._revoke_class()
|
|
108
|
+
|
|
109
|
+
def run_sta(self) -> None:
|
|
110
|
+
from comtypes import messageloop
|
|
111
|
+
|
|
112
|
+
messageloop.run()
|
|
113
|
+
|
|
114
|
+
def run_mta(self) -> None:
|
|
115
|
+
self._queue = queue.Queue()
|
|
116
|
+
self._queue.get()
|
|
117
|
+
|
|
118
|
+
def Lock(self) -> None:
|
|
119
|
+
oledll.ole32.CoAddRefServerProcess()
|
|
120
|
+
|
|
121
|
+
def Unlock(self) -> None:
|
|
122
|
+
rc = oledll.ole32.CoReleaseServerProcess()
|
|
123
|
+
if rc == 0:
|
|
124
|
+
if self._queue:
|
|
125
|
+
self._queue.put(42)
|
|
126
|
+
else:
|
|
127
|
+
windll.user32.PostQuitMessage(0)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class InprocServer(object):
|
|
131
|
+
def __init__(self) -> None:
|
|
132
|
+
self.locks = c_long(0)
|
|
133
|
+
|
|
134
|
+
def Lock(self) -> None:
|
|
135
|
+
_InterlockedIncrement(self.locks)
|
|
136
|
+
|
|
137
|
+
def Unlock(self) -> None:
|
|
138
|
+
_InterlockedDecrement(self.locks)
|
|
139
|
+
|
|
140
|
+
def DllCanUnloadNow(self) -> int:
|
|
141
|
+
if self.locks.value:
|
|
142
|
+
return hresult.S_FALSE
|
|
143
|
+
if COMObject._instances_:
|
|
144
|
+
return hresult.S_FALSE
|
|
145
|
+
return hresult.S_OK
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
_T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class COMObject(object):
|
|
152
|
+
_com_interfaces_: ClassVar[List[Type[IUnknown]]]
|
|
153
|
+
_outgoing_interfaces_: ClassVar[List[Type["hints.IDispatch"]]]
|
|
154
|
+
_instances_: ClassVar[Dict["COMObject", None]] = {}
|
|
155
|
+
_reg_clsid_: ClassVar[GUID]
|
|
156
|
+
_reg_typelib_: ClassVar[Tuple[str, int, int]]
|
|
157
|
+
__typelib: "hints.ITypeLib"
|
|
158
|
+
_com_pointers_: Dict[GUID, "_Pointer[_Pointer[Structure]]"]
|
|
159
|
+
_dispimpl_: Dict[Tuple[int, int], Callable[..., Any]]
|
|
160
|
+
|
|
161
|
+
def __new__(cls, *args, **kw):
|
|
162
|
+
self = super(COMObject, cls).__new__(cls)
|
|
163
|
+
if isinstance(self, c_void_p):
|
|
164
|
+
# We build the VTables only for direct instances of
|
|
165
|
+
# CoClass, not for POINTERs to CoClass.
|
|
166
|
+
return self
|
|
167
|
+
if hasattr(self, "_com_interfaces_"):
|
|
168
|
+
self.__prepare_comobject()
|
|
169
|
+
return self
|
|
170
|
+
|
|
171
|
+
def __prepare_comobject(self) -> None:
|
|
172
|
+
# When a CoClass instance is created, COM pointers to all
|
|
173
|
+
# interfaces are created. Also, the CoClass must be kept alive as
|
|
174
|
+
# until the COM reference count drops to zero, even if no Python
|
|
175
|
+
# code keeps a reference to the object.
|
|
176
|
+
#
|
|
177
|
+
# The _com_pointers_ instance variable maps string interface iids
|
|
178
|
+
# to C compatible COM pointers.
|
|
179
|
+
self._com_pointers_ = {}
|
|
180
|
+
# COM refcount starts at zero.
|
|
181
|
+
self._refcnt = c_long(0)
|
|
182
|
+
|
|
183
|
+
# Some interfaces have a default implementation in COMObject:
|
|
184
|
+
# - ISupportErrorInfo
|
|
185
|
+
# - IPersist (if the subclass has a _reg_clsid_ attribute)
|
|
186
|
+
# - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
|
|
187
|
+
# - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_
|
|
188
|
+
# attribute)
|
|
189
|
+
#
|
|
190
|
+
# Add these if they are not listed in _com_interfaces_.
|
|
191
|
+
interfaces = tuple(self._com_interfaces_)
|
|
192
|
+
if ISupportErrorInfo not in interfaces:
|
|
193
|
+
interfaces += (ISupportErrorInfo,)
|
|
194
|
+
if hasattr(self, "_reg_typelib_"):
|
|
195
|
+
from comtypes.typeinfo import LoadRegTypeLib
|
|
196
|
+
|
|
197
|
+
self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
|
|
198
|
+
if hasattr(self, "_reg_clsid_"):
|
|
199
|
+
if IProvideClassInfo not in interfaces:
|
|
200
|
+
interfaces += (IProvideClassInfo,)
|
|
201
|
+
if (
|
|
202
|
+
hasattr(self, "_outgoing_interfaces_")
|
|
203
|
+
and IProvideClassInfo2 not in interfaces
|
|
204
|
+
):
|
|
205
|
+
interfaces += (IProvideClassInfo2,)
|
|
206
|
+
if hasattr(self, "_reg_clsid_"):
|
|
207
|
+
if IPersist not in interfaces:
|
|
208
|
+
interfaces += (IPersist,)
|
|
209
|
+
for itf in interfaces[::-1]:
|
|
210
|
+
self.__make_interface_pointer(itf)
|
|
211
|
+
|
|
212
|
+
def __make_interface_pointer(self, itf: Type[IUnknown]) -> None:
|
|
213
|
+
finder = self._get_method_finder_(itf)
|
|
214
|
+
iids, vtbl = create_vtbl_mapping(itf, finder)
|
|
215
|
+
for iid in iids:
|
|
216
|
+
self._com_pointers_[iid] = pointer(pointer(vtbl))
|
|
217
|
+
if hasattr(itf, "_disp_methods_"):
|
|
218
|
+
self._dispimpl_ = create_dispimpl(itf, finder)
|
|
219
|
+
|
|
220
|
+
def _get_method_finder_(self, itf: Type[IUnknown]) -> _MethodFinder:
|
|
221
|
+
# This method can be overridden to customize how methods are found.
|
|
222
|
+
return _MethodFinder(self)
|
|
223
|
+
|
|
224
|
+
################################################################
|
|
225
|
+
# LocalServer / InprocServer stuff
|
|
226
|
+
__server__: _UnionT[None, InprocServer, LocalServer] = None
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def __run_inprocserver__() -> None:
|
|
230
|
+
if COMObject.__server__ is None:
|
|
231
|
+
COMObject.__server__ = InprocServer()
|
|
232
|
+
elif isinstance(COMObject.__server__, InprocServer):
|
|
233
|
+
pass
|
|
234
|
+
else:
|
|
235
|
+
raise RuntimeError("Wrong server type")
|
|
236
|
+
|
|
237
|
+
@staticmethod
|
|
238
|
+
def __run_localserver__(
|
|
239
|
+
classobjects: Sequence["hints.localserver.ClassFactory"],
|
|
240
|
+
) -> None:
|
|
241
|
+
assert COMObject.__server__ is None
|
|
242
|
+
# XXX Decide whether we are in STA or MTA
|
|
243
|
+
server = COMObject.__server__ = LocalServer()
|
|
244
|
+
server.run(classobjects)
|
|
245
|
+
COMObject.__server__ = None
|
|
246
|
+
|
|
247
|
+
@staticmethod
|
|
248
|
+
def __keep__(obj: "COMObject") -> None:
|
|
249
|
+
COMObject._instances_[obj] = None
|
|
250
|
+
_debug("%d active COM objects: Added %r", len(COMObject._instances_), obj)
|
|
251
|
+
if COMObject.__server__:
|
|
252
|
+
COMObject.__server__.Lock()
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def __unkeep__(obj: "COMObject") -> None:
|
|
256
|
+
try:
|
|
257
|
+
del COMObject._instances_[obj]
|
|
258
|
+
except AttributeError:
|
|
259
|
+
_debug("? active COM objects: Removed %r", obj)
|
|
260
|
+
else:
|
|
261
|
+
_debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj)
|
|
262
|
+
_debug("Remaining: %s", list(COMObject._instances_.keys()))
|
|
263
|
+
if COMObject.__server__:
|
|
264
|
+
COMObject.__server__.Unlock()
|
|
265
|
+
|
|
266
|
+
#
|
|
267
|
+
################################################################
|
|
268
|
+
|
|
269
|
+
#########################################################
|
|
270
|
+
# IUnknown methods implementations
|
|
271
|
+
def IUnknown_AddRef(
|
|
272
|
+
self,
|
|
273
|
+
this: Any,
|
|
274
|
+
__InterlockedIncrement: Callable[[c_long], int] = _InterlockedIncrement,
|
|
275
|
+
_debug=_debug,
|
|
276
|
+
) -> int:
|
|
277
|
+
result = __InterlockedIncrement(self._refcnt)
|
|
278
|
+
if result == 1:
|
|
279
|
+
self.__keep__(self)
|
|
280
|
+
_debug("%r.AddRef() -> %s", self, result)
|
|
281
|
+
return result
|
|
282
|
+
|
|
283
|
+
def _final_release_(self) -> None:
|
|
284
|
+
"""This method may be overridden in subclasses
|
|
285
|
+
to free allocated resources or so."""
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
def IUnknown_Release(
|
|
289
|
+
self,
|
|
290
|
+
this: Any,
|
|
291
|
+
__InterlockedDecrement: Callable[[c_long], int] = _InterlockedDecrement,
|
|
292
|
+
_debug=_debug,
|
|
293
|
+
) -> int:
|
|
294
|
+
# If this is called at COM shutdown, _InterlockedDecrement()
|
|
295
|
+
# must still be available, although module level variables may
|
|
296
|
+
# have been deleted already - so we supply it as default
|
|
297
|
+
# argument.
|
|
298
|
+
result = __InterlockedDecrement(self._refcnt)
|
|
299
|
+
_debug("%r.Release() -> %s", self, result)
|
|
300
|
+
if result == 0:
|
|
301
|
+
self._final_release_()
|
|
302
|
+
self.__unkeep__(self)
|
|
303
|
+
# Hm, why isn't this cleaned up by the cycle gc?
|
|
304
|
+
self._com_pointers_ = {}
|
|
305
|
+
return result
|
|
306
|
+
|
|
307
|
+
def IUnknown_QueryInterface(
|
|
308
|
+
self,
|
|
309
|
+
this: Any,
|
|
310
|
+
riid: "_Pointer[GUID]",
|
|
311
|
+
ppvObj: _UnionT[c_void_p, "_CArgObject"],
|
|
312
|
+
_debug=_debug,
|
|
313
|
+
) -> int:
|
|
314
|
+
# XXX This is probably too slow.
|
|
315
|
+
# riid[0].hashcode() alone takes 33 us!
|
|
316
|
+
iid = riid[0]
|
|
317
|
+
ptr = self._com_pointers_.get(iid, None)
|
|
318
|
+
if ptr is not None:
|
|
319
|
+
# CopyComPointer(src, dst) calls AddRef!
|
|
320
|
+
_debug("%r.QueryInterface(%s) -> S_OK", self, iid)
|
|
321
|
+
return CopyComPointer(ptr, ppvObj)
|
|
322
|
+
_debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
|
|
323
|
+
return hresult.E_NOINTERFACE
|
|
324
|
+
|
|
325
|
+
def QueryInterface(self, interface: Type[_T_IUnknown]) -> _T_IUnknown:
|
|
326
|
+
"Query the object for an interface pointer"
|
|
327
|
+
# This method is NOT the implementation of
|
|
328
|
+
# IUnknown::QueryInterface, instead it is supposed to be
|
|
329
|
+
# called on an COMObject by user code. It allows to get COM
|
|
330
|
+
# interface pointers from COMObject instances.
|
|
331
|
+
ptr = self._com_pointers_.get(interface._iid_, None)
|
|
332
|
+
if ptr is None:
|
|
333
|
+
raise COMError(
|
|
334
|
+
hresult.E_NOINTERFACE,
|
|
335
|
+
FormatError(hresult.E_NOINTERFACE),
|
|
336
|
+
(None, None, None, 0, None),
|
|
337
|
+
)
|
|
338
|
+
# CopyComPointer(src, dst) calls AddRef!
|
|
339
|
+
result = POINTER(interface)()
|
|
340
|
+
CopyComPointer(ptr, byref(result))
|
|
341
|
+
return result # type: ignore
|
|
342
|
+
|
|
343
|
+
################################################################
|
|
344
|
+
# ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
|
|
345
|
+
def ISupportErrorInfo_InterfaceSupportsErrorInfo(
|
|
346
|
+
self, this: Any, riid: "_Pointer[GUID]"
|
|
347
|
+
) -> int:
|
|
348
|
+
if riid[0] in self._com_pointers_:
|
|
349
|
+
return hresult.S_OK
|
|
350
|
+
return hresult.S_FALSE
|
|
351
|
+
|
|
352
|
+
################################################################
|
|
353
|
+
# IProvideClassInfo::GetClassInfo implementation
|
|
354
|
+
def IProvideClassInfo_GetClassInfo(self) -> ITypeInfo:
|
|
355
|
+
try:
|
|
356
|
+
self.__typelib
|
|
357
|
+
except AttributeError:
|
|
358
|
+
raise WindowsError(hresult.E_NOTIMPL)
|
|
359
|
+
return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
|
|
360
|
+
|
|
361
|
+
################################################################
|
|
362
|
+
# IProvideClassInfo2::GetGUID implementation
|
|
363
|
+
|
|
364
|
+
def IProvideClassInfo2_GetGUID(self, dwGuidKind: int) -> GUID:
|
|
365
|
+
# GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
|
|
366
|
+
if dwGuidKind != 1:
|
|
367
|
+
raise WindowsError(hresult.E_INVALIDARG)
|
|
368
|
+
return self._outgoing_interfaces_[0]._iid_
|
|
369
|
+
|
|
370
|
+
################################################################
|
|
371
|
+
# IDispatch methods
|
|
372
|
+
@property
|
|
373
|
+
def __typeinfo(self):
|
|
374
|
+
# XXX Looks like this better be a static property, set by the
|
|
375
|
+
# code that sets __typelib also...
|
|
376
|
+
iid = self._com_interfaces_[0]._iid_
|
|
377
|
+
return self.__typelib.GetTypeInfoOfGuid(iid)
|
|
378
|
+
|
|
379
|
+
def IDispatch_GetTypeInfoCount(self):
|
|
380
|
+
try:
|
|
381
|
+
self.__typelib
|
|
382
|
+
except AttributeError:
|
|
383
|
+
return 0
|
|
384
|
+
else:
|
|
385
|
+
return 1
|
|
386
|
+
|
|
387
|
+
def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo):
|
|
388
|
+
if itinfo != 0:
|
|
389
|
+
return hresult.DISP_E_BADINDEX
|
|
390
|
+
try:
|
|
391
|
+
ptinfo[0] = self.__typeinfo
|
|
392
|
+
return hresult.S_OK
|
|
393
|
+
except AttributeError:
|
|
394
|
+
return hresult.E_NOTIMPL
|
|
395
|
+
|
|
396
|
+
def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
|
|
397
|
+
# This call uses windll instead of oledll so that a failed
|
|
398
|
+
# call to DispGetIDsOfNames will return a HRESULT instead of
|
|
399
|
+
# raising an error.
|
|
400
|
+
try:
|
|
401
|
+
tinfo = self.__typeinfo
|
|
402
|
+
except AttributeError:
|
|
403
|
+
return hresult.E_NOTIMPL
|
|
404
|
+
return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId)
|
|
405
|
+
|
|
406
|
+
def IDispatch_Invoke(
|
|
407
|
+
self,
|
|
408
|
+
this,
|
|
409
|
+
dispIdMember,
|
|
410
|
+
riid,
|
|
411
|
+
lcid,
|
|
412
|
+
wFlags,
|
|
413
|
+
pDispParams,
|
|
414
|
+
pVarResult,
|
|
415
|
+
pExcepInfo,
|
|
416
|
+
puArgErr,
|
|
417
|
+
):
|
|
418
|
+
try:
|
|
419
|
+
self._dispimpl_
|
|
420
|
+
except AttributeError:
|
|
421
|
+
try:
|
|
422
|
+
tinfo = self.__typeinfo
|
|
423
|
+
except AttributeError:
|
|
424
|
+
# Hm, we pretend to implement IDispatch, but have no
|
|
425
|
+
# typeinfo, and so cannot fulfill the contract. Should we
|
|
426
|
+
# better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
|
|
427
|
+
# clients call IDispatch_Invoke with 'known' DISPID_...'
|
|
428
|
+
# values, without going through GetIDsOfNames first.
|
|
429
|
+
return hresult.DISP_E_MEMBERNOTFOUND
|
|
430
|
+
# This call uses windll instead of oledll so that a failed
|
|
431
|
+
# call to DispInvoke will return a HRESULT instead of raising
|
|
432
|
+
# an error.
|
|
433
|
+
interface = self._com_interfaces_[0]
|
|
434
|
+
ptr = self._com_pointers_[interface._iid_]
|
|
435
|
+
return windll.oleaut32.DispInvoke(
|
|
436
|
+
ptr,
|
|
437
|
+
tinfo,
|
|
438
|
+
dispIdMember,
|
|
439
|
+
wFlags,
|
|
440
|
+
pDispParams,
|
|
441
|
+
pVarResult,
|
|
442
|
+
pExcepInfo,
|
|
443
|
+
puArgErr,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
# XXX Hm, wFlags should be considered a SET of flags...
|
|
448
|
+
mth = self._dispimpl_[(dispIdMember, wFlags)]
|
|
449
|
+
except KeyError:
|
|
450
|
+
return hresult.DISP_E_MEMBERNOTFOUND
|
|
451
|
+
|
|
452
|
+
# Unpack the parameters: It would be great if we could use the
|
|
453
|
+
# DispGetParam function - but we cannot since it requires that
|
|
454
|
+
# we pass a VARTYPE for each argument and we do not know that.
|
|
455
|
+
#
|
|
456
|
+
# Seems that n arguments have dispids (0, 1, ..., n-1).
|
|
457
|
+
# Unnamed arguments are packed into the DISPPARAMS array in
|
|
458
|
+
# reverse order (starting with the highest dispid), named
|
|
459
|
+
# arguments are packed in the order specified by the
|
|
460
|
+
# rgdispidNamedArgs array.
|
|
461
|
+
#
|
|
462
|
+
params = pDispParams[0]
|
|
463
|
+
|
|
464
|
+
if wFlags & (4 | 8):
|
|
465
|
+
# DISPATCH_PROPERTYPUT
|
|
466
|
+
# DISPATCH_PROPERTYPUTREF
|
|
467
|
+
#
|
|
468
|
+
# How are the parameters unpacked for propertyput
|
|
469
|
+
# operations with additional parameters? Can propput
|
|
470
|
+
# have additional args?
|
|
471
|
+
args = [
|
|
472
|
+
params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs)))
|
|
473
|
+
]
|
|
474
|
+
# MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or
|
|
475
|
+
# DISPATCH_PROPERTYPUTREF is specified.
|
|
476
|
+
return mth(this, *args)
|
|
477
|
+
|
|
478
|
+
else:
|
|
479
|
+
# DISPATCH_METHOD
|
|
480
|
+
# DISPATCH_PROPERTYGET
|
|
481
|
+
# the positions of named arguments
|
|
482
|
+
#
|
|
483
|
+
# 2to3 has problems to translate 'range(...)[::-1]'
|
|
484
|
+
# correctly, so use 'list(range)[::-1]' instead (will be
|
|
485
|
+
# fixed in Python 3.1, probably):
|
|
486
|
+
named_indexes = [
|
|
487
|
+
params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs)
|
|
488
|
+
]
|
|
489
|
+
# the positions of unnamed arguments
|
|
490
|
+
num_unnamed = params.cArgs - params.cNamedArgs
|
|
491
|
+
unnamed_indexes = list(reversed(list(range(num_unnamed))))
|
|
492
|
+
# It seems that this code calculates the indexes of the
|
|
493
|
+
# parameters in the params.rgvarg array correctly.
|
|
494
|
+
indexes = named_indexes + unnamed_indexes
|
|
495
|
+
args = [params.rgvarg[i].value for i in indexes]
|
|
496
|
+
|
|
497
|
+
if pVarResult and getattr(mth, "has_outargs", False):
|
|
498
|
+
args.append(pVarResult)
|
|
499
|
+
return mth(this, *args)
|
|
500
|
+
|
|
501
|
+
################################################################
|
|
502
|
+
# IPersist interface
|
|
503
|
+
def IPersist_GetClassID(self) -> GUID:
|
|
504
|
+
return self._reg_clsid_
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
__all__ = ["COMObject"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ctypes
|
|
2
|
-
from typing import Any, NamedTuple
|
|
2
|
+
from typing import Any, Literal, NamedTuple
|
|
3
3
|
from typing import Dict, List, Tuple, Type
|
|
4
4
|
from typing import Optional, Union as _UnionT
|
|
5
5
|
from typing import Callable, Iterator
|
|
@@ -43,7 +43,7 @@ def _unpack_argspec(
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def _resolve_argspec(
|
|
46
|
-
items: Tuple[_ArgSpecElmType, ...]
|
|
46
|
+
items: Tuple[_ArgSpecElmType, ...],
|
|
47
47
|
) -> Tuple[Tuple[_ParamFlagType, ...], Tuple[Type[_CData], ...]]:
|
|
48
48
|
"""Unpacks and converts from argspec to paramflags and argtypes.
|
|
49
49
|
|
|
@@ -64,7 +64,7 @@ def _resolve_argspec(
|
|
|
64
64
|
elif typ is ctypes.POINTER(VARIANT):
|
|
65
65
|
defval = ctypes.pointer(VARIANT.missing)
|
|
66
66
|
else:
|
|
67
|
-
# msg =
|
|
67
|
+
# msg = f"'optional' only allowed for VARIANT and VARIANT*, not for {typ.__name__}"
|
|
68
68
|
# warnings.warn(msg, IDLWarning, stacklevel=2)
|
|
69
69
|
defval = typ()
|
|
70
70
|
if defval is _NOTHING:
|
|
@@ -92,7 +92,7 @@ class _ComMemberSpec(NamedTuple):
|
|
|
92
92
|
class _DispMemberSpec(NamedTuple):
|
|
93
93
|
"""Specifier for a slot of dispinterface method or property."""
|
|
94
94
|
|
|
95
|
-
what:
|
|
95
|
+
what: Literal["DISPMETHOD", "DISPPROPERTY"]
|
|
96
96
|
name: str
|
|
97
97
|
idlflags: Tuple[_UnionT[str, int], ...]
|
|
98
98
|
restype: Optional[Type[_CData]]
|
|
@@ -118,6 +118,78 @@ def _is_spec_prop(m: _MemberSpec):
|
|
|
118
118
|
return any(f in ("propget", "propput", "propputref") for f in m.idlflags)
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
################################################################
|
|
122
|
+
# IDL stuff
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class helpstring(str):
|
|
126
|
+
"Specifies the helpstring for a COM method or property."
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class defaultvalue(object):
|
|
130
|
+
"Specifies the default value for parameters marked optional."
|
|
131
|
+
|
|
132
|
+
def __init__(self, value):
|
|
133
|
+
self.value = value
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class dispid(int):
|
|
137
|
+
"Specifies the DISPID of a method or property."
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# XXX STDMETHOD, COMMETHOD, DISPMETHOD, and DISPPROPERTY should return
|
|
141
|
+
# instances with more methods or properties, and should not behave as an unpackable.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def STDMETHOD(restype, name, argtypes=()) -> _ComMemberSpec:
|
|
145
|
+
"Specifies a COM method slot without idlflags"
|
|
146
|
+
return _ComMemberSpec(restype, name, argtypes, None, (), None)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def DISPMETHOD(idlflags, restype, name, *argspec) -> _DispMemberSpec:
|
|
150
|
+
"Specifies a method of a dispinterface"
|
|
151
|
+
return _DispMemberSpec("DISPMETHOD", name, tuple(idlflags), restype, argspec)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def DISPPROPERTY(idlflags, proptype, name) -> _DispMemberSpec:
|
|
155
|
+
"Specifies a property of a dispinterface"
|
|
156
|
+
return _DispMemberSpec("DISPPROPERTY", name, tuple(idlflags), proptype, ())
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# tuple(idlflags) is for the method itself: (dispid, 'readonly')
|
|
160
|
+
|
|
161
|
+
# sample generated code:
|
|
162
|
+
# DISPPROPERTY([5, 'readonly'], OLE_YSIZE_HIMETRIC, 'Height'),
|
|
163
|
+
# DISPMETHOD(
|
|
164
|
+
# [6], None, 'Render', ([], c_int, 'hdc'), ([], c_int, 'x'), ([], c_int, 'y')
|
|
165
|
+
# )
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def COMMETHOD(idlflags, restype, methodname, *argspec) -> _ComMemberSpec:
|
|
169
|
+
"""Specifies a COM method slot with idlflags.
|
|
170
|
+
|
|
171
|
+
XXX should explain the sematics of the arguments.
|
|
172
|
+
"""
|
|
173
|
+
# collect all helpstring instances
|
|
174
|
+
# We should suppress docstrings when Python is started with -OO
|
|
175
|
+
# join them together(does this make sense?) and replace by None if empty.
|
|
176
|
+
helptext = "".join(t for t in idlflags if isinstance(t, helpstring)) or None
|
|
177
|
+
paramflags, argtypes = _resolve_argspec(argspec)
|
|
178
|
+
if "propget" in idlflags:
|
|
179
|
+
name = f"_get_{methodname}"
|
|
180
|
+
elif "propput" in idlflags:
|
|
181
|
+
name = f"_set_{methodname}"
|
|
182
|
+
elif "propputref" in idlflags:
|
|
183
|
+
name = f"_setref_{methodname}"
|
|
184
|
+
else:
|
|
185
|
+
name = methodname
|
|
186
|
+
return _ComMemberSpec(
|
|
187
|
+
restype, name, argtypes, paramflags, tuple(idlflags), helptext
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
################################################################
|
|
192
|
+
|
|
121
193
|
_PropFunc = Optional[Callable[..., Any]]
|
|
122
194
|
_DocType = Optional[str]
|
|
123
195
|
|
|
@@ -310,7 +382,7 @@ class PropertyGenerator(object):
|
|
|
310
382
|
# Hm, must be a descriptor where the __get__ method
|
|
311
383
|
# returns a bound object having __getitem__ and
|
|
312
384
|
# __setitem__ methods.
|
|
313
|
-
prop = named_property("
|
|
385
|
+
prop = named_property(f"{self._cls_name}.{name}", fget, fset, doc)
|
|
314
386
|
yield (name, prop)
|
|
315
387
|
|
|
316
388
|
def to_propget_keys(self, m: _MemberSpec) -> Tuple[str, _DocType, int]:
|
|
@@ -360,7 +432,7 @@ class DispPropertyGenerator(PropertyGenerator):
|
|
|
360
432
|
|
|
361
433
|
|
|
362
434
|
class ComMemberGenerator(object):
|
|
363
|
-
def __init__(self, cls_name: str, vtbl_offset: int, iid: comtypes.GUID) -> None:
|
|
435
|
+
def __init__(self, cls_name: str, vtbl_offset: int, iid: "comtypes.GUID") -> None:
|
|
364
436
|
self._vtbl_offset = vtbl_offset
|
|
365
437
|
self._iid = iid
|
|
366
438
|
self._props = ComPropertyGenerator(cls_name)
|
|
@@ -533,11 +605,11 @@ class bound_named_property(object):
|
|
|
533
605
|
self.fset(self.instance, index, value)
|
|
534
606
|
|
|
535
607
|
def __repr__(self):
|
|
536
|
-
return "<bound_named_property
|
|
608
|
+
return f"<bound_named_property {self.name!r} at {id(self):x}>"
|
|
537
609
|
|
|
538
610
|
def __iter__(self):
|
|
539
611
|
"""Explicitly disallow iteration."""
|
|
540
|
-
msg = "
|
|
612
|
+
msg = f"{self.name!r} is not iterable"
|
|
541
613
|
raise TypeError(msg)
|
|
542
614
|
|
|
543
615
|
|
|
@@ -558,4 +630,4 @@ class named_property(object):
|
|
|
558
630
|
raise AttributeError("Unsettable attribute")
|
|
559
631
|
|
|
560
632
|
def __repr__(self):
|
|
561
|
-
return "<named_property
|
|
633
|
+
return f"<named_property {self.name!r} at {id(self):x}>"
|