【问题标题】:What are the files required for a COM client to connect a COM server (out-of-process scenario)?COM 客户端连接 COM 服务器需要哪些文件(进程外场景)?
【发布时间】:2019-09-17 10:55:54
【问题描述】:

我想了解本文中提到的文件的用途,并将知识链接到我当前的COM服务器和COM客户端场景,以便我可以实现我的COM服务器使用COM服务器:this

我有一个 COM 服务器,它是一个在后台运行的 exe 或服务。现在,我知道有一个继承自 IUnknown 和 IDispatch 的公开接口。此外,我还生成了以下文件:

  1. xxx_i.c 定义了所有的 CLSID 和 IID

  2. xxx_i.h 定义了接口支持的所有方法

  3. xxx_p.c ?

  4. dlldata.c ?

我现在使用自动化方式 IDispatch -> Invoke() 来访问接口方法。虽然这种方式在不使用上述任何文件的情况下似乎可以正常工作,但我仍然想了解它们的用途,同时使用常规方式 IUnknown -> QueryInterface() 来访问这些方法。

由于我是 COM 世界的新手,任何建议阅读都将不胜感激!谢谢!

【问题讨论】:

  • @HansPassant 谢谢!由于我没有足够的声誉来评论该帖子,因此我需要您的建议。根据那篇文章,似乎 include _i.h 只需要自己处理“编组”,但 include .tlb 不需要。我的解释正确吗?
  • 类型库是为使用服务器的程序员准备的。创建服务器时,您将使用 .h 文件。编组是代理/存根的工作,它是由两个 .c 文件构建的。明智的做法是使用 Visual-C++ 中的 ATL 项目模板以及类向导,所有这些东西都会自动整理出来。
  • @HansPassant 1. .h文件不是MIDL编译器生成的吗? “创建服务器”是什么意思? 2.如果我使用tlb,我必须先为客户端生成代理/存根吗?如果是这样,为什么我在客户端上使用 .h 文件仍然有效?
  • 1.是的。 “COM 服务器和 COM 客户端”,即服务器。 2. 如果接口足够简单并且您正在处理所需的注册表项,则客户端可以使用 tlb 进行编组,但效率不高。如果它是用 C++ 编写的,则只能在客户端中使用 .h 文件,类型库几乎可以被任何语言使用。即使您使用 C++ 作为客户端,您仍然倾向于使用#import,自动生成的包装器非常好。

标签: c++ com msdn idispatch iunknown


【解决方案1】:

阅读材料的请求超出了 StackOverflow 的范围,但我不禁推荐 Don Box: Essential COM 的开创性工作,该工作已印刷并在其他地方作为电子书提供。以下是 Don 对该主题的描述:

盒子,唐。基本 COM。 Addison-Wesley,1998 年,第 350 页:

COM 基于具有先验知识的客户端程序 接口在开发时的定义。这是完成的 通过 C++ 头文件(用于 C++ 客户端)或通过类型 库(用于 Java 和 Visual Basic 客户端)。一般来说,这不是 一个问题,因为用这些语言编写的程序通常会通过 部署之前的某种编译阶段。一些语言 不要在开发时经历这样的编译阶段,并且 而是以源代码形式部署以在运行时进行解释。

也许最普遍的此类语言是基于 HTML 的脚本 在 Web 浏览器或 Web 服务器的上下文。在这两个 在这种情况下,脚本文本以其原始形式存储在 HTML 文件中, 并且周围的运行时动态执行脚本文本作为 HTML 被解析。为了提供丰富的编程环境,这些 环境允许脚本调用 COM 对象上的方法,这些方法可能 在脚本文本本身或可能在 HTML 的其他地方创建 流(例如,也是网页一部分的控件)。在这些 环境中,目前无法使用类型库或 为运行时引擎提供描述的其他先验手段 正在使用的接口。这意味着对象本身 必须协助口译员将原始脚本文本翻译成 有意义的方法调用。

允许从 解释性环境,例如 Visual Basic Sc​​ript 和 JavaScript, COM 定义了一个接口来表达 解释。


Tl;dr:在 COM 中有两种方法可以做任何事情(忽略 IInspectable 和双接口):

  1. IUnknown
    标准虚方法调用。快速,无需额外代码。需要客户端调用的编译时接口信息(.h 或 .tlb)
  2. IDispatch
    “后期绑定”。缓慢,大量的解释代码。无需客户端编译或接口规范。

