扩展 MIDL 接口和 COM 对象设计

2023-12-23

我读过有关各种 COM 设计模式的详细信息COM 程序员的食谱 http://msdn.microsoft.com/en-us/library/ms809982.aspx以及一些相关的 SO 线程,特别是讨论组合与多重继承的线程 https://stackoverflow.com/questions/3613491/c-com-design-composition-vs-multiple-inheritance。可能是因为我对 C++ 和 COM 都太陌生,所以我可能会错过各种来源中提出的观点,所以这是我用一句话表达的问题:

我可以扩展 MIDL 生成的接口以供 DLL 内部使用吗?如果可以,在给定 MIDL/COM 限制的情况下,如何正确处理钻石问题/并行层次结构?

肮脏的细节...

希望能帮助其他人找出我的困惑所在,以下是我的假设:

1)COM不支持虚拟继承,只允许通过接口进行多重继承。

2)即使COM看不到它,只要我不希望COM直接公开它,那么使用不受支持的C++继承就不应该是非法的。

3)因为MIDL只允许接口的单一继承,如果我有一个并行的层次结构,我需要将它们聚合到组件类中。

4) MIDL 似乎没有声明 coclass 本身,因此我需要编写一个 .h 文件来声明实际的类,在那里,我可以根据需要进行扩展,并理解 COM 使用者无法使用它(这没关系)。

我想要做的是拥有一个处理大部分实现细节并将某些特定功能委托给子类的基础对象(我尚未决定它是否是抽象的,但我认为现在会是抽象的)。客户端通常会使用子类。所以,

项目.idl

import "oaidl.idl"
import "ocidl.idl"

[
  object,
  uuid(...),
  dual,
  oleautomation
]
interface IBase : IDispatch {
   //stuff I want to show to COM
};

[
  object,
  uuid(...),
  dual,
  oleautomation
]
interface IChild1 : IBase {
   //stuff (in addition to base) I want to show to COM
};

[
  object,
  uuid(...),
  dual,
  oleautomation
]
interface IChild2 : IBase {
   //stuff (in addition to base) I want to show to COM
};

[
   uuid(...),
   version(...),
]
library myproject {
   importlib("stdole32.tlb");
   interface IBase;
   interface IChild1;
   interface IChild2;
   [
      uuid(...),
   ]
   coclass Base {
      [default]interface IBase;
      interface IOle*; //include other IOle* interfaces required for the functionality
   };
   [
      uuid(...),
   ]
   coclass Child1 {
      [default]interface IChild1;
      interface IOle*; //those are delegated to the base members
   };
   [
      uuid(...),
   ]
   coclass Child2 {
      [default]interface IChild2;
      interface IOle*; //those are delegated to the base members
   };
};

base.h

#include base_h.h //interfaces generated by MIDL

// I assume I need to re-include IOle* because IBase has no relationship
// and C++ wouldn't know that I want the object base to also have those
// interfaces...
class base : public IBase,
             public IOle* {
    //handle all IUnknown, IDispatch and other IOle* stuff here
    //as well as the common implementations as appropriate
};

child1.h

#include base.h

//I'm not sure if I need to re-include the IOle* interfaces...
//I also assume that by inheriting base, child1 also inherits its interface
class Child1 : public Base,
               public IChild1 {
  //specific details only, let base handle everything else.
};

child2.h

#include base.h

//I'm not sure if I need to re-include the IOle* interfaces...
class Child2 : public Base,
               public IChild2 {
  //specific details only, let base handle everything else.
};

从概念上讲,创建一个新的 child* 对象总是意味着创建基对象,因为需要基对象来处理实现细节,所以我认为让基对象处理 QueryInterface 和引用计数也是合适的,但我很困惑分以下几点:

1) 编译器抱怨由于并行层次结构导致成员不明确; IUnknown 从我的自定义接口和附加 IOle* 接口中重新实现了多次。文档表明,预计每个对象实际上只需要一个实现,但我不清楚如何解决编译器的问题,并且我觉得进行强制转换在某种程度上是错误的?我还想知道我是否应该让所有接口都被虚拟继承seems对于 C++ 来说是有效的,尽管 COM 不会没有这样的理解,但它也不应该关心(?)。

