ATL接口映射宏详解[7]

原创 2004年07月19日 11:19:00
六、COM_INTERFACE_ENTRY_AGGREGATE_BLIND 参ATL例程COMMAP

  上一节我们讲了COM_INTERFACE_ENTRY_AGGREGATE,这节要介绍的宏与它很类似。

#define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)/
    {NULL,/
    (DWORD)offsetof(_ComMapClass, punk),/
    _Delegate},

  从定义上就可以看出,它与上一节介绍宏的唯一区别就在于,它没有指明接口ID!!
  所以在它的定义中第一项也是NULL。

  这个宏的用法与我们COM_INTERFACE_ENTRY_AGGREGATE一模一样。大家可以参考上一节内容以及ATL的例程COMMAP。

  我们来看看AtlInternalQueryInterface()中的相关代码。

ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis,
    const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
    //如果是IUnknown,....
    while (pEntries->pFunc != NULL)
    {
        BOOL bBlind = (pEntries->piid == NULL);
        if (bBlind || InlineIsEqualGUID(*(pEntries->piid), iid))
        {
            if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY) //offset
            {
                ATLASSERT(!bBlind);
                IUnknown* pUnk = (IUnknown*)((int)pThis+pEntries->dw);
                pUnk->AddRef();
                *ppvObject = pUnk;
                return S_OK;
            }
            else
            {
                HRESULT hRes = pEntries->pFunc(pThis, iid, ppvObject, pEntries->dw);
                if (hRes == S_OK || (!bBlind && FAILED(hRes))) return hRes;
            }
        }
        pEntries++;
    }
    return E_NOINTERFACE;
}

  注意变量bBlind:

  BOOL bBlind = (pEntries->piid == NULL);

若没指定接口ID,也继续执行后面的操作,可见即使并非我们所需要的IID,也会执行_Delegate.
  从上可见,这个宏适用于一个聚集组件有多个接口的情况,这样只要是查询这个聚集组件的接口,就会进入_Delegate函数。但要特别注意的是这个宏的位置!! 比如若是这样的顺序:

BEGIN_COM_MAP
    COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_pUnkAggBlind.p)
    COM_INTERFACE_ENTRY(IOuter)
END_COM_MAP


  当查询IOuter接口时就会出错!!!

七、COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)

  先看看这个宏的定义:

#define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)/
    {&iid,/
    (DWORD)&_CComCacheData</
        CComAggregateCreator< _ComMapClass, &clsid >,/
        (DWORD)offsetof(_ComMapClass, punk)/
        >::data,/
    _Cache},

先看看它的典型用法:

class CAutoAgg :
    public IDispatchImpl< IAutoAgg, &IID_IAutoAgg, &LIBID_AGGREGLib >,
    public ISupportErrorInfo,
    public CComObjectRoot,
    public CComCoClass< CAutoAgg,&CLSID_CAutoAgg >
{
    ......
};

与一般的组件并无二样。

class COuter :
    public CChainBase,
    public IDispatchImpl,
    public CComCoClass
{
    BEGIN_COM_MAP(COuter)
        COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_IAutoAgg, m_pUnkAutoAgg.p, CLSID_CAutoAgg)
    END_COM_MAP()

    CComPtr m_pUnkAutoAgg;
};

  与宏COM_INTERFACE_ENTRY_AGGREGRATE(_)不同,COuter不用在FinalConstruct中创建聚集组件。外部组件会自动创建聚集组件!!!

1。

template < class Creator, DWORD dwVar >
_ATL_CACHEDATA _CComCacheData< Creator, dwVar >::data = {dwVar, Creator::Creat eInstance};

2。

static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)
{
    HRESULT hRes = E_NOINTERFACE;
    _ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
    IUnknown** pp = (IUnknown**)((DWORD)pv + pcd->dwOffsetVar);
    if (*pp == NULL) hRes = pcd->pFunc(pv, IID_IUnknown, (void**)pp);
    if (*pp != NULL) hRes = (*pp)->QueryInterface(iid, ppvObject);
    return hRes;
}

3。

template < class T, const CLSID* pclsid >
class CComAggregateCreator
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv )
    {
        ATLASSERT(*ppv == NULL);
        ATLASSERT(pv != NULL);
        T* p = (T*) pv;
        return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_ALL, IID_IUnknown, ppv);
    }
};

  因为_Cache,_CComCacheData,CComAggregateCreator这几个类和函数我们已经在前面见过或者见过类似的,所以就不再多讲了。总之我们可以看到,若m_pUnkAutoAgg.p不为空则直接查询,否则创建聚集组件。

  与宏COM_INTERFACE_ENTRY_AGGREGATE相比,这个宏似乎更好一些,仅当需要时才会创建,使用更简单。

  八、COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND( punk, clsid )

  看看它的定义:

