分享

通过ATL开发COM

 紫殿 2011-07-24
一》》、通过ATL开发COM_1概述
ATL 是为了减轻程序员开发COM的负担而提供的一套模板库
ATL提供的支持:
1. CComModule封装对组件的宿主支持,掩盖了(DLL和EXE)之间的差别。
2. 对IUnknown的支持
3. 对类工厂的支持
4. 自动化 : IDispatchImpl
COM 数据类型 : CComBSTR, CComVariant
接口指针 : CComPtr, CComQIPtr
错误处理 :ISupportErrorInfoImpl, CComObject
连接点 : IConnectionPointContainerImpl, IConnectionPointImpl :支持服务器的回叫信号(callback)或事件(event)
异步属性下载 : CBindStatusCallback
自注册 : 
视窗和对话框 : Cwindow, CwindowImpl, CDialogImpl, CmessageMap
每个COM组件需要实现这三个功能
1. 实现IUnknown接口 (通过 CComObjectRootEx 实现)
2. 实现一个类工厂,支持组件的创建 (通过 CComCoClass 实现)
3. 实现自注册
一个典型ATL COM组件的定义
  1. class ATL_NO_VTABLE CAtlMath :  
  2.     public CComObjectRootEx<CComSingleThreadModel>,  
  3.     public CComCoClass<CAtlMath, &CLSID_AtlMath>,  
  4.     public IDispatchImpl<IAtlMath, &IID_IAtlMath, &LIBID_ATL_ServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>  
  5. {//......  
  6. }  
CComObjectRootEx 提供 IUnknown支持
CComCoClass 提供类工厂的支持


每个COM组件需要实现这三个功能
1. 实现IUnknown接口 (通过 CComObjectRootEx 实现)
2. 实现一个类工厂,支持组件的创建 (通过 CComCoClass 实现)
3. 实现自注册

 

ATL是如何实现IUnknown接口的?

 

组件通过派生CComObjectRootEx 获得 IUnknown支持

  1. template <class ThreadModel>  
  2. class CComObjectRootEx : public CComObjectRootBase  
  3. {  
  4.     typedef ThreadModel _ThreadModel;  
  5.     ULONG InternalAddRef()  
  6.     {  
  7.         return _ThreadModel::Increment(&m_dwRef);  
  8.     }  
  9.     ULONG InternalRelease()  
  10.     {  
  11.         return _ThreadModel::Decrement(&m_dwRef);  
  12.     }  
  13. };  
  14. class CComObjectRootBase  
  15. {  
  16.     static HRESULT WINAPI InternalQueryInterface(void* pThis,  
  17.         const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)  
  18.     {  
  19.         HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);  
  20.         return _ATLDUMPIID(iid, pszClassName, hRes);  
  21.     }  
  22.     ULONG OuterAddRef()  
  23.     {  
  24.         return m_pOuterUnknown->AddRef();  
  25.     }  
  26.     ULONG OuterRelease()  
  27.     {  
  28.         return m_pOuterUnknown->Release();  
  29.     }  
  30.     HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)  
  31.     {  
  32.         return m_pOuterUnknown->QueryInterface(iid, ppvObject);  
  33.     }  
  34.     union  
  35.     {  
  36.         long m_dwRef;  
  37.         IUnknown* m_pOuterUnknown;  
  38.     };  
  39. };  
CComObjectRootBase 提供集合的IUnknown方法支持 :OuterAddRef 和 OuterRelease
CComObjectRootEx 提供非集合的IUnknown方法支持 :InternalAddRef 和 InternalRelease
另外CComObjectRootBase还提供 IUnknown的QueryInterface方法支持 :InternalQueryInterface 和 OuterQueryInterface

IUnknown方法最终通过 CComObject 对用户开放:
  1. template <class Base> //Base = CAtlMath  
  2. class CComObject : public Base  
  3. {  
  4.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}  
  5.     STDMETHOD_(ULONG, Release)()  
  6.     {  
  7.         ULONG l = InternalRelease();  
  8.         if (l == 0)  
  9.             delete this;  
  10.         return l;  
  11.     }  
  12.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()  
  13.     {  
  14.         return _InternalQueryInterface(iid, ppvObject);  
  15.     }  
  16. };  

