您现在的位置是: 软件 > 开发者网络 > 程序方舟 > 开发专栏 > Visual C++开发 > 正文
·速成电脑精英(包分配)白领高薪一族从这里开始



-Java套接字编程(下)
-MediaStudio Pro 6.5教程
-三款卸载软件最新试用
-基于Visual C++的Winsock API研究

ATL接口映射宏详解
2002-05-22· ·lostall ··COM集中营

上一页  1 2 3 4 5 6 7 8 9 10  下一页

2:

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{

    return _Module.GetClassObject(rclsid, riid, ppv);
}

  其中值得注意的是_Module变量,在DLL中定义了全局变量:

  CComModule _Module;

  ATL通过一组宏:

BEGIN_OBJECT_MAP(ObjectMap)
    OBJECT_ENTRY(CLSID_MyObject, CMyObject)
END_OBJECT_MAP()

#define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
#define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry, \
        class::_ClassFactoryCreatorClass::CreateInstance, \//关键
        class::_CreatorClass::CreateInstance, \
        NULL, 0, class::GetObjectDescription, \
        class::GetCategoryMap, class::ObjectMain },
  #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};

  生成一个静态全局_ATL_OBJMAP_ENTRY型数组:ObjectMap[];
  然后ATL又在

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/

{
    .....
    _Module.Init(ObjectMap, hInstance, &LIBID_TEST2Lib);
    .....
}

  中初始化_Module //注意在有的情况下是在InitInstance()中初始化_Module

  那么_Module初始化都做了些什么呢,其实他什么也没做,在CComModule::Init中,它调用AtlModuleInit(_ATL_MODULE* pM, _ATL_OBJMAP_ENTRY* p, HINSTANCE h),在其中关键的只有一句:pM->m_pObjMap = p;可见_Module仅仅是把这个全局对象映射数组 ObjectMap[]给存了起来。那么为什么可以通过_Module.GetClassObject得到类厂呢?其实关键在于我们的组件CMyObject继承的又一个基类CComCoClass! 在CComCoClass中缺省定义了一个宏DECLARE_CLASSFACTORY()而

#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(CComClassFactory)
#define DECLARE_CLASSFACTORY_EX(cf)
    typedef CComCreator< ccomobjectcached< cf > > _ClassFactoryCreatorClass;

  CComCreator,CComObjectCached我们暂且不管,但一看到CComClassFactory,顾名思义,我们就知道我们要的类厂终于出现了!每个组件内部原来都有一个类厂对象。绕了一大圈,我们现在已经知道了_Module中包含了我们所要的每个组件的类厂对象,这对目前来说已经足够了,现在继续路由下去!

3:

HRESULT CComModule::GetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)
{
    return AtlModuleGetClassObject(this, rclsid, riid, ppv);
}

CComModule::GetClassObject的实现非常简单,仅仅是调用ATL的API函数。

4:

ATLINLINE ATLAPI AtlModuleGetClassObject(_ATL_MODULE* pM, REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    _ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap;//从_Module中取出对象映射数组

    while (pEntry->pclsid != NULL)
        {
        if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))
        {
            if (pEntry->pCF == NULL)
            {
                hRes = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance,
                            IID_IUnknown, (LPVOID*)&pEntry->pCF);
            }
            if (pEntry->pCF != NULL)
                hRes = pEntry->pCF->QueryInterface(riid, ppv);
            break;
        }
        pEntry = _NextObjectMapEntry(pM, pEntry);
    }
}

现在好象已经有点看不懂了,看来我们得看看_ATL_OBJMAP_ENTRY的结构了

struct _ATL_OBJMAP_ENTRY
{
    const CLSID* pclsid;
    HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
    _ATL_CREATORFUNC* pfnGetClassObject;
    _ATL_CREATORFUNC* pfnCreateInstance;
    IUnknown* pCF;
    DWORD dwRegister;
    _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription;
    _ATL_CATMAPFUNC* pfnGetCategoryMap;
}

  pclsid很清楚就代表着我们组件的CLSID;pfnGetClassObject我们也已经知道了它就是CMyObject::_ClassFactoryCreatorClass::CreateInstance(我们组件所包含的类厂对象的CreateInstance函数);pCF我们也可以猜出它是指向这个类厂的IUnknown指针,代表这个类厂对象是否被创建过,若类厂对象已经存在,就不用再创建新的类厂对象了。现在就剩下pfnCreateInstance我们还不明白怎么回事。其实答案还是在 CComCoClass中!
  在CComCoClass中缺省定义了宏DECLARE_AGGREGATABLE(x),这个宏表示这个组件既可以是聚集的也可以是非聚集的,关于聚集的概念我们暂且不理,先看它的定义:

#define DECLARE_AGGREGATABLE(x) public:\
    typedef CComCreator2< ccomcreator< CComObject< x > >, \
        CComCreator< ccomaggobject< x > > > _CreatorClass;

我们看到了一个熟悉的字符串_CreatorClass, 原来这还有一个组件包含的对象。但还有一个问题我们没有搞清楚,就是为什么_ClassFactoryCreator和_CreatorClass后面都要跟着一个CreateInstance? 看来我们必须先来看看CComCreator是个什么东西了。

template < class T1 >
class CComCreator
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {.....
    }
};

  原来它里面只有一个CreateInstance函数,我们现在终于大体明白_ClassFactoryCreatorClass::CreateInstance 表示什么意思了,它就代表CComClassFactory::CreateInstance(..)吧,差不多就是这样了。那我们再来看看CComCreator2有什么不同:

template < class T1, class T2 >
class CComCreator2
{
public:
    static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
    {
        return (pv == NULL) ?
            T1::CreateInstance(NULL, riid, ppv) :
            T2::CreateInstance(pv, riid, ppv);
    }
};

  这个类与CComCreator很类似,都只有一个CreateInstance成员函数,从_CreatorClass 中我们可以知道它实际上包含两个类CComObject,CComAggObject的CreateInstance函数(通过CComCreator),其中CComObject用于非聚集对象,CComAggObject用于聚集对象根据情况它建立相应的对象。(ATL中实际生成的组件对象不是CMyObject,而是 CComObject,CComAggObject或CComPolyObject对象,这个概念很重要,但现在暂且不谈) 现在我们对AtlModuleGetClassObject(...)基本已经知道是怎么回事了,它就是根据存在对象映射数组中的创建类厂的函数的地址来创建类厂。pfnGetClassObject以及 pfnCreateInstance我们基本上都已经知道是怎么回事了,但还有一个问题为什么要把pEntry->pfnCreateInstance作为pEntry->pfnGetClassObject(...)中的一个参数传递?答案在下面呢,让我们继续路由下去!

上一页  1 2 3 4 5 6 7 8 9 10  下一页

■ 相关内容
 在ATL中实现窗口
 Visual C++ MFC/ATL开发
 用ATL服务器构建 XML Web 服务
 ATL服务器:用VC++创建高性能的Web应用程序和XML Web服务
 如何在VS.net中使用ATL?
 为MFC和ATL控件创建签署的CAB文件
感谢 访问天极网,如果您觉得该文章涉及版权问题,请看这里!