托管 C++ 遗留 C++ 的包装器 图书馆

发布于 2024-07-11 15:32:41 字数 86 浏览 5 评论 0原文

我们正在考虑使用托管 C++ 为一些旧版 C++ 库编写一个 .Net 可调用包装器。

一切看起来都很简单。 有什么需要我们注意的吗?

We're looking at writing a .Net-callable wrapper for some legacy C++ libraries using managed C++.

It all looks pretty easy. Is there anything we need to watch out for?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

仙气飘飘 2024-07-18 15:32:41

我发现在 C++/CLI 中包装一些现有的 C++ 库通常非常容易,并且遇到的陷阱相对较少。 我记得的是:

  • 在同一个可执行文件/DLL 中混合非托管 C++ 代码和 C++/CLI 代码是一个非常糟糕的主意。 我在关机时遇到了与竞争内存管理器相关的问题(基本上是 .NET 运行时和常规 C++ 运行时,在关机时清理内存时会互相踩对方的脚趾,从而导致不确定的行为哪一个释放了什么)。 我没有将静态旧 C++ 库链接到 C++/CLI 库,而是创建了一个包含旧 C++ 的 DLL,并将其链接到 C++/CLI DLL,这一劳永逸地解决了问题。
  • 如果您的代码使用枚举,则必须将它们包装在适当的 C++/CLI 枚举类中,否则其他 .NET 语言将无法查看和使用它们。
  • C++/CLI 对象只能保存指向非托管 C++ 对象的指针。 不幸的是,在某些情况下,这意味着您将必须创建薄包装层来处理某些对象。 我“最喜欢”的是,我必须以这种方式包装 boost::shared_ptrs (从而添加另一层间接),或者在跨越 .NET/native 边界后将它们放入带有空删除器的共享_ptrs 中。 当您必须处理大量使用此类构造的 API 时,这两种方法都不是很好。 RAII 不会跨越此边界,因此请注意,您必须投入一些时间来调整它以匹配 .NET 方式。
  • C++/CLI 不执行多重继承,因此如果您的遗留库正在使用它,您可能必须使用接口等对其进行建模。
  • 内部编组代码似乎能够处理大多数 POD 转换,但您会发现/borrow 转换 std::strings 的代码等。这段代码已经存在,在 Google 上几分钟就可以找到它(抱歉,目前这里没有任何链接)。

I found it generally quite easy to wrap some existing C++ libraries in C++/CLI and encountered comparatively few pitfalls. The ones I can remember were:

  • Mixing unmanaged C++ code and C++/CLI code in the same executable/DLL is a really bad idea. I've run into problems with competing memory managers at shutdown time that way (basically the .NET runtime and the regular C++ runtime where stepping on each other's toes when it came to cleaning up memory on shutdown, resulting in non-deterministic behaviour as to which one freed what). Instead of linking the static legacy C++ library into the C++/CLI library, I created a DLL containing the legacy C++ and linked that against the C++/CLI DLL, which solved the problem once and for all.
  • If your code is using enums, you have to wrap those in the appropriate C++/CLI enum classes, otherwise other .NET languages won't be able to see and use them.
  • C++/CLI objects can only hold pointers to unmanaged C++ objects. Unfortunately in certain cases, this means you will have to create thin wrapper layers to handle certain objects. My "favourite" was that I had to either wrap boost::shared_ptrs that way (and thus add another layer of indirection) or put them into shared_ptrs with null deleters after crossing the .NET/native boundary. Neither is very nice when you have to deal with APIs that use this sort of construct a lot. RAII doesn't cross this boundary, so be warned, you will have to invest some time into tweaking it to match the .NET way.
  • C++/CLI doesn't do multiple inheritance, so if your legacy library is making use of that you might have to model this using interfaces etc.
  • The internal marshalling code seems to be able to handle most POD conversions, but you'll have find/borrow code that converts std::strings etc. This code is around, a few minutes on Google should bring it up (sorry, don't have any links handy here at the moment).
鹿! 2024-07-18 15:32:41

它非常简单并且运行良好。 它比 PInvoke 容易得多。

您需要注意的一件大事是托管标头中没有任何非托管成员,包括私有成员、方法签名等。不过,拥有指向托管类型的指针的私有成员是可以的,只需对您的托管头使用前向声明即可。类。

另外,请注意对象的生命周期。 由于许多 .NET 程序员不习惯自行清理内存,因此很容易出现内存泄漏。 确保您创建的任何包装类(如果它们包含指针)都是一次性的,并确保在托管代码中处置它们。 托管 C++ 中 IDisposable 的语法也很奇怪,但它在文档中。

另外,请记住,每次跨越托管/非托管边界时,您都会遭受轻微的影响,因此请尝试相应地规划您的界面。 如果在循环中重复调用任何内容,最好将该循环移过边界,以便只跨越一次。 不过,除非您正在通话数百万个电话,否则不要太担心这一点。

这篇文章反其道而行之,但它有一些有用的观点。

使用我们的 ManWrap 库在本机 C++ 代码中充分利用 .NET

另请参阅

Visual Studio 2005 中的托管代码
删除托管对象、包装库等

It is pretty straight-forward and works well. It is a lot easier than PInvoke.

