如何在.NET应用程序中使用C++项目?

6
我是一名普通的.NET开发人员,旨在将一个C++库集成到.NET项目中。我有一些想法,但由于我对C++不熟悉,我不知道我正在尝试使用的技术的限制。 C++项目本质上是一个快速的声音渲染器,可以播放带有各种不同后处理技巧的多轨音频文件。所有这些都很酷,但考虑到我想要与简单的.NET WinForms应用程序集成,事情开始变得混乱。
  1. 首先,C++项目没有.NET绑定或ActiveX/COM集成。它只是一个普通的MS VC++ 9项目。如果我要在我的.NET应用程序中使用该项目,我必须以某种方式与之进行接口,即创建类实例、设置属性、调用方法、传输数据等。

  2. 其次,它被构建为独立的Windows应用程序,并使用MS Windows API管理其自己的窗口。这很好,但不知何故,我需要在后台运行.NET VM,管理所有我的C#代码并运行它们。我不写C++,所以我需要坚持使用C#来构建一个围绕这个库的应用程序。

  3. 第三,无论我是否在与C++库相同的进程中运行,我都需要一种方法将这两个独立的应用程序构建/接口/调试,就像它们是一个应用程序一样。除了我编写了一些用于高性能数据操作的C++ DLL外,我没有任何C++编程背景。

因此,有许多问题,但不知从何开始!

我可以完全编译此库并将其放入VC EXE中,但是如何将我的.NET代码与其一起进行协同编译?或者,如何将C++代码编译为.NET EXE,以便在托管环境中运行?请注意,它并不是为此而设计的,如果尝试更改太多可能会出现问题。
主要问题是与之进行接口。如何公开某些C++类以从.NET中访问?我知道我需要哪些类,我只需要几十个类及其相关方法/属性可从.NET中使用。我不介意在.NET中手写包装器类来帮助.NET VM了解来回传输的字节的类结构。我希望可以直接从托管环境中使用C++对象,这样大部分我的代码可以保留在.NET中。
即使我将其作为独立应用程序运行,我是否必须诉诸套接字或其他通信方式?这是最坏的情况,我会尽一切努力避免这种情况。
任何帮助或指针都将不胜感激,我希望我已经清楚地表达了自己手头的任务,我的问题足够具体和可回答。感谢任何帮助!
编辑:如果我编写包装类或生成它们,我可以使用P/Invoke创建类实例并调用它们的方法,并让它们在后台运行本机C++代码吗?这样的C++对象的内存将存储和管理在哪里?在.NET堆内还是外部?

可能是从C DLL到.NET的接口的重复问题。 - oefe
@oefe C DLL转换到.NET更直接。答案几乎总是使用P/Invoke + 在.NET结构体上使用属性来重新创建你的C结构体。C++转换到.NET可能会更复杂,因为涉及到非托管对象。 - Pete Baughman
2个回答

3

选项1

如果您打算使用非托管的C++对象,最好编写一个C++/CLI的托管包装器,该包装器具有与其包装的类相同的接口,但具有托管构造函数和析构函数以清理非托管资源。在C++/CLI中,您可以像C++一样创建非托管对象,需要自己删除,或者您可以使用gcnew关键字创建托管对象。包装器的.NET面对方将采用托管对象。包装器的本地面对方可以操作所有已经存在的非托管数据类型。

例如,考虑非托管类。 在C++/CLI中,您将创建一个名为的类,该类将具有与完全相同的方法,并包含的私有实例。 在构造函数中,您将创建私有的实例。 在析构函数中,您将删除私有的实例。 您包装器类中的每个方法将简单地调用私有的实例上的方法。

选项2

如果您只想从C++世界中调用c-style函数(我想是C#中的静态函数),那么P/Invoke可能是正确的选择,因为这样您就不必担心包装器类的所有细节。 例如,如果您使用包装器类将来自托管世界的数组传递到非托管世界,则必须担心诸如固定数组位置以使其不会在.NET运行时期间被托管世界玩弄等问题。 在P/Invoke中,这些细节大多已为您处理。


使用选项1,C++代码是否仍能以全速运行?还是它会在受控环境中运行,并被编译为CIL,这将比原始的C++慢得多?当然,使用包装器的性能损失可以忽略不计,我只关心实际的C++代码。而且C++代码将如何编译?它将作为常规x86汇编存储在DLL内,而包装器则作为CIL对象存储吗?还是所有内容都变成了CIL对象? - Robin Rodricks
1
@Geotarget 写一个包装类不需要重新编译非托管的C++代码。你只需要引用已经编译好的代码和相关的头文件。当你完成时,你会得到原始的非托管二进制文件、一个包含了你的包装类引用原始二进制文件的C++/CLI DLL和引用了你的C++/CLI DLL的C#可执行文件。 - Pete Baughman

3
您可以编写托管的 C++ (C++/CLI) 封装器来包装不受管控的 C++ 代码。这将是最灵活的解决方案。基本上,您将使用 C++ 编写一个 .NET 程序集,该程序集公开调用您的不受管控代码的托管类。然后,您可以从 C# 项目中引用此程序集。
有一篇非常基本的文章介绍了如何实现:http://www.windowsdevcenter.com/pub/a/dotnet/2004/03/29/mcpp_part3.html 这也可能会有所帮助:http://www.multicoreconsulting.co.uk/blog/c-snippets/how-to-call-unmanaged-cplusplus-from-csharp/ 以及 MSDN 文章:.NET Programming in Visual C++

你的方法和这个一样吗?http://www.codeproject.com/Articles/14180/Using-Unmanaged-C-Libraries-DLLs-in-NET-Applicatio - Robin Rodricks
并不是真的,一个好的“现实生活”托管包装器的良好示例可能是mpg123库(考虑到您必须熟悉声音处理 :))。如果您下载sources,则在ports\MSVC++\2008clr文件夹中有一个。 - Olexander Ivanitskyi
1
@Geotarget,实际的C++代码性能不会受到影响,它仍将在“非托管模式”下运行。但是,您的托管C++/CLI类(以ref__gc关键字为前缀)将由CLR处理,并带有垃圾收集器等内容。因此,如果您在托管包装器中使用非托管C++类,则需要在其析构函数/终结器中释放非托管内存指针。 - Olexander Ivanitskyi
1
编译后,您可以获得2个DLL:托管的CLR程序集,它将使用非托管库。两者都将在其范围内运行。 - Olexander Ivanitskyi
谢谢您的评论。您的答案是否与Pete的答案中的Option 1相同? - Robin Rodricks
是的。关于他的第二个选项:如果C++项目通过C风格动态链接库公开其API,那将会非常有用。在这种情况下,DllImportAttribute(http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx)会更加有效(在开发时间方面)。但这也取决于您需要调整多少结构布局和编组;) - Olexander Ivanitskyi

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