我对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实现的接口。
提前致谢。
答案 0 :(得分:14)
将COM视为二进制兼容的方式,以跨DLL边界共享接口。由于在各种编译器版本之间进行了非标准名称修改,因此无法从DLL轻松导出C ++类。 COM允许一个DLL或可执行文件中的代码,从另一个DLL或EXE创建接口的实现,只要该实现遵循定义的接口和调用约定。这允许COM类用C#编写,并从C ++,Python和许多其他COM感知语言调用。
COM接口只是包含所有纯虚函数并从IUnknown派生的标准C ++类。 IUnknown是一个预定义的接口,所有兼容的COM接口都必须从这个接口派生,提供公共设施,如引用计数和查询对象是否实现特定接口的能力。
希望宣传他们可以创建COM接口实现的事实的DLL通过导出4个函数来实现:
所以回答你的问题:
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对象(即以容忍程序员错误而不是崩溃的方式)。AddRef
/ Release
必须完全按照定义工作,因此当引用计数大于零时,永远不能销毁对象,必须可以使用{ {1}}从任何接口找到QueryInterface
,并从那里返回到原始接口,从任何接口获得的IUnknown
必须始终具有相同的内存地址(所以它可以用于身份比较)。例如:不要在堆栈上创建COM对象,也不要从IUnknown
返回单独的对象(即,具有返回不同接口的QueryInterface
的对象)。QueryInterface
界面超出了我,但他们没有。IString
)