浅析ATL中类厂的创建及其IUnkown接口的获取

先贴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对象,过程类似不再重复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值