The big thing you need to watch out for is not having any unmanaged members in your managed headers, including private members, method signatures, etc. It is okay to have private members that are pointers to managed types though, just use forward declarations for your classes.

Also, watch out for object lifetime. It is easy to introduce memory leaks since many .NET programmers are not used to cleaning up after themselves. Make sure any wrapper classes that you create are disposable if they contain pointers and make sure you dispose of them in your managed code. The syntax for IDisposable in managed C++ is also weird, but it is in the docs.

Also, remember that you incur a slight hit every time you cross the managed/unmanaged boundary, so try to plan your interface accordingly. If anything gets called repeatedly in loops, it is probably better to move that loop across the boundary so you only cross once. Don't worry too much about this though unless you are talking millions of calls.

This article goes the other way, but it has some useful points.

Use Our ManWrap Library to Get the Best of .NET in Native C++ Code

See also

Managed Code in Visual Studio 2005 and
Deleting Managed Objects, Wrapping a Library, and More

橙味迷妹 2024-07-18 15:32:41

只是我们遇到的一些问题:

  • 内存/资源生命周期管理(GC/IDisposable 与析构函数)。 我认为这是众所周知的,Rob 的帖子有一些关于它的内容,所以我不会在这里详细介绍......
  • 字符串编码/解码。 如果您的本机代码是 UNICODE 构建,则不必太担心这一点,但如果不是,请在本机字符串和 .Net 字符串之间转换时仔细考虑编码。
  • C++ 不支持 [Conditional("Debug")],这意味着 Debug.Assert、Debug.Trace 等也将在发布版本中被调用。 请改用传统的 C++ 宏。
  • 64 位支持:.Net 默认情况下根据平台生成 32 或 64 位代码,但您的本机代码可能只是 32 位...

Just some issues which we encountered:

  • Memory/Resource lifetime management (GC/IDisposable vs. Destructors). I think this is well-known, and Rob's post has a couple of things about it, so I won't go into detail here...
  • String encoding/decoding. If your native code is an UNICODE build, you won't have to worry about this a lot, but if not, be think careful about encodings when converting between native strings and .Net Strings.
  • C++ doesn't honor [Conditional("Debug")], meaning that Debug.Assert, Debug.Trace etc. will also be called in release builds. Use the traditional C++ macros instead.
  • 64-Bit support: .Net by default generates 32 or 64-Bit code depending on the platform, but your native code will probably be 32-Bit only...
何止钟意 2024-07-18 15:32:41

我将添加每个人都已经说过的内容,

pin_ptr wch = PtrToStringChars(string); (其中 string 是 System::String)

将成为您的朋友。

您不能直接将非托管类包含到托管类中,但您可以放置​​一个指向非托管类的指针,并在构造函数中新建它,并在析构函数中删除它。

我还没有遇到 Timo Geusch 提到的在一个 DLL 中混合 C++ 和 C++/CLI 代码的问题。 我的 DLL 广泛使用两者,没有出现任何问题。

C++/CLI 并不困难(如果您了解 C++ 和 .NET)并且效果很好。

I'll just add to what everyone has already said,

pin_ptr wch = PtrToStringChars(string); (where string is a System::String)

will become your friend.

You can't directly include a non-managed class into a managed class but you can put a pointer to the unmanaged class and new it in your constructor and delete it in your destructor.

I haven't had the problems Timo Geusch mentioned with mixing C++ and C++/CLI code in one DLL. My DLL uses both extensively without problems.

C++/CLI is not difficult (if you know C++ and .NET) and works great.

氛圍 2024-07-18 15:32:41

正如其他人所说:98% 的时间它都能正常工作、可调试且速度快。

到目前为止我遇到的问题还没有提到:

  • 不要将所有遗留的 C++ 代码编译为托管代码。 有一些文章建议这会很有用,但通常只是速度较慢。
  • 不要忘记捕获非托管异常并将其作为托管异常重新抛出。
  • 如果您使用 MFC,请注意您无法使用 .lib 运行时,因此您也将部署 MFC 运行时。
  • OpenMP(线程库)无法在​​ C++/CLI 中运行。
  • 当我们从我们自己的代码中使 C++/CLI dll 依赖于 C# dll 时,我们在 VS2005 中遇到了一些构建问题。

它甚至运行得非常好,以至于我开始编写 C++/CLI 代码来对 C++ 代码运行单元测试。 NUnit/Resharper 会很高兴地在 C++/CLI DLL 中找到并运行单元测试,它可以在任何级别直接调用您的本机代码,甚至测试您的模板容器类。

As said by others: 98% of the time it just works, its debuggable, and fast.

What I encountered beyond mentiond so far:

  • Don't compile all your legacy c++ code as managed. There were some articles suggesting that would be useful, but it is usually just slower.
  • Don't forget to catch unmanaged exceptions and rethrow them as managed ones.
  • If you use MFC, note that you you can't use the .lib runtime, so you'll be deploying MFC runtimes as well.
  • OpenMP (a threading library) won't run in C++/CLI.
  • we had some build issues in VS2005 when we made the C++/CLI dll's dependent on C# dlls from our own code.

It even worked so well that I started on writing C++/CLI code to run unit tests on C++ code. NUnit/Resharper will happily find and run the unit test in a C++/CLI DLL, that can directly call into your native code at ANY LEVEL, even test your template container classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文