关于响应ActiveX组件方法

相关内容搜集自网络:

一、CDialog类响应ActiveX事件的实现

 
在大多数ATL工程中,客户端为了能够响应服务的事件,往往需要继承于IDispEventImpl或IDispEventSimpleImpl的模板类;由于服务本身实现了IDispatch接口,它可以很方便得通过BEGIN_SINK_MAP和END_SINK_MAP实现对事件的分发响应。但当我们为MFC的对话框里添加一个ActiveX后,会发现尽管CDialog并不继承与这两个模板类,却仍然可以实现对事件的响应;而且简单到似乎仅仅只是添加了BEGIN_EVENTSINK_MAP和END_EVENTSINK_MAP。那么问题就是,服务端既然必须通过IDispatch接口来分发事件,那CDialog的IDispatch接口实现在了哪里? 
  通过在事件响应函数里下断点,观察CallStack,已经可以比较清楚得看出端倪,实际上这不是CDialog的专利,而已由CWnd实现的,它没有继承IDispatch接口,却包含和一个继承于IDispatch接口的成员,通过这个成员告诉CWnd该调用哪个响应函数;这样大大简化了CWnd的实现。 

  具体的实现情况是: 

1,BEGIN_EVENTSINK_MAP和END_EVENTSINK_MAP的作用仅仅是把事件响应函数放到对话框的窗口函数; 

2,CWnd 拥有一个COleControlContainer型成员m_pCtrlCont; 

3,m_pCtrlCont拥有多个COleControlSite成员,这样可以保证一个对话框上有多个ActiveX而不会互相干扰;

4,每个COleControlSite拥有一个继承于IDispatch的嵌套类XEventSink及其成员m_xEventSink。通过以下这样一段宏实现: 

BEGIN_INTERFACE_PART(EventSink, IDispatch) 

INIT_INTERFACE_PART(COleControlSite, EventSink) 

STDMETHOD(GetTypeInfoCount)(unsigned int*); 

STDMETHOD(GetTypeInfo)(unsigned int, LCID, ITypeInfo**); 

STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, unsigned int, LCID, DISPID*); 

STDMETHOD(Invoke)(DISPID, REFIID, LCID, unsigned short, DISPPARAMS*, VARIANT*, EXCEPINFO*, unsigned int*); 

END_INTERFACE_PART(EventSink) 
  在Invoke中,实际上就是调用对话框的OnCmdMsg,从而很方便得实现了事件的分发,而对客户端而言却丝毫感觉不到影响。 

  从这个实现,可以发现使用包含的设计方式往往比继承更具有灵活性;同时也提供了另一种客户端对事件响应的实现方式。实际上,不需要一定要通过宏修改窗口函数,而只要适当修改Invoke令其实现事件分发即可。
 
ATL中,使用Begin_Sink_map   mfc中,使用Begin_eventSink_map。
 
更多关于网页端、MFC、ATL的dispatch实现
http://blog.csdn.net/kuanghong/article/details/1765119
 
二、关于参数vtsparam
The vtsParams argument is a space-separated list of values from the VTS_ constants. 
posted @ 2020-05-27 16:49  IceArrow  阅读(351)  评论(0编辑  收藏  举报