有关COM的新手问题

时间:2010-03-27 01:06:12

标签: c++ com dll

我对COM很陌生,所以这个问题可能看起来很幼稚。

Q1。关于Windows DLL

根据我的理解,Windows DLL可以导出函数,类型(类)和全局变量。这种理解是对的吗?

Q2。关于COM

我天真的理解是:COM DLL似乎只是一种新的逻辑方式来组织标准Windows DLL导出的函数和类型。 COM DLL导出两个函数,如 DllRegisterServer() DllGetClassObject(),以及实现 IUnknown Classes em>界面。这种理解是对的吗?

Q3。 * .def& *的.idl

* .def用于定义Windows DLL以传统方式导出的函数,例如 DllGetClassObject()。    * .idl用于定义COM coclass实现的接口。

提前致谢。

3 个答案:

答案 0 :(得分:14)

将COM视为二进制兼容的方式,以跨DLL边界共享接口。由于在各种编译器版本之间进行了非标准名称修改,因此无法从DLL轻松导出C ++类。 COM允许一个DLL或可执行文件中的代码,从另一个DLL或EXE创建接口的实现,只要该实现遵循定义的接口和调用约定。这允许COM类用C#编写,并从C ++,Python和许多其他COM感知语言调用。

COM接口只是包含所有纯虚函数并从IUnknown派生的标准C ++类。 IUnknown是一个预定义的接口,所有兼容的COM接口都必须从这个接口派生,提供公共设施,如引用计数和查询对象是否实现特定接口的能力。

希望宣传他们可以创建COM接口实现的事实的DLL通过导出4个函数来实现:

  • DllGetClassObject =>返回所请求接口的类工厂
  • DllCanUnloadNow =>是否所有发放的实例都已发布
  • DllRegisterServer =>注册此DLL在注册表中提供的类型
  • DllUnregisterServer =>从注册表中取消注册此DLL及其类型

所以回答你的问题:

  

Q1。关于Windows DLL根据我的理解,Windows DLL可以导出函数,   类型(类)和全局变量。这种理解是对的吗?

DLL可以导出函数和类(不确定全局变量,但你不想导出它们,即使你可以!:-))但是,导出的类将被命名为mangledled,因此只能被其他类使用碰巧具有相同名称的DLL或EXE(不是开展业务的好方法)。具有C风格调用约定的函数没有名称损坏,因此可以从其他地方导出和调用而没有问题。

  

Q2。 COM DLL导出两个函数,如DllRegisterServer()和DllGetClassObject(),   以及实现IUnknown接口的类。是这种理解吗?   正确?

中途,有4个函数可以导出为完全符合COM的DLL(如上所示)。您可以在MSDN中搜索任何这些名称,以查看它们的完整签名。您对DllGetClassObject的实现将是外部各方将使用的主要实现。他们可以使用它来获取DLL提供的接口的IClassFactory,然后使用它来创建实例。

COM是一个庞大而复杂的野兽,但其基础相当简单。您还可以查看此链接COM Intro以获取更多信息。祝好运!

答案 1 :(得分:5)

要添加到cpalmer的好答案,没有特别的理由需要使用注册表和四个推荐的函数从DLL导出COM。

您可以使用无注册表的COM或COM-lite方法,只需导出工厂方法,例如

__ declspec(dllexport)void MyDllCreateFoo(IFoo ** ppFoo);

DLL用户会调用你的工厂来创建实现IFoo的类CMyFoo。什么DllRegisterServer等。人。 do允许在注册表中查找CMyFoo和其他类,等等。

第三季:事实上你是正确的,如果不是精神上的话。 .def文件和.idl文件是完全不同的野兽。 .def文件仅由链接器使用,甚至不需要 - 您可以导出所需的所有功能 __declspec(dllexport)void foo(){ }

在C ++代码中。

.idl文件用于生成C ++标头(.h文件),DLL和它的客户端都包含这些标头。它生成接口以及一些粘合代码,用于执行参数编组等操作。

同样,你不需要使用IDL来使用COM,但它可以使事情更方便。

我这样打破它的原因是为了说明COM不是一个很大的整体事物,而是一个非常小的东西,周围有很多东西可以选择使用,或者不是,尝尝。

答案 2 :(得分:4)

到目前为止,你完全正确。我要澄清的唯一一点是“实现IUnknown接口的类”。类由实现IClassFactory接口的对象表示。您可以通过在DLL中调用DllGetClassObject来获得这样的类工厂,然后您可以要求类工厂创建该类的对象。这与许多其他面向对象的系统类似:有许多对象代表类,可用于制造实例。

关于COM的其他有用的事实:

  • 有一个小而复杂的辅助函数库,大多以前缀Co命名。这些实际上加载DLL,找到导出的函数并调用它们。客户端代码通常不会直接调用DLL导出(尽管为简单的进程内COM对象编写自己的托管系统是一件相当简单的事情。)
  • 有一个重要的接口IDispatch,它添加了另一层抽象,以便可以动态识别调用对象的方法,使用字符串查找方法并传递参数值数组。这允许脚本语言安全地调用COM对象(即以容忍程序员错误而不是崩溃的方式)。
  • 有一个更复杂的“编组”系统,允许从其他线程,其他进程甚至其他计算机调用对象;在其远程(和安全感知)的形式,它被称为DCOM。它在其他COM使用的规模上没有成功。
  • 跨进程支持是OLE2的基础,这是20世纪90年代早期每个应用程序都急于支持的噱头,其中大多数都错误地实现了(非常复杂的)接口,因此崩溃到处都是。
  • 更成功的是OLE控件,它在技术上更简单(不使用编组),并提供了扩展Visual Basic的方法。
  • 至少有一个广泛分布的COM启发式系统与COM不兼容,但它共享完全相同的概念(至少是简单的东西),它被称为XPCOM,是Mozilla Firefox Web浏览器的基础。 / LI>
  • 如果你普遍使用COM,你将有一个很好的方式与.NET框架集成,因为它包括与COM的卓越互操作性。但是你必须严格遵循COM的规则:AddRef / Release必须完全按照定义工作,因此当引用计数大于零时,永远不能销毁对象,必须可以使用{ {1}}从任何接口找到QueryInterface,并从那里返回到原始接口,从任何接口获得的IUnknown必须始终具有相同的内存地址(所以它可以用于身份比较)。例如:不要在堆栈上创建COM对象,也不要从IUnknown返回单独的对象(即,具有返回不同接口的QueryInterface的对象)。
  • COM的一个主要问题是它至少有两种表示字符串的标准方法。两者都不使用引用计数。为什么他们从未定义过QueryInterface界面超出了我,但他们没有。
  • 如果您尝试编写没有智能指针来保存引用的COM代码,或者没有基类来帮助您实现接口,那么您将会疯狂。 IString