#define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)/
    {NULL,/
    (DWORD)&_CComCacheData</
        CComAggregateCreator< _ComMapClass, &clsid >,/
        (DWORD)offsetof(_ComMapClass, punk)/
    >::data,/
    _Cache},

  呵呵,这个宏综合了 COM_INTERFACE_ENTRY_AUTOAGGREGATE() 和 COM_INTERFACE_ENTRY_AGGREGATE_BLIND() 的特点,既可以自动创建也可以很方便地查询聚集组件中的多个接口。不再赘述!!

ATL接口映射宏详解

这几天看了看ATL的接口映射宏,不知不觉看得比较深入了,突然就萌发了把它写出来的想法。ATL中定义了很多接口映射宏,有几个还是比较重要的,虽然好象没有必要把它所有的细节都弄得很清楚,但深入学习的过程中...
  • FrankieWang008
  • FrankieWang008
  • 2014年06月13日 17:20
  • 1128

ATL接口映射宏详解

ATL接口映射宏详解(下)   五.COM_INTERFACE_ENTRY_AGGREGATE(iid, punk) 参ATL例程COMMAP       这一节中将介绍ATL中用于聚...
  • Andeewu
  • Andeewu
  • 2013年03月27日 09:20
  • 543

ATL字符串转换宏

有比MultiByteToWideChar和WideCharToMultiByte更简单的字符串转换宏,你相信吗? 头文件 d:/program files/microsoft visual ...
  • u011135902
  • u011135902
  • 2016年07月20日 14:21
  • 782

通过ATL实现IUnknown接口

每个COM组件需要实现这三个功能 1. 实现IUnknown接口 (通过 CComObjectRootEx 实现) 2. 实现一个类工厂,支持组件的创建 (通过 CComCoClass 实现) ...
  • wishfly
  • wishfly
  • 2013年09月27日 10:10
  • 820

ATL-连接点和接口方法的使用

前言在做COMDLL, 用MFC测试程序插入注册好的ATL控件. 测试连接点的添加, 控件方法的添加,测试程序被控件调用连接点函数, 测试程序去调用控件的接口方法.效果图工程下载点srcUserLo...
  • LostSpeed
  • LostSpeed
  • 2016年04月20日 12:25
  • 1246

MFC消息映射笔记

大家有没有思考过当一个消息出现,应用程序框架是如何将消息与对象建立关系的?1.消息宏\quad为了支持消息映射,MFC提供了3种宏。1.1消息映射的声明和分解宏消息映射的声明和分界宏包含在CCmdTa...
  • q__y__L
  • q__y__L
  • 2016年05月03日 19:45
  • 1220

使用ATL创建简单ActiveX控件(三) —— 添加连接点

创建过程以VS2010为例,分三篇(创建ATL项目、添加方法/属性和枚举、添加连接点)演示。本篇演示添加连接点。 传送门: 《使用ATL创建简单ActiveX控件(一) —— 创建ATL项目 》 ...
  • mrxyz098
  • mrxyz098
  • 2015年09月20日 14:06
  • 2872

ATL--创建简单的ATL之dll工程,添加类和类的接口并在MFC中调用

开发环境 Windows Server 2012  VS2010 Sp1 番茄助手 创建ATL简单dll工程 1、打开VS2010,新建ATL COM 项目,步骤:“文件” “新建” “项目”,选择“...
  • sakawa_x
  • sakawa_x
  • 2017年06月07日 07:39
  • 1071

ATL实现一个组件多个dual接口,multidisp

最近想自己写个按键精灵的插件,于是接触到这个问题: 怎么在一个组件里实现两个自动化接口。 主要针对的ATL,MFC貌似没这个问题,具体MFC是怎么实现的自己没有深究。 按键精灵的插件会在一...
  • jzkdl
  • jzkdl
  • 2014年11月29日 03:42
  • 1952

ATL字符串转换宏

有比MultiByteToWideChar和WideCharToMultiByte更简单的字符串转换宏,你相信吗? 头文件 d:/program files/microsoft visual ...
  • earbao
  • earbao
  • 2013年09月15日 00:58
  • 5159
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ATL接口映射宏详解[7]
举报原因:
原因补充:

(最多只允许输入30个字)