通过ATL开发COM_3实现类厂和组件的创建
2009-08-18 18:31
441 查看
类工厂的实现,组件的创建过程
1. 在*_Server.cpp 中有
展开后是这样:
定义了一个_ATL_OBJMAP_ENTRY 类型的全局数组变量 ObjectMap
然后在 Dll 被载入时用这个数组初始化全局的 _Module 变量
当用户代码中调用 CoCreateInstance 时
HRESULT hr = CoCreateInstance( CLSID_Math,
NULL,
CLSCTX_INPROC,
IID_IMath,
(void**) &pMath );
Dll 中的 DllGetClassObject 会被调用,最终调用 CMath::_ClassFactoryCreatorClass::CreateInstance 创建CMath组件
接下来看 CComCoClass 又是如何帮助实现 CMath::_ClassFactoryCreatorClass::CreateInstance 创建类厂的
可见在 CComCoClass 中有两个typedef的定义,
_ClassFactoryCreatorClass 用于创建类厂
而 _CreatorClass用于创建组件实例
DllGetClassObject 最终调用了其中的 _ClassFactoryCreatorClass 的 CreateInstance函数创建类厂
将 _ClassFactoryCreatorClass 展开
DllGetClassObject 调用
然后在这里面创建了类厂 :ATL::CComObjectCached< ATL::CComClassFactory >* p = new ATL::CComObjectCached< ATL::CComClassFactory >(pv));
最终获得类厂的接口 :p->QueryInterface(riid, ppv);
类厂类是ATL::CComClassFactory 它的定义
这里面有趣的是 SetVoid(void* pv) 它将 CMath::_CreatorClass::CreateInstance 传给了类厂指针成员变量 _ATL_CREATORFUNC* m_pfnCreateInstance
然后,在调用类厂 CreateInstance 创建对象实例时, 它会在检查参数后,调用 CMath::_CreatorClass::CreateInstance
那再看看 CMath::_CreatorClass::CreateInstance 会是如何实现创建组件实例
它会通过pv参数判断组件是否组合,然后选择相应的创建模板类
-------------------------------------------------------------------------------------------------------------
总结一下类厂和组件的创建过程
类厂创建过程:
1. 在*_Server.cpp 中定义CComModule _Module 全局变量和一个数组,里面填入组件创建的相关函数信息
2. Dll 加载时完成_Module的初始化
3. 用户调用 CoCreateInstance 时,dll导出函数 DllGetClassObject 会被调用
4. DllGetClassObject 会导致 CMath::_ClassFactoryCreatorClass::CreateInstance 的调用
*********************************************************************************
组件的创建过程:
1. CComCreator::CreateInstance 创建类厂后,会调用 SetVoid(pv) 将组件创建的函数指针创给了类工厂
2. 用户调用的 CoCreateInstance, 在成功创建类厂后,会调用类厂的 CreateInstance接口
3. 类厂的 CreateInstance 会调用通过 SetVoid 获取的组件创建的函数指针, 也就是CMath::_CreatorClass::CreateInstance
4. CComCreator2 会通过检查pv参数,确定是创建组合对象还是非组合对象,最终还是通过 CComCreator 创建组件
到此,组件创建完成。
1. 在*_Server.cpp 中有
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Math, CMath) END_OBJECT_MAP()
展开后是这样:
struct _ATL_OBJMAP_ENTRY30 { const CLSID* pclsid; HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister); _ATL_CREATORFUNC* pfnGetClassObject; _ATL_CREATORFUNC* pfnCreateInstance; IUnknown* pCF; DWORD dwRegister; _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription; _ATL_CATMAPFUNC* pfnGetCategoryMap; void (WINAPI *pfnObjectMain)(bool bStarting); }; static ATL::_ATL_OBJMAP_ENTRY ObjectMap[] = { { &CLSID_Math, CMath::UpdateRegistry, CMath::_ClassFactoryCreatorClass::CreateInstance, CMath::_CreatorClass::CreateInstance, NULL, 0, CMath::GetObjectDescription, CMath::GetCategoryMap, CMath::ObjectMain }, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} };
定义了一个_ATL_OBJMAP_ENTRY 类型的全局数组变量 ObjectMap
然后在 Dll 被载入时用这个数组初始化全局的 _Module 变量
CComModule _Module; BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) {//...... if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance); } } inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE /*h*/, const GUID* plibid) throw() {//...... m_pObjMap = p; _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap; while (pEntry->pclsid != NULL) { pEntry->pfnObjectMain(true); //这里就是 CMath::ObjectMain pEntry++; } }
当用户代码中调用 CoCreateInstance 时
HRESULT hr = CoCreateInstance( CLSID_Math,
NULL,
CLSCTX_INPROC,
IID_IMath,
(void**) &pMath );
Dll 中的 DllGetClassObject 会被调用,最终调用 CMath::_ClassFactoryCreatorClass::CreateInstance 创建CMath组件
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _Module.GetClassObject(rclsid, riid, ppv); } inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() { _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap; while (pEntry->pclsid != NULL) { if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid)) { //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF); pEntry->pCF->QueryInterface(riid, ppv); break; } pEntry++; } }
接下来看 CComCoClass 又是如何帮助实现 CMath::_ClassFactoryCreatorClass::CreateInstance 创建类厂的
class ATL_NO_VTABLE CMath : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CMath, &CLSID_Math>, //...... { } template <class T, const CLSID* pclsid = &CLSID_NULL> //T = CMath, pclsid = CLSID_Math class CComCoClass { public: //DECLARE_CLASSFACTORY() //DECLARE_AGGREGATABLE(T) typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass; typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass; typedef T _CoClass; template <class Q> static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp) { return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp); } };
可见在 CComCoClass 中有两个typedef的定义,
_ClassFactoryCreatorClass 用于创建类厂
而 _CreatorClass用于创建组件实例
DllGetClassObject 最终调用了其中的 _ClassFactoryCreatorClass 的 CreateInstance函数创建类厂
将 _ClassFactoryCreatorClass 展开
//typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass; template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂 //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > 组件 class CComCreator { public: static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) { *ppv = NULL; HRESULT hRes = E_OUTOFMEMORY; T1* p = new T1(pv)); //这里创建了组件或类厂 if (p != NULL) { p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance 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; } };
DllGetClassObject 调用
//pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF); 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 它的定义
typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void* pv, REFIID riid, LPVOID* ppv); class CComClassFactory : public IClassFactory, public CComObjectRootEx<CComGlobalsThreadModel> { public: BEGIN_COM_MAP(CComClassFactory) COM_INTERFACE_ENTRY(IClassFactory) END_COM_MAP() STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj) { HRESULT hRes = E_POINTER; *ppvObj = NULL; if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数 { ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object")); hRes = CLASS_E_NOAGGREGATION; } else hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); return hRes; } void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance { m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; } _ATL_CREATORFUNC* m_pfnCreateInstance; };
这里面有趣的是 SetVoid(void* pv) 它将 CMath::_CreatorClass::CreateInstance 传给了类厂指针成员变量 _ATL_CREATORFUNC* m_pfnCreateInstance
然后,在调用类厂 CreateInstance 创建对象实例时, 它会在检查参数后,调用 CMath::_CreatorClass::CreateInstance
那再看看 CMath::_CreatorClass::CreateInstance 会是如何实现创建组件实例
typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass; template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > > class CComCreator2 { public: static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) { ATLASSERT(ppv != NULL); return (pv == NULL) ? ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) : ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv); } };
它会通过pv参数判断组件是否组合,然后选择相应的创建模板类
-------------------------------------------------------------------------------------------------------------
总结一下类厂和组件的创建过程
类厂创建过程:
1. 在*_Server.cpp 中定义CComModule _Module 全局变量和一个数组,里面填入组件创建的相关函数信息
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Math, CMath) END_OBJECT_MAP()
2. Dll 加载时完成_Module的初始化
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID ) { if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance); } } inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE , const GUID* plibid) throw() { m_pObjMap = p; //...... }
3. 用户调用 CoCreateInstance 时,dll导出函数 DllGetClassObject 会被调用
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _Module.GetClassObject(rclsid, riid, ppv); } //rclsid = CLSID_Math inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() {//...... _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap; while (pEntry->pclsid != NULL) { if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid)) { //pEntry->pfnGetClassObject == CMath::_ClassFactoryCreatorClass::CreateInstance //pEntry->pfnCreateInstance == CMath::_CreatorClass::CreateInstance hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF); break; } pEntry++; } }
4. DllGetClassObject 会导致 CMath::_ClassFactoryCreatorClass::CreateInstance 的调用
CMath::_ClassFactoryCreatorClass 类型是 CComCreator, 也就是 CComCreator::CreateInstance 被调用,创建了类厂 //typedef ATL::CComCreator< ATL::CComObjectCached< ATL::CComClassFactory > > _ClassFactoryCreatorClass; template <class T1> //T1 = ATL::CComObjectCached< ATL::CComClassFactory > 类厂 class CComCreator {//...... static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) { *ppv = NULL; HRESULT hRes = E_OUTOFMEMORY; T1* p = new T1(pv)); //这里创建了类厂 if (p != NULL) { p->SetVoid(pv); //pv = CMath::_CreatorClass::CreateInstance p->QueryInterface(riid, ppv); //获取组件接口指针 //...... } } };
*********************************************************************************
组件的创建过程:
1. CComCreator::CreateInstance 创建类厂后,会调用 SetVoid(pv) 将组件创建的函数指针创给了类工厂
class CComClassFactory : //..... {//..... void SetVoid(void* pv) //pv = CMath::_CreatorClass::CreateInstance { m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; } _ATL_CREATORFUNC* m_pfnCreateInstance; };
2. 用户调用的 CoCreateInstance, 在成功创建类厂后,会调用类厂的 CreateInstance接口
class CComClassFactory : //..... {//..... STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj) { HRESULT hRes = E_POINTER; *ppvObj = NULL; if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) //检查参数 { ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object")); hRes = CLASS_E_NOAGGREGATION; } else hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); //调用组件创建函数 return hRes; } _ATL_CREATORFUNC* m_pfnCreateInstance; //m_pfnCreateInstance = CMath::_CreatorClass::CreateInstance };
3. 类厂的 CreateInstance 会调用通过 SetVoid 获取的组件创建的函数指针, 也就是CMath::_CreatorClass::CreateInstance
//typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< CMath > >, ATL::CComCreator< ATL::CComAggObject< CMath > > > _CreatorClass; template <class T1, class T2> //T1 = ATL::CComCreator< ATL::CComObject< CMath > >, T2 = ATL::CComCreator< ATL::CComAggObject< CMath > > class CComCreator2 { public: static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) { ATLASSERT(ppv != NULL); return (pv == NULL) ? ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv) : ATL::CComCreator< ATL::CComAggObject< CMath > >::CreateInstance(pv, riid, ppv); } };
4. CComCreator2 会通过检查pv参数,确定是创建组合对象还是非组合对象,最终还是通过 CComCreator 创建组件
//ATL::CComCreator< ATL::CComObject< CMath > >::CreateInstance(NULL, riid, ppv); template <class T1> //T1 = ATL::CComCreator< ATL::CComObject< CMath > > 或 ATL::CComCreator< ATL::CComAggObject< CMath > > 创建组件 class CComCreator {//..... static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) { *ppv = NULL; HRESULT hRes = E_OUTOFMEMORY; //ATL::CComObject< CMath > *p = new ATL::CComObject< CMath > (pv); T1* p = new T1(pv)); //这里创建了组件或类厂 //..... hRes = p->QueryInterface(riid, ppv); //获取组件接口指针 return hRes; } };
到此,组件创建完成。
相关文章推荐
- 通过ATL开发COM_2实现IUnknown接口
- 通过ATL实现类厂和组件的创建
- iPhone开发之UIScrollView滚动组件的使用(六)通过代理实现手势缩放——(拖线实现)
- 一步一步实现ATL开发的ActiveX组件与javascript的交互(一)
- 通过 JACOB 实现 Java 与 COM 组件的互操作
- 【Java Servlet 开发系列之二】创建WebApp详细步骤,通过Servlet实现http简单交互
- 【Java Servlet 开发系列之二】创建WebApp详细步骤,通过Servlet实现http简单交互
- 通过ATL开发COM_1概述
- 【VS开发】ATL辅助COM组件开发
- vba调用vs2005使用atl开发的com组件
- C# 无需COM组件创建快捷方式的实现代码
- VS2012创建ATL工程及使用MFC测试COM组件
- [cocos2d-x][游戏开发]通过cocos2d-x实现简易飞机大战02 主界面创建
- Win7下使用ATL开发的COM组件
- vc6 0 atl工程开发的com组件输出事件到VB,VB接收不到中件响应
- 通过Visual C#创建一个Windows组件,然后把其接口以COM形式发布即可(转贴)
- 【Android开发】线程与消息处理-通过实现Runnable接口来创建线程
- 基于ssh2框架下多表查询的单个模块开发。其中的页面跳转是通过MVC中的ModelandView实现的。
- 通过动态代理(Proxy)实现的数据库连接池的创建连接与归还链接的操作的简单的实现流程
- 企业管理软件开发之九 以数据绑定为基础的控件只读,创建时可写,必须大写,必须小写的原理与实现