连接点
本文介绍如何使用 MFC 类 CCmdTarget
和 CConnectionPoint
来实现连接点(以前称为 OLE 连接点)。
过去,组件对象模型 (COM) 定义了允许对象在接口中实现和公开功能的常规机制 (IUnknown::QueryInterface
*)。 但是,未定义允许对象公开调用特定接口的功能的相应机制。 也就是说,COM 定义了处理对象传入指针(指向该对象的接口的指针)的方式,但它没有用于传出接口(该对象保存的指针指向其他对象的接口)的显式模型。 COM 现在有一个名为连接点的模型,该模型支持此功能。
连接有两个部件:调用接口的对象,称为源,以及实现接口的对象,称为接收器。 连接点是由源公开的接口。 通过公开连接点,源允许接收器建立与自身(源)的连接。 通过连接点机制(IConnectionPoint
接口),将指向接收器接口的指针传递给源对象。 使用此指针,源就可以访问接收器对一组成员函数的实现。 例如,若要触发接收器实现的事件,源可以调用接收器实现的相应方法。 下图演示了刚刚描述的连接点。
已实现的连接点
MFC 在 CConnectionPoint 和 CCmdTarget 类中实现此模型。 派生自 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
接口的连接点。 下图说明了此示例。
使用 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
。