Exporting events from Python COM class.

Mark Hammond MarkH at ActiveState.com
Thu Nov 9 22:23:00 EST 2000


> I also think there's a bug in win32com\server\connect.py's
> Advise implementation -- if a client tries to connect (to
> the one-and-only source interface), with an object that
> also implements some _other_ dispatch-interface (and
> returns that 'other' when QI's for IDispatch), the methods
> being called when events are fired are going to be methods
> on the _default_ IDispatch version of the client-object,
> NOT on the specific dispinterface it asked to connect.  I
> think this violates COM's rules, and, while it's unlikely
> that a specific client implementation will trigger this
> bug, I expect _very_ subtle, hard to reproduce, hard to
> understand, little semantics disasters if/when it happens.
> 
> Is the second call to QueryInterface on that Advise method
> really necessary...?  I guess so, since commenting it out
> makes win32com.demos.connect.test() fail with an AttributeError
> on Invoke, but I don't really understand why... (would it
> work OK if the source-interface were to inherit IDispatch
> as it should and the event-generating Python COM server
> was properly apprised of that...?)


Actually, I'm not sure of the COM semantics here.

The code in question is:

     interface = pUnk.QueryInterface(self._connect_interfaces_[0],1)
     interface = interface.QueryInterface(pythoncom.IID_IDispatch)

And actually exposes the reason for one of the hacks in win32com. 
Notice the second arg to the first QI.  This is to say "even though I am 
QIing for an interface you dont support, give me back an object anyway".

The problem is that the first line is doing a QI for a specific 
interface - a vtable based COM interface.

Consider a C++ implemented object that supports an event sink, but does 
_not_ support IDispatch.  ie, the event interface is not dual.  In this 
case, the QI has given us the real vtable.  But if we assume the vtable 
is really for IDispatch, we will crash.

Indeed, way back when this sample was written, there was a C++ "connect" 
ATL sample.  This "connect" sample was such an interface - it did not 
support IDispatch.  Much of this code was tested against that component.

Later versions of ATL upgraded this sample.  It is now IDispatch based - 
thus, you can fire events against the vtable, or against IDispatch.  The 
Python COM C++ test component, derived from this "connect" sample also 
supports dual interfaces.

As I mentioned, I am not 100% sure of the COM semantics here.  At the 
time, I could not find documentation to imply that COM QI rules could be 
violated for events - thus, doing a QI for a specific interface is 
expected to return that interface, and not IDispatch.

Hence we have the second QI for specifically IDispatch.

Mark.




More information about the Python-list mailing list