实际上,除非您从 VBA、VBScript 调用或有一些旧的 VB6 客户端,否则最好只使用IUnknown

【讨论】:

  • 感谢您的回复!现在我让我的 com 客户端只使用 xxx_i.h,但我仍然不知道如果没有像 .tlb 文件中的任何 coclass 定义,它是如何工作的?
  • 而且 xxx_i.h 也缺少像 xxx_i.c 中的 UUID 定义。客户端如何正确地向服务器发送和接收?
  • 仅使用接口定义,您可以通过将调用结果转换为CoCreateInstance 或其他工厂或接口检索机制(例如,运行对象表)来调用com 服务器。 CoClasses 只是调用方构造,使实例化和 QueryInterface 更容易。 COM 是一个传递接口引用的系统——而不是类引用。
【解决方案2】:

在最简单的形式中,COM 只是vtable 二进制合约加上所有接口之母:IUnknown。 COM 是一种无需源代码即可重用代码的方法,使用 组件,它是某种动态转换机制。如果我知道你支持的类(CLSID),它们公开的接口(@98​​7654324@),以及这些接口的方法布局、参数、顺序、类型等,我可以使用你的 COM 服务器.

但是为了简化 COM 客户端和 COM 服务器之间的“通信”,您可以/应该使用一些标准机制/文档并添加工具,以便无需任何努力即可处理诸如编组(=序列化)之类的管道工作。这在进程外的情况下至关重要,对进程内的情况不太重要(我将在这里避开“公寓”的概念......)

因此,您会在 COM 中找到很多东西(如注册、工具、IDL、类型库等)实际上是可选的,但也非常有用(因此它们最终会成为强制性的)。 idl(用于“接口语言定义”)之类的东西的目的是定义并向您的 COM 客户端公开您的 COM 服务器支持的内容,以便工具可以为您和您的客户端自动生成大量代码(.c、.h , .tlb)。请注意,如果没有在 idl 中定义它们,没有什么可以阻止您实现接口或 coclass。没有任何义务要求您提供 .idl 或 .tlb。在这种情况下,只有知道它们的 IID、方法布局等,我才能使用它们。

然后,在IUnknown 之上,Microsoft 创建了一个名为IDispatch 的通用接口(这也称为“自动化”或“后期绑定”,而不是IUnknown 的“早期绑定”),位于当时针对 VB/VBA 客户端(甚至在 VBScript、JScript 和许多其他 COM 客户端之前,.NET 支持 IUnknown 和 IDispatch)。 IDispatch,如果你走这条路,可能是你必须实现的最后一个接口,因为它的语义允许完全发现和调用任何方法,只要它支持一组有限的已定义数据类型,“自动化类型":BSTR、VARIANT 等。

所以,如果你支持IDispatch,提供一个 TLB(类型库)并将所有类型限制为自动化类型,那么你不需要处理封送处理,你不需要代理和存根,你可以忘记所有这一点,即使在进程外的情况下也是如此,因为 Microsoft 会自动实现这一点。过去,我们习惯将“oleaut32.dll”称为“通用封送器”。

双接口是同时支持IUnknown 和派生类以及IDispatch 的接口。它们的存在主要是为了同时支持 C/C++ 客户端自动化客户端。在 C/C++ 中使用自动化(BSTR、VARIANT 等)有点痛苦,因为它们最初不打算由 C/C++ 客户端使用……注意微软提出了 C++ 智能包装类:CComBSTRCComVARIANT使用 ATL,或 _variant_t_bstr_t 使用 Windows SDK。

【讨论】:

  • 感谢您的解释!关于第三段,假设使用 IUnknown,我是否必须自己处理编组?如果是,它是否也与代理和存根有关?
  • 一般来说,如果您使用相关工具,您很少需要自己处理编组。例如,当使用 Visual Studio 时,它将构建代理和存根项目(或包含在主项目中的文件)。这些将进行编组。如果您使用 TLB、IDispatch 和限制为自动化类型,这些代理存根是无用的,但在 IUnknown 场景中使用。如果您使用零工具(例如没有 Visual Studio,没有 IDL/MIDL)并且想要在进程外进行,是的,您必须自己构建所有这些(不建议这样做)
猜你喜欢
  • 2014-02-18
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
  • 2013-10-30
  • 2017-08-30
  • 2013-01-20
  • 2012-09-06
  • 1970-01-01
相关资源
最近更新 更多