先贴2个很重要的数据结构:对象映射表和接口映射表
struct _ATL_OBJMAP_ENTRY
{
const CLSID* pclsid;
HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
_ATL_CREATORFUNC* pfnGetClassObject; //创建类厂的函数指针
_ATL_CREATORFUNC* pfnCreateInstance; //创建com对象的函数指针
IUnknown* pCF; //类厂的IUnknow接口指针
DWORD dwRegister;
_ATL_DESCRIPTIONFUNC* pfnGetObjectDescription;
_ATL_CATMAPFUNC* pfnGetCategoryMap;
}
struct _ATL_INTMAP_ENTRY
{
const IID* piid; // the interface id (IID)
DWORD_PTR dw;
_ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr
};
类厂的创建
9.ATL::AtlInternalQueryInterface(...)
8.ATL::CComObjectRootBase::InternalQueryInterface(...)
7.ATL::CComClassFactory::_InternalQueryInterface(...)
6.ATL::CComObjectCached::QueryInterface(...)
5.ATL::CComCreator >::CreateInstance(...)
4.ATL::AtlModuleGetClassObject(...)
3.ATL::CComModule::GetClassObject(...)
2.DllGetClassObject(...)
1.CoCreateInstance(...)(客户端)
1:CoCreateInstance(CLSID_MyObject, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk);
其内部将调用OLE API函数CoGetClassObject(), 而CoGetClassObject则会通过 Load Library(...)装入DLL,并调用DLL中的DllGetClassObject()函数。
4:
ATLINLINE ATLAPI AtlComModuleGetClassObject(_ATL_COM_MODULE* pComModule, REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
...
for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++)
{
if (*ppEntry != NULL)
{
_ATL_OBJMAP_ENTRY* pEntry = *ppEntry;
if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))
{
if (pEntry->pCF == NULL)
{
CComCritSecLock<CComCriticalSection> lock(pComModule->m_csObjMap, false);
hr = lock.Lock();
if (FAILED(hr))
{
ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in AtlComModuleGetClassObject\n"));
ATLASSERT(0);
break;
}
if (pEntry->pCF == NULL)
hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);
}
if (pEntry->pCF != NULL)
hr = pEntry->pCF->QueryInterface(riid, ppv);
break;
}
}
}
if (*ppv == NULL && hr == S_OK)
hr = CLASS_E_CLASSNOTAVAILABLE;
return hr;
}
此函数遍历对象映射表,逐一创建类厂。对象映射表是通过OBJECT_ENTRY_AUTO宏来插入数据项的。ATL建立一个section及3个字段(a,m,z),在a,z两个段分别安插一个全局指针,并将其赋值给m_ppAutoObjectMapFirst和m_ppAutoObjectMapLast,然后通过宏
OBJECT_ENTRY_AUTO所定义的_ATL_OBJMAP_ENTRY 结构指针插入到m段,以此来达到遍历的目的。
调用pfnGetClassObject创建类厂,此指针指向的函数是CComCreator<CComObjectCached< CComClassFactory > >::CreateInstance
5-6:
template <class T1>
class CComCreator
{
public:
static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
{
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
HRESULT hRes = E_OUTOFMEMORY;
T1* p = NULL;
#pragma warning(push)
#pragma warning(disable: 6014)
/* prefast noise VSW 489981 */
ATLTRY(p = new T1(pv))
#pragma warning(pop)
if (p != NULL)
{
p->SetVoid(pv);
p->InternalFinalConstructAddRef();
hRes = p->_AtlInitialConstruct();
if (SUCCEEDED(hRes))
hRes = p->FinalConstruct();
if (SUCCEEDED(hRes))
hRes = p->_AtlFinalConstruct();
p->InternalFinalConstructRelease();
if (hRes == S_OK)
hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
}
return hRes;
}
};
T1的
CComObjectCached<CComClassFactory>,类型为创建类厂对象后并将创建com类对象的函数指针传递给类厂对象。创建类厂后再获取其IUnknow指针,
CComObjectCached::
QueryInterface
7:
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
{return _InternalQueryInterface(iid, ppvObject);}
_InternalQueryInterface是在BEGIN_COM_MAP中定义的,调用基类CComObjectRootBase::InternalQueryInterface
8:
static HRESULT WINAPI InternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
// Only Assert here. AtlInternalQueryInterface will return the correct HRESULT if ppvObject == NULL
#ifndef _ATL_OLEDB_CONFORMANCE_TESTS
ATLASSERT(ppvObject != NULL);
#endif
ATLASSERT(pThis != NULL);
// First entry in the com map should be a simple map entry
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
#if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI)
LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
#endif // _ATL_DEBUG_INTERFACES
HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
#ifdef _ATL_DEBUG_INTERFACES
_AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, pszClassName, iid);
#endif // _ATL_DEBUG_INTERFACES
return _ATLDUMPIID(iid, pszClassName, hRes);
}
9:
ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
ATLASSERT(pThis != NULL);
ATLASSERT(pEntries!= NULL);
if(pThis == NULL || pEntries == NULL)
return E_INVALIDARG ;
// First entry in the com map should be a simple map entry
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
if (ppvObject == NULL)
return E_POINTER;
*ppvObject = NULL;
if (InlineIsEqualUnknown(iid)) // use first interface
{
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
pUnk->AddRef();
*ppvObject = pUnk;
return S_OK;
}
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_PTR)pThis+pEntries->dw);
pUnk->AddRef();
*ppvObject = pUnk;
return S_OK;
}
else //actual function call
{
HRESULT hRes = pEntries->pFunc(pThis,
iid, ppvObject, pEntries->dw);
if (hRes == S_OK || (!bBlind && FAILED(hRes)))
return hRes;
}
}
pEntries++;
}
return E_NOINTERFACE;
}
全局函数AtlInternalQueryInterface通过借口映射表来返回查询的接口。到此类厂对象的创建及其IUnknow接口的获取解析完成,类厂创建完后再调用其CreateInstance来创建com对象,过程类似不再重复。