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 > > _CreatorClass; |
我们看到了一个熟悉的字符串_CreatorClass, 原来这还有一个组件包含的对象。但还有一个问题我们没有搞清楚,就是为什么_ClassFactoryCreator和_CreatorClass后面都要跟着一个CreateInstance 看来我们必须先来看看CComCreator是个什么东西了。
template class CComCreator { { public: static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) {..... } }; |
原来它里面只有一个CreateInstance函数,我们现在终于大体明白_ClassFactoryCre
atorClass::CreateInstance表示什么意思了,它就代表CComClassFactory::CreateIn
stance(..)吧,差不多就是这样了。那我们再来看看CComCreator2有什么不同:
template 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(...)中的一个参数传递?答案在下面呢,让我们继续路由下去!
5:CComCreator::CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
{
T1* p = NULL;
ATLTRY(p = new T1(pv))//创建类厂对象
if (p != NULL)
{
p->SetVoid(pv);
p->InternalFinalConstructAddRef();
hRes = p->FinalConstruct();
p->InternalFinalConstructRelease();
if (hRes == S_OK)
hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
}
}
}
注意这里的T1是CComObjectCached,这是我们给CComCreator的模板参数。我们又一次看到了我们熟悉的操作符'new'!直到现在我们终于创建了组件的类厂。但还没完,继续往下走,看看SetVoid(pv)里干了些什么?
void CComClassFactory::SetVoid(void* pv) { m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; } |
大家还记得我们曾经把CMyObject::_CreatorClass::CreateInstance作为参数传给 pEntry->pfnGetClassObject(...)吧,当时我们不明白是怎么回事,现在已经豁然开朗!原来是类厂需要它来创建组件对象!虽然我们只是从字面意思猜出这一点,但实际上也正如我们所预料的那样,在CComClassFactory::CreateInstance(...)中,我们看到了m_pfnCreateInstance(pUnkOuter, riid, ppvObj);现在一切都已经明白了,ATL为我们创建类厂而作的层层包装我们都已经打开,剩下的创建组件的过程已经是我们很熟悉的过程了!
但是现在还没有完,我们还需要为类厂对象查询一个IUnknown指针,这个指针就存在我们在前面所看到的pEntry->pCF中。