然而,我正在为C ++ CLI编写一个包装器,为我们的应用程序提供一些新的部件(用C#编写)保存并轻松访问旧的本机库。因此,我需要将一些结构从C#传递给C ++。这些结构在C ++ Cli(dotnet)和C ++中定义。
例:
\\C+++
typedef struct
{
INFO16 jahr ;
INFO8 monat ;
INFO8 tag ;
INFO8 stunde ;
INFO8 minute ;
}
SDATUM;
\\c++ cli
[StructLayout(LayoutKind::Explicit)]
public value struct SDATUM
{
public:
[FieldOffset(0)]
UInt16 jahr;
[FieldOffset(2)]
Byte monat;
[FieldOffset(3)]
Byte tag;
[FieldOffset(4)]
Byte stunde;
[FieldOffset(5)]
Byte minute;
};
现在我在C ++ cli中提供了一些函数,它们以pass by值的形式接受这种类型的dotnet类型SDATUM,引用(sdatum%)和指针sdatum *就像那里有相应的本机函数一样。我需要转换/转换这些结构?
我不会做任何演员。而是编写一个包含SDATUM的ref类。公开设置基础SDATUM的方法和属性。从C#端开始,使用这个ref类(或者更好的是,创建一个这个类实现的接口,让C#端与接口一起工作)。在C ++ / CLI中,您可以访问本机版本的类,并根据需要将其传递给本机方法。
请注意,C ++和.NET的复制语义根本不同:.NET使用垃圾收集共享引用,C ++使用复制构造函数。
C ++ / CLI不允许您将本机对象用作托管类的成员,您必须使用指针。所以我将使用boost共享指针来模仿.NET语义。
这可以抽象出来。这是我用来向.NET世界公开C ++类的类:
template <typename T>
ref class Handle
{
boost::shared_ptr<T>* t;
!Handle()
{
if (t != nullptr)
{
delete t;
t = nullptr;
}
}
~Handle() { this->!Handle(); }
public:
Handle() : t(new boost::shared_ptr<T>((T*)0)) {}
Handle(T* ptr) : t(new boost::shared_ptr<T>(ptr)) {}
Handle% operator=(T* p)
{
if (p != t->get()) t->reset(p);
return *this;
}
T* get() { return t->get(); }
// Remember that operators are static in .NET
static boost::shared_ptr<T> operator->(Handle% h) { return *h.t; }
T& reference() { return *t->get(); }
T const& const_reference() { return *t->get(); }
};
然后你可以使用:
ref class MyStruct
{
public:
// Expose your .NET interface here, make it use the handle variable.
internal:
Handle<Native::MyStruct> handle;
};
并在C ++代码中使用handle
成员变量,没有任何限制。它不会在.NET中显示。然后,您可以以.NET方式公开属性,访问器,运算符等。
我找到了另一个非常简单,简单并且不需要复制数据的解决方案。您可以通过这种方式调用需要C SDATUM的本机函数:
//signature
void someFunction(SDATUM datum);
void someFunctionWrapper(SDATUM datum){
pin_ptr<SDATUM> datum_pin=&datum;
//::SDATUM refers to the C-Type
someFunction(*(::SDATUM*)datum_pin);
}
我测试了它,它的工作原理是因为两个SDATUM结构具有相同的位结构。因为我只调用短的本机函数,所以我认为碎片是没有问题的。