| 关键词: 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; } |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|