COM学习笔记

 

COM 学习笔记

康  林 2004年11月

关键词:组件、接口、动态链接库、注册表、CLSID、GUID、IID、UUID

  1. 概念:

    1. 类型库:

    2. 组件:是一个接口的集合。

    3. 接口:是一个包含一个函数接针数组的内存结构。每一个数组元素包含的是一个由组件所实现的函数的地址。

      组件是接口的集合,接口是函数的集合。

  2. QueryInterface 的实现规则:

    1. QueryInterface 返回的总是同一个 IUnknown 指针。

    2. 若客户曾经获得过某个接口,那么它将总能获取此接口。

    3. 客户可以再次获得已经拥有的接口。

    4. 客户可以返回到起始接口。

    5. 若能够从某个接口获得某按按特定接口,那么可以从任意接口都将可以获得此接口。

  3. ProgID 与 CLSID的转换:

    1. ProgIDFromCLSID
      HRESULT CLSIDFromProgID(
        LPCOLESTR
      lpszProgID//Pointer to the ProgID
        LPCLSID pclsid         //Pointer to the CLSID
      );

    2. CLSIDFromProgID
      WINOLEAPI ProgIDFromCLSID(
        REFCLSID
      clsid//CLSID for which the ProgID is requested
        LPOLESTR * lplpszProgID
                         //Address of output variable that receives a
                         // pointer to the requested ProgID string
      );
       

  4. CLSID 与字符串的转换:

    1. CLSIDFromString
      HRESULT CLSIDFromString(
        LPOLESTR
      lpsz//Pointer to the string representation of the CLSID
        LPCLSID pclsid  //Pointer to the CLSID
      );

    2. StringFromCLSID
      WINOLEAPI StringFromCLSID(
        REFCLSID
      rclsid, //CLSID to be converted
        LPOLESTR * ppsz  //Address of output variable that receives a
                         // pointer to the resulting string
      );

    3. StringFromGUID2
      int StringFromGUID2(
        REFGUID
      rguid//Interface identifier to be converted
        LPOLESTR lpsz//Pointer to the resulting string on return
        int cchMax       //Character count of string at lpsz
      );
       

    4. StringFromIID
      WINOLEAPI StringFromIID(
        REFIID
      rclsid,     //Interface identifier to be converted
        LPOLESTR * lplpsz  //Address of output variable that receives a
                           // pointer to the resulting string
      );

    5. IIDFromString
      WINOLEAPI IIDFromString(
        LPOLESTR
      lpsz//Pointer to the string representation of the IID
        LPIID lpiid     //Pointer to the requested IID on return
      );

  5. 注册:

    1. 用程序注册:regsvr32.exe

    2. 调用动态函数库中的注册函数:DllRegisterServer

    3. 调用动态函数库中的反注册函数:DllUnregisterServer

  6. COM库函数:

    1. CoCreateInstance
        STDAPI CoCreateInstance(
           REFCLSID
      rclsid,     //Class identifier (CLSID) of the object
           LPUNKNOWN pUnkOuter, //Pointer to whether object is or isn't part
                                  // of an aggregate
           DWORD dwClsContext//Context for running executable code
           REFIID riid,         //Reference to the identifier of the interface
           LPVOID * ppv         //Address of output variable that receives
                                 // the interface pointer requested in riid
        );
      CoCreateInstance 实际上是调用
      CoGetClassObject 实现的。CoGetClassObject 将在注册表中查找指定的组件。找到之后,它将装载实现此组件的 DLL(用 CoLoadLibrary)。装载成功之后,它将调用在 DLL 服务器中的实现的 DllGetClassObject。此函数的作用是创建相应的类厂。另外 DllGetClassObject 还将查询 IClassFactory 接口,并将其返回给 CoCreateInstance。然后,CoCreatInstnce 将使用此接口来调用 IClassFactory::CreateInstance 函数。并查询指 CoCreateInstance 参数 riid 中指定的接口。在得到了此接口之后,CoCreateInstance 将释放相应的类厂并将此接口的指针返回给客户。然后客户就能使用此指针来调用组件中的某个方法了。

    2. CoGetClassObject
      STDAPI CoGetClassObject(
        REFCLSID
      rclsid//CLSID associated with the class object
        DWORD dwClsContext,
                          //Context for running executable code
        COSERVERINFO * pServerInfo,
                          //Pointer to machine on which the object is to
                          // be instantiated
        REFIID riid,      //Reference to the identifier of the interface
        LPVOID * ppv      //Address of output variable that receives the
                          // interface pointer requested in riid
      );

    3. CoFreeUnusedLibraries:释放不再使用的DLL
       
  7. 包容与聚合:
  8. 接口指针类(智能接口指针):

    1. ATL中有 CComPrt 和 CComQIprt(#include <ATLBASE.H>)

    2. MFC中有CIP(#include <afxcom_.h>)

    3. 使用接口类的成员函数,用 . 操作符。例如:
      CComQIPtr <InterfaceClass, &IID> spIF;
      spIF.Release(); //释放接口指针
    4. 释放接口指针类(智能接口指针):
      CComQIPtr <InterfaceClass, &IID> spIF;
      spIF = NULL; //释放接口指针
  9. C++包装类:(MFC OLE)

用嵌套类实现接口:

用 ATL 实现接口

  • 增加 ATL 对象类
    1. 操作步骤 步骤1:菜单 Insert/New ATL Object...(或者用鼠标右键在 ClassView 卡片中弹出菜单)并选择Object 分类,选中 Simple Object 项目。见图二。


      图二、选择建立简单COM对象

         Category Object 普通组件。其中可以选择的组件对象类型很多,但本质上,就是让向导帮我们默认加上一些接口。比如我们选 "Simple Object",则向导给我们的组件加上 IUnknown 接口;我们选 "Internet Explorer Object",则向导除了加上 IUnknown 接口外,再增加一个给 IE 所使用的 IObjectWithSite 接口。当然了,我们完全可以手工增加任何接口。
         Category Controls ActiveX 控件。其中可以选择的 ActiveX 类型也很多。我们在后续的专门介绍 ActiveX 编程中再讨论。
         Category Miscellaneous 辅助杂类组件。
         Categroy Data Access 数据库类组件(我最讨厌数据库编程了,所以我也不会)。

        步骤2:增加自定义类 CFun(接口 IFun) ,见图三。


      图三、输入类中的各项名称
         其实,我们只需要输入短名(Short Name),其它的项目会自动填写。没什么多说的,只请大家注意一下 ProgID 项,默认的 ProgID 构造方式为“工程名.短名”。

         步骤3:填写接口属性,见图四。

      图四、接口属性

         Threading Model 选择组件支持的线程模型。COM 中的线程,我认为是最讨厌,最复杂的部分。COM 线程和公寓的概念,留待后续介绍。现在吗......大家都选 Apartment,它代表什么那?简单地说:当在线程中调用组件函数的时候,这些调用会排队进行。因此,这种模式下,我们可以暂时不用考虑同步的问题。(注1)
         Interface 接口基本类型。Dual 表示支持双接口(注2),这个非常 非常重要,非常非常常用,但我们今天不讲。Custom 表示自定义借口。 切记!切记!我们的这第一个 COM 程序中,一定要选择它!!!!(如果你选错了,请删除全部内容,重新来过。)
         Aggregation 我们写的组件,将来是否允许被别人聚合(注3)使用。Only 表示必须被聚合才能使用,有点类似 C++ 中的纯虚类,你要是总工程师,只负责设计但不亲自写代码的话,才选择它。
         Support ISupportErrorInfo 是否支持丰富信息的错误处理接口。以后就讲。
         Support Connection Points 是否支持连接点接口(事件、回调)。以后就讲。
         Free Threaded Marshaler 以后也不讲,就算打死你,我也不说!(注4)

    2. 增加的内容 增加的文件:
      Fun.cpp:
      Fun.h:
      Fun.rgs:关于注册值:

       

      ATLCOM.idl文件中增加的内容:

       

      ATLCOM.CPP增加的内容:
      编译后增加的文件:
      ATLCOM_p.c
      dlldata.c
     
  • 添加接口函数
    1. 操作步骤
    2. 增加内容
       

    其它文章索引

    1. 字符串的处理,见 VC知识库第九期 《COM编程入门——第一部分》
    2. 用ATL建立轻量级的COM对,见 VC 知识库第十三期
  • 你可能感兴趣的:(object,Microsoft,null,Class,library,interface)