1
+ import functools
1
2
import logging
2
3
from _ctypes import COMError
3
- from ctypes import pointer
4
- from typing import TYPE_CHECKING , ClassVar , Dict , List , Tuple , Type
4
+ from ctypes import c_void_p , pointer
5
+ from ctypes .wintypes import DWORD
6
+ from typing import TYPE_CHECKING , Any , Callable , Dict , Iterator , List , Tuple , Type
7
+ from typing import Union as _UnionT
5
8
6
- from comtypes import COMObject , IUnknown
9
+ from comtypes import GUID , COMObject , IUnknown
7
10
from comtypes .automation import IDispatch
8
11
from comtypes .connectionpoints import IConnectionPoint
9
12
from comtypes .hresult import *
10
13
from comtypes .typeinfo import ITypeInfo , LoadRegTypeLib
11
14
15
+ if TYPE_CHECKING :
16
+ from ctypes import _Pointer
17
+ from typing import ClassVar
18
+
19
+ from comtypes import hints # type: ignore
20
+
12
21
logger = logging .getLogger (__name__ )
13
22
14
23
__all__ = ["ConnectableObjectMixin" ]
@@ -31,7 +40,9 @@ def __init__(
31
40
# per MSDN, all interface methods *must* be implemented, E_NOTIMPL
32
41
# is no allowed return value
33
42
34
- def IConnectionPoint_Advise (self , this , pUnk , pdwCookie ):
43
+ def IConnectionPoint_Advise (
44
+ self , this : Any , pUnk : IUnknown , pdwCookie : "_Pointer[DWORD]"
45
+ ) -> "hints.Hresult" :
35
46
if not pUnk or not pdwCookie :
36
47
return E_POINTER
37
48
logger .debug ("Advise" )
@@ -43,21 +54,25 @@ def IConnectionPoint_Advise(self, this, pUnk, pdwCookie):
43
54
self ._connections [self ._cookie ] = ptr
44
55
return S_OK
45
56
46
- def IConnectionPoint_Unadvise (self , this , dwCookie ) :
57
+ def IConnectionPoint_Unadvise (self , this : Any , dwCookie : int ) -> "hints.Hresult" :
47
58
logger .debug ("Unadvise %s" , dwCookie )
48
59
try :
49
60
del self ._connections [dwCookie ]
50
61
except KeyError :
51
62
return CONNECT_E_NOCONNECTION
52
63
return S_OK
53
64
54
- def IConnectionPoint_GetConnectionPointContainer (self , this , ppCPC ):
65
+ def IConnectionPoint_GetConnectionPointContainer (
66
+ self , this : Any , ppCPC : c_void_p
67
+ ) -> "hints.Hresult" :
55
68
return E_NOTIMPL
56
69
57
- def IConnectionPoint_GetConnectionInterface (self , this , pIID ):
70
+ def IConnectionPoint_GetConnectionInterface (
71
+ self , this : Any , pIID : "_Pointer[GUID]"
72
+ ) -> "hints.Hresult" :
58
73
return E_NOTIMPL
59
74
60
- def _call_sinks (self , name , * args , ** kw ) :
75
+ def _call_sinks (self , name : str , * args : Any , ** kw : Any ) -> List [ Any ] :
61
76
results = []
62
77
logger .debug ("_call_sinks(%s, %s, *%s, **%s)" , self , name , args , kw )
63
78
# Is it an IDispatch derived interface? Then, events have to be delivered
@@ -66,61 +81,33 @@ def _call_sinks(self, name, *args, **kw):
66
81
# for better performance, we could cache the dispids.
67
82
dispid = self ._typeinfo .GetIDsOfNames (name )[0 ]
68
83
for key , p in self ._connections .items ():
69
- try :
70
- result = p .Invoke (dispid , * args , ** kw )
71
- except COMError as details :
72
- if details .hresult == RPC_S_SERVER_UNAVAILABLE :
73
- logger .warning (
74
- "_call_sinks(%s, %s, *%s, **%s) failed; removing connection" ,
75
- self ,
76
- name ,
77
- args ,
78
- kw ,
79
- exc_info = True ,
80
- )
81
- try :
82
- del self ._connections [key ]
83
- except KeyError :
84
- pass # connection already gone
85
- else :
86
- logger .warning (
87
- "_call_sinks(%s, %s, *%s, **%s)" ,
88
- self ,
89
- name ,
90
- args ,
91
- kw ,
92
- exc_info = True ,
93
- )
94
- else :
95
- results .append (result )
84
+ mth = functools .partial (p .Invoke , dispid ) # type: ignore
85
+ results .extend (self ._call_sink (name , key , mth , * args , ** kw ))
96
86
else :
97
- for p in self ._connections .values ():
98
- try :
99
- result = getattr (p , name )(* args , ** kw )
100
- except COMError as details :
101
- if details .hresult == RPC_S_SERVER_UNAVAILABLE :
102
- logger .warning (
103
- "_call_sinks(%s, %s, *%s, **%s) failed; removing connection" ,
104
- self ,
105
- name ,
106
- args ,
107
- kw ,
108
- exc_info = True ,
109
- )
110
- del self ._connections [key ]
111
- else :
112
- logger .warning (
113
- "_call_sinks(%s, %s, *%s, **%s)" ,
114
- self ,
115
- name ,
116
- args ,
117
- kw ,
118
- exc_info = True ,
119
- )
120
- else :
121
- results .append (result )
87
+ for key , p in self ._connections .items ():
88
+ mth = getattr (p , name )
89
+ results .extend (self ._call_sink (name , key , mth , * args , ** kw ))
122
90
return results
123
91
92
+ def _call_sink (
93
+ self , name : str , key : int , mth : Callable [..., Any ], * args : Any , ** kw : Any
94
+ ) -> Iterator [Any ]:
95
+ try :
96
+ result = mth (* args , ** kw )
97
+ except COMError as details :
98
+ if details .hresult == RPC_S_SERVER_UNAVAILABLE :
99
+ warn_msg = "_call_sinks(%s, %s, *%s, **%s) failed; removing connection"
100
+ logger .warning (warn_msg , self , name , args , kw , exc_info = True )
101
+ try :
102
+ del self ._connections [key ]
103
+ except KeyError :
104
+ pass # connection already gone
105
+ else :
106
+ warn_msg = "_call_sinks(%s, %s, *%s, **%s)"
107
+ logger .warning (warn_msg , self , name , args , kw , exc_info = True )
108
+ else :
109
+ yield result
110
+
124
111
125
112
class ConnectableObjectMixin (object ):
126
113
"""Mixin which implements IConnectionPointContainer.
@@ -143,13 +130,17 @@ def __init__(self) -> None:
143
130
typeinfo = tlib .GetTypeInfoOfGuid (itf ._iid_ )
144
131
self .__connections [itf ] = ConnectionPointImpl (itf , typeinfo )
145
132
146
- def IConnectionPointContainer_EnumConnectionPoints (self , this , ppEnum ):
133
+ def IConnectionPointContainer_EnumConnectionPoints (
134
+ self , this : Any , ppEnum : c_void_p
135
+ ) -> "hints.Hresult" :
147
136
# according to MSDN, E_NOTIMPL is specificially disallowed
148
137
# because, without typeinfo, there's no way for the caller to
149
138
# find out.
150
139
return E_NOTIMPL
151
140
152
- def IConnectionPointContainer_FindConnectionPoint (self , this , refiid , ppcp ):
141
+ def IConnectionPointContainer_FindConnectionPoint (
142
+ self , this : Any , refiid : "_Pointer[GUID]" , ppcp : c_void_p
143
+ ) -> "hints.Hresult" :
153
144
iid = refiid [0 ]
154
145
logger .debug ("FindConnectionPoint %s" , iid )
155
146
if not ppcp :
@@ -169,7 +160,9 @@ def IConnectionPointContainer_FindConnectionPoint(self, this, refiid, ppcp):
169
160
logger .debug ("No connectionpoint found" )
170
161
return CONNECT_E_NOCONNECTION
171
162
172
- def Fire_Event (self , itf , name , * args , ** kw ):
163
+ def Fire_Event (
164
+ self , itf : _UnionT [int , Type [IDispatch ]], name : str , * args : Any , ** kw : Any
165
+ ) -> Any :
173
166
# Fire event 'name' with arguments *args and **kw.
174
167
# Accepts either an interface index or an interface as first argument.
175
168
# Returns a list of results.
0 commit comments