使用C++/CLI封装非托管C++ - 一个正确的方法

8
如标题所述,我希望将我的旧C++库工作在托管的.NET环境中。我想到了两种可能性:
1)我可以尝试使用/clr编译库,并尝试“一切正常”的方法。
2)我可以编写一个托管包装器来操作非托管库。
首先,我希望我的库能够快速工作,就像在非托管环境中一样。因此,我不确定第一种方法是否会导致性能大幅下降。但是,它似乎更快地实现(假设对我有效)。
另一方面,我想到了一些在编写包装器时可能出现的问题(例如,如何包装一些STL集合(例如 vector )?)。我考虑写一个与非托管C ++代码位于同一项目中的包装器-这是一个合理的方法吗(例如,在同一项目中有 MyUnmanagedClass 和 MyManagedClass ,后者包装前者)?
在这个问题上,您会提出什么建议?哪种解决方案会给我带来更好的代码性能?
感谢您提前提供的任何建议和线索!
干杯
3个回答

6
首先,忘掉Managed C++。使用C++/CLI。
区别在于,Managed C++是微软的第一次尝试将C++扩展到与.NET一起使用,老实说,它非常可怕。
所以他们放弃了这个,设计了C++/CLI,它的工作效果要好得多。
其次,如果您将有效的C++代码编译为C++/CLI,则应该“只需运行”,因此这似乎是明显的方法。
当然,为了将您的C++类型公开给.NET程序集,您需要编写一些包装器。对于STL类型,您可以查看Microsoft的 STL/CLR库。
但总的来说,只需添加/cli开关,将您的代码编译为C++/CLI,然后添加所需的包装器即可。没有理由您的代码会变得更慢或其他什么。

写“managed C++”时,我显然想到了C++/CLI :-) - 现在已经编辑过了,谢谢 :) - Jamie
是的,混淆它们很常见。但这也可能导致困惑。 :) - jalf
1
双下划线语法引起了如此多的仇恨 :P - YeenFei
请注意,如果您的代码包含任何本机类,则无法在不受信任的模式下运行。 如果您想部署Silverlight xap中的内容,请考虑这一点。 那么您必须使用/clr:pure,这意味着您必须基本上重写所有内容。 - Billy ONeal

3
我的做法是:
  1. 创建一个普通的非托管 .lib。确保链接到标准运行时作为 DLL(如果 .lib 在程序集中则必需)

  2. 创建一个 C++/CLI 程序集。

  3. 将 .lib 添加到程序集的链接中。

  4. 创建一个托管接口。

  5. 尽量减少跨托管/非托管调用的粒度。这意味着,最好获取大块数据(如数据结构),而不是从托管端使用非托管数据结构的接口。这是因为跨边界的调用很慢。

像 std::vector 这样的东西需要手动包装在 System.Collections 中,但是对于内置类型甚至函数指针,“它只是工作”。

其他需要注意的事项。回调需要使用 stdcall 才能转换为委托,并且发送给非托管回调的委托不持有引用(因此,请安排在其他地方持有引用,否则对象被垃圾回收时会崩溃)。


那么第四步我假设是使用P/Invoke方法吗? - Arman Bimatov
不。在C++/CLI中,您可以创建托管类和非托管类。没有P/Invoke——两个类都在同一个程序集中。 - Lou Franco
我在发表评论后不久就意识到了这一点。它是IJW(It Just Works)。我实际上通过Visual Studio->添加引用将非托管和CLI库作为同一解决方案的两个项目进行链接,就像在这个问题中所述:http://stackoverflow.com/questions/18302784/including-headers-from-an-unmanaged-c-code-inside-c-cli-code/18303380#18303380 是的,我不得不为大多数数组、向量和其他复杂类型编写转换。MS Marshaling库帮了很大的忙:http://msdn.microsoft.com/en-us/library/vstudio/bb384865.aspx - Arman Bimatov

1

如果你有很多未受管控的函数需要封装,你应该考虑使用SWIG。它为你编写所有包装和互操作代码,并具有预先编写的支持std::vector、std::string、Windows类型等的SWIG接口文件。

如果你感兴趣,我有一个完整的示例,可以公开未受管控的C++ DLL函数。


1
马克,我想看一个完整的例子。 - user1304232

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