怎么通俗的解释COM组件?

来源:互联网 发布:淘宝如何删除我的回答 编辑:程序博客网 时间:2024/05/08 23:19

https://www.zhihu.com/question/49433640/answer/115952604


作者:灵剑
链接:https://www.zhihu.com/question/49433640/answer/115952604
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

解释不解释也都是死掉了的技术了啊……
COM主要是一套给C/C++用的接口,当然为了微软的野心,它也被推广到了VB、Delphi以及其他一大堆奇奇怪怪的平台上。它主要为了使用dll发布基于interface的接口。我们知道dll的接口是为了C设计的,它导出的基本都是C的函数,从原理上来说,将dll加载到内存之后,会告诉你一组函数的地址,你自己call进去就可以调用相应的函数。
但是对于C++来说这个事情就头疼了,现在假设你有一个类,我们知道使用一个类的第一步是创建这个类:new MyClass()。这里直接就出问题了,new方法通过编译器计算MyClass的大小来分配相应的内存空间,但是如果库升级了,相应的类可能会增加新的成员,大小就变了,那么使用旧的定义分配出来的空间就不能在新的库当中使用。
要解决这问题,我们必须在dll当中导出一个CreateObject的方法,用来代替构造函数,然后返回一个接口。然而,接口的定义在不同版本当中也是有可能会变化的,为了兼容以前的版本同时也提供新功能,还需要让这个对象可以返回不同版本的接口。接口其实是一个只有纯虚函数的C++类,不过对它进行了一些改造来兼容C和其他一些编程语言。
在这样改造之后,出问题的还有析构过程~MyClass()或者说delete myClass,因为同一个对象可能返回了很多个接口,有些接口还在被使用,如果其中一个被人delete了,其他接口都会出错,所以又引入了引用计数,来让许多人可以共享同一个对象。
其实到此为止也并不算是很奇怪的技术,我们用C++有的时候也会使用Factory方法来代替构造函数实现某些特殊的多态,也会用引用计数等等。COM技术的奇怪地方在于微软实在是脑洞太大了,它们构造了一个操作系统级别的Factory,规定所有人的Interface都统一用UUID来标识,以后想要哪个Interface只要报出UUID来就行了。这样甚至连链接到特定的dll都省了。

这就好比一个COM程序员,只要他在Windows平台上,调用别的库就只要首先翻一下魔导书,查到了一个用奇怪文字写的“Excel = {xxx-xxx-xxxx...}”的记号,然后它只要对着空中喊一声:“召唤,Excel!CoCreateInstance, {xxx-xxx-xxxx...}”
然后呼的从魔法阵里面窜出来了一个怪物,它长什么样我们完全看不清,因为这时候它的类型是IUnknow,这是脑洞奇大无比的微软为所有接口设计的一个基类。我们需要进一步要求它变成我们能控制的接口形态,于是我们再喊下一条指令:
“变身,Excel 2003形态!QueryInterface, {xxx-xxx-xxxx...}”
QueryInterface使用的是另一个UUID,用来表示不同版本的接口。于是怪物就变成了我们需要的Excel 2003接口,虽然我们不知道它实际上是2003还是2007还是更高版本。
等我们使唤完这只召唤兽,我们就会对它说“回去吧,召唤兽!Release!”但是它不一定听话,因为之前给它的命令也许还没有执行完,它会忠诚地等到执行完再回去,当然我们并不关心这些细节。

微软大概会觉得自己设计出了软件史上最完美的二进制接口,从今以后所有的第三方库都可以涵盖在这套接口之下。然而历史的车轮是无情的,它碾过那些自以为是的人的速度总是会比想象的更快。Java的直接基于类的接口被广泛应用,开发使用起来远远来的简单,即便偶尔出点问题大家也都想办法解决了,事实证明程序员并不愿意花10倍的编写代码的时间来解决二进制库的版本兼容问题,他们更愿意假装没看见。很快微软也抄了一个.NET托管dll的方案出来,于是纯的二进制接口COM就慢慢被抛弃了。

COM,OLE,ActiveX,OCX,VBScript,历史不会忘记你们的,如果历史忘了,我替历史记住你们。安息吧。

0 0
原创粉丝点击