我目前正在学习COM技术。我发现COM DLL在传统DLL架构的基础上进行了扩展。当我们创建COM DLL时,仍然依赖于传统的DLL导出方法,以便找到内部COM组件。
如果COM是用于在二进制级别重用组件,我认为传统的DLL也可以实现相同的功能。它们都公开函数,它们都是二进制的,那么转向COM的意义何在呢?
目前,我感觉传统的DLL以“平面”方式公开方法,而COM DLL则以“面向对象”的层次结构方式公开方法。面向对象的方式似乎更好。这是否是COM盛行的原因?
非常感谢。
我目前正在学习COM技术。我发现COM DLL在传统DLL架构的基础上进行了扩展。当我们创建COM DLL时,仍然依赖于传统的DLL导出方法,以便找到内部COM组件。
如果COM是用于在二进制级别重用组件,我认为传统的DLL也可以实现相同的功能。它们都公开函数,它们都是二进制的,那么转向COM的意义何在呢?
目前,我感觉传统的DLL以“平面”方式公开方法,而COM DLL则以“面向对象”的层次结构方式公开方法。面向对象的方式似乎更好。这是否是COM盛行的原因?
非常感谢。
不,它们有很大的区别。COM拥有明确定义的协议用于创建对象、公开方法、管理内存、发布类型信息、管理线程等方面。几乎所有编程语言都支持使用COM服务器。
如果直接暴露你自己的函数,则无法获得这些功能。这种方式可能只能在使用C/C++编写的程序中使用(因此可以读取头文件),还要使用完全相同版本的C++编译器,并且存在各种互操作问题。暴露像std::string这样的C++类对象就不安全了。既不能保证内存布局兼容,也没有任何内存所有权协议。
虽然它可能更符合面向对象编程(OOP)的特点,但是COM不支持继承,因为在二进制级别上实现OOP非常困难。这个问题需要所有代码都采用运行时支持,例如.NET和Java的虚拟机。
COM DLL是一个具有特定COM入口点的DLL。COM公开了用于创建COM对象的类工厂,因此需要一种获取由COM服务器实现的类工厂的方法。这就是DllGetClassObject的作用。此外,COM DLL是自注册的:它们可以通知Windows可用的类和接口。让DLL自行注册的入口点是DllRegisterServer。
还有一些其他的入口点,但它们大致如此。
如果没有明确定义的DllRegisterServer入口点,客户端将无法使DLL自行注册。这将使安装COM组件更加复杂。
如果没有标准化的入口点来获取类工厂,则每个DLL都必须定义自己的入口点,而该信息必须放在Windows注册表中,以便COM基础结构知道如何访问每个DLL的类工厂。没有必要增加额外的复杂性,因此也标准化了该入口点。
至于COM与“C”之间的区别,主要区别在于合同的概念。COM鼓励程序员从模块之间的抽象接口出发思考,而不是分层、自上而下的功能分解。这是一种“面向对象编程”的方式,但IMO这个术语太宽泛了,用处不大。面向合同的方法对于像C/C++这样的强类型、静态链接的语言有着多方面的优点。
DLL在Windows中有许多用途,其中许多类型的库代码存储在DLL中。例如, .net assemblies 就是其中一种不同的东西。
COM DLL不比“普通二进制PE DLL”更好,因为COM DLL也是一个普通的DLL。将DLL变成COM DLL的原因是要暴露某些导出项(查找条目IUnknown),这些导出项匹配特定的契约(签名),或者甚至是多种经过规范化的接口(查找条目“dual interface”), 这允许在DLL内部实例化特定对象以及自动发现服务,包括功能名称和参数类型。
由于双重接口使得链接到脚本语言(在Web、shell脚本、教育程序等中使用)非常方便。由COM DLL公开的双重接口允许脚本运行时查询它所期望的确切类型并执行相应的强制转换,对用户来说无缝地完成。
这种灵活性使得整个巨大的COM基础设施被构建起来,包括组件注册、DCOM(网络调用)等。它使得将COM接口提供给windows组件(例如WMI)和Office组件变得相当方便。许多其他流行的接口都是在COM之上实现的,例如ADO等。
尽管如此,COM在任何意义上都不是“占主导地位”的。COM DLL仅是 DLL 的一小部分。 普通DLL和.NET DLL非常受欢迎。 Microsoft认为.NET接口优于COM。许多Unix狂热者和其他人认为DLL完全是个坏主意,因为它无法像Unix共享对象那样提供运行时链接服务。尽管我是一个Windows开发人员,但我也认为SO提供了更好的替代方案,并希望未来能够使用他们。