最终我们可以这样声明和使用ATL COM组件
  1. class ATL_NO_VTABLE CAtlMath :  
  2.     public CComObjectRootEx<CComSingleThreadModel>,  
  3.     public CComCoClass<CAtlMath, &CLSID_AtlMath>,  
  4.     public IDispatchImpl<IAtlMath, &IID_IAtlMath, &LIBID_ATL_ServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>  
  5. {//......  
  6. }  
  7. IAtlMath *pIMath = new CComObject <CAtlMath>; //非集合  
-------------------------------------------------------------------------------------------------------------
其实共有9个类似 CComObject 的类用于处理对用户开放的IUnknown接口,创建可实例化的COM组件。
CComObject : 不支持集合,不能处理引用计数
CComObjectNoLock : 同CComObject, 且该对象生命周期不影响组件宿主文件的锁定计数。ATL在宿主类工厂实现中使用该类 
CComAggObject : 支持集合
CComContainedObject : 类似一个集合对象
CComPolyObject 支持集合和标准实现,是一个占位实现
CComObjectStack :完全不支持引用计数,结合栈创建COM对象一起使用
CComObjectGlobal : 生存期与组件宿主文件生存期相同,类似全局C++对象
CComObjectCached :存储在对象的缓存里,ATL用它实现组件的类工厂
CComTearOffObject :只在需要时创建类

-------------------------------------------------------------------------------------------------------------
总结一下 IUnknown 的实现
1. 类厂会这样创建组件 CAtlMath
IAtlMath *pIMath = new CComObject <CAtlMath>; //非集合

2. CComObject 提供了IUnknown 接口的实现,它会调用 CAtlMath 的非集合内部IUnknown接口
  1. template <class Base> //Base = CAtlMath  
  2. class CComObject : public Base  
  3. {  
  4.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}  
  5.     STDMETHOD_(ULONG, Release)() { ULONG l = InternalRelease(); //......}  
  6.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() { return _InternalQueryInterface(iid, ppvObject); }  
  7. };  
3. 组件 CAtlMath 会派生于 CComObjectRootEx, CComObjectRootEx提供了部分非集合IUnknown接口
  1. class ATL_NO_VTABLE CAtlMath :  
  2.     public CComObjectRootEx<CComSingleThreadModel>, //......  
  3. {//......  
  4. }  
  5. template <class ThreadModel>  
  6. class CComObjectRootEx : public CComObjectRootBase  
  7. {//......  
  8.     ULONG InternalAddRef() { return _ThreadModel::Increment(&m_dwRef); }  
  9.     ULONG InternalRelease() { return _ThreadModel::Decrement(&m_dwRef); }  
  10. };  
4. CComObjectRootEx 派生于 CComObjectRootBase,CComObjectRootBase提供了部分非集合IUnknown接口和全部集合IUnknown接口
  1. class CComObjectRootBase  
  2. {//......  
  3.     //集合IUnknown接口  
  4.     static HRESULT WINAPI InternalQueryInterface(void* pThis,  
  5.         const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)  
  6.     {  
  7.         HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);  
  8.         return _ATLDUMPIID(iid, pszClassName, hRes);  
  9.     }  
  10.     ULONG OuterAddRef() { return m_pOuterUnknown->AddRef(); }  
  11.     ULONG OuterRelease() { return m_pOuterUnknown->Release(); }  
  12.      
  13.     //非集合IUnknown接口  
  14.     HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)  
  15.     {  
  16.         return m_pOuterUnknown->QueryInterface(iid, ppvObject);  
  17.     }  
  18.      
  19.     union  
  20.     {  
  21.         long m_dwRef;  
  22.         IUnknown* m_pOuterUnknown;  
  23.     };  
  24. };  
  25. ATL_NO_VTABLE : __declspec (novtable)
告诉编译器不要为类生成或初始化一个Vtable结构,可让类的构造函数和析构函数更小,并减小内存使用


类工厂的实现,组件的创建过程
1. 在*_Server.cpp 中有

  1. BEGIN_OBJECT_MAP(ObjectMap)  
  2.     OBJECT_ENTRY(CLSID_Math, CMath)  
  3. END_OBJECT_MAP()  
