COM学习笔记(一)初识COM

COM--ComponentObject Model,组件对象模型。一向以难学著称,有人曾说过这样的话:世界上只有两个程序员真正理解COM,他们都在微软工作。这句话虽然有点过,但基本上说出了COM确实有些难理解。不过,不用担心,本文并不探求多深多高的技术领域,而是带领大家浏览一下我们的COM,就像本文的题目一样:初识COM。

首先,我们先来了解一下有关COM的概念:

COMComponent Object Model组件对象模型是微软公司的最高级的、包罗万象的二进制通信规范,用于软件组件间跨越多个进程、机器、硬件和操作系统进行互操作。

下面我们来看看COM的一些特点:

在COM中,应用程序不是通过诸如ShowWindow()的API函数进行操纵。程序是由对象组成的,对象向外提供一个或多个接口。接口是一组相关的函数,函数操作他们所属的对象。不能直接访问对象中的数据,而只能通过对象的接口函数访问。学过C++和数据结构的人应该对上述说法并不陌生。

在COM中,没有指向对象的指针这种东西,有的只是指向对象接口的指针。实际上,是指向另一个指针的指针。第二个指针指向一个指针表,表中的指针指向接口成员函数。该指针表称为VTBL。将指针指向对象后,就可以通过调用接口中的成员函数与该对象通信。

如何将指针指向第一个对象呢?可以调用一个返回指向对象指针的COM函数如:CoCreateInstace()
COM对象都提供一个叫IUnknown的接口,该接口包含方法AddRef()Release()QueryInterface()。每个接口都是从IUnknown接口派生出来的。前两个方法操纵一个控制对象使用期限的内部引用计数。当对象第一次被创建时,创建者必须调用该对象的AddRef(),将计数加1。每当其他的用户将一个指针指向该对象时,必须再次调用该对象的AddRef()方法。当用户不再使用对象时,它调用对象的Release()方法,将引用计数减1。当最后一个用户调用对象的Release()方法后,计数值变为0,导致对象释放自己。

下面是AddRef()Release()方法的简单实现:

ULONG IUnknown::AddRef(void)
    {
       m_RefCount++;
       return m_RefCount;
    }

ULONG IUnknown::Release(void)
    {
       m_RefCount--;
       if(m_RefCount==0)
        {
           delete this;
           return 0;
        }
       return m_RefCount;
     }

由于每一个对象都支持IUnknown接口,因此可以通过QueryInterface()来询问对象是否支持您感兴趣的其它接口。接口通过接口ID来标识。

HRESULT IUnknown::QueryInterface(REFIID riid,LPVOID FAR *ppv)
  {
     if(riid==IID_IUnknown||riid==IID_IDropTarget)
      {
        *ppv=(LPVOID)this;
         AddRef();
         Return S_OK;
      }
     else {
     *ppv=NULL;
     return E_NOINTERFACE;
  }

用于唯一地区分COM中条目的标识符是一个被称为GUID(全局唯一标识符)或UUID(通用唯一标识符)。

Typedef struct_GUID
    {
       unsigned long Data1;
       unsigned short Data2;
       unsigned short Data3;
       unsigned char Data[8];
    }GUID;

GUID的取值范围非常大,16个字节可能形成的不同组合为3.4ⅹ10^38。

在COM中传输格式化数据的工作是通过数据对象处理的,数据对象是支持IDataObject接口的对象。IDataObject接口支持以下方法:

IDataObject::GetData
IDataObject::GetDataHere
IDataObject::QueryGetData
IDataObject::GetCanonicalFormatEtc
IDataObject::SetData
IDataObject::EnumFormatEtc
IDataObject::DAdvise
IDataObject::DUnadvise
IDataObject::EnumDAdvise

决定了设计方案以及接口中需要包括的方法和参数后,必须使用接口描述语言(IDL)编写接口的抽象定义。编写好.IDL文件后,使用VC++和PlatformSDK自带得MicrosoftIDL编译器编译,并生成头文件、勇于构建调度借口调用的代理和占为程序的代码以及实现开发工具和调用接口所必需的类型库。

自动化,通过它COM对象可以将其功能提供给解释型客户(如脚本编写语言)而不是编译型客户使用。在开发阶段,当COM接口客户被编译时,编译器读取源代码,通过查阅头文件或类型库中的接口定义将方法名称解析为VTBL条目,并生成目标代码,以便将必须的参数压入堆栈并跳到接口VTBL中相应条目保存的地址。编译过程可能需要很长时间,但编译后运行二进制代码的速度相对较快。而解释型客户在真正执行之前,不会将源代码解析为机器代码。自动化对象通过一个叫做IDispatch的标准接口暴露其所有的功能,而不是将每项功能作为自定义接口的VTBL中的条目来暴露。对对象的任何内部方法的调用都是通过该接口进行处理的。IDispatch接口的方法包括:

IDispatch::Invoke
IDispatch::GetIDsOfNames
IDispatch::GetTypeInfo
IDispatch::GetTypeInfoCount

当客户想调用自动化对象的内部方法时,它调用对象的IDispatch::Invoke()
客户可使用IDispatch::GetIDsOfNames获得想要做事情的ID。

类型库是对象厂商提供的静态数据结构的集合,通过ItypeLib接口进行访问,包含关于单个对象、接口或类的信息。类型库可以包含描述下述内容的信息:

服务器支持的对象类型

·  每个对象方法及其参数和类型

·  每个对象属性及其类型

·  枚举常量值

·  到在线文档中特定条目的引用

COM Language Requirements

Theonly language requirement for COM is that code is generated in a language thatcan create structures of pointers and, either explicitly or implicitly, callfunctions through pointers. Object-oriented languages such as C++ andSmalltalk? provide programming mechanisms that simplify the implementation ofCOM objects, but languages such as C, Pascal, Ada, Java, and even BASICprogramming environments can create and use COM objects.

以上摘自MSDN,重要的是C, Pascal, Ada, Java,and even BASIC都可以用来编写COM。

以上初步介绍了关于COM的一些东西,不多也很浅,理解以上的部分就够花费很长一段时间的了,如果真地对COM感兴趣的话,最好有一定的基础,包括:数据结构,面向对象的程序设计,Windows编程等,不过也不一定都学,只是这些会对你学习COM并在短时间内掌握并深入理解COM会有相当的好处。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值