现在的位置: 首页 > 综合 > 正文

ATL源码学习3—接口的查询支持

2013年04月27日 ⁄ 综合 ⁄ 共 7176字 ⁄ 字号 评论关闭

1.    ATL的QueryInterface调用追踪

a. 组件的QueryInterface函数定义

 

b. _InternalQueryInterface函数调用InternalQueryInterface函数,定义在BEGIN_COM_MAP宏内部

#define BEGIN_COM_MAP(x) public: /
    typedef x _ComMapClass; /
    static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw()/
    {/
        _ComMapClass* p = (_ComMapClass*)pv;/
        p->Lock();/
        HRESULT hRes = E_FAIL; /
        __try /
        { /
            hRes = ATL::CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);/
        } /
        __finally /
        { /
            p->Unlock();/
        } /
        return hRes;/
    }/
    IUnknown* _GetRawUnknown() throw() /
    { ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((INT_PTR)this+_GetEntries()->dw); } /
    _ATL_DECLARE_GET_UNKNOWN(x)/
    HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() /
    { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } /


    const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { /
    static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)

 

c. InternalQueryInterface函数定义在CComObjectRootBase类中(这里显示的代码已经删除了调试扩展的内容)。


 

InternalQueryInterface委派全局函数AtlInternalQueryInterface来提供接口查询的实现。在查询接口之前,先检查查询的接口IID,如果请求的是IUnknown,从表中取出第一个表项立即返回,不需要偏历表的剩余部分。
    关于表的遍历,对于表中的每个表项,根据指向表项接口标识符的piid成员是否为NULL。
    1. 如果不为NULL,表项IID与请求IID进行比较,如果匹配,pFunc引用的函数被调用,结果返回客户。如果不匹配,进入下一个表现搜索。
    2. 如果piid为NULL,则不管请求的IID是什么,都会调用pFunc。如果接口是S_OK,则返回结果给客户。否则继续搜索下一个表项。所有的COM_INTERFACE_ENTRY_XXX_BLIND宏都使用了这种行为。比如COM_INTERFACE_ENTRY_AGGREGATE_BLIND。

 

2.接口映射表的源码分析

通过上面的函数调用追踪,我们可以发现函数最终是遍历_ATL_INTMAP_ENTRY数组结构。关于_ATL_INTMAP_ENTRY数组的定义在BEGIN_COM_MAP宏内部。是一个静态数据变量。

下面我们来看看_ATL_INTMAP_ENTRY结构的定义

_ATL_CREATORARGFUNC函数类型的定义

 

3.常用的 pFunc 函数的定义

常用的pFunc函数在CComObjectRootBase函数中有定义,其中包括_Creator、_Delegate、_ChainAttr、_Cache、_Break、_NoInterface。

 

4.ATL接口的查询的扩展

#define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)/
    {&iid, dw, func},
#define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)/
    {NULL, dw,func},
这两个宏其实是ATL的QueryInterface实现的通用后门,用户可以自定义func,在func函数中暴露COM接口,但需要遵守COM实体身份规则。

 

抱歉!评论已关闭.