COM接口映射表

来源:互联网 发布:mac安装matlab 编辑:程序博客网 时间:2024/05/11 02:27
针。

class CClassB : public CComObjectRootEx<CComSingleThreadMode>
{
    BEGIN_COM_MAP(CClassA)
        COM_INTERFACE_ENTRY(IIntC)
        COM_INTERFACE_ENTRY(IIntD)
        COM_INTERFACE_ENTRY2(IDispatch, IIntD)
    END_COM_MAP()
    ......
};

2. 接口映射表的实现与所提供的功能

将CClassB中的宏扩展可以得到以下代码并稍作精简得:
class CClassB : public CComObjectRootEx<CComSingleThreadMode>
{
// BEGIN_COM_MAP(CClassB)
public:
    typedef CClassB _ComMapClass;
    static HRESULT _Cache(void* pv, REFIID iid, void* ppvObject, DWORD_PTR dw)
    {
        _ComMapClass* p = (_ComMapClass*)pv;
        p->Lock();
        HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);
        p->Unlock();
        return hRes;
    }


    IUnknown* _GetRawUnknown()
    {  return (IUnknown*)((INT_PTR)this + _GetEntries()->dw); }


    HRESULT _InternalQueryInterface(REFIID iid, void** ppvObj)
    { return InternalQueryInterface(this, _GetEntries(), iid, ppvObj);  }


    const static ATL::_ATL_INTMAP_ENTRY* _GetEntries()
    {
        static const ATL::_ATL_INTMAP_ENTRY _entries[] =
        {
// COM_INTERFACE_ENTRY(IIntC)
            { &_ATL_IIDOF(IIntC),
              offsetofclass(IIntC, _ComMapClass),
              _ATL_SIMPLEMAPENTRY
            },
// COM_INTERFACE_ENTRY(IIntD)
            { &_ATL_IIDOF(IIntD),
              offsetofclass(IIntD, _ComMapClass),
              _ATL_SIMPLEMAPENTRY
            },
// COM_INTERFACE_ENTRY2(IDispatch, IIntD)
            { &_ATL_IIDOF(IIntD),
              reinterpret_cast<DWORD_PTR>(static_cast<IDispatch*>(
              static_cast<IIntD*>(reinterpret_cast<_ComMapClass*>(8)))) - 8,
              _ATL_SIMPLEMAPENTRY
            },
// END_COM_MAP()
            { NULL, 0, 0}
        };
        return &_entries;
    }
    virtual ULONG AddRef()  = 0;
    virtual ULONG Release() = 0;
    HRESULT QueryInterface(REFIID, void*) = 0; (#add 此三个函数顺序怎么是这样?)
};

根据上述代码,BEGIN_COM_MAP()等宏的作用,关键在于提供了一个静态的_GetEntries()方法,用于获取在该方法中创建的一个静态COM接口映射表。其中,当base类(或接口)是derived类(或接口)的父类(或接口)时,offsetofclass(base,derived)宏用于返回base接口(或类)指针在类中相对derived指针的在派生类虚表中的指针偏移值。_ATL_SIMPLEMAPENTRY常量表示_ATL_INTMAP_ENTRY结构的第二个成员dw表示base与derived指针的偏移值。COM_INTERFACE_ENTRY2与COM_INTERFACE_ENTRY的主要区别即为此偏移值的计算。

同时,END_COM_MAP()宏还将IUnknown的AddRef()和Release()方法声明为纯虚函数。由此看出,IUnknown接口的方法将注定有该类的子类实现。


3. 结论

每个基于ATL的COM对象必须首先创建一个静态的接口映射表,这个表的创建工作由BEGIN_COM_MAP、END_COM_MAP、COM_INTERFACE_ENTRY与COM_INTERFACE_ENTRY2这四个宏来完成。它们创建了接口映射表和接口映射表的获取函数,同时还将IUnknown的方法声明为纯虚函数,它们将由其派生类实现。

原创粉丝点击