本文主要是介绍进程内COM对象的创建过程(AC5),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
AC5,由VS2005的ATL向导生成的默认COM对象代码分析ATL如何实现COM,第五部分。
Com库创建COM对象可以使用三个方法:
- CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv);
- CoCreateInstanceEx(IN REFCLSID Clsid, IN IUnknown * punkOuter, IN DWORD dwClsCtx, IN COSERVERINFO * pServerInfo, IN DWORD dwCount, IN OUT MULTI_QI * pResults );
- CoGetClassObject(IN REFCLSID rclsid, IN DWORD dwClsContext, IN LPVOID pvReserved, IN REFIID riid, OUT LPVOID FAR* ppv);
常用的是CoCreateInstance,内部实现上,CoCreateInstance和CoCreateInstanceEx都先调用CoGetClassObject,可以说,CoGetClassObject是Com库创建com对象第一个被调用的方法。
具体的调用过程是这样的:
1.CoCreateInstance调用CoGetClassObject函数
2.COM库找到dll程序并进入进程
3.调用DllGetClassObject函数
4.DllGetClassObject函数创建类厂
5.DllGetClassObject函数把类厂接口返回给CoGetClassObject函数
6.CoGetClassObject函数把类厂返回给CoCreateInstance函数
7.CoCreateInstace函数得到类厂后,调用类厂的对象创建函数
8.类厂创建COM对象
9.类厂把COM对象返回给CoCreateInstance函数,CoCreateInstance函数返回
10.客户直接调用COM对象
从ATL COM服务器的角度上来说:
加载dll阶段
1._DllMainCRTStartup
2.DoInitialization初始化CAtlComModule、_AtlBaseModule、_AtlWinModule、_Module
3.CoCreateInstance调用CoGetClassObject函数
4.dll函数DllGetClassObject被调用
5.转到_AtlModule.DllGetClassObject(CAtlDllModuleT< Your_COM_Module >::DllGetClassObject)
6.CAtlDllModuleT< Your_COM_Module >:: GetClassObject
7.ATLAPI AtlComModuleGetClassObject(&_AtlComModule作为pComModule参数)
8.找到预先保存的ATL¥__m中的_ATL_OBJMAP_ENTRY指针
9.XXX:: _ClassFactoryCreatorClass::CreateInstance(通过映射表获得)
10.CComCreator:: CreateInstance
11.new CComObjectCached< CComClassFactory >
12.给CComClassFactory对象设置创建com对象方法(SetVoid方法设置了CreateInstance里要使用到的指针,别忘了CComClassFactory的CreateInstance是非静态的)
13.CComClassFactory对象的IUnknown接口(使用了QI方法)其实就是IClassFactory的IUnknow接口了
14.使用IClassFactory的IUnknown查询到IClassFactory接口
15.逐层返回到DllGetClassObject
16.CoCreateInstance得到了类厂接口
17.CoCreateInstance调用类厂的CreateInstance方法(该CreateInstance非静态,所以必须使用类厂接口调用)
18.因为之前我们已经给类厂对象保存了com对象的CreateInstance指针(该方法为静态,在CoComCreator2中),所以CoComCreator2直接向两个CoComCreator转发CreateInstance请求。(根据pOuter,如果非聚合,使用CComObject,聚合的话,则使用CComAggObject)
19.(不聚合)CComObject<XXX>::CreateInstance(该方法为静态方法),该类不处理聚合情况,所以pOuter传入NUL
19.(聚合)CComAggObject同CComObject相比,不同点在QI,CComObject是自己直接调用查询方法,而CComAggObject则是把请求转发给pOuter,在CComAggObject的构造函数中,pOuter被赋值给了m_contained,该指针类型为CComContainedObject<contained>,实际转发工作由这个类完成。通过_InternalQueryInterface,对,我说过定义这个函数的宏。
20.(不聚合)按照CoComCreator的定式,调用setVoid方法,但CoComObject没有定义setVoid方法,所以向基类XXX求助,XXX转向CComObjectRootEx而后CComObjectRootBase,终于找到了setVoid方法。(可惜这个方法什么也不做,不过我们传递的参数也是NUL,互相“欺诈”贝丷丷)
21.CComCreator例行公事的调用了_AtlInitialConstruct 、FinalConstruct、_AtlFinalConstruct方法,当然这些方法都是“欺诈行为”,不过可喜的是FinalConstruct在我们定义的类里,我们可以在这里定制一些初始化时的行为。
22.CComCreator调用QI方法,这次传递的参数是我们在使用CoCreateInstance时传递的参数,因而用户的接口查询请求在这里完成。
这篇关于进程内COM对象的创建过程(AC5)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!