展开后是这样:
  1. struct _ATL_OBJMAP_ENTRY30  
  2. {  
  3.     const CLSID* pclsid;  
  4.     HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);  
  5.     _ATL_CREATORFUNC* pfnGetClassObject;  
  6.     _ATL_CREATORFUNC* pfnCreateInstance;  
  7.     IUnknown* pCF;  
  8.     DWORD dwRegister;  
  9.     _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription;  
  10.     _ATL_CATMAPFUNC* pfnGetCategoryMap;  
  11.     void (WINAPI *pfnObjectMain)(bool bStarting);  
  12. };  
  13. static ATL::_ATL_OBJMAP_ENTRY ObjectMap[] =  
  14. {  
  15.     {  
  16.         &CLSID_Math,  
  17.         CMath::UpdateRegistry,  
  18.         CMath::_ClassFactoryCreatorClass::CreateInstance,  
  19.         CMath::_CreatorClass::CreateInstance,  
  20.         NULL,  
  21.         0,  
  22.         CMath::GetObjectDescription,  
  23.         CMath::GetCategoryMap,  
  24.         CMath::ObjectMain  
  25.     },  
  26.     {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}  
  27. };  
定义了一个_ATL_OBJMAP_ENTRY 类型的全局数组变量 ObjectMap
然后在 Dll 被载入时用这个数组初始化全局的 _Module 变量
  1. CComModule _Module;  
  2. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)  
  3. {//......  
  4.     if (dwReason == DLL_PROCESS_ATTACH)  
  5.     {  
  6.         _Module.Init(ObjectMap, hInstance);  
  7.     }  
  8. }  
  9. inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE /*h*/const GUID* plibid) throw()  
  10. {//......  
  11.     m_pObjMap = p;  
  12.     _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;  
  13.     while (pEntry->pclsid != NULL)  
  14.     {  
  15.         pEntry->pfnObjectMain(true); //这里就是 CMath::ObjectMain  
  16.         pEntry++;  
  17.     }  
  18. }  
当用户代码中调用 CoCreateInstance 时
HRESULT hr = CoCreateInstance( CLSID_Math,
                                  NULL,
                                  CLSCTX_INPROC,
                                  IID_IMath,
                                  (void**) &pMath );

Dll 中的 DllGetClassObject 会被调用,最终调用 CMath::_ClassFactoryCreatorClass::CreateInstance 创建CMath组件
  1. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)  
  2. {  
  3.     return _Module.GetClassObject(rclsid, riid, ppv);  
  4. }  
  5. inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw()  
  6. {  
  7.     _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;  
  8.     while (pEntry->pclsid != NULL)  
  9.     {  
  10.         if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))  
  11.         {  
  12.             //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance  
  13.             //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance  
  14.             pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);  
  15.             pEntry->pCF->QueryInterface(riid, ppv);  
  16.             break;  
  17.         }  
  18.         pEntry++;  
  19.     }  
  20. }  
接下来看 CComCoClass 又是如何帮助实现 CMath::_ClassFactoryCreatorClass::CreateInstance 创建类厂的
  1. class ATL_NO_VTABLE CMath :  
  2.    public CComObjectRootEx<CComSingleThreadModel>,  
  3.    public CComCoClass<CMath, &CLSID_Math>,  
  4.    //......  
  5. {  
  6. }  
  7. template <class T, const CLSID* pclsid = &CLSID_NULL> //T = CMath, pclsid = CLSID_Math  
  8. class CComCoClass  
  9. {  
  10. public:  
  11.     //DECLARE_CLASSFACTORY()  
  12.     //DECLARE_AGGREGATABLE(T)  
  13.     typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;  
  14.     typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;  
  15.     typedef T _CoClass;  
  16.     template <class Q>  
  17.     static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp)  
  18.     {  
  19.         return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp);  
  20.     }  
  21. };  

可见在 CComCoClass 中有两个typedef的定义, 
_ClassFactoryCreatorClass 用于创建类厂
而 _CreatorClass用于创建组件实例
DllGetClassObject 最终调用了其中的 _ClassFactoryCreatorClass 的 CreateInstance函数创建类厂

