用 C++/CLI 包装非托管 C++ - 一种正确的方法
Posted
技术标签:
【中文标题】用 C++/CLI 包装非托管 C++ - 一种正确的方法【英文标题】:Wrapping unmanaged C++ with C++/CLI - a proper approach 【发布时间】:2011-01-10 00:07:33 【问题描述】:如标题所述,我想让我的旧 C++ 库在托管 .NET 中工作。我想到了两种可能:
1) 我可能会尝试使用 /clr 编译库并尝试“It Just Works”的方法。
2) 我可能会为非托管库编写托管包装器。
首先,我想让我的库快速运行,就像它在非托管环境中一样。因此,我不确定第一种方法是否会导致性能大幅下降。但是,实施起来似乎更快(不是一个正确的词:-))(假设它对我有用)。
另一方面,我想到了在编写包装器时可能出现的一些问题(例如,如何包装一些 STL 集合(例如vector
)?)我想编写一个与非托管 C++ 存在 - 这是一种合理的方法吗(例如,MyUnmanagedClass
和 MyManagedClass
在同一个项目中,第二个包装另一个)?
你对那个问题有什么建议?哪种解决方案可以让我获得更好的结果代码性能?
提前感谢您的任何建议和线索!
干杯
【问题讨论】:
【参考方案1】:首先,忘记托管 C++。使用 C++/CLI。
不同之处在于,Managed C++ 是 Microsoft 首次尝试将 C++ 扩展为与 .NET 一起使用,老实说,这真是太可怕了。
所以他们放弃了,转而设计了 C++/CLI,效果更好。
其次,如果您将其编译为 C++/CLI,则有效的 C++ 代码应该正常工作,因此这似乎是显而易见的方法。
当然,为了将 C++ 类型公开给 .NET 程序集,无论哪种方式,您都必须编写一些包装器。对于 STL 类型,您可以查看 Microsoft 的 STL/CLR 库。
但一般来说,只需添加 /cli 开关,将您的代码编译为 C++/CLI,然后添加您需要的包装器。您的代码没有任何理由会神奇地变慢或发生任何事情。
【讨论】:
编写“托管 C++” 我显然想到了 C++/CLI :-) - 现在已编辑,谢谢 :) 是的,把它们混在一起很常见。但这也可能导致混乱。 :) 对双下划线语法有如此多的仇恨:P 请记住,如果您的代码包含 any 本机类,那么它将不会在不受信任的模式下运行。如果您转身并想在 silverlight xap 中部署某些东西,则需要考虑一些事情。然后你必须使用/clr:pure
,这意味着你必须重写所有内容。【参考方案2】:
我的做法是
创建一个普通的非托管 .lib。确保作为 DLL 链接到标准运行时(如果 .lib 在程序集中,则需要)
创建 C++/CLI 程序集。
将 .lib 添加到程序集的链接中
创建托管接口
最小化跨托管/非托管调用的粒度。意思是,更喜欢获取大块数据(如数据结构),而不是使用来自托管端的非托管数据结构的接口。这是因为跨界调用很慢。
像 std::vector 这样的东西需要在 System.Collections 中手动包装——但是,“它只是工作”对于内置类型甚至函数指针都有好处。
其他问题。回调需要是 stdcall 才能转换为委托,并且发送到非托管回调的委托不持有引用(因此,安排在其他地方持有引用或在对象被 GC 时崩溃)。
【讨论】:
所以我假设第 4 步是使用 P/Invoke 方法? 没有。在 C++/CLI 中,您可以创建托管类和非托管类。没有 P/Invoke -- 两个类都在同一个程序集中 我实际上是在发表评论后不久才意识到的。这是 IJW(它只是工作)。我实际上是通过 Visual Studio 将非托管库和 CLI 库链接为同一解决方案的两个项目 -> 添加参考,就像在这个问题中一样:***.com/questions/18302784/… 是的,我必须为大多数数组、向量和其他编写转换复杂的类型。 MS Marshaling 库帮助很大:msdn.microsoft.com/en-us/library/vstudio/bb384865.aspx【参考方案3】:如果你有很多非托管函数要包装,你应该考虑使用SWIG。它为您编写所有包装器和互操作代码,并预先编写了支持 std::vector、std::string、windows 类型等的 SWIG 接口文件。
如果你有兴趣,我有一个完整的例子来展示非托管 C++ DLL 函数。
【讨论】:
马克我想看一个完整的例子以上是关于用 C++/CLI 包装非托管 C++ - 一种正确的方法的主要内容,如果未能解决你的问题,请参考以下文章