包装C ++用于C# [英] Wrapping C++ for use in C#

查看:151
本文介绍了包装C ++用于C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,基本上有一个大C ++项目(国际)的,我想换行这样我可以在我的C#项目中使用它。



我一直在努力,现在一会儿做到这一点,这是我到目前为止所。我使用C ++ / CLI来包装,我需要这样我可以在C#中使用它们的类。



不过,也有一吨的结构和枚举的,我还需要在我的C#项目。所以,我怎么包装吗?



我现在使用是增加DLLEXPORT的基本方法调用本地C ++代码,编译为一个dll / lib目录,添加此LIB我的C ++ / CLI项目并导入C ++头,然后编译CLI项目成一个dll,最后加入这个DLL作为我的C#项目的引用。我感谢所有帮助。



下面是一些需要code..I自从C ++项目是如此之大,这样的管理的方式。

  // **本地托管C ++代码
//**Recast.h

枚举rcTimerLabel
$ { b $ b比率,
b,
C
};

的externC{

类__declspec(dllexport)的rcContext
{
公众:
直列rcContect(布尔州);
虚拟〜rcContect(){}
内嵌无效resetlog方式(){如果(m_logEnabled)doResetLog(); }

保护:
布尔m_logEnabled;
}

结构rcConfig
{
INT宽度;
INT高度;
}

} //对外部


// **托管代码CLI
// ** MyWrappers.h $结束b $ b#包括Recast.h

命名空间封装器
{
公共引用类MyWrapper
{
私人:
rcContect * _NativeClass;
公众:
MyWrapper(布尔州);
〜MyWrapper();
无效resetlog方式();
无效enableLog(布尔州){_NativeClass-> enableLog(状态); }
};
}

//**MyWrapper.cpp
#包括MyWrappers.h

命名空间封装器
{
MyWrapper :: MyWrapper(布尔州)
{
_NativeClass =新rcContext(州);
}

MyWrapper ::〜MyWrapper()
{
删除_NativeClass;
}
无效MyWrapper :: resetlog方式()
{
_NativeClass-> resetlog方式();
}
}


// ** C#代码
// ** Program.cs的

命名空间recast_cs_test
{
公共类节目
{
静态无效的主要()
{
MyWrapper myWrapperTest =新MyWrapper(真);
myWrapperTest.resetLog();
myWrapperTest.enableLog(真);
}
}
}


解决方案

作为一个规则,在C / C ++结构用于与本机代码沟通,而你使用.NET代码创建沟通CLI类。 C结构都在,他们只能存储数据的哑。 .NET编程,在另一方面,期望他们的数据结构为智能。例如:



如果我改变高度参数中的一个结构,我知道对象的高度不会实际改变,直到我传递结构给更新功能。然而,在C#中,常见的成语是值表示为属性,更新财产将立即做出这些变化的活。



这样我可以做的事情这样的: myshape.dimensions.height = 15 ,只是希望它的工作。



要在一定程度上,则露出到.NET显影剂(如班)的结构实际上是在该API,与行为被映射到在这些类的属性和方法。而在C中,结构被简单地用作传入和传出该做的工作职能变量。换句话说,.NET通常是一个面向对象的范例,而C是没有的。和很多C ++代码实际上是C,抛出的香料一些看中位。



如果您在C和.NET之间书写转换层再大的你工作的一部分是设计的对象,这将使你的新的API,并提供翻译的基本功能。在C代码的结构不一​​定是你的新对象层次结构的一部分; 。他们只是在C API的一部分



编辑补充:



还要考虑



此外,你可能要重新考虑你的选择使用C ++ / CLI,并考虑C#和p /调用代替。由于种种原因,我曾经写过使用C ++ / CLI OpenSSL的包装,而这是令人印象深刻的是多么容易建立,以及它如何无缝工作,有一些烦恼。具体来说,装帧紧,所以父项目(OpenSSL的)加速运转他们的图书馆,我不得不重新编译我的包装,以配合每一次。另外,我的包装是永远依赖于特定的体系结构(无论是64位或32位),它也有相匹配的基础库的构建架构。你仍然可以架构与问题的P / Invoke,但他们一点就好办了。此外,C ++ / CLI不反省工具,如反射打出好成绩。最后,你建库是不能移植到单声道。我不认为这将最终成为一个问题。但最后,我不得不从头开始,并在C#中使用对重新做整个项目/调用代替。



在一方面,我高兴我做到了C ++ / CLI的项目,因为我学到了很多都在同一个项目,托管和非托管代码和内存的工作。但在另一方面,它肯定是一个很大的时间,我可以在其他事情上度过的。


Ok, basically there is a large C++ project (Recast) that I want to wrap so that I can use it in my C# project.

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#.

However, there are a ton of structs and enums that I will also need in my C# project. 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. I appreciate any help.

Here is some code..I need manageable way of doing this since the C++ project is so large.

//**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 structs are "dumb" in that they can only store data. .NET programmers, on the other hand, expect their data-structures to be "smart". 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. However, in C#, the common idiom is that values are represented as Properties, and updating the property will immediately make those changes "live".

That way I can do things like: myshape.dimensions.height = 15 and just expect it to "work".

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. While in C, the structures are simply used as variables passed to and from the functions that do the work. In other words, .NET is usually an object-oriented paradigm, while C is not. And a lot of C++ code is actually C with a few fancy bits thrown in for 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. The structs in the C code aren't necessarily part of your new object hierarchy; they're just part of the 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. 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. 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. 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. You still get architecture issues with p/invoke, but they're a bit easier to handle. Also, C++/CLI doesn't play well with introspection tools like Reflector. And finally, the library you build isn't portable to 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.

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. But on the other hand, it sure was a lot of time I could have spent on other things.

这篇关于包装C ++用于C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