分类: C/C++
2008-03-18 16:31:47
连接
COM 编程最单调乏味的一个方面是使用连接点来支持 outbound 接口。IConnectionPoint/IConnectionPointContainer 的设计好像是专门用来解决这个问题的,但是经验证明,不论是在性能方面,还是在易用性方面,它还是存在不足之处。ATL为每一个这样的接口提供了缺省的实现类,多少解决了一些易用性问题。
要理解ATL如何实现连结点,最容易的方式是看例子:假设定义了如下的 outbound 接口:
interface IPageSink : IUnknown { HRESULT OnPageReceived(void); } interface IStopSink : IUnknown { HRESULT OnShutdown(void); }为了支持这两个 outbound 接口,下面的ATL代码已经足够:
class CPager : public CComObjectRoot, public CComCoClass大多数有经验的 COM 程序员首先注意到的是 CPager 类从一个接口(IConnectionPoint)派生的,这个接口并不作为 COM 本身的一部分提供。为了实现这种诀窍,ATL 类 IConnectionPointImpl 不从接口 IConnectionPoint 派生,而是象 IConnectionPoint 那样以相同的顺序定义它的虚函数。, public IPager, public IConnectionPointContainerImpl , public IConnectionPointImpl , public IConnectionPointImpl { BEGIN_COM_MAP(CPager) COM_INTERFACE_ENTRY(IPager) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) END_COM_MAP() BEGIN_CONNECTION_POINT_MAP(CPager) CONNECTION_POINT_ENTRY(IID_IPageSink) CONNECTION_POINT_ENTRY(IID_IStopSink) END_CONNECTION_POINT_MAP() };
typedef IConnectionPointImpl编写多点传送例程十分繁琐。所幸的是,ATL提供了 Visual Studio 组件—— ATL 代理产生器(ATL Proxy Generator),(如下图五)它们会读取接口的类型库描述并产生 IConnectionPointImpl 派生类,为每一个 outbound 方法添加适当的 Fire 例程。连结点代理便被产生出来。base; for (IUnknown** pp = base::m_vec.begin(); pp < base::m_vec.end(); pp++) if (*pp) ((IPageSink*)(*pp))->OnPageRecieved();
class CPager : public CComObjectRoot, public CComCoClass为了发送出境方法通知,你只要调用适当的Fire_XXX方法即可:, public IPager, public IConnectionPointContainerImpl , public CProxyIPageSink , public CProxyIStopSink { BEGIN_COM_MAP(CPager) COM_INTERFACE_ENTRY(IPager) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) END_COM_MAP() BEGIN_CONNECTION_POINT_MAP(CPager) CONNECTION_POINT_ENTRY(IID_IPageSink) CONNECTION_POINT_ENTRY(IID_IStopSink) END_CONNECTION_POINT_MAP() };
STDMETHODIMP CPager::SendMessage(LPCOLESTR pwsz) { // send outbound notifications HRESULT hr = Fire_OnPageRecieved(); // process normally return hr; }机器产生代理的一个限制是必须要 outbound 接口的类型库定义。对于大量的 COM 接口而言,这是不可能的,因为类型库在转换方面与 IDL 特性背道而驰。对于更复杂的接口,你可以从机器所产生的代理开始并修改这些代码来进行尝试。