随笔 - 64, 文章 - 11, 评论 - 12, 引用 - 0
数据加载中……

ATL连接点开发总结

 

连接点语义


         第一种说法:是一种逻辑上的反馈机制,这种机制允许对象暴露其调用一个或者多个指定接口的能力

         第二种说法:QueryInterface允许客户从对象中取得一个指向对象实现的接口指针,连接点允许客户给予对象一个由客户实现的接口指针.

在这种情形下:COM对象是源,客户提供的方法是接收器.

源必须实现IConnectionPoint

 

Interface IConnectionPoint

{

         HRESULT GetConnectionInterface([out] IID *pIID);

         HRESULT GetConnectionPointContainer([out] IConnectionPointContainer** ppCPC);

         HRESULT Advise([in] IUnknnown *punkSing, [Out] DWORD *pdwCookie);

         HRESULT Unadvise([in]DWORD dwCookie);

         HREUSLT EnumConnections([out] IEnumConnections** ppEnum);

}

 

Interface IConnectionPointContainer

{

         HRESULT EnumConnectionPoints([out] IEnumConnectionPoints **ppEnum);

         HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint **ppcP);

}

 

客户的使用方法:

IUnKnown *pSource;

ISpeakerEvent *pSink;

DWORD dwCookie;

IConnectionPointContainer pcpc;

Hr = pSource->QueryInterface(&pcpc);

IConnectionPoint pcp;

Hr = pcpc->FindConnection(__uuidof(ISpeakerEvent));

Hr = pcp->Advise(pSink,&dwCookie);

Hr = pcp->Unadvise(dwCookie);

便捷的的宏:

AtlAdivse(psource, pSink, __uuidof(ISpeakerEvent), &dwCookie);

AtlUnadvise(psource, __uuidof(ISpeakerEvent), dwCookie);

 

 

建立可连接对象的步聚:

1:实现IConnectionPointContainer接口

         Class ATL_NO_VTABLE className:

                   ….

                   Public IConnectionPointContainerImpl<className>

{…..

};

2:QueryInterfaceDIID_IConnectionPointContainer的请求作出响应

         BEGIN_COM_MAP

COM_INTERFACE_ENTRY(IConnectionPointContainer)

END_COM_MAP

 

3:我们要为每个可连接对象支持的源接口实现IConnectionPoint

                  Class ATL_NO_VTABLE className:

                   ….

                   Public IConnectionPointContainerImpl<className>,

                   Public IConnectionPointImpl<className, &DIID__对外的接口>

{…..

};

4:我们要提供一个连接映射表,也就是一个IID和连接点实现联系起来的表.

         BEGIN_CONNECTION_POINT_MAP

                   CONNECTION_POINT_MAP_ENTRY(DIID__对外的接口)

                   ….

         END_CONNECTION_POINT_MAP()

 

5:我们必须更新可连接对象在IDL文件中coClass的定义,以便指定每个源接口.每个源接口必须具有属性,主源接口应具有[default, source]属性.

         Coclass 类厂名

         {……

                   [default,source] dispinterface _对外接口;

         };

6:一般来说,我们希望通过辅助方法为所有连接的接收器调用接收器方法.

         HRESULT Fire_事件(parameter)

         {

                   依次调用每个接收器的方法

         }

        

         可以使用IDE来生成连接点代理类.这样我们的源可以从其派生,而不再从IConnectionPointImpl派生.

7:我们必须在适当的时机调用辅助方法.

 

 

建立接收事件的对象:

1:实现事件接收器.可先的方案有从

IDispEventSimpleImpl<UINT nID, class T, const IID *pdIID = &IID_NULL>

或者:

IDispEventImpl< UINT nID, class T, const IID *pdIID = &IID_NULL,

                            Const GUID*plibid= &GUID_NULL,

                            DWORD wMajor = 0, WORD wMinor = 0,

                            Class tihclass = CComTypeInfoHolder>

派生.

   例如:

   static const int DEFSOURCEID = 1;

   class CEarPolitic;

         typedef IDispEventImpl< DEFSOURCEID, CEarPolitic, &DIID__ISpeackerEvents

                            &LIBID_ATLINTERNALSLIB, LIBMAJOR,LIBMINOR> DefSource;

Class ATL_NO_VTABLE CEarPolitic

         :public DefSource

{

         ….

}

 

2:事件接收器映射表

 BEGIN_SINK_MAP(CEarPolitic)

         SINK_ENTRY_EX(source, DIID, DISPID, EventHandlerFunc)

         SINK_ENTRY_EX(source, DIID, DISPID, EventHandlerFunc, &info)

 END_SINK_MAP()

 

         例如:

         void  __stdcall OnHearPlaintiffWhisper(BSTR bstrText);//sink接口的一个方法.

  

_ATL_FUNC_INFO OnHearPlaintiffWhisper =

                   {CC_STDCALL, VT_EMPTY, 1, { VT_BSTR}};

Static const int SOURCEID = 1;

 

BEGIN_SINK_MAP(CEarPolitic)

                   SINK_ENTRY_EX(SOURCEID, DIID__对外接口, 方法的DISPID, OnHearPlaintiffWhisper)

END_SINK_MAP()

 

3:进一步实现这个回调函数.

4:把事件接收器连接到数据源

 

posted on 2008-09-30 16:01 Robertxiao 阅读(2597) 评论(0)  编辑 收藏 引用 所属分类: RPC/COM/ATL散谈


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理