这几天学习ATL,想起了《深入浅出MFC》中的方法:仿真,折腾了大半天,弄出了点东西,愿与正在ATL的坚韧难懂中挣扎却不懈努力的同志共享。编写的时候我怕写成了ATL的COPY所以没有看它的源码,很多名字只凭记忆,还有些名字我觉得我所取的名字自己更易理解,所以名字可能有点不同,别怪我!由于怕又陷入了那个大迷宫里,所以没有客气的把一些初学者不好理解的东西都“砍掉”,比如,我在仿真时完全没有考虑聚合的情况。另外,我没有引用其它类库的东西(以免你要到处找类库手册),甚至没有没有用API。里头加了些注解。不说了,你看吧!但愿对你有点用。
//---------AtlMy.h
#include <iostream.h>
//常用类型定义
typedef unsigned long HRESULT;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef int BOOL;
//返回值
#define S_OK 0
#define E_FAIL 1;
#define INTERFACE class
#ifdef _DEBUG_ON
#define ASSERT(b) {if(!b) __asm int 3h}
#else
#define ASSERT(b)
#endif
//计算接口的偏移
#define _ATL_PACKING 8
#define offsetofclass(base, derived) ((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
//标识符类型定义
typedef unsigned long GUID;
typedef GUID IID;
typedef GUID CLSID;
#define DEFINEIID(X,N) const IID_##X = N
//调试输出
#ifdef _DEBUG_ON
#define TRACELN(x) cout << " | DEBUG : " << x <<endl
#define TRACE(x) cout << " | DEBUG : " << x
#define TRACEA(x) cout << x
#define TRACELNA(x) cout << x <<endl
#else
#define TRACELN(x)
#define TRACE(x)
#define TRACEA(x)
#define TRACELNA(x)
#endif
//定义接口方法
#define METHOD(X) public: virtual HRESULT X
//定义IUnknown
DEFINEIID(IUnknown,0x010001);
INTERFACE IUnknown
{
METHOD(QueryInterface)(IID iid,void** ppv) = 0;
METHOD(AddRef)(void) = 0;
METHOD(Release)(void) = 0;
};
//定义IClassFactory
DEFINEIID(IClassFactory,0x347a24);
INTERFACE IClassFactory : public IUnknown
{
METHOD(CreateInstance)( IUnknown * pUnkOuter,
IID riid, void ** ppvObject) = 0;
METHOD(LockServer)(BOOL bLook) = 0;
};
//define class mapping entry struct
typedef HRESULT(* CreateFunc)(void* pv, IID riid, void** ppv);
typedef struct{
CLSID clsid;
CreateFunc pfnCreateObject;
CreateFunc pfnCreateInstance;
IUnknown* pCF; //类厂IUnknown
}_OBJECT_MAP_ENTRY;
#define DEFINECLSID(X,N) const CLSID_##X = N
#define BEGIN_OBJECT_MAP(x) static _OBJECT_MAP_ENTRY x[] = {
#define OBJECT_ENTRY(clsid,class) {clsid,class::_ClassFactory::CreateInstance, class::_CreatorObject::CreateInstance , NULL},
#define OBJECT_ENTRYEX(class) {CLSID_##class,class::_ClassFactory::CreateInstance, class::_CreatorObject::CreateInstance , NULL},
#define END_OBJECT_MAP() {0,NULL,NULL,NULL} };
//define Interface map entry struct
typedef struct{
IID iid;
DWORD dw;
}_INTERFACES_ENTRY;
//define interface mapping macro
#define BEGIN_INTERFACES_MAP(CN) public: typedef CN _ComClass; const static _INTERFACES_ENTRY* _GetInterfaceMap() { static _INTERFACES_ENTRY _Entry[] = { {IID_IUnknown,0},
#define INTERFACE_ENTRY(IN) {IID_##IN,offsetofclass(IN,_ComClass)},
#define END_INTERFACES_MAP() {0,0} }; return &_Entry[1]; } METHOD(QueryInterface)(IID iid,void** ppv) = 0; METHOD(AddRef)(void) = 0; METHOD(Release)(void) =0;
//类定义
template<typename T>
class CComObjectRoot
{
public:
METHOD(FinalAddRef)(void)
{
m_dwRef ++;
TRACE(" AddRef m_dwRef = ");
TRACELNA(m_dwRef);
return S_OK;
}
METHOD(FinalRelease)(void)
{
m_dwRef --;
ASSERT((m_dwRef >= 0));
TRACE(" Release m_dwRef = ");
TRACELNA(m_dwRef);
if(m_dwRef <= 0){
delete this;
TRACELN(" Delete ... ");
}
return S_OK;
}
METHOD(FinalQueryInterface)(void* pThis,IID iid,void** ppv)
{
ASSERT(pThis && iid);
const _INTERFACES_ENTRY* pEntry = T::_GetInterfaceMap();
ASSERT(pEntry);
while(!(pEntry->dw == 0 && pEntry->iid ==0))
{
if(iid == IID_IUnknown)
{
*ppv = (IUnknown*)((T*)pThis);
FinalAddRef();
TRACELN(" QueryInterface IUnknown ");
return S_OK;
}
if(iid == pEntry->iid){
*ppv = (void *)(((DWORD)pThis) + pEntry->dw);
FinalAddRef();
TRACELN(" QueryInterface OK");
return S_OK;
}
pEntry ++;
}
TRACELN(" QueryInterface Failed ");
return E_FAIL;
}
public:
CComObjectRoot()
{
m_dwRef = 0;
}
void SetVoid(void* pv){}
DWORD m_dwRef;
};
template<typename T>
class CComObject : public T
{
METHOD(QueryInterface)(IID iid,void** ppv)
{
return FinalQueryInterface(this,iid,ppv);
}
METHOD(AddRef)(void)
{
return FinalAddRef();
}
METHOD(Release)(void){
return FinalRelease();
}
};
class CComClassFactory :
public CComObjectRoot<CComClassFactory>,
public IClassFactory
{
METHOD(CreateInstance)(IUnknown* pUnkOuter , IID iid,
void** ppv)
{
return m_pfnCreateInstance(pUnkOuter ,
iid , ppv);
}
METHOD(LockServer)(BOOL bLock)
{
return S_OK;
}
void SetVoid(void* pv)
{
m_pfnCreateInstance = (CreateFunc )pv;
}
CreateFunc m_pfnCreateInstance;
BEGIN_INTERFACES_MAP(CComClassFactory)
INTERFACE_ENTRY(IClassFactory)
END_INTERFACES_MAP()
};
template<typename T>
class CComCreator
{
public:
static HRESULT CreateInstance(void* pv, IID riid, void** ppv)
{
ASSERT(riid);
T* p = new T;
if(p->QueryInterface(riid,ppv) != S_OK){
delete p;
return E_FAIL;
}
p->SetVoid(pv);
return S_OK;
}
};
#define DEFINE_CLASSFACTORY() typedef CComCreator< CComObject< CComClassFactory> > _ClassFactory;
#define DEFINE_OBJECT(x) typedef CComCreator< CComObject< x > > _CreatorObject;
template<typename T>
class CComCoClass
{
public:
DEFINE_CLASSFACTORY()
DEFINE_OBJECT(T)
};
class CComModule
{
public:
void Init(_OBJECT_MAP_ENTRY* p)
{
m_pObjectMap = p;
}
void Trim()
{
ASSERT(m_pObjectMap);
_OBJECT_MAP_ENTRY* pEntry = m_pObjectMap;
while(pEntry->clsid != NULL)
{
if(pEntry->pCF != NULL)
pEntry->pCF->Release();
pEntry ++;
}
}
_OBJECT_MAP_ENTRY* m_pObjectMap;
METHOD(GetClassObjcet)(CLSID clsid, IID riid, void** ppv)
{
ASSERT(m_pObjectMap);
_OBJECT_MAP_ENTRY* pEntry = m_pObjectMap;
while(pEntry->clsid != NULL)
{
if(pEntry->clsid == clsid)
{
if(pEntry->pCF == NULL){
HRESULT hRes = pEntry->pfnCreateObject(pEntry->pfnCreateInstance,
riid,(void**)&pEntry->pCF);
*ppv = (void *)pEntry->pCF;
return S_OK;
}
else
{
*ppv = (void *)pEntry->pCF;
return S_OK;
}
}
pEntry ++;
}
return E_FAIL;
}
};
//Test.cpp
#include "stdafx.h"
#include "atlmy.h"
DEFINEIID(IMy,0x34242);
INTERFACE IMy : public IUnknown
{
METHOD(F1)(void) = 0;
};
DEFINECLSID(MyClass,0x25346);
class MyClass :
public CComObjectRoot<MyClass>,
public CComCoClass<MyClass>,
public IMy
{
METHOD(F1)(void)
{
cout << "Hello" <<endl;
return S_OK;
}
BEGIN_INTERFACES_MAP(MyClass)
INTERFACE_ENTRY(IMy)
END_INTERFACES_MAP()
};
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRYEX(MyClass)
END_OBJECT_MAP()
CComModule _Module;
int main(int argc, char* argv[])
{
_Module.Init(ObjectMap);
IClassFactory *pCF = NULL;
IMy* pMy = NULL;
_Module.GetClassObjcet(CLSID_MyClass,IID_IClassFactory,(void**)&pCF);
pCF->CreateInstance(NULL,IID_IMy,(void** )&pMy);
IMy* pMy1 = NULL;
IClassFactory *pCF1 = NULL;
_Module.GetClassObjcet(CLSID_MyClass,IID_IClassFactory,(void**)&pCF1);
pCF1->CreateInstance(NULL,IID_IMy,(void** )&pMy1);
pMy1->F1();
pMy1->Release();
pMy->F1();
pMy->Release();
_Module.Trim();
return 0;
}