简体   繁体   English

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

[英]Wrapping C++ for use in C#

Ok, basically there is a large C++ project (Recast) that I want to wrap so that I can use it in my C# project. 好吧,基本上我要包装一个大的C ++项目(Recast) ,以便我可以在我的C#项目中使用它。

I've been trying to do this for a while now, and this is what I have so far. 我一直试图这样做一段时间,这就是我到目前为止所做的。 I'm using C++/CLI to wrap the classes that I need so that I can use them in C#. 我正在使用C ++ / CLI来包装我需要的类,以便我可以在C#中使用它们。

However, there are a ton of structs and enums that I will also need in my C# project. 但是,我的C#项目中还需要大量的结构和枚举。 So how do I wrap these? 那么如何包装这些呢?

The basic method I'm using right now is adding dllexport calls to native c++ code, compiling to a dll/lib, adding this lib to my C++/CLI project and importing the c++ headers, then compiling the CLI project into a dll, finally adding this dll as a reference to my C# project. 我现在使用的基本方法是将dllexport调用添加到本机c ++代码,编译为dll / lib,将此lib添加到我的C ++ / CLI项目并导入c ++头文件,然后将CLI项目编译为dll,最后添加此dll作为我的C#项目的参考。 I appreciate any help. 我感谢任何帮助。

Here is some code..I need manageable way of doing this since the C++ project is so large. 这里有一些代码。由于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);
      }
   }
}

As a rule, the C/C++ structs are used for communicating with the native code, while you create CLI classes for communicating with the .NET code. 通常,C / C ++结构用于与本机代码通信,同时您创建用于与.NET代码通信的CLI类。 C structs are "dumb" in that they can only store data. C结构是“愚蠢的”,因为它们只能存储数据。 .NET programmers, on the other hand, expect their data-structures to be "smart". 另一方面,.NET程序员期望他们的数据结构“聪明”。 For example: 例如:

If I change the "height" parameter in a struct, I know that the height of the object won't actually change until I pass that struct to an update function. 如果我更改结构中的“height”参数,我知道在我将该结构传递给更新函数之前,对象的高度实际上不会改变。 However, in C#, the common idiom is that values are represented as Properties, and updating the property will immediately make those changes "live". 但是,在C#中,常见的习惯用法是将值表示为Properties,更新属性将立即使这些更改“生效”。

That way I can do things like: myshape.dimensions.height = 15 and just expect it to "work". 这样我可以做的事情: myshape.dimensions.height = 15 ,只是期望它“工作”。

To a certain extent, the structures you expose to the .NET developer (as classes) actually ARE the API, with the behaviors being mapped to properties and methods on those classes. 在某种程度上,您向.NET开发人员公开的结构(作为类)实际上是API,其行为被映射到这些类的属性和方法。 While in C, the structures are simply used as variables passed to and from the functions that do the work. 在C语言中,结构仅用作传递给执行工作的函数的变量。 In other words, .NET is usually an object-oriented paradigm, while C is not. 换句话说,.NET通常是面向对象的范例,而C则不是。 And a lot of C++ code is actually C with a few fancy bits thrown in for spice. 而且很多C ++代码实际上都是C,并且有一些花哨的位用于spice。

If you're writing translation layer between C and .NET, then a big part of your job is to devise the objects that will make up your new API and provide the translation to your underlying functionality. 如果您在C和.NET之间编写转换层,那么您的工作很大一部分就是设计构成新API的对象并为您的基础功能提供转换。 The structs in the C code aren't necessarily part of your new object hierarchy; C代码中的结构不一定是新对象层次结构的一部分; they're just part of the C API. 它们只是C API的一部分。

edit to add: 编辑添加:

Also to Consider 还要考虑一下

Also, you may want to re-consider your choice to use C++/CLI and consider C# and p/invoke instead. 此外,您可能需要重新考虑使用C ++ / CLI并考虑使用C#和p / invoke。 For various reasons, I once wrote a wrapper for OpenSSL using C++/CLI, and while it was impressive how easy it was to build and how seamless it worked, there were a few annoyances. 出于各种原因,我曾经使用C ++ / CLI为OpenSSL编写了一个包装器,虽然令人印象深刻的是它构建起来有多容易以及它的工作无缝,但有一些烦恼。 Specifically, the bindings were tight, so every time the the parent project (OpenSSL) revved their library, I had to re-compile my wrapper to match. 具体来说,绑定是紧的,所以每次父项目(OpenSSL)加速他们的库时,我不得不重新编译我的包装器来匹配。 Also, my wrapper was forever tied to a specific architecture (either 64-bit or 32-bit) which also had to match the build architecture of the underlying library. 此外,我的包装器永远绑定到特定的体系结构(64位或32位),它也必须与底层库的构建体系结构相匹配。 You still get architecture issues with p/invoke, but they're a bit easier to handle. 您仍然可以通过p / invoke获得体系结构问题,但它们更容易处理。 Also, C++/CLI doesn't play well with introspection tools like Reflector. 此外,C ++ / CLI与Reflector等内省工具不兼容。 And finally, the library you build isn't portable to Mono. 最后,您构建的库不能移植到Mono。 I didn't think that would end up being an issue. 我认为这不会成为一个问题。 But in the end, I had to start over from scratch and re-do the entire project in C# using p/invoke instead. 但最后,我不得不从头开始并使用p / invoke在C#中重新执行整个项目。

On the one hand, I'm glad I did the C++/CLI project because I learned a lot about working with managed and unmanaged code and memory all in one project. 一方面,我很高兴我做了C ++ / CLI项目,因为我学到了很多关于在一个项目中使用托管和非托管代码和内存的知识。 But on the other hand, it sure was a lot of time I could have spent on other things. 但另一方面,我确实花了很多时间在其他事情上。

I would look at creating a COM server using ATL . 我会看一下使用ATL创建一个COM服务器。 It won't be a simple port, though. 但它不会是一个简单的端口。 You'll have to create COM compatible interfaces that expose the functionality of the library you're trying to wrap. 您必须创建COM兼容接口,以显示您尝试包装的库的功能。 In the end, you will have more control and a fully supported COM Interop interface. 最后,您将拥有更多控制权和完全支持的COM Interop接口。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM