229199496

COM 基础入门 (一)

前段时间应组织需要,做一ActiveX 插件 , 但是ActiveX是基于COM的,于是打算把COM好好学学,但是COM是老技术了当然也是相当经典的技术,国内的书籍对于COM的介绍相对不是特别的多。小研究了一下,今天写点东西和大家一起学习学习。

 

说道COM首先要引入的是组件模型的概念。那么什么又是组件模型呢?C++相信大家都知道,即使不是C++。 那么C++是基于类对象的思想,对象和组件又有什么不同呢?我们暂且这么理解(深入之后并不止是这么简单) 假设一台带鼠标和外接键盘的笔记本。如果用对象思想来描述笔记本和鼠标以及外接键盘的关系:他们三是连在一起的,接口一旦插上就不能再换别的鼠标了,如果想再换别的鼠标怎么办呢?重新编译笔记本和鼠标以及键盘构成的这个整体(重新返厂修改)。一块铁板上焊接死的原理。

 

这个问题的解决方法之一是接口与实现分离(既是组件思想的一部分)

那么组件思想呢?这里设计到一个重用性,这台带鼠标和外接键盘的笔记本是由电脑这个组件 和 鼠标 和 外接键盘 这三个东西共同构成的。而鼠标和键盘在电脑上是用可拔插的USB进行连接的。那么当我想把滚珠鼠标换成光电鼠标的时候,只需要拔下鼠标的USB,然后换一个光电鼠标重新接上这个接口就完事了,不需要返厂,更不会影响键盘和整个设备的使用。一句话,整个系统由各自不相关的组件组合成,而组件之间用接口连接在系统上。想换什么东西直接对那个组件进行操作就行,别的完全不受影响,只要接口不改变(USB2.0 不会突然改变到 USB3.0)。

插曲如果生产鼠标的厂家自己定义了一组规则(接口规则),而笔记本生产厂家也定义了自己的一组规则,鼠标接口是圆形的,笔记本接鼠标的地方是方形的。怎么办?

于是,万恶的微软站出来了!说:你们现在都听我的!我要求你们生产这些东西都要按照我定的规则! ...于是COM诞生了...

那么有了组件思想之后我们就可以进入COM了。

什么是COM呢?开发语言?不是! 开发模型?不准确!确切的说,COM只是一组规则,人们用这组规则来规划软件的开发,这样到达软件开发组件化的目的。

那么这组规则又是什么呢?这个规则又是用什么来实现的呢?接下来将给大家解释。 由于COM的特殊性,在此先介绍COM思想的实现工具:C++ 然后阐述原理就会更加易懂。

C++最经典的思想之一莫过于多态了,怎么理解多态呢?我们暂时将它理解为一个接口能调用多个不同的对象。而C++的接口思想,给COM的实现奠下了基础。COM的实现多选择C++(VB和其他语言也可以)这是因为C++在内存里的编译出来的结构和COM所描述的很吻合:

C++虚表:

我们可以把这些F函数理解为接口,vtbl为接口指针,当派生类继承了这个接口结构之后(注意定义接口的时候,接口是不占用内存的,只是一个结构而已),派生类实现了这些接口函数,于是,这些接口函数在不同的对象里,就有着不同的内存地址的指向:

那么当把不同的对象值传给vtbl指针的时候,再用vtbl指针调用,就能调出不同对象的接口函数(接口函数相同,但是函数里面的内容不相同)了(实现了多态)。

了解了C++的虚表之后,现在可以进入COM的世界了。

之前我们提到,COM是组件模型的基础,接口也是组件模型的基础,其实COM的所有核心就是接口。我们在后文称为COM接口,COM接口。

C++的接口并使真正的COM接口,他虽然实现了多态,但是没有统一每个组件的接口应该写成什么样...A公司生产一个组件,有3个接口,一个叫张三,一个叫李4,一个叫王麻子,用户(用组件的开发团队)拿到这个组件傻眼了!又得查一遍接口说明等等乱七八糟的东西...此时,微软拿着COM走出来了!说:你们!生产组件用COM规则,每个组件都必须有以下接口作为基础----IUnkown。那么什么又是IUnknow接口呢?顾名思义?不对!其实他的作用和他的名字恰好相反。

每个组件都以IUnknown为最初的接口,然后用自己的接口来继承IUnknow接口。这样,组件用户省了很多事,只需要定义一个IUnknow指针,就能对这个组件的其他接口进行查询和使用。

接下来IUnknow的原型将呈现出来:

我们暂时对第一个接口函数进行说明,这是一个查询接口的函数。参数1为要查询的接口 , 而参数2为指向要查询的接口的指针。

构建以下结构的组件:

如图:

我们只要在CX里实现QueryInterface函数即可:

在这个函数里,保存着组件本身的每一个接口的地址(这些地址对于组件本身而言是可知的。)接下来是客户端的使用情况:

可见,用户没有使用任何的其他接口定义,而只是知道了一个IUnknow接口指针,然后通过这个指针对组件进行操作。那么这样就解决了之前的接口不变,组件实现可以各种变的问题。

现在将整个流程描述一遍:

我开发了一个组件,以IUnknow为标准组件接口,组件用IX , IY两个功能接口,而在组件实现的地方,用IUnknow里的QueryInterface保存好组件的每个接口的地址。现在我把组件发布出去,我的客户定义了一个IUnknow的接口指针,然后用这个指针调出组件IUnknow接口里的QueryInterface函数来查询功能实现的接口,所以他只关心IUnknow接口就足够了。(至于这种保存接口地址的能力,请参照前文的C++虚表的使用)

现在考虑以下情况:

例子组件是我发布的第一期组件,只有IX,IY两个接口和对应的功能,现在我又想给我的组件增加功能,怎么办呢?我只要继续以IUnknow为基接口,重写FX()功能,但是对于客户而言,他所看到的依然是IUnknow,用的也是这个接口!那么客户使用我的组件新功能,只要卸载掉他的软件里旧的组件部分,把新组件放进去,继续使用,他的整个软件不需要一点变动。

这不仅实现了软件的重用,还保证了软件工业化上的接口统一。对于提高软件的开发效率和重用性有很大的帮助。

谢谢大家花时间阅读。 欢迎点评 本人将会第一时间改正。 本文章属于初级入门,很多核心没有叙述,后续COM学习内容将会陆续发布。谢谢支持

posted on 2009-02-18 13:52  Rs  阅读(2678)  评论(13编辑  收藏  举报

导航