进程内COM对象的创建过程(AC5)

来源:互联网 发布:股票记账软件 编辑:程序博客网 时间:2024/05/16 07:49

AC5,由VS2005的ATL向导生成的默认COM对象代码分析ATL如何实现COM,第五部分。

  Com库创建COM对象可以使用三个方法:

[csharp] view plaincopy
  1. CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv);  
  2.   
  3. CoCreateInstanceEx(IN REFCLSID Clsid, IN IUnknown * punkOuter, IN DWORD dwClsCtx, IN COSERVERINFO * pServerInfo, IN DWORD dwCount, IN OUT MULTI_QI * pResults );  
  4.   
  5. 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时传递的参数,因而用户的接口查询请求在这里完成。

原创粉丝点击