可连接对象这章,作者在写MFC对连接和时间的支持这章有点乱。我稍微整理了下。
一、mfc实现连接点类IConnectionPoint接口
mfc用CConnectionPoint类继承了CCmdTarget类,并用一个数组枚举器管理连接。
class CConnectionPoint::CCmdTarget
{
public: CConnectionPoint();
POSITION GetStartPosition() const;
LPUNKNOWN GetNextConnection(POSITION &pos) const;
const CPtrArray * GetConnections()//obsolete
。。
protected:
...
CPtrArray * m_pConnections;//书上说的数组枚举器应该就是它了吧
//Interface maps
public:
//这里才是CConnectionPoint类定义了ConnPt嵌套类,并且实现IConnectionPoint接口
BEGIN_INTERFACE_PART(ConnPt, IConnectionPoint)
INIT_INTERFACE_PART(CConnectionPoint,ConnPt)
STDMETHOD(GetConnectionInterface)(IID* pIID);
STDMETHOD(GetConnectionPointContainer)(...);
STDMETHOD(Advise)(...);
STDMETHOD(Unadvise)();
STDMETHOD(EnumConnections)();
END_INTERFACE_PART(ConnPt)
}
二、CCmdTarget提供的支持连接点对象的一组宏
1、首先在源对象定义中使用DECLARE_CONNECTION_MAP宏,定义一张连接(点)映射表以及有关表的操作函数。其宏内容如下:
#ifdef _AFXDLL
#define DECLARE_CONNECTION_MAP() /
private: /
static const AFX_CONNECTIONMAP_ENTRY _connectionEntries[]; /
protected: /
static AFX_DATA const AFX_CONNECTIONMAP connectionMap; /
static const AFX_CONNECTIONMAP* PASCAL _GetBaseConnectionMap(); /
virtual const AFX_CONNECTIONMAP* GetConnectionMap() const; /
#else
#define DECLARE_CONNECTION_MAP() /
private: /
static const AFX_CONNECTIONMAP_ENTRY _connectionEntries[]; /
protected: /
static AFX_DATA const AFX_CONNECTIONMAP connectionMap; /
virtual const AFX_CONNECTIONMAP* GetConnectionMap() const; /
#endif
#endif //!_AFX_NO_OLE_SUPPORT
2、然后用
BEGIN_CONNECTION_PART (CMySourceObj,MyEventSet)
//可以用下面的类定义重载更多的虚函数
virtual void OnAdvise(Bool bAdvise);
virtual REFIID GetIID();// 有时也用CONNECTION_IID(IID_IMyEventSet)
virtual LPUNKNOWN QuerrySinkInterface(LPUNKNOWN pUkSink);
END_CONNECTION_PART (MyEventSet)
来声明及定义连接点对象MyEventSet。该宏的定义如下。
#define BEGIN_CONNECTION_PART(theClass, localClass) /
class X##localClass : public CConnectionPoint /
{ /
public: /
X##localClass() /
{ m_nOffset = offsetof(theClass, m_x##localClass); }
#define CONNECTION_IID(iid) /
REFIID GetIID() { return iid; }
#define END_CONNECTION_PART (localClass) /
} m_x##localClass; /
friend class X##localClass;
显然,这里定义了一个嵌套类XMyEventSet,并且它继承了CConnectionPoint类,实现了对IConnectionPoint接口的继承。最后END_CONNECTION_PART定义了一个内嵌的类成员m_xMyEventSet,在激发事件函数中要用到此成员。
3、DECLARE_CONNECTION_MAP建立一张连接映射表,源对象CMySourceObj
BEGIN_CONNECTION_MAP (CMySourceObj, CCmdTarget)
CONNECTION_PART ( CMySourceObj, IID_IMyEventSet,MyEventSet)
END_CONNECTION_MAP ()
实现连接映射表。M_xMyEventSet
#ifdef _AFXDLL
#define BEGIN_CONNECTION_MAP (theClass, theBase) /
const AFX_CONNECTIONMAP* PASCAL theClass::_GetBaseConnectionMap() /
{ return &theBase::connectionMap; } /
const AFX_CONNECTIONMAP* theClass::GetConnectionMap() const /
{ return &theClass::connectionMap; } /
AFX_COMDAT const AFX_DATADEF AFX_CONNECTIONMAP theClass::connectionMap = /
{ &theClass::_GetBaseConnectionMap, &theClass::_connectionEntries[0], }; /
AFX_COMDAT const AFX_DATADEF AFX_CONNECTIONMAP_ENTRY theClass::_connectionEntries[] = /
{ /
#else
#define BEGIN_CONNECTION_MAP(theClass, theBase) /
const AFX_CONNECTIONMAP* theClass::GetConnectionMap() const /
{ return &theClass::connectionMap; } /
AFX_COMDAT const AFX_DATADEF AFX_CONNECTIONMAP theClass::connectionMap = /
{ &(theBase::connectionMap), &theClass::_connectionEntries[0], }; /
AFX_COMDAT const AFX_DATADEF AFX_CONNECTIONMAP_ENTRY theClass::_connectionEntries[] = /
{ /
#endif
#define CONNECTION_PART (theClass, iid, localClass) /
{ &iid, offsetof(theClass, m_x##localClass) }, /
#define END_CONNECTION_MAP() /
{ NULL, (size_t)-1 } /
}; /
4、接口映射表
BEGIN_INTERFACE_MAP (CSourceObj, CCmdTarget)
INTERFACE_PART(CSourceObj,IID_ISourceObj,Dispatch)
//上一句其实就是定义了AFX_INTERFACEMAP_ENTRY的一个值,iid和offset
// INTERFACE_PART(theClass, iid, localClass)localClass用来计算接口的偏移量
END_INTERFACE_MAP ()
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
METHOD_PROLOGUE_EX (theClass, localClass)
这个宏就是为了获得外围类的指针。
METHOD_PROLOGUE_EX(CDictionary, Dictionary)这句话之外,还需要知道CDictionary和Dictionary类的定义。这个方法的主要用法就是知道嵌套类的指针,怎样获取外围类的指针。找到偏移,减去即可。