BEGIN_COM_MAP

1,offsetofclass
获取基类相对于子类的偏移位置。

#define _ATL_PACKING 8
#define offsetofclass(base, derived) ((DWORD_PTR)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)

_ATL_PACKING非零就行,只是作为一个地址。因为为了避免虚类无法创建对象的问题所以没有通过类对象来计算。



2,
//If you get a message that FinalConstruct is ambiguous then you need to
// override it in your class and call each base class' version of this
#define BEGIN_COM_MAP(x) public: \
    typedef x _ComMapClass; \
    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)


struct _ATL_INTMAP_ENTRY
{
    const IID* piid; // the interface id (IID)
    DWORD_PTR dw;
    _ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr
};


#define DEBUG_QI_ENTRY(x) \
        {NULL, \
        (DWORD_PTR)_T(#x), \
        (ATL::_ATL_CREATORARGFUNC*)0},

typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw);


#define COM_INTERFACE_ENTRY(x)\
    {&_ATL_IIDOF(x), \
    offsetofclass(x, _ComMapClass), \
    _ATL_SIMPLEMAPENTRY},

#define _ATL_IIDOF(x) __uuidof(x)
//__uuidof获取与x相关的GUID值

#define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC*)1)

#define END_COM_MAP() \
    __if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\
    {NULL, 0, 0}}; return &_entries[1];} \
    virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \
    virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \
    STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;

3,
static HRESULT WINAPI CComObjectRootBase ::InternalQueryInterface(void* pThis,
        const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
    {
        ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
        HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
        return _ATLDUMPIID(iid, pszClassName, hRes);
    }


// QI support
ATLINLINE ATLAPI AtlInternalQueryInterface(
    _Inout_ void* pThis,
    _In_ const _ATL_INTMAP_ENTRY* pEntries,
    _In_ REFIID iid,
    _COM_Outptr_ void** ppvObject)
{
    // First entry in the com map should be a simple map entry
    ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);

    if (InlineIsEqualUnknown(iid)) // use first interface
    {
        IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }

    HRESULT hRes;
    for (;; pEntries++)
    {
        if (pEntries->pFunc == NULL)
        {
            hRes = E_NOINTERFACE;
            break;
        }

        BOOL bBlind = (pEntries->piid == NULL);
        if (bBlind || InlineIsEqualGUID(*(pEntries->piid), iid))
        {
            if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY) //offset
            {
                ATLASSERT(!bBlind);
                IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
                pUnk->AddRef();
                *ppvObject = pUnk;
                return S_OK;
            }

            // Actual function call 
            hRes = pEntries->pFunc(pThis,
                iid, ppvObject, pEntries->dw);
            if (hRes == S_OK)
                return S_OK;
            if (!bBlind && FAILED(hRes))
                break;
        }
    }

    *ppvObject = NULL;
    return hRes;
}
CComObjectRootBase的InternalQueryInterface内部调用AtlInternalQueryInterface遍历_ATL_INTMAP_ENTRY数组(包含所有实现接口的映射表),找到基类的虚函数表返回。
(我原来用的VS2005,没有AtlInternalQueryInterface的实现,蛋疼了好久这个接口映射表的怎么返回的,我猜也是遍历但是没有看见源码一直心头惴惴不安。后面擦查看VS2013里面给出了AtlInternalQueryInterface的实现才把这口气舒出来。)

4,
ATL提供了BEGIN_COM_MAP、END_COM_MAP、COM_INTERFACE_ENTRY与COM_INTERFACE_ENTRY2这4个宏来创建接口映射表。
假设一个类CClassA继承了接口IIntA1和IIntA2,则该类的接口映射表创建如下:

class CClassA : public CComObjectRootEx<CComSingleThreadMode>
{
    BEGIN_COM_MAP(CClassA)
        COM_INTERFACE_ENTRY(IIntA1)
        COM_INTERFACE_ENTRY(IIntA2)
    END_COM_MAP()
    ......
};

static const ATL::_ATL_INTMAP_ENTRY _entries[] =
{
{NULL,     (DWORD_PTR)_T(#x),     (ATL::_ATL_CREATORARGFUNC*)0},
{& __uuidof(IIntA1), offsetofclass(IIntA1, CClassA), (ATL::_ATL_CREATORARGFUNC*)1},
{& __uuidof(IIntA2), offsetofclass(IIntA2, CClassA), (ATL::_ATL_CREATORARGFUNC*)1},
{NULL, 0, 0}
};



而当CClassB继承了IIntB1和IIntB2,并且IIntB1和IIntB2都继承自IDispatch接口。
此时,如果客户程序在查询IDispatch接口,QueryInterface所返回的IDispatch接口指针将无法确定其属于IIntB1还是IIntB2。
在这种情况下,需要指定IDispatch接口指针的默认指向。 COM_INTERFACE_ENTRY2()宏即是用于完成该功能。
下面代码将对IDispatch接口的请求默认指向属于IIntB2的IDispatch接口指针。
class CClassB : public CComObjectRootEx<CComSingleThreadMode>
{
    BEGIN_COM_MAP(CClassB)
        COM_INTERFACE_ENTRY(IIntB1)
        COM_INTERFACE_ENTRY(IIntB2)
        COM_INTERFACE_ENTRY2(IDispatch, IIntB2)
    END_COM_MAP()
    ......
};


#define COM_INTERFACE_ENTRY2(x, x2)\
    {&_ATL_IIDOF(x),\
    reinterpret_cast<DWORD_PTR>(static_cast<x*>(static_cast<x2*>(reinterpret_cast<_ComMapClass*>(8))))-8,\
    _ATL_SIMPLEMAPENTRY},

5,总结:
BEGIN_COM_MAP通过一个静态的_GetEntries()方法,来获取在该方法中创建的一个静态COM接口映射表。

原文:https://www.cnblogs.com/liuhan333/p/5843313.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值