通过BEGIN_COM_MAP看接口的三剑客的实现和调用(AC8)

  AC8,由VS2005的ATL向导生成的默认COM对象代码分析ATL如何实现COM,第八部分。

  接口三剑客AddRef、Release、QueryInterface不用说了,他是在CComObjectRootEx中被实现的,但是调用过程却不是简单的依照虚函数路线向上查找到了这个类,而是由通过了系列宏BEGIN_COM_MAP。

  已经说过,我们使用ATL向导添加的class不是最终的com对象,而是该对象的基类,也就是说三剑客被调用的入口点应该是CComObject(或CComAggObject)类。分析BEGIN_COM_MAP组宏可以发现一些不太明显的细节。

  仍以XXX类示例,这组宏可能是这样:

BEGIN_COM_MAP(CMeee)

	COM_INTERFACE_ENTRY(IMeee)

	COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

  END_COM_MAP中有三个非常重要的定义:

	virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; 

	virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; 

	STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;

  这组声明让调用明朗起来,三剑客必须是有XXX的继承类实现的,这与我先前说的三剑客由CComObjectRootEx实现不符,其实并不冲突,查看CComObject、CComAggObject类知道,

	STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}

	STDMETHOD_(ULONG, Release)()

	{

		ULONG l = InternalRelease();

		if (l == 0)

			delete this;

		return l;

	}

	STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
	{return _InternalQueryInterface(iid, ppvObject);}

  AddRef和Release非常直接的由子类转发给了CComObjectRootEx,QI则调用了奇怪的_InternalQueryInterface方法,没错,BEGIN_COM_MAP声明并定义了这个方法,它调用了InternalQueryInterface方法,而这个方法在CComObjectRootBase(CComObjectRootEx的基类)中被实现。

  关于这组宏的其他东西:

  1. offsetofclass(base, derived)   在多重继承的情况下,多个基类对象各有自己的起始地址,而class模化出了object,因此,对同一个class的任意对象而言,基类对象的起始地址之间的差值是固定的(vtable偏移),offsetofclass宏用以计算这种便宜,从内存布局上来说,该宏计算出来的值可以使用继承系中的任意一个object的位置换算其他object位置。 2. _ATL_INTMAP_ENTRY   这是一个结构,

    struct _ATL_INTMAP_ENTRY 
    { 
        const IID* piid; // the interface id (IID) 
        DWORD_PTR dw; 
        _ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr 
    }; 
  可以猜测,事实上也是,offsetofclass计算出来的偏移值是通过该结构的dw保存的,通过代码注释知道,如果dw存放其他值,dw有不同的意义。 3. _ATL_IIDOF   直接使用__uuidof 4. _ATL_SIMPLEMAPENTRY   其实就是CREATORARGFUNC(1)的情况,它在_ATL_INTMAP_ENTRY结构中被使用,也就是说,这个simpleMapEntry指示了dw的做偏移解释。 5.这组宏最大的意义在于定义了   const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() 方法   该方法的static const ATL::_ATL_INTMAP_ENTRY _entries[]是核心,注意它是静态的,也就是说通过我们的宏一次构建,以后通用,它类似这样的结构:
    _entries[] = 
    { 
        {&__uuidof(XXX),offsetofclass,pfunc}, 
    } 

 

你可能感兴趣的:(ATL)