rainit2006 / C-Program

C# Program knowledge
0 stars 0 forks source link

关于COM #23

Open rainit2006 opened 7 years ago

rainit2006 commented 7 years ago

COM基本概念 https://www.zhihu.com/question/49433640 https://www.zhihu.com/question/53350764 https://www.zhihu.com/question/26704046

-GUID GUID(Globally Unique Identifier全局唯一标识符)它能保证时间及空间上的唯一。 GUID:全局唯一标识符,可以看成是唯一的一个ID,类似于物理网址那样。

-IID:也就是接口的唯一ID。C++中本没有接口的概念,是COM强行引入的,也就是一个类中全部都是纯虚函数,这样的类称为接口(interface),微软甚至定义了一个宏,大概就是这样:#define interface struct;

所有的COM类其实都继承了IUnknown。
但是,我拿个IUnknown接口有毛用啊,我还是需要把它转为我的具体类才行。
假设有个汽车类Car,它继承于ICar,像这样:
IUnknown* pUnk = NULL;
CreateCar(&pUnk);
ICar* pCar = (ICar*)pUnk;
这样,我们拿到ICar指针才有意义。

但是微软认为,直接由用户来转型是不安全的,比如,你怎么知道pUnk一定可以转成ICar*呢。
除此之外,ICar这个类不具有唯一性,我们需要唯一的一个标识符来确定一个类,那么这个标识符就是GUID。类ID就叫作CLSID,接口ID就叫作IID。

我们需要一个转型的函数叫QueryInterface。QueryInterface作为IUnknown中的一个纯虚函数,做的事情其实很简单,判断自己能不能转成某个GUID所指向的类而已。如果不可以,则返回E_NOTIMPL(谢谢 @Gee Law 指出),可以的话返回S_OK,并将转换后的指针作为参数返回
链接:https://www.zhihu.com/question/49433640/answer/115952604
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!”
但是它不一定听话,因为之前给它的命令也许还没有执行完,它会忠诚地等到执行完再回去,当然我们并不关心这些细节。

-DCOM/COM+ DCOM/COM+又把这个规范扩展到了网络上,变成了一个通用的RPC规范。

rainit2006 commented 7 years ago

COM 过时了? https://www.zhihu.com/question/19998748

-COM应用在底层技术了,.net等很多是基于COM技术的。但是.net编程人员不需要必须掌握繁琐的COM技术,他们有更简单方便的实现方法。 新的Windows API基本都是通过COM搞出来的,整套.net和Metro也是建立在COM上面的。COM在Windows里面就跟水厂电厂一样,你自己会直接生产水电吗,这未必。但是你是不可能不用的。

COM的问题和不足: -COM这种意图打通语言边界,进程边界乃至机器边界的设计是非常难以面面俱到的。一个典型的代价是,COM的规范为了适配不同的语言,对象类型的机制非常复杂。如果你用过typelib系列的API的话,就知道对象成员,方法,参数的信息表达是很不直观的,为了考虑语言特性,会有很多兼容设计。嵌套类型想要解析出来也需要下一番功夫。另外还有一个问题,COM需要统一注册,而很多人喜欢用绿色软件往往缺少这个过程导致功能异常。已经删除的软件由于程序员的疏忽也非常容易在注册表里留下垃圾。

一个类似的例子是Android的Binder框架。它要解决的问题跟COM很相似: 1,跨语言:C++、JAVA 2,服务的可见性:组件需要注册到Service Manager 3,线程的安全性:组件自己解决,框架不管 4,调用的权限控制:checkPermission。。。 5,跨进程:Binder Driver

rainit2006 commented 7 years ago

DLL hell http://www.cnblogs.com/mountain-mist/articles/1597877.html 简单地讲, DLL Hell 是指当多个应用程序试图共享一个公用组件(如某个动态连接库(DLL)或某个组件对象模型(COM)类)时所引发的一系列问题。最典型的情况是,某个应用程序将要安装一个新版本的共享组件,而该组件与机器上的现有版本不向后兼容。虽然刚安装的应用程序运行正常,但原来依赖前一版本共享组件的应用程序也许已无法再工作。在某些情况下,问题的起因更加难以预料。比如,当用户浏览某些 Web 站点时会同时下载某个 Microsoft ActiveX® 控件。如果下载该控件,它将替换机器上原有的任何版本的控件。如果机器上的某个应用程序恰好使用该控件,则很可能也会停止工作。

这些问题的原因是应用程序不同组件的版本信息没有由系统记录或加强。而且系统为某个应用程序所做的改变会影响机器上的所有应用程序—现在建立完全从变化中隔离出来的应用程序并不容易。

在 .NET 中,side by side 概念是版本问题的核心。"Side by side" 是在同一台机器上同时运行不同版本的相同组件的能力。

并行执行是在同一台计算机上运行应用程序或组件的多个版本的能力。在同一台计算机上,可以同时安装公共语言运行库的多个版本,还可以同时安装使用运行库的某个版本的应用程序和组件的多个版本。

下图显示了几个应用程序,这些应用程序使用同一计算机上两个不同的运行库版本。应用程序 A、B 和 C 使用运行库 1.0 版,而应用程序 D 使用运行库 1.1 版。 两个运行库版本的并行执行 image

在 Microsoft Windows XP 和 .NET Framework 之前,发生 DLL 冲突的原因是应用程序不能区别同一代码的不同的不兼容版本。包含在 DLL 中的类型信息仅绑定到文件名。应用程序无法知道包含在 DLL 中的类型是否同用来生成该应用程序的类型相同。因此,组件的新版本会覆盖旧版本,并会破坏应用程序。

为消除 DLL 冲突,并行执行和 .NET Framework 提供了下列功能:

按照设计,.NET Framework 1.0 版和 1.1 版可相互兼容。使用 .NET Framework 1.0 版生成的应用程序应当能够在 1.1 版上运行,而使用 .NET Framework 1.1 版创建的应用程序也应当能够在 1.0 版上运行。但是要注意,.NET Framework 1.1 版中添加的 API 功能无法在 .NET Framework 1.0 版中运行。使用 2.0 版创建的应用程序只能在 2.0 版上运行。2.0 版应用程序不能在 1.1 版或更早的版本上运行。