如何在C#和.NET中使用C++库?

5
我的问题与 DLL 如何导出 C++ 类和泛型方法紧密相关(关于 C++ 语言特性而没有 C# 平行)。我相信你可以通过引用 DLL 并使用 DLLImport 来从 C# 中调用 extern "C" 块内的函数。但是你能实例化一个带有模板的 C++ 类型吗?如果 C++ 类型做了一些 C# 不支持的 疯狂的事情,该怎么办?是否有 RFC 或相关部分的 C# 规范?谢谢...
编辑:我现在偶然发现了 P/Invoke,这应该很有价值,但我仍在寻找有关此事的规范或标准。
3个回答

7

一个明智的方法是使用托管的 C++ 来访问非托管的 C++ 并编译为一个程序集。


还有更多关于这个的信息吗?我是Windows编程新手,我习惯于Unix、静态链接和Makefiles...在VS2010中如何使用C++创建托管DLL或非托管DLL? - Robert Karl
@robert 上面的链接展示了非常古老过时的托管 C++ 语法,例如在现代语法中 __gc 变成了 ref - jdehaan
请查看此链接底部,其中漂亮的示例展示了语法差异:http://www.visualcplusdotnet.com/visualcplusdotnet18b.html - jdehaan

2
我认为你可以通过引用DLL从C#中的extern "C"块内调用函数。

不对,你必须使用DllImport或所谓的PInvoke(平台调用)来从托管代码中调用本地C函数。引用仅适用于.NET程序集或具有自动生成的互操作dll的COM

使用C++从C#变得非常困难,因为名称混淆等原因。

如果可以的话,你可以编译一个托管的C++ Dll作为包装器,使两个世界相遇。这也有一个优点,你可以将你的程序集标记为ComVisible,从而使它可用于大量处理COM的工具。

另一种选择是在C++ API周围编写一个C包装器,这可能会很繁琐和丑陋。
编辑:
帮助决定使用哪种方法:
1)您有一个本地的C dll
警告:如果您使用来自Managed C++的.lib,则dll不是真正的动态链接,不能用较新的兼容版本简单地替换它。
首选:从任何.NET语言使用P/Invoke(可以进行简单的替换)。

  • 2)您有一个本地的C++ dll
    • 不要使用P/Invoke,这是一个真正的噩梦(因为名称混淆等原因)
    • 首选:使用托管C++构建包装器.NET dll,仅在您拥有与用于编译本地dll的编译器兼容的编译器时才有效。
    • 如果本地DLL是使用与您可以用于托管C++的编译器(编译器C)不兼容的编译器(编译器A)进行构建的,则建议使用相同的编译器A围绕本地C++ dll构建C包装器。然后使用P/Invoke方法使用此包装器C dll,如1)所述

谢谢您的纠正。您能用C++创建一个.NET程序集吗? - Robert Karl
是的,你可以使用托管C++来链接本地C++ DLL,但实际上它并不是真正的C++。如果你恰好使用与生成纯C++ DLL的人相同的编译器,那么就可以进行链接。 - jdehaan
不是真的 :-),但这是一种真正从.NET对第三方C dll进行动态链接的好方法。使用托管C++很容易用本地内容污染纯.NET世界。 - jdehaan

1

对于C#来说,DLL内部的操作是无关紧要的。请记住,C++模板在实例化之前不会生成任何代码。如果该模板仅在DLL头文件中定义,则DLL中不会有该模板的生成代码。另一方面,如果DLL显式实例化并导出某些模板类型,则理论上可以从C#调用它们。

您需要解决两个问题。第一个问题是C++编译器混淆其方法名称,因此您必须确定正确的PInvoke名称。第二个问题是没有办法直接在C#中创建CRT对象。您必须定义一些工厂方法并将其导出。

坦白地说,我认为这一切都比它值得的麻烦多了。最好为DLL创建一个C样式API,并从C#调用这些函数。在内部,函数可以创建和操作相关的C++对象。


好的,听起来很麻烦。创建C API是一个合理的解决方案,但我很惊讶为什么没有更灵活的交互机制... - Robert Karl
1
Interop机制必须处理任何编译器的所有可能的名称修饰方案,因为没有标准(这是一个大问题),并且封送/解封也不是简单的。在COM的情况下,一切都在接口中指定,并且类型以大小和对齐方式明确定义。 - jdehaan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接