2

我试图了解从非托管 C++ 调用 C# 库实现的选项。

我的顶级模块是一个非托管 C++ COM/ATL dll。我想集成现有托管 C# dll 的功能。我有,并且可以重新编译这两个库的源代码。

我从阅读MSDN 上的这篇概述之类的文章和这个 SO 问题中了解到,有可能创建一个“混合模式”dll,它允许本机 C++ 代码调用 C# 库。

我对这种方法有几个问题:

  1. 我该如何设置呢?我可以简单地更改现有 COM/ATL 项目的一些属性以允许使用 C# 模块吗?
  2. 这些混合模式调用与 COM 互操作调用的性能有何不同?是否有一种通用的字符串格式可用于防止模块之间的转换或深度复制?
  3. 如果这个 dll 是在混合模式下创建的,它的 COM 客户端是否仍然可以以相同的方式接口/使用它,或者它们是否需要了解混合模式?
  4. 加载此 COM 对象时,包含 CLR 是否会产生大量开销?

我是 Windows 开发的新手,所以如果问题陈述中的任何内容需要澄清或更正,请发表评论。

提前致谢。

4

2 回答 2

4

我该如何设置呢?我可以简单地更改现有 COM/ATL 项目的一些属性以允许使用 C# 模块吗?

如果您完全控制该项目,那么更改此类设置不是问题,那么可以确定。您只需要启用/clr此项目(在项目属性中,打开“常规”页面,并查找“公共语言运行时”支持)。现在,您可以根据需要在项目中使用托管句柄 ( ^) 和其他 C++/CLI 位。所有用纯 C++ 编写的现有代码都应该继续工作(它现在将尽可能编译为 MSIL,但其语义将保持不变)。

这些混合模式调用与 COM 互操作调用的性能有何不同?是否有一种通用的字符串格式可用于防止模块之间的转换或深度复制?

混合模式调用会更快,因为它使用更快的调用约定,并且不会像 COM 互操作那样进行任何封送处理(您要么使用本质上兼容的类型,要么进行自己的显式转换)。

没有通用的字符串格式——问题是System::String既分配又拥有它的缓冲区,并且还要求它是不可变的;因此您不能自己创建缓冲区然后将其包装为String,或者创建 aString然后将其用作缓冲区以将文本输出到。

如果这个 dll 是在混合模式下创建的,它的 COM 客户端是否仍然可以以相同的方式接口/使用它,或者它们是否需要了解混合模式?

它可以有相同的接口,但如果它是通过本机入口点进入的,它将尝试将 CLR 加载到进程中,除非已经加载了一个。如果调用客户端在调用之前已经加载了 CLR(或者客户端本身是从托管代码调用的),那么您将获得已经加载的 CLR,这可能与您的代码所需的 CLR 不同(例如客户端可能已经加载了 1.1,而您的代码需要 2.0)。

加载此 COM 对象时,包含 CLR 是否会产生大量开销?

这取决于您对开销的定义。代码大小?运行时惩罚?内存占用?

无论如何,加载 CLR 意味着您获得了所有 GC 和 JIT 机器。那些都不便宜。也就是说,如果您最终需要调用托管代码,则无法解决此问题 - 您必须将 CLR 加载到某个进程中才能执行此操作。COM Interop 和混合模式 C++/CLI 程序集之间的惩罚不会有所不同。

于 2009-12-16T17:25:12.073 回答
0

我不能说太多细节,例如字符串问题,因为我从未积极使用过这种方法。

但是您可以轻松地使用任何 C# 代码中的任何 COM 接口,只需让 VS 向导为您创建一个代理即可,除了调用 COM 和 .NET 时始终存在的性能开销之外,它没有任何性能开销。

另一个方向,您只需将 C# 程序集设置ComVisibleAttribute为 true(在 VS 中,它是项目属性中的一个简单复选框),然后编译器会自动为您创建 COM 接口。同样,没有额外的性能损失。

于 2009-12-16T17:24:12.063 回答