ere*_*l55 8 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
通常,C/C++ 结构用于与本机代码通信,而您创建 CLI 类用于与 .NET 代码通信。C 结构体是“哑”的,因为它们只能存储数据。另一方面,.NET 程序员希望他们的数据结构是“智能的”。例如:
如果我更改结构中的“高度”参数,我知道在将该结构传递给更新函数之前,对象的高度实际上不会改变。然而,在 C# 中,常见的习惯用法是值表示为属性,更新属性将立即使这些更改“生效”。
这样我就可以做类似的事情:myshape.dimensions.height = 15并期望它“起作用”。
在某种程度上,您向 .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 项目,因为我学到了很多关于在一个项目中使用托管和非托管代码和内存的知识。但另一方面,我确实可以花很多时间在其他事情上。