天天看點

Win32程式設計點滴5 - 響應ActiveX控件的事件

Win32程式設計點滴5 - 響應ActiveX控件的事件
Win32程式設計點滴5 - 響應ActiveX控件的事件

然後,來說一下Dispath事件。如果IConnectionPoint::GetConnectionInterface傳回的IID代表的接口是繼承于IDispatch的話,這個事件就是一個Dispath事件。當事件發生時,産生事件的對象不會直接調用pObj->OnEvent(),而會調用pObj->Invoke(…)。例如,Flash控件的事件對象:(通過vc的#import指令生成的)

Win32程式設計點滴5 - 響應ActiveX控件的事件
Win32程式設計點滴5 - 響應ActiveX控件的事件

當Flash控件産生事件時,它會調用IDispath::Invoke而不是,OnReadyStateChange等方法。隻有在vc,atl等架構裡面,這些架構會自動生成Invoke函數,在Invoke函數中根據參數的不同(第一個參數memid代表代表哪個方法被調用),再調用OnReadyStateChange等方法。

是以,雖然IConnectionPoint要求實作的接口是_IShockwaveFlashEvents,但是我們的虛表中,隻要存在IDispath的方法即可,虛表中之後_IShockwaveFlashEvents的方法不會被直接調用(如果我們自己實作Invoke,也不會去調用的)。我們告訴Flash控件,這是一個_IShockwaveFlashEvents接口,雖然它隻實作了IDispath。就像CGeneralEventSink中的代碼:

Win32程式設計點滴5 - 響應ActiveX控件的事件
Win32程式設計點滴5 - 響應ActiveX控件的事件

其中m_iid是IConnectionPoint要求實作的接口,通過CGeneralEventSink構造函數參數傳入的。當然,m_iid一定要是一個dispatch接口(繼承于IDispatch)。如果IConnectionPoint要求的接口不是繼承于IDispatch的,則m_iid會被設定為IID_NULL,然後IConnectionPoint便得不到所要求的接口,Advise就會失敗,否則的話控件就會調用一個虛表中不存在的方法(不是IDispatch事件的話,控件隻能直接調用接口的方法,而不是Invoke),産生錯誤。

那麼,如何判斷m_iid是Dispatch接口呢?首先,得到代表此接口的ITypeInfo指針,這個請參考代碼中的:

簡單的說,就是控件的接口pRelateObj會實作IProvideClassInfo接口,來提供它本身的ITypeInfo。再通過ITypeInfo::GetRefTypeInfo可以得到相關事件的ITypeInfo。

接着,此ITypeInfo的TYPEATTR結構中的typekind表明了,此ITypeInfo是否的Dispatch接口,代碼如下:

Win32程式設計點滴5 - 響應ActiveX控件的事件
Win32程式設計點滴5 - 響應ActiveX控件的事件

最後,CGeneralEventSink的IDispatch方法全部傳回E_NOTIMPLE就可以了,畢竟控件隻是通知我們事件發生了,而不關心我們有什麼反應。當然,為了讓提供的示例更有趣,代碼裡面的Invoke做了詳細的log(在得到接口的ITypeInfo的同時,也枚舉了MEMID/DISPID對應的名字。還從系統資料庫中把iid變成了接口的名字,所有這一切參考CGeneralEventSink的構造函數)。

<a href="http://files.cnblogs.com/Greatest/TestActiveX2.zip">代碼下載下傳</a>

繼續閱讀