2) However, if I do declare all of inherited interfaces as virtual in the .h files, compiler then complains that inherited members are not allowed when I try to implement QueryInterface in the Base class.cpp. I've googled on that error but am not clear what it is trying to tell me here.

编辑:我回答了我自己的问题。英特尔有文档 http://software.intel.com/en-us/articles/cdiag341/对于这个错误,我最初没有单击链接,假设它可能不适用于 Visual Studio。无论如何我希望我这样做,但现在我明白为什么我会收到此错误,因为我试图在 Base:: 中执行所有实现,而不是 IUnknown:: 或 IDispatch:: 。现在这就引出了一个新问题,它可能会澄清我最初的主要问题——如果可能的话,我如何将实现从 IUnknown (和其他)推迟到 Base 并仅从 Base 工作?看来,如果我只使用 IUnknown::xxx,它就不再可以访问 Base 的私有成员,这似乎是合理的预期,所以这可能不是我想要的。我尝试将除基础接口之外的所有其他接口声明为虚拟接口,但这并没有真正实现。 (同样,这可能是我的经验不足,没有看到明显的解决方案。)

3)Base的QueryInterface无法将base转换为子接口,这是一个合理的抱怨,所以我认为无论如何我都必须为所有子接口重新实现QI,但是一旦我确定请求的接口不是子接口,我就可以将其委托回base的QI。奇怪的是,编译器坚持认为 child* 类是抽象的,因为缺少 IUnknown 和 IDispatch 的成员,但基类是否已经实现了,因此子类也应该具有这些成员?

各种编译器错误让我担心,我对语言和框架中的任何一个或两者都缺乏经验,这导致我对如何设计 COM 对象和继承层次结构以及实现细节做出了有缺陷的假设,我在这里肯定遗漏了一些东西。任何指点,甚至是打在头上的一记耳光,都将不胜感激。

Thanks!


您在这里的想法是正确的,您所缺少的只是在最派生的类中解决一些松散的问题。作为一名 COM 开发人员,您希望类对象上的所有 AddRef/Release/QI 实现都是相同的;但面向 C++ 的编译器不知道这一点,因此将它们视为可能是独立的。这里的两个 impl 是 Base 中的一个和您添加的任何接口中的一个。

在这里直接设置编译器非常简单:在最派生的类中,重新定义所有 IUnknown 方法,并将它们定向到适当的基类 - 例如。

class ChildX: public Base,
              public IChildA
              ... more COM interfaces if needed ...
{
    ...

    // Direct IUnknown methods to Base which does the refcounting for us...
    STDMETHODIMP_(ULONG) AddRef() { return Base::AddRef(); } 
    STDMETHODIMP_(ULONG) Release() { return Base::Release(); } 
    ... suggest implementing QI explicitly here.
}

这基本上是说,所有名为 AddRef 的方法,无论它们如何在 ChildX 中结束,都将获得特定的实现。

在这里直接实现 QI 最简单,并且只将 AddRef/Release 委托给 Base。 (从技术上讲,Base 可以使用 static_cast 转换为 Child,但是您需要在 Child 完全定义后将代码放入函数中;但是,不建议这样做,因为基类很少有充分的理由了解从它派生的类。)

其他需要注意的事情:确保 Base 声明了一个虚拟 dtor - 即使只是空的,这样当 Base 在 ref 变为 0 时执行“删除此操作”时,它将调用派生类和任何资源中的 dtor他们分配的内容得到适当的清理。另外,请确保引用计数正确,并且在需要时确保线程安全;查看任何关于 COM 的优秀介绍书籍(例如“Inside Distributed COM”,尽管有这个名称,但都是以普通 COM 开头),看看其他人是如何做到这一点的。

