首页 电脑 电脑学堂 查看内容

COM学习笔记

2009-5-25 11:57 746 0

摘要:       COM(Component Object Model,组件对象模型)是构造二进制兼容软件组件的规范,它不是编程语言、代码库或编译器,而是一...
关键词: nbsp 接口 HRESULT C++ IMyInterface string virtual 指针 对象 查询

      COM(Component Object Model,组件对象模型)是构造二进制兼容软件组件的规范,它不是编程语言、代码库或编译器,而是一个二进制规范,可以建立能够相互通信的组件,而不管这些组件用什么编程语言完成。 COM接口使应用程序和其它组件可以和COM组件的功能进行通信。 COM接口的vtable的唯一要求是表里的第一个字段为IUnknown的指针。它是任何组件变为COM组件必须实现的唯一接口,是所有接口的大门,因为所有其它接口都是从IUnknown继承而来的。 注意:1、接口不是类,不能够被实例化;2、接口不是对象,所有的调用是通过指针完成的;3、接口有唯一性;4、接口是不可变的。 所有的COM接口都有三个同样的方法:QueryInterface:用于寻找对象提供的所有接口。AddRef:使用接口。Release:完成接口的使用后,用此方法释放。 接口的所有方法返回类型为HRESULT,除了IUnknown的AddRef和Release之外。 接口的方法如果有字符串参数,那么必须是Unicode字符串接口描述语言IDL它可以用于定义COM接口,也可以描述自定义的数据结构。对于接口成员函数,可以指定每个参数的类型、输入输出特性,甚至可以支持可变长度数组的描述。例如: interface IMyInterface{  HRESULT func1();  HRESULT func2([in]string);  HRESULT func3([in]string, [out]string*);}; VC中提供的工具MIDL可以将IDL接口描述文件(*.idl)编译成C/C++兼容的接口描述头文件(*.h)。 接口的内存模型以IMyInterface为例,它的C++实现如下: C++代码class IMyInterface    {      virtual HRESULT func1() = 0;      virtual HRESULT func2(string) = 0;      virtual HRESULT func3(string, string*) = 0;    };   相应的COM对象实现则为: C++代码class CMyObject : public IMyInterface    {    public:      CMyObject();      ~CMyObject();      virtual HRESULT func1();      virtual HRESULT func2(string);      virtual HRESULT func3(string, string*);    private:      // 其它的成员    };   此外,还需要实现一个创建COM对象实例的函数以将IMyInterface的接口指针和一个指向CMyObject对象的指针关联起来。这样在调用了该函数对接口指针初始化之后,就可以利用C++继承和多态的特性用借口来访问和操作这个COM对象了。接口描述语言IDL它可以用于定义COM接口,也可以描述自定义的数据结构。对于接口成员函数,可以指定每个参数的类型、输入输出特性,甚至可以支持可变长度数组的描述。例如: interface IMyInterface{  HRESULT func1();  HRESULT func2([in]string);  HRESULT func3([in]string, [out]string*);}; VC中提供的工具MIDL可以将IDL接口描述文件(*.idl)编译成C/C++兼容的接口描述头文件(*.h)。 接口的内存模型以IMyInterface为例,它的C++实现如下: C++代码class IMyInterface    {      virtual HRESULT func1() = 0;      virtual HRESULT func2(string) = 0;      virtual HRESULT func3(string, string*) = 0;    };   相应的COM对象实现则为: C++代码class CMyObject : public IMyInterface    {    public:      CMyObject();      ~CMyObject();      virtual HRESULT func1();      virtual HRESULT func2(string);      virtual HRESULT func3(string, string*);    private:      // 其它的成员    };   此外,还需要实现一个创建COM对象实例的函数以将IMyInterface的接口指针和一个指向CMyObject对象的指针关联起来。这样在调用了该函数对接口指针初始化之后,就可以利用C++继承和多态的特性用借口来访问和操作这个COM对象了。IUnknown IDL描述: interface IUnknown{  HRESULT QueryInterface([in]REFIID iid, [out]void** ppv);  ULONG AddRef(void);  ULONG Release(void);} 构造函数、AddRef、Release的某种实现可能 C++代码class CUnknown : public IUnknown    {    public:      CUnknown();      ~CUnknown();      virtual HRESULT QueryInterface(const IID& iid, void** ppv);      virtual ULONG AddRef();      virtual ULONG Release();    private:      int m_Ref;    };    CUnknown::CUnknown()    {      m_Ref = 0;      // 其它的初始化工作    }    ULONG CUnknown::AddRef()    {      m_Ref++;      return (ULONG)m_Ref;    }    ULONG CUnknown::Release()    {      m_Ref--;      if (m_Ref == 0)      {        delete this;        return 0;      }      return (ULONG)m_Ref;    }   接口查询 QueryInterface可用于获得对象所支持的任何一个接口指针。 HRESULT QueryInterface([in]REFIID iid, [out]void** ppv); iid为查询接口的IID,ppv用来保存查询得到的接口指针。 返回值:S_OK:查询成功完成。E_NOINTERFACE:对象不支持要查询的接口。E_UNEXPECTED:意外错误。 查询原则:1、对于同一个对象的不同接口指针,查询得到的IUnknown接口必须完全相同。2、对一个接口查询自身必须是成功的。3、从第一个接口查询到第二个接口,则从第二个接口查询第一个接口应成功。4、从第一个接口查询到第二个接口,从第二个接口查询到第三个接口,则一定能从第三个接口查询到第一个接口。5、查询借口成功与否应该与时间无关。 QueryInterface的某种实现 C++代码HRESULT CMyObject::QueryInterface(const IID& iid, void** ppv)    {      if (iid == IID_IUnknown)      {        *ppv = (IMyInterface *)this;       ((IMyInterface *)(*ppv))->AddRef();      }      else if (iid == IID_IMyInterface)      {        *ppv = (IMyInterface *)this;        ((IMyInterface *)(*ppv))->AddRef();      }      else if (iid == IID_Another)      {        *ppv = (IAnother *)this;        ((IAnother *)(*ppv))->AddRef();      }      else     {        *ppv = NULL;        return E_NOINTERFACE;      }      return S_OK;    }  
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部