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

时间:2012-03-01 18:34:20

标签: c# c++ dll c++-cli wrapper

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

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

但是,我的C#项目中还需要大量的结构和枚举。那么如何包装这些?

我现在使用的基本方法是将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);
      }
   }
}

4 个答案:

答案 0 :(得分:4)

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

如果我更改结构中的“height”参数,我知道在将该结构传递给更新函数之前,对象的高度实际上不会改变。但是,在C#中,常见的习惯用法是将值表示为Properties,更新属性将立即使这些更改“生效”。

这样我可以做一些事情:myshape.dimensions.height = 15并期望它“工作”。

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

如果您正在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项目,因为我学到了很多关于在一个项目中使用托管和非托管代码和内存的知识。但另一方面,我确实花了很多时间在其他事情上。

答案 1 :(得分:2)

我会考虑使用ATL创建COM服务器。但它不会是一个简单的端口。您必须创建COM兼容接口,以显示您尝试包装的库的功能。最后,您将拥有更多控制权和完全支持的COM Interop接口。

答案 2 :(得分:2)

答案 3 :(得分:0)

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