使用 C# 创建 COM 扩展 - 值得吗?

Posted

技术标签:

【中文标题】使用 C# 创建 COM 扩展 - 值得吗?【英文标题】:Creating COM extension using C# - is it worth it? 【发布时间】:2010-11-03 19:23:00 【问题描述】:

我正在处理以下问题:(第三方)软件 (Software A )我们广泛使用的允许使用组件对象模型(COM)接口(实际上是几个接口)对所谓的“扩展”进行编程。它为这些接口提供 MIDL 文件以及作为 SDK 一部分的 Visual C++ 的“项目模板”(IDL 文件、头文件和接口已经存在,只是缺少接口函数的实现)。为了兼容,所有扩展都必须符合(即必须实现)给定的 COM 接口结构。

但是,由于我对 C++ 的熟悉程度相当有限,我希望在 C# 和 .NET 中实现 COM - 另一方面,预定义接口大量使用指针和自定义数据结构,所以我想知道我是否最好在其原生 C++ 中实现接口,而不是尝试在 C# 中重新创建所有内容。

可能需要更多背景知识:最终目标是从软件 A 内部控制一块自定义硬件(通过 USB)。我已经编写了一个使用 DLLimport 包装驱动程序(另一个第三方软件)的小型 .NET 应用程序,这是令人惊讶的无痛。换句话说,我要构建的 COM 对象本质上是(第三方)软件 A 和(第三方)设备驱动程序 B 之间的桥梁,它必须符合 A 给出的接口规范。


示例 MIDL 代码:

[id(0x00000004)] HRESULT GetWaveData([in] BSTR name, [out] IWaveData ** data ); [ id(0x00000005)] HRESULT GetImageData([in] BSTR name, [out] IImageData ** data, [out] Palette * Palette); [ id(0x00000006)] HRESULT SetVariable([in] BSTR name, [in] IVariableData * variable );

【问题讨论】:

【参考方案1】:

如果不完全了解问题,实际上不可能回答这个问题。但一般来说,我会选择 C++ 路线。通过向世界添加 CLR,您将不得不处理 C# 中的互操作问题并可能处理令人讨厌的指针问题(因为它的本质是处理与硬件相关的低级问题)。因此,您真正的选择可能是不干净的 C# 源代码或使用 C++。我想我会选择后者。

【讨论】:

【参考方案2】:

从技术上讲,您不是在 C++ 中实现接口,而是在 MIDL 中实现。 它是一种独立的界面语言,如果您要进行 COM 工作,值得了解。

无论如何,使用 .NET 互操作来实现 COM 对象并不少见,但这两者并不是真正兼容的技术。除非您编写非常简单的对象,否则您会遇到问题。

为了让您入门,这里有一些随机分类的指针以及我过去使用过的几篇文章。

COM 是一种接口驱动技术。一遍又一遍地对自己重复。 使用 MIDL 单独开发接口定义。 COM 垃圾回收是确定性的(引用计数),但在与 .NET 一起使用时,这开始崩溃,其中垃圾回收会自动发生且不可预测。 处理事件接收器/事件处理程序是丑陋的。

您会遇到的头痛类型的小尝试: http://www.codeproject.com/KB/cs/LingeringCOMObjects.aspx

更多关于为什么不应让 Visual Studio 为您自动生成 COM 接口的信息: http://blogs.msdn.com/mbend/archive/2007/04/17/classinterfacetype-none-is-my-recommended-option-over-autodispatch-autodual.aspx

桥接事件: http://www.west-wind.com/presentations/dotnetfromVfp/DotNetFromVfp_EventHandling.asp

【讨论】:

+1 特别是对于 Eventsinks 项目符号。过去这对我来说是个大问题。 感谢您的链接! MIDL 定义已经存在 - 这正是问题所在:我如何将 MIDL 接口定义转换为 .NET,因为我的理解是向 COM 公开 .NET 库不涉及 MIDL(我错了吗?)幸运的是,事件不是问题. COM 所做的只是 set/get 类型的显式函数调用。所以它可能是一个相当简单的对象。 向 COM 公开 .NET 库不必涉及 MIDL,但让 Visual Studio 为您自动生成接口定义是不好的做法。在您的情况下,您很幸运,因此我认为它为尝试互操作解决方案提供了更强有力的案例。无论如何,我给你的第二个链接给你一个非常小的例子,说明如何使用 C# 实现一个接口,所以我认为你很好。【参考方案3】:

如果 .NET 能给您带来优势,您应该只将其用于此目的。例如,我们曾经需要 web 服务调用,并且在 .NET 中对它的支持要好得多,所以我们就这样做了。在您的情况下,优势是您更熟悉 .NET,这可能值得选择。

但是,如果您在 .NET 中实现 COM 对象,则必须在必须使用该对象的每台机器上都需要 .NET 运行时。此外,您在实现具有难以编组的自定义类型的接口时可能会遇到问题。

您需要将优势(在您的情况下更加熟悉)与您遇到的技术负担(可能的部署和编组问题)进行比较。

我个人的观点是,只有在需要功能随时可用的情况下才选择 .NET 路径(例如 web 服务调用)。

【讨论】:

【参考方案4】:

听起来您正在做出的决定是选择原生应用程序还是基于 .NET 的应用程序。

你需要考虑以下几点:

    部署问题:您打算在哪里部署此应用程序?它会在数百个工作站上运行,还是只在几个工作站上运行?您将对安装它的机器拥有多少控制权?请记住,您必须确保安装了正确版本的 .NET 平台;

    维护问题:您显然对 .NET 更熟悉,但谁来长期维护该应用程序?他们会被期望熟悉 C++ 吗?原生开发确实与托管开发不同,因为“管家”是其中非常重要的一部分;

    第三方依赖项:在我看来,您正在尝试使用第三方 COM 库通过 USB 与您的设备进行通信。但是,您提到您已经为硬件驱动程序编写了一个 .NET 包装器——您能否详细说明一下,因为这有点令人困惑。如果可能,如果不是太麻烦,不要引入依赖;

    资源限制:如果您的应用要“在野外”安装,硬件限制是什么?使用非托管环境进行编程允许您对应用程序将使用的内存量以及 CPU 密集程度进行细粒度控制——当然,这是与让托管层负责资源管理的权衡.

一般来说,如果您要开发的应用程序不需要部署到具有不同硬件配置的数千名用户,我会选择 .NET 平台。 .NET 上的 COM 互操作相对轻松,在托管平台上编程意味着您可以专注于重要的事情。如果您以前从未在非托管环境中编程过 (C/C++),那么您会感到震惊。

【讨论】:

感谢您的回复!我编辑了我原来的问题,使事情更清楚一些。正如您正确怀疑的那样,部署不是问题,资源限制也不是问题,所以我宁愿避免进入非托管代码。

以上是关于使用 C# 创建 COM 扩展 - 值得吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 的泛型中使用扩展

2019 年,C# 还值得学习吗?

我们可以使用 QT 和 C# 来创建 GUI 吗?

c# 将字符串作为代码执行...值得付出努力吗?

这个对象生命周期扩展闭包是 C# 编译器错误吗?

在 c# winforms 中扩展文本框