1
1
import ctypes
2
+ from typing import Any , Dict , Optional , Set , Type , TypeVar
2
3
3
4
from comtypes import automation
4
5
from comtypes .client import lazybind
5
- from comtypes import COMError , hresult as hres , _is_object
6
+ from comtypes import COMError , GUID , IUnknown , hresult as hres , _is_object
6
7
8
+
9
+ _T_IUnknown = TypeVar ("_T_IUnknown" , bound = IUnknown )
7
10
# These errors generally mean the property or method exists,
8
11
# but can't be used in this context - eg, property instead of a method, etc.
9
12
# Used to determine if we have a real error or not.
17
20
18
21
19
22
def Dispatch (obj ):
20
- # Wrap an object in a Dispatch instance, exposing methods and properties
21
- # via fully dynamic dispatch
23
+ """Wrap an object in a Dispatch instance, exposing methods and properties
24
+ via fully dynamic dispatch.
25
+ """
22
26
if isinstance (obj , _Dispatch ):
23
27
return obj
24
28
if isinstance (obj , ctypes .POINTER (automation .IDispatch )):
@@ -33,19 +37,19 @@ def Dispatch(obj):
33
37
class MethodCaller :
34
38
# Wrong name: does not only call methods but also handle
35
39
# property accesses.
36
- def __init__ (self , _id , _obj ) :
40
+ def __init__ (self , _id : int , _obj : "_Dispatch" ) -> None :
37
41
self ._id = _id
38
42
self ._obj = _obj
39
43
40
- def __call__ (self , * args ) :
44
+ def __call__ (self , * args : Any ) -> Any :
41
45
return self ._obj ._comobj .Invoke (self ._id , * args )
42
46
43
- def __getitem__ (self , * args ) :
47
+ def __getitem__ (self , * args : Any ) -> Any :
44
48
return self ._obj ._comobj .Invoke (
45
49
self ._id , * args , _invkind = automation .DISPATCH_PROPERTYGET
46
50
)
47
51
48
- def __setitem__ (self , * args ) :
52
+ def __setitem__ (self , * args : Any ) -> None :
49
53
if _is_object (args [- 1 ]):
50
54
self ._obj ._comobj .Invoke (
51
55
self ._id , * args , _invkind = automation .DISPATCH_PROPERTYPUTREF
@@ -57,22 +61,26 @@ def __setitem__(self, *args):
57
61
58
62
59
63
class _Dispatch (object ):
60
- # Expose methods and properties via fully dynamic dispatch
61
- def __init__ (self , comobj ):
64
+ """Expose methods and properties via fully dynamic dispatch."""
65
+
66
+ _comobj : automation .IDispatch
67
+ _ids : Dict [str , int ]
68
+ _methods : Set [str ]
69
+
70
+ def __init__ (self , comobj : "ctypes._Pointer[automation.IDispatch]" ):
62
71
self .__dict__ ["_comobj" ] = comobj
63
- self .__dict__ [
64
- "_ids"
65
- ] = {} # Tiny optimization: trying not to use GetIDsOfNames more than once
72
+ # Tiny optimization: trying not to use GetIDsOfNames more than once
73
+ self .__dict__ ["_ids" ] = {}
66
74
self .__dict__ ["_methods" ] = set ()
67
75
68
- def __enum (self ):
69
- e = self ._comobj .Invoke (- 4 ) # DISPID_NEWENUM
76
+ def __enum (self ) -> automation . IEnumVARIANT :
77
+ e : IUnknown = self ._comobj .Invoke (- 4 ) # DISPID_NEWENUM
70
78
return e .QueryInterface (automation .IEnumVARIANT )
71
79
72
- def __hash__ (self ):
80
+ def __hash__ (self ) -> int :
73
81
return hash (self ._comobj )
74
82
75
- def __getitem__ (self , index ) :
83
+ def __getitem__ (self , index : Any ) -> Any :
76
84
enum = self .__enum ()
77
85
if index > 0 :
78
86
if 0 != enum .Skip (index ):
@@ -82,11 +90,13 @@ def __getitem__(self, index):
82
90
raise IndexError ("index out of range" )
83
91
return item
84
92
85
- def QueryInterface (self , interface , iid = None ):
93
+ def QueryInterface (
94
+ self , interface : Type [_T_IUnknown ], iid : Optional [GUID ] = None
95
+ ) -> _T_IUnknown :
86
96
"""QueryInterface is forwarded to the real com object."""
87
97
return self ._comobj .QueryInterface (interface , iid )
88
98
89
- def _FlagAsMethod (self , * names ) :
99
+ def _FlagAsMethod (self , * names : str ) -> None :
90
100
"""Flag these attribute names as being methods.
91
101
Some objects do not correctly differentiate methods and
92
102
properties, leading to problems when calling these methods.
@@ -100,7 +110,7 @@ def _FlagAsMethod(self, *names):
100
110
"""
101
111
self ._methods .update (names )
102
112
103
- def __getattr__ (self , name ) :
113
+ def __getattr__ (self , name : str ) -> Any :
104
114
if name .startswith ("__" ) and name .endswith ("__" ):
105
115
raise AttributeError (name )
106
116
# tc = self._comobj.GetTypeInfo(0).QueryInterface(comtypes.typeinfo.ITypeComp)
@@ -119,20 +129,16 @@ def __getattr__(self, name):
119
129
try :
120
130
result = self ._comobj .Invoke (dispid , _invkind = flags )
121
131
except COMError as err :
122
- (hresult , text , details ) = err .args
132
+ (hresult , _ , _ ) = err .args
123
133
if hresult in ERRORS_BAD_CONTEXT :
124
134
result = MethodCaller (dispid , self )
125
135
self .__dict__ [name ] = result
126
136
else :
127
- # The line break is important for 2to3 to work correctly
128
- raise
129
- except :
130
- # The line break is important for 2to3 to work correctly
131
- raise
137
+ raise err
132
138
133
139
return result
134
140
135
- def __setattr__ (self , name , value ) :
141
+ def __setattr__ (self , name : str , value : Any ) -> None :
136
142
dispid = self ._ids .get (name )
137
143
if not dispid :
138
144
dispid = self ._comobj .GetIDsOfNames (name )[0 ]
@@ -142,7 +148,7 @@ def __setattr__(self, name, value):
142
148
flags = 8 if _is_object (value ) else 4
143
149
return self ._comobj .Invoke (dispid , value , _invkind = flags )
144
150
145
- def __iter__ (self ):
151
+ def __iter__ (self ) -> "_Collection" :
146
152
return _Collection (self .__enum ())
147
153
148
154
# def __setitem__(self, index, value):
@@ -156,10 +162,10 @@ def __iter__(self):
156
162
157
163
158
164
class _Collection (object ):
159
- def __init__ (self , enum ):
165
+ def __init__ (self , enum : automation . IEnumVARIANT ):
160
166
self .enum = enum
161
167
162
- def __next__ (self ):
168
+ def __next__ (self ) -> Any :
163
169
item , fetched = self .enum .Next (1 )
164
170
if fetched :
165
171
return item
0 commit comments