【问题标题】:Why is the COM interface contract immutable?为什么 COM 接口契约是不可变的?
【发布时间】:2015-03-15 23:36:16
【问题描述】:

我在谷歌上搜索了很多,发现没有人愿意解释为什么 COM 接口是不可变的,这很奇怪。我想您无法从 COM 接口中删除任何方法的原因是因为依赖该接口的客户端会遇到错误,这不好。但是,为什么向界面添加新功能会改变这一切呢?这和底层的 vtable 有关系吗?

【问题讨论】:

  • 合同是合同,是合同......
  • 当然,但是向接口添加新方法如何破坏使用 COM 组件的客户端?
  • 你必须提供一个额外的接口。 COM 合同是固定的,不能扩展,而不会破坏您的客户。这是 IDL 编译器的本质。

标签: c++ com


【解决方案1】:

COM 有一个非常严重的 DLL Hell 问题。几个基本原因:

  • 参与编写服务器和客户端代码的程序员很少相互认识,不一起工作并且有自己的发布时间表。
  • 默认情况下,注册服务器是机器范围的,会影响依赖于服务器的每个客户端程序。具有无注册清单的隔离 COM 是一种解决方法。
  • 早期绑定的 COM(使用 v-table)非常有效,但对 v-table 更改极为不容忍。当客户端代码只是调用完全错误的函数或传递错误的参数时,很难诊断不匹配。通过 IDispatch 进行后期绑定的调用是一种解决方法,但速度较慢。
  • COM 程序员作弊的动机非常强烈,更改界面 {guids} 会导致非常脾气暴躁的客户端程序员和尴尬的支持电话。使接口向后兼容相对容易,使其向前兼容永远行不通。只有更改界面 guid 才是真正安全的。
  • COM 服务器的部署通常是客户的职责,他们通常对服务器了解不足,无法解决和纠正问题。

这些是其他通用的版本控制问题,许多运行时实现都遭受了各种痛苦。 COM 的一个特殊优势是您可以对它做一些事情。更改 {guids},很多讨厌的东西都烟消云散了。

【讨论】:

  • “更改 {guids},很多麻烦都烟消云散了”。我同意。我发现您可以通过模板化 C++ 接口类来使 COM 合同接口可变。我现在要做的就是更改我的 IID_T、CLSID_T 和 LIBID_T GUID 模板参数,并添加或更改任何我想要区分我的相关项目的代码。我不仅获得了轻松更改 GUID 的能力,而且还获得了模板化代码重用的好处。您获得的是让界面向不同方向迁移的能力,而不会影响以前发布的版本。
【解决方案2】:

如果您添加一个方法,使用该方法的较新客户端在使用旧版本的组件时会失败。

组件的旧版本不会有新方法,除非您专门添加代码来实现它,重新构建组件,然后在使用该组件的所有机器上重新安装该组件。

如果较新版本的客户端尝试在没有该方法的较旧版本的组件上调用新方法,则会发生未定义的行为(可能会崩溃,但也可能会导致无提示的数据损坏)。新客户端将尝试通过 vtable 中的指针条目调用方法,该指针条目在构建旧客户端时不存在,因此旧客户端将在此位置具有一些不相关的值。

当然,如果您同时控制客户端和组件并将它们部署在一起,这对您来说不是问题,但 COM 设计用于比这更广泛的用例。

【讨论】:

  • 根据接口的本质,“组件的旧版本”不会实现方法吗?还是我们有一些 COM 仍在运行,自接口更新以来尚未重新启动,因此缺少方法?
  • 不知道为什么有人反对我的回答。这是问题正文中所提问题的正确答案。
  • @Amnestic 嗯?如果我使用您的接口创建一个 DLL,然后您更新您的接口,那么我的 DLL 不会神奇地更新以实现新功能!尝试调用新函数的代码只会在我的 vtable 结束后读取内存中的任何垃圾,因为我的 vtable 比“新”接口规范要求的短。
  • @DavidAnderson 有些人不喜欢一句话的答案;也许您可以详细说明一些细节。
  • 我不知道为什么我很难理解,显然我们可以让客户端使用较旧的 COM 和较新的接口。只是我是个白痴。
猜你喜欢
  • 2011-04-09
  • 2012-01-23
  • 1970-01-01
  • 2011-02-25
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
相关资源
最近更新 更多