这是 COM 中非常常见的习惯用法,许多框架使用 #define 宏或派生更多的模板类来添加到最派生类的 AddRef/Release/QI(如 MFC 所做的),然后将它们委托给处理大部分内务工作的著名基类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扩展 MIDL 接口和 COM 对象设计 的相关文章

  • pywin32:如何从进程句柄获取窗口句柄,反之亦然

    两个用例 枚举窗口 然后获取每个窗口的进程句柄 枚举进程 然后获取每个进程的主应用程序窗口句柄 枚举窗口 然后获取每个窗口的进程句柄 您需要这些 API win32gui EnumWindows http timgolden me uk p
  • C++ 将控制台文本颜色设置为 RGB 值

    我想将控制台的文本颜色设置为 RGB 颜色 我创建了一个函数来获取控制台的 ColorTable 并更改其中的颜色 但它不起作用 我不知道如何将文本颜色设置为颜色表中的值 因此我只是更改整个颜色表 但它没有执行任何操作 void setCo
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 查找给定城市的 UTC 偏移量

    在 Windows 上的 C 中 给定一个城市 比如伦敦 纽约 悉尼或新加坡等 我如何找到每个城市的 UTC 偏移量 即该函数应该能够接受城市名称并返回 UTC 偏移量当前的情况 即考虑夏令时 任何想法如何使用 win32 API 来完成此
  • 从 SinkWriter 或 ICodecAPI 或 IMFTransform 获取编码器名称

    我使用 SinkWriter 来使用媒体基础对视频进行编码 初始化 SinkWriter 后 我想获取它使用的底层编码器 并打印出它的名称 这样我就可以看到它使用的编码器 就我而言 编码器很可能是H 264 视频编码器 http msdn
  • 如何在 Rust winapi 编程中使用 COM VARIANT?

    我正在尝试转换C COM 代码 https technet microsoft com pt br aa382113 v vs 71 for TaskSchedulerRust 并坚持VARIANT的论证ITaskService Conne
  • 当应用程序继续运行时,如何清理 .NET 中的 COM 引用?

    我正在开发一个 NET 程序 该程序启动 Excel 的新实例 执行一些工作 然后结束 但必须让 Excel 保持运行 稍后 当程序再次运行时 它将尝试挂钩到前一个实例 在这种情况下处理 COM 对象释放的最佳方法是什么 如果我第一次没有对
  • 如何从更高级别启动用户级别的 Exe

    我希望一个进程始终在用户级别运行 当它由以管理员级别运行的安装程序 自定义 而不是 msi 启动时 或者当用户登录时 环顾四周 我不确定这是否可能 最简单的方法是有 2 个进程 一种是普通用户 它启动提升 管理进程 然后管理进程可以使用 I
  • 枚举 EMF 时丢失文本

    我在列举发票 emf http www mediafire com kdjwvvo7odyvwa6并将其复制到另一个但文本丢失了 令人惊讶的是 当我将其输出到窗口时 它绘制得非常完美 int CALLBACK EnhMetaFileProc
  • 如何从系统属性获取Windows操作系统环境变量

    我遇到一个关于系统属性环境变量的奇怪问题 如你所知 我们可以打开Computer gt Property gt Advanced System Settings gt Advanced gt System Environment Varia
  • 如何将IDL导入到Delphi中?

    我如何导入接口定义语言 idl 文件存入Delphi 将类型和接口转换为 pascal 文件 我试过了 File Open 它只显示 idl 文本文件的文本 Project 添加到项目 它只是 就像 添加了一个 idl文本文件到项目 成分
  • 寻找示例项目和“如何创建”VB6 Activex EXE

    我正在学习如何创建 VB6 Active X EXE 我需要为许多 VB6 应用程序添加 打电话回家 到服务器的功能 我想集中此功能 但不想使用 DLL 来实现 因为我只想需要防火墙权限one程序 phone home ActiveX EX
  • 如何从 Java 访问 Windows 设备管理器中的信息?

    我有一个串行 USB 设备 并且其中多个设备可以连接到计算机 我需要查询和检索设备连接到的 COM 端口列表 在 Windows 设备管理器中 您可以获得当前连接的设备的 COM 端口 友好名称 该列表是动态的 从注册表中读取不工作 htt
  • PHP 和 ADODB 连接失败

    我的任务是迁移服务器 这包括移动我没有构建的应用程序 其中一些具有 ADODB connection 我似乎无法在新服务器上修复它 我只得到空白屏幕 我已经对 ADODB connection 与 PHP 进行了相当广泛的研究 但找不到明确
  • 如何拥有程序执行时间的控制台?

    我正在尝试编写一个在控制台或 GUI 模式下工作的程序 具体取决于执行参数 我已经成功编写了以下示例代码 using System using System Collections Generic using System Linq usi
  • 有没有其他方法可以在delphi上观看youtube视频?

    我看到http www delphiflash com demo youtube video http www delphiflash com demo youtube video关于如何在 delphi 上加载 flash 视频 但它不是
  • 如何使用 DirectWrite 平衡面向脚本的 OpenType 功能与其他 OpenType 功能?

    全面披露 我正在开发 libui GUI 框架的文本 API 它包装了 Windows 上的 DirectWrite OS X 上的 Core Text 以及其他 Unix 上的 Pango 使用 HarfBuzz 进行 OpenType
  • 原子 x86 指令与 MS 的 InterlockedCompareExchange 文档的对齐要求?

    微软提供了InterlockedCompareExchange http msdn microsoft com en us library ms683560 28VS 85 29 aspx用于执行原子比较和交换操作的函数 还有一个 Inte
  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • Win32:是否可以构建一个容纳其他应用程序的应用程序?

    我想知道 您将如何编写一个基本上包含其他应用程序的应用程序 我问这个问题的原因是我想构建一个应用程序来 征服 我目前打开的窗口数量激增的情况 我以前使用过虚拟窗口管理器 它们非常好 但是我可以使用我提到的应用程序做很多事情 或者 有人知道有

