通过ATL实现类厂和组件的创建

来源:互联网 发布:视频剪辑的电脑软件 编辑:程序博客网 时间:2024/04/28 01:36

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

[cpp] view plaincopyprint?
  1. BEGIN_OBJECT_MAP(ObjectMap)  
  2.     OBJECT_ENTRY(CLSID_Math, CMath)  
  3. END_OBJECT_MAP()  
 

展开后是这样:

[cpp] view plaincopyprint?
  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 变量
[cpp] view plaincopyprint?
  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组件
[cpp] view plaincopyprint?
  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 创建类厂的
[cpp] view plaincopyprint?
  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 展开

[cpp] view plaincopyprint?
  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 调用
[cpp] view plaincopyprint?
  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 它的定义
[cpp] view plaincopyprint?
  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 会是如何实现创建组件实例
[cpp] view plaincopyprint?
  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 全局变量和一个数组,里面填入组件创建的相关函数信息
[cpp] view plaincopyprint?
  1. CComModule _Module;  
  2. BEGIN_OBJECT_MAP(ObjectMap)  
  3.     OBJECT_ENTRY(CLSID_Math, CMath)  
  4. END_OBJECT_MAP()  
 

2. Dll 加载时完成_Module的初始化
[cpp] view plaincopyprint?
  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 会被调用
[cpp] view plaincopyprint?
  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 的调用

[cpp] view plaincopyprint?
  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) 将组件创建的函数指针创给了类工厂

[cpp] view plaincopyprint?
  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接口
[cpp] view plaincopyprint?
  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
[cpp] view plaincopyprint?
  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 创建组件
[cpp] view plaincopyprint?
  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. };  
 

到此,组件创建完成。

http://blog.csdn.net/hongjiqin/article/details/4460095

原创粉丝点击