包装C++以在C#中使用

Wrapping C++ for use in C#

本文关键字:C++ 以在 包装      更新时间:2023-10-16

好的,基本上有一个大型C++项目(Recast),我想包装它,以便在我的C#项目中使用它。

我已经尝试了一段时间了,这就是我目前为止所做的。我正在使用C++/CLI来包装我需要的类,以便在C#中使用它们。

然而,在我的C#项目中,我还需要大量的structs和enum。那么我该如何包装这些呢?

我现在使用的基本方法是将dllexport调用添加到本机c++代码中,编译到dll/lib,将此lib添加到我的c++/CLI项目中并导入c++头,然后将CLI项目编译到dll中,最后将此dll添加为对我的c#项目的引用。我感谢你的帮助。

这是一些代码。。我需要一种可管理的方法来做这件事,因为C++项目太大了。

//**Native unmanaged C++ code
//**Recast.h
enum rcTimerLabel
{
   A,
   B,
   C
};
extern "C" {
class __declspec(dllexport) rcContext
{
   public:
   inline rcContect(bool state);
   virtual ~rcContect() {}
   inline void resetLog() { if(m_logEnabled) doResetLog(); }
   protected:
   bool m_logEnabled;
}
struct rcConfig
{
   int width;
   int height;
}
} // end of extern

// **Managed CLI code
// **MyWrappers.h
#include "Recast.h"
namespace Wrappers
{
   public ref class MyWrapper
   {
   private:
     rcContect* _NativeClass;
   public:
     MyWrapper(bool state);
     ~MyWrapper();
     void resetLog();
     void enableLog(bool state) {_NativeClass->enableLog(state); }
   };
}
//**MyWrapper.cpp
#include "MyWrappers.h"
namespace Wrappers
{
   MyWrapper::MyWrapper(bool state)
   {
      _NativeClass = new rcContext(state);
   }
   MyWrapper::~MyWrapper()
   {
      delete _NativeClass;
   }
   void MyWrapper::resetLog()       
   {
      _NativeClass->resetLog();
   }
}

// **C# code
// **Program.cs
namespace recast_cs_test
{
   public class Program
   {
      static void Main()
      {
          MyWrapper myWrapperTest = new MyWrapper(true);
          myWrapperTest.resetLog();
          myWrapperTest.enableLog(true);
      }
   }
}

通常,C/C++结构用于与本机代码通信,而创建CLI类用于与.NET代码通信。C结构是";愚蠢的";因为它们只能存储数据。NET程序员则期望他们的数据结构是";"聪明";。例如:

如果我改变";高度";参数,我知道对象的高度实际上不会改变,直到我将该结构传递给更新函数。然而,在C#中,常见的习惯用法是将值表示为Properties,更新该属性将立即做出这些更改"生活";。

这样我就可以做一些事情,比如:CCD_;工作";。

在某种程度上,您向.NET开发人员公开的结构(作为类)实际上是API,行为映射到这些类的属性和方法。而在C中,结构只是用作传递给执行工作的函数的变量。换句话说,.NET通常是一种面向对象的范例,而C则不是。很多C++代码实际上都是C,并添加了一些有趣的部分。

如果您正在编写C和.NET之间的翻译层,那么您的工作的很大一部分就是设计构成新API的对象,并为底层功能提供翻译。C代码中的结构不一定是新对象层次结构的一部分;它们只是C API的一部分。

编辑以添加:

还要考虑

此外,您可能需要重新考虑使用C++/CLI的选择,并考虑使用C#和p/invoke。出于各种原因,我曾经使用C++/CLI为OpenSSL编写了一个包装器,虽然构建起来非常容易,工作起来非常无缝,但也有一些烦恼。具体来说,绑定很紧,所以每次父项目(OpenSSL)更新它们的库时,我都必须重新编译我的包装器以匹配。此外,我的包装器永远绑定到一个特定的体系结构(64位或32位),该体系结构还必须与底层库的构建体系结构相匹配。使用p/invoke仍然会遇到体系结构问题,但它们更容易处理。此外,C++/CLI不能很好地与Reflector等内省工具配合使用。最后,您构建的库不能移植到Mono。我没想到这会成为一个问题。但最终,我不得不从头开始,并使用p/invoke在C#中重新完成整个项目。

一方面,我很高兴我完成了C++/CLI项目,因为我学到了很多关于在一个项目中处理托管和非托管代码以及内存的知识。但另一方面,我本可以花很多时间在其他事情上。

我会考虑使用ATL创建COM服务器。不过,这不会是一个简单的端口。您必须创建COM兼容接口,以公开您试图包装的库的功能。最终,您将拥有更多的控制权和完全支持的COM互操作接口。

如果您准备使用p/Invoke,SWIG软件可能会帮助您:http://www.swig.org/