随机推荐

  • GetExternalLoginInfoAsync 返回 null dotnet core 2.0

    我正在尝试使用 dot net core 2 0 设置 Facebook 身份验证 但在我的ExternalLoginCallbackAsync 方法中 我总是得到 null 作为响应 我已遵循文档 到目前为止 这就是我所做的 在我的Con
  • 在 Eclipse Mars 中将 m2e 降级到 1.5 版本

    我有个问题 我需要在 Eclipse Mars 中使用 Maven 2 x 它有 m2e 1 6 不支持 Maven 2 x 我必须将 m2e 降级到 1 5 版本 但我不知道如何 不可能在 Eclipse 中卸载它 我从包含 m2e 文件
  • Hyperledger Fabric v1.0 上的隐私

    您能否解释一下 Hyperledger Fabric v1 0 中的一些隐私机制 那些已经实现的以及计划在未来实现的机制 我知道渠道就像单独的区块链 我还浏览了该文档https jira hyperledger org browse FAB
  • tabindex="-1" 的模态将焦点放在选项卡上

    我目前正在使用 Twitter Bootstrap 并且在模态的 tabindex 中遇到一个奇怪的问题 我试图通过模式内的表单元素进行切换 但在最后一个按钮之后 焦点在返回到关闭按钮之前消失了 我在控制台中添加了一行来记录正在聚焦的元素
  • 在 Meteor 事件处理程序中访问模板帮助程序字典

    在 Meteor 中 我将两个对象从我的数据库发送到模板 Template myTemplate helpers helper1 function var object1 this data context set in iron rout
  • Route53 中 A Rec 和 CNAME 之间的区别

    由于Amazon Route 53允许您使用Alias将A记录或CNAME设置为不同的子域名 我现在想知道A记录和CNAME之间有什么区别 为了澄清我的问题 传统NameServer中的CNAME和A记录之间的区别在于 只有CNAME可以用
  • 调用多个api url并同时调用

    我有三个 API url 每个都有相同的对象名称 我希望同时调用所有 api 到目前为止我的js document ready function var first https first var second https second v
  • 确定 JavaScript e.keyCode 是否为可打印(非控制)字符

    我只是想知道 JavaScript 的范围keyCode对应于可输入字符的 s 或者 不可输入 控制 字符的范围 如退格 转义 命令 移位等 这样我就可以忽略它们 我问的原因是打电话String fromCharCode 导致控制键出现奇数
  • UIView 中只有白色填充颜色是透明的

    我有一个UIView即设置为opaque NO一切都很好 在里面drawRect我正在做自定义绘图 这有效 CGContextSetFillColor context CGColorGetComponents UIColor blueCol
  • 在Tomcat上部署war文件

    有没有办法在 Tomcat 服务器上部署给定的 war 文件 我想在不使用网络界面的情况下执行此操作 部署 Tomcat Web 应用程序有多种方法 正如已经提到的 进入 CATALINA HOME webapps Using your b
  • 如何在 Flutter 中处理 Android 设备的 BACK 按钮按下?

    如何处理设备后退按钮onPressed Android 版 Flutter 中 我知道我必须为 iOS 手动添加一个后退按钮 但 Android 设备有内置的后退按钮 用户可以按下它 怎么处理呢 您可以使用WillPopScope为了达成这
  • 有没有办法在 r 中自动重新安装软件包及其依赖项?

    所以我在Rstudio上使用installR将R更新到版本4 0 0 并将我的包文件复制到R中的库文件中 目录是 C Users Ibrahim Documents R R 4 0 0 library 每当我调用一个包时 例如 tidyte
  • 在 Linux 命令行中使用低功耗蓝牙

    我正在研究在 Linux 上使用蓝牙低功耗调制解调器 我正在使用命令行选项 即hcitool 我可以使用以下命令找到设备 hcitool scan 它对我来说工作正常 我也可以使用以下方式广播我的设备 sudo hciconfig hci0
  • RecyclerView 中最后一个子元素的边距/填充

    我试图在最后一行添加填充 边距底部 并在第一行添加填充 边距顶部 我不能在项目 xml 中执行此操作 因为它会影响我所有的孩子 我的 RecyclerView 适配器中有标题和子项 所以我无法使用 android padding 4dp a
  • Django REST Framework 序列化速度极慢

    我使用的是 Python 2 7 和 Django 1 7 1 以及 django rest 框架 我有一个 API 它返回一些从数据库中获取的特定值 它使用如下所示的自定义序列化器 class InventarioSerializer s
  • 使用 MLCP 复制数据时出现异常

    我正在尝试使用 MLCP 将 100 万个文档从一个数据库复制到另一个数据库 但出现以下异常 19 08 30 11 48 08 ERROR contentpump DatabaseContentReader RuntimeExceptio
  • 我如何搜索文件并将它们压缩到一个 zip 文件中

    我尝试使用以下命令搜索文件并压缩它们 find regexpression exec zip 但是它不起作用 我怎样才能做到这一点 您使用的命令将分别对每个文件运行 zip 请尝试以下操作 find name
  • IIS 站点和 nant/nantcontrib?

    是否可以使用 NAnt 管理 IIS Web 应用程序 例如停止或启动它 Nant 具有 servicecontroller 任务 您可以使用它仅停止 启动 Web 服务器或整个 IIS 我通常使用它来停止 启动 Web 服务器
  • 如何在 php 中正确为我的 tbl_item 制作下拉列表菜单

    我的下拉列表菜单遇到问题 它不断出现 wamp 错误 我的下拉列表菜单将来自 tbl 项目的项目名称 postgres DB funcContainer php 页面 function DropdownListMenu label name
  • 扩展 MIDL 接口和 COM 对象设计

    我读过有关各种 COM 设计模式的详细信息COM 程序员的食谱 http msdn microsoft com en us library ms809982 aspx以及一些相关的 SO 线程 特别是讨论组合与多重继承的线程 https s