CDialog类响应ActiveX事件的实现

转自:http://news.newhua.com/news/2008/0828/45243.shtml

核心提示:在大多数ATL工程中,客户端为了能够响应服务的事件,往往需要继承于IDispEventImpl或IDispEventSimpleImpl的模板类;由于服务本身实现了IDispatch接口,它可以很方便得通过BEGIN_SINK_MAP和END_SINK_MAP实现对事件的分发响应
   在大多数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。
其他:
http://blog.youkuaiyun.com/kuanghong/article/details/1765119

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值