学习笔记 Real COM with the MFC Library (译四)

来源:互联网 发布:电力系统潮流计算算法 编辑:程序博客网 时间:2024/06/05 11:28

  COM客户程序如何调用外组件

  COM挂接一个独立的EXE组件可是比挂接一个DLL组件要复杂的多。EXE组件不在同一的进程内,并且可能不在同一个机器内,不过,不用担心。尽管把它当作DLL来写你的程序。COM通过它的远程构架来处理这些细节,这个远程控制访问的结构体系通常已经包含了Remote Procedure Call(RPC)。

  在RPC中,客户程序会调用一个特殊的DLL即代理(proxy), proxy发送数据流给残根(stub),stub在组件进程的一个DLL中。当客户程序调用一个组件方法,proxy发送一条信息给组件程序来通知stub,这些是在隐藏的windows窗口内进行的。转换接受和发送的数据参数的这种机制叫做marshal(装配)。

  如果你使用标准的接口(这些接口已经被Microsoft定义),如IClassFactory和IPersist(这个接口我们还没有看到过,不过如果你查一下COM的固化(persistence)你将会看到),proxy和stub的代码是用来执行marshal的,它有windows的OLE32 DLL提供。如果你创造一种你自己的接口,比如IMotion和IVisual,那么你将需要编写你自己的proxy和stub。编写proxy和stub类,其中包含用IDL(Interface Definition Language)定义你自己的接口,以及编译这些代码,幸运的是,这些已经被MIDL(Microsoft Interface Definition Language)编译器实现了。

  下面是EXE客户程序与EXE组件交互的伪代码,把它和上面的DLL版本作个比较,注意客户端的调用是完全一致的。

Client
  CLSID clsid;
  IClassFactory* pClf;
  IUnknown* pUnk;
  CoInitialize(NULL);//Initialize COM
  CLSIDFromProgID("componentname", &clsid);

COM
  COM通过注册表寻找"componentname"的类ID

Client
  CoGetClassObject(clsid, CLSCTX_LOCAL_SERVER, NULL, IID_IClassFactory, (void**)&pClf);

COM
  COM用类ID在内存中寻找该组件
  if(如果EXE组件没有被载入,或者我们需要另外一个实例){
    COM从注册表中取得EXE组件的文件名
    COM载入EXE组件
  }

EXE Component
  if(已经被载入){
    全局factory对象被构建
    InitInstance被调用(仅仅针对MFC)
    CoInitialize(NULL);
    for each factory对象{
      CoRegisterClassObject(...);
      Return IClassFactory* 指针给COM
    }
  }

COM
  COM返回请求的接口指针给客户端程序
  (客户端的指针与组件接口的指针并不相同)

Client
  pClf->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);

EXE Component
  class factory的CreateInstance方法被调用
  (通过marshal转换直接访问调用)
  构建"componentname"类对象
  间接返回请求的接口指针

Client
  pClf->Release();
  pUnk->Release();

EXE Component
  间接接调用"componentname"的释放函数
  if (引用计数 == 0){
    对象进行自我销毁
  }
  if(所有的对象被释放){
    组件自行退出
  }

Client
  CoUninitialize();//准备退出

COM
  COM调用Release用来释放所有客户程序没有释放掉的对象

EXE Component
  组件退出

COM
  COM释放所有资源

Client
  客户程序退出

  就像你所看到的那样,COM在客户程序和组件之间扮演了一个很重要的角色。COM将把被调用的EXE组件内的一系列的class factory登记在内存中,但是它并不记录自定的COM对象,不如CSpaceship。自定COM有责任通过AddRef/Release机制自我销毁,来更新引用计数。当客户程序退出时,COM将会完成这些操作。如果客户程序使用的是进程外组件。COM在通讯中将监听,并跟踪登记每一个对象的引用计数。当客户程序退出时,COM将断开与组件的连接。在某种境况下,将引起组件释放自己,但是不要依靠这些行为来完成这项工作。在退出之前,请确保你的客户端程序释放了所有的接口指针。



下一节:The MFC Interface Macros