将 _ClassFactoryCreatorClass 展开
  1. //typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;  
  2. template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂  
  3.                     //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > 组件  
  4. class CComCreator  
  5. {  
  6. public:  
  7.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)  
  8.     {  
  9.         *ppv = NULL;  
  10.         HRESULT hRes = E_OUTOFMEMORY;  
  11.         T1* p =  new T1(pv)); //这里创建了组件或类厂  
  12.         if (p != NULL)  
  13.         {  
  14.             p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance  
  15.             p->InternalFinalConstructAddRef();  
  16.             hRes = p->_AtlInitialConstruct();  
  17.             if (SUCCEEDED(hRes))  
  18.                 hRes = p->FinalConstruct();  
  19.             if (SUCCEEDED(hRes))  
  20.                 hRes = p->_AtlFinalConstruct();  
  21.             p->InternalFinalConstructRelease();  
  22.             if (hRes == S_OK)  
  23.                 hRes = p->QueryInterface(riid, ppv); //获取组件接口指针  
  24.             if (hRes != S_OK)  
  25.                 delete p;  
  26.         }  
  27.         return hRes;  
  28.     }  
  29. };  
DllGetClassObject 调用 
  1. //pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);  
  2. CMath::_ClassFactoryCreatorClass::CreateInstance (CMath::_CreatorClass::CreateInstance, __uuidof(IUnknown), (LPVOID*)NULL);  
然后在这里面创建了类厂 :ATL::CComObjectCached< ATL::CComClassFactory >* p = new ATL::CComObjectCached< ATL::CComClassFactory >(pv));
最终获得类厂的接口 :p->QueryInterface(riid, ppv);
类厂类是ATL::CComClassFactory 它的定义
  1. typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void* pv, REFIID riid, LPVOID* ppv);  
  2. class CComClassFactory :  
  3.     public IClassFactory,  
  4.     public CComObjectRootEx<CComGlobalsThreadModel>  
  5. {  
  6. public:  
  7.     BEGIN_COM_MAP(CComClassFactory)  
  8.         COM_INTERFACE_ENTRY(IClassFactory)  
  9.     END_COM_MAP()  
  10.      
  11.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)  
  12.     {  
  13.         HRESULT hRes = E_POINTER;  
  14.         *ppvObj = NULL;  
  15.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数  
  16.         {  
  17.             ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));  
  18.             hRes = CLASS_E_NOAGGREGATION;  
  19.         }  
  20.         else  
  21.             hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);  
  22.         return hRes;  
  23.     }  
  24.     void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance  
  25.     {  
  26.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;  
  27.     }  
  28.     _ATL_CREATORFUNC* m_pfnCreateInstance;  
  29. };  
这里面有趣的是 SetVoid(void* pv) 它将 CMath::_CreatorClass::CreateInstance 传给了类厂指针成员变量 _ATL_CREATORFUNC* m_pfnCreateInstance

然后,在调用类厂 CreateInstance 创建对象实例时, 它会在检查参数后,调用 CMath::_CreatorClass::CreateInstance
那再看看 CMath::_CreatorClass::CreateInstance 会是如何实现创建组件实例
  1. typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;  
  2. template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > >  
  3. class CComCreator2  
  4. {  
  5. public:  
  6.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)  
  7.     {  
  8.         ATLASSERT(ppv != NULL);  
  9.         return (pv == NULL) ?  
  10.             ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) :  
  11.             ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv);  
  12.     }  
  13. };  
它会通过pv参数判断组件是否组合,然后选择相应的创建模板类
-------------------------------------------------------------------------------------------------------------
总结一下类厂和组件的创建过程
类厂创建过程:
1. 在*_Server.cpp 中定义CComModule _Module 全局变量和一个数组,里面填入组件创建的相关函数信息
  1. CComModule _Module;  
  2. BEGIN_OBJECT_MAP(ObjectMap)  
  3.     OBJECT_ENTRY(CLSID_Math, CMath)  
  4. END_OBJECT_MAP()  
2. Dll 加载时完成_Module的初始化
  1. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID )  
  2. {  
  3.     if (dwReason == DLL_PROCESS_ATTACH)  
  4.     {  
  5.         _Module.Init(ObjectMap, hInstance);  
  6.     }  
  7. }  
  8. inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE , const GUID* plibid) throw()  
  9. {  
  10.     m_pObjMap = p;  
  11.     //......  
  12. }  
