COM组件基础
##序言
首先了解下组件的概念:
组件的定义:含有可独立性,可通用性,可组合性,可替换性的事物,我们把它称作组件。
##COM
COM是微软组件对象模型的简称(是Component Object Model (组件对象模型)的缩写)。COM组件是可以以二进制的形式发布,具有指定规则的二进制结构,是可以被其它应用程序来调用的。正因为COM具有二进制代码共享的特性,所以它具备了高可开发性、高度可维护性和高度的可移植性(跨开发语言),以至于在Windows上面的诸多应用软件采用了COM来做整体的架构。比如微软的DirectX等。
COM组件的三个优点
- 采用COM组件架构我们的软件,会使我们更方便地进行模块划分,而且各模块独立性高,耦合度低,从而更方便地进行开发任务的分工。(开发性)
- 采用COM组件架构我们的软件,会使我们更方便地维护、升级软件,因为我们可以很方便地直接用新模块替换旧模块,而不影响软件的其它功能。(维护性)
- 采用COM组件架构我们的软件,可以使我们已编写好的功能模块可以很方便地移植到其它平台,如从C++的MFC平台移植到C#的WinForm平台。因为COM组件是跨应用的,可以被C++调用也可以被C#调用。(移植性)
注意:COM组件是完全与编程语言无关的,但是COM组件只能被运行在Windows操作系统平台上面,Linux,Mac不能适用。
##接口
接口的定义:是组件与组件之间,组件与外部事物之间进行交互的协议。
组件与组件,组件与其它设备的交互工作是通过接口进行的。 CPU跟主板之间有固定的接口,内存条跟主板之间也有固定的接口。如果CPU要更换,被更换的CPU必须与旧的CPU拥有相同的使用接口。
主板不直接认识CPU,只认识CPU的接口。主板也不直接认识内存条,只认识内存条的接口。
所以接口的约定是很重要的。在组件的开发之前,必须先约定组件与外界交互的接口协议。
接口协议只要确定后,往往是不能再改变的,比如5号电池不能再做得大一点或再小一点,然后去替换旧的5号电池。
采用组件与接口的思想来开发设备,体现了社会分工的一个现象,也是社会生产力发展的必然过程,做CPU的厂商只管做CPU,不用告诉主板关于CPU本身的实现细节,也不用去了解主板的实现细节。
接口,是一种约定,一种协议。它是抽象的,指明了具体含义,但却没有实现这个定义。
我们看一下C++的纯虚函数:求最大公约数
//求a与b的最大公约数。
virtual int GreatestCommonDivisor(int a, int b) = 0;
这个函数的定义很明确,但没有实现这个含义的具体方法,所以,是抽象的。
我们一般采用interface这个英文单词表示C++中的接口,它在Microsoft Visual Studio 安装目录\VC\PlatformSDK\include\objbase.h中被预定义。
#define interface struct
//接口IX
interface IX
{
virtual void Fx1() = 0;
virtual void Fx2() = 0;
};
//接口IY
interface IY
{
virtual void Fy1() = 0;
virtual void Fy2() = 0;
};
组件是派生于接口的,现在我们定义一个组件CA,它派生于IX和IY
//组件CA
class CA: public IX, public IY
{
public:
virtual void Fx1() { cout << "Fx1" << endl; }
virtual void Fx2(){ cout << "Fx2" << endl; }
virtual void Fy1() {cout << "Fy1" << endl; }
virtual void Fy2() { cout << "Fy2" << endl; }
};
##进阶
1.COM组件的内存结构和C++编译器为抽象基类所生成的内存结构是相同的。因此可以用C++的抽象基类来定义COM接口。
2.COM组件必须继承于最基本的COM接口: IUnknow。
3.IUnknow有三个函数,为别是QueryInterface, AddRef, Release。
interface IUnknown
{
virtual HRESULT QueryInterface(const IID &iid, void **ppv) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};