连接点

本文介绍如何使用 MFC 类 CCmdTargetCConnectionPoint 来实现连接点(以前称为 OLE 连接点)。

过去,组件对象模型 (COM) 定义了允许对象在接口中实现和公开功能的常规机制 (IUnknown::QueryInterface*)。 但是,未定义允许对象公开调用特定接口的功能的相应机制。 也就是说,COM 定义了处理对象传入指针(指向该对象的接口的指针)的方式,但它没有用于传出接口(该对象保存的指针指向其他对象的接口)的显式模型。 COM 现在有一个名为连接点的模型,该模型支持此功能。

连接有两个部件:调用接口的对象,称为源,以及实现接口的对象,称为接收器。 连接点是由源公开的接口。 通过公开连接点,源允许接收器建立与自身(源)的连接。 通过连接点机制(IConnectionPoint 接口),将指向接收器接口的指针传递给源对象。 使用此指针,源就可以访问接收器对一组成员函数的实现。 例如,若要触发接收器实现的事件,源可以调用接收器实现的相应方法。 下图演示了刚刚描述的连接点。

Diagram showing an implemented connection point.
已实现的连接点

MFC 在 CConnectionPointCCmdTarget 类中实现此模型。 派生自 CConnectionPoint 的类实现 IConnectionPoint 接口,该接口用于向其他对象公开连接点。 派生自 CCmdTarget 的类实现 IConnectionPointContainer 接口,该接口可以枚举某个对象的所有可用连接点或查找特定连接点。

对于类中实现的每个连接点,必须声明实现该连接点的连接部件。 如果实现一个或多个连接点,则还需在类中声明单个连接映射。 连接映射是 ActiveX 控件支持的连接点表。

以下示例演示了一个简单的连接映射和一个连接点。 第一个示例声明连接映射和点;第二个示例实现映射和点。 请注意,CMyClass 必须是 CCmdTarget 派生类。 在第一个示例中,代码插入到类声明中的 protected 节下:

class CMyClass : public CCmdTarget
{
protected:
   // Connection point for ISample interface
   BEGIN_CONNECTION_PART(CMyClass, SampleConnPt)
      CONNECTION_IID(IID_ISampleSink)
   END_CONNECTION_PART(SampleConnPt)

   DECLARE_CONNECTION_MAP()

BEGIN_CONNECTION_PART 和 END_CONNECTION_PART 宏声明嵌入式类 XSampleConnPt(派生自 CConnectionPoint)来实现此特定连接点。 如果要替代任何 CConnectionPoint 成员函数,或添加自己的成员函数,请在这两个宏之间声明它们。 例如,CONNECTION_IID 宏在位于这两个宏之间时将替代 CConnectionPoint::GetIID 成员函数。

在第二个示例中,代码将插入到控件的实现文件(.cpp 文件)中。 此代码实现连接映射(其中包括连接点 SampleConnPt):

BEGIN_CONNECTION_MAP(CMyClass, CCmdTarget)
    CONNECTION_PART(CMyClass, IID_ISampleSink, SampleConnPt)
END_CONNECTION_MAP()

如果类有多个连接点,请在 BEGIN_CONNECTION_MAP 宏与 END_CONNECTION_MAP 宏之间插入其他 CONNECTION_PART 宏。

最后,在类的构造函数中添加对 EnableConnections 的调用。 例如:

CMyClass::CMyClass()
{
   EnableConnections();
}

插入此代码后,CCmdTarget 派生类会公开 ISampleSink 接口的连接点。 下图说明了此示例。

Diagram showing a Connection point implemented by using MFC.
使用 MFC 实现的连接点

通常,连接点支持“多播”,即向连接到同一接口的多个接收器进行广播的功能。 以下示例段演示如何通过循环访问连接点上的每个接收器来进行多播:

void CMyClass::CallSinkFunc()
{
   POSITION pos = m_xSampleConnPt.GetStartPosition();
   ISampleSink* pSampleSink;
   while (pos != NULL)
   {
      pSampleSink = (ISampleSink*)(m_xSampleConnPt.GetNextConnection(pos));
      if (pSampleSink != NULL)
         pSampleSink->SinkFunc();
   }
}

此示例通过调用 CConnectionPoint::GetConnections 检索 SampleConnPt 连接点上的当前连接集合。 然后,它循环访问连接,并调用每个活动连接上的 ISampleSink::SinkFunc

另请参阅

MFC COM