3. 用户调用 CoCreateInstance 时,dll导出函数 DllGetClassObject 会被调用
  1. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)  
  2. {  
  3.     return _Module.GetClassObject(rclsid, riid, ppv);  
  4. }  
  5. //rclsid = CLSID_Math  
  6. inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw()  
  7. {//......  
  8.     _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap;  
  9.     while (pEntry->pclsid != NULL)  
  10.     {  
  11.         if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))  
  12.         {  
  13.             //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance  
  14.             //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance  
  15.             hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);  
  16.             break;  
  17.         }  
  18.         pEntry++;  
  19.     }  
  20. }  

4. DllGetClassObject 会导致 CMath::_ClassFactoryCreatorClass::CreateInstance 的调用

  1. CMath::_ClassFactoryCreatorClass 类型是 CComCreator, 也就是 CComCreator::CreateInstance 被调用,创建了类厂  
  2. //typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass;  
  3. template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂  
  4. class CComCreator  
  5. {//......  
  6.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)  
  7.     {  
  8.         *ppv = NULL;  
  9.         HRESULT hRes = E_OUTOFMEMORY;  
  10.         T1* p =  new T1(pv)); //这里创建了类厂  
  11.         if (p != NULL)  
  12.         {  
  13.             p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance  
  14.             p->QueryInterface(riid, ppv); //获取组件接口指针  
  15.             //......  
  16.         }  
  17.     }  
  18. };  

*********************************************************************************

组件的创建过程:
1. CComCreator::CreateInstance 创建类厂后,会调用 SetVoid(pv) 将组件创建的函数指针创给了类工厂

  1. class CComClassFactory : //.....  
  2. {//.....  
  3.     void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance  
  4.     {  
  5.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;  
  6.     }  
  7.     _ATL_CREATORFUNC* m_pfnCreateInstance;  
  8. };  
2. 用户调用的 CoCreateInstance, 在成功创建类厂后,会调用类厂的 CreateInstance接口
  1. class CComClassFactory : //.....  
  2. {//.....  
  3.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)  
  4.     {  
  5.         HRESULT hRes = E_POINTER;  
  6.         *ppvObj = NULL;  
  7.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数  
  8.         {  
  9.             ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));  
  10.             hRes = CLASS_E_NOAGGREGATION;  
  11.         }  
  12.         else  
  13.             hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); //调用组件创建函数  
  14.         return hRes;  
  15.     }  
  16.     _ATL_CREATORFUNC* m_pfnCreateInstance; //m_pfnCreateInstance = CMath::_CreatorClass::CreateInstance  
  17. };  
3. 类厂的 CreateInstance 会调用通过 SetVoid 获取的组件创建的函数指针, 也就是CMath::_CreatorClass::CreateInstance
  1. //typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > > _CreatorClass;  
  2. template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > >  
  3. class CComCreator2  
  4. {  
  5. public:  
  6.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)  
  7.     {  
  8.         ATLASSERT(ppv != NULL);  
  9.         return (pv == NULL) ?  
  10.             ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) :  
  11.             ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv);  
  12.     }  
  13. };  
4. CComCreator2 会通过检查pv参数,确定是创建组合对象还是非组合对象,最终还是通过 CComCreator 创建组件
  1. //ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv);  
  2. template <class T1> //T1 = ATL::CComCreator< ATL::CComObject< CMath > > 或 ATL::CComCreator< ATL::CComAggObject< CMath > > 创建组件                     
  3. class CComCreator  
  4. {//.....  
  5.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)  
  6.     {  
  7.         *ppv = NULL;  
  8.         HRESULT hRes = E_OUTOFMEMORY;  
  9.         //ATL::CComObject< CMath > *p = new ATL::CComObject< CMath > (pv);  
  10.         T1* p =  new T1(pv)); //这里创建了组件或类厂  
  11.         //.....  
  12.         hRes = p->QueryInterface(riid, ppv); //获取组件接口指针  
  13.         return hRes;  
  14.     }  
  15. };  
到此,组件创建完成。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多