用于包装C库的P / Invoke或C ++ / CLI

时间:2010-04-01 16:19:35

标签: c# .net c++-cli pinvoke

需要从C#项目调用中等大小(40多个函数)的C API。这些函数在逻辑上分解,形成一些类,这些类将API呈现给项目的其余部分。

在稳健性,可维护性,部署等方面,是否有任何客观理由倾向于使用P / Invoke或C ++ / CLI来实现该API下的互操作性?

我能想到的问题可能是,但不是问题:

  • C ++ / CLI需要单独的程序集,P / Invoke类可以在主程序集中。 (我们已经有多个组件,无论如何都会有C dll,所以不是主要问题。)
  • 两种方法之间的性能似乎没有明显差异。

我不确定的问题是:

  • 我的感觉是,如果存在操作间问题,C ++ / CLI将更容易调试,这是真的吗?
  • 语言熟悉,人们都知道C#和C ++,但是对C ++ / CLI的细节知识很少见。

还有别的吗?

6 个答案:

答案 0 :(得分:15)

在我使用现有C库的情况下,我更喜欢PInvoke。 PInvoke虽然有时候有点乏味和麻烦,但它是一种相当容易理解的技术,它拥有越来越多的工具和互联网文档。一般来说,无论遇到什么问题,网上都有可用的样本,或者快速检查堆栈溢出将提供解决方案。

C ++ / CLI是一项很棒的技术,但是对于互操作特定情况,恕我直言,其文档与PInvoke相比是有限的。它也没有PInvoke所具有的互操作解决方案的工具基础结构。为可以通过PInvoke解决的场景添加C ++ / CLI程序集对我来说似乎太昂贵了。

另一方面,如果我正在使用大型C ++库,我会更多地考虑C ++ / CLI。 PInvoke不能与C ++一起使用,我最终必须添加某种中间层。要么包含所有C ++函数调用的小C层,要么用C ++ / CLI库来弥补差距。在这种情况下,C ++ / CLI对我来说感觉更自然。

答案 1 :(得分:7)

这在很大程度上取决于如何处理内存所有权。仅当内存管理是几种特定方式之一(通常是调用者分配的缓冲区)时,P / invoke才能编组指针。如果你的API返回指针(通过返回值或输出参数,无所谓)并期望它们稍后被交还给销毁函数... p / invoke将执行自动编组或直接访问指针您需要稍后发回的价值,而不是两者。因此,在这种情况下,C ++ / CLI成为一种非常理想的方法。

答案 2 :(得分:4)

将P / Invoke视为平台调用,您是否正在调用类似于非常P / Invoke友好的Win32 API或者您是否需要为非托管库提供.NET绑定?

由于包装器通常非常薄,因此C ++ / CLI包装器并不需要您专门了解C ++ / CLI。您需要了解的内容可以在language specification中找到,它是一个包含大量示例的大量文档。对于较小的已建立的现有库,P / Invoke是一个很好的功能,但如果调用该库的接口发生更改,则会遇到问题。使用C ++ / CLI,您仍然可以在C ++ / CLI项目中拥有一个公共托管接口,该接口为托管代码公开,并以这种方式更轻松地处理对C API的更改。

如果你想摆脱额外的DLL你总是可以尝试ILMerge,但我不确定它是否能够处理混合程序集,(apparently not),但看起来可以链接这两个和PlatformSDK链接器的非托管* .obj文件,如下所示:

cl.exe /MD /c /clr Unmanaged.cpp
csc.exe /target:module /addmodule:*.obj Managed.cs
link.exe /DLL /LTCG /NOENTRY /CLRIMAGETYPE:IJW *.obj Managed.netmodule

答案 3 :(得分:2)

如果您的人员知道如何调试C ++,那么C ++ / CLI将更容易调试。如果你不这样做,可能会更难。

我建议这里的权衡取决于互操作组件的消费者易用性与组件本身的易维护性之间的关系。如果您拥有熟悉C ++且可以可靠地维护程序集的高级工程师,那么对于不熟悉本机代码的团队其他成员来说,为他们提供完全托管的界面将会更容易他们的一切。

另一方面,如果你是店里唯一具有C ++经验的人,我会非常谨慎地将C ++模块嵌入到项目中,万一其他人必须在以后维护它。

答案 4 :(得分:2)

对于这个大小的API(大约40个入口点),我会根据你在C#中复制多少“头文件gunk”来绘制C ++ / CLI和P / Invoke之间的分界线。如果它是一个小(适度)的数量,P / Invoke是好的。一旦你开始在C#中复制很多.H文件 - 特别是对于那些没有在.NET API中公开的东西 - 你可能最好使用C ++ / CLI。

答案 5 :(得分:0)

这里有很多好的答案 - 另一个视角是现有C API的计划。 使用PInvoke的参数包括:

  • 您需要保留一个C API 与其他C消费者的兼容性
  • 您需要将代码保存在C中 它很大,迁移也是如此 昂贵

使用C ++ / CLI的参数包括:

  • 您希望将尽可能多的代码移动到CLR

在这种情况下,您可以从C ++ / CLI开始,然后越来越多地转移到C#