Wrapper for DOTNET to native written in C++ CLI BestWay to pass structures?
Yet I am writing a wrapper in C++ CLI for our application to give some new parts (written in C#) save and easy access to old native libraries. Therefore I need to pass some structures from C# to C++. These structures are defined in C++ Cli (dotnet) and also in C++.
Example:
\\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;
};
开发者_如何转开发Now I provide some functions in C++ cli which accept this type as dotnet type SDATUM in form of pass by value,by reference (sdatum%) and pointer sdatum* like there corresponding native functions. What do I need to convert/cast these struct?
I wouldn't do any casting. Rather, write a ref class that contains an SDATUM. Expose methods and properties that set the underlying SDATUM. From the C# side, work with this ref class (or better yet, create an interface that this class implements and have the C# side work with the interface). In C++/CLI you can access the native version of class and pass it to native methods as needed.
Beware that copy semantics of C++ and .NET fundamentally differ: .NET use garbage collected shared references and C++ use copy constructors.
C++/CLI won't let you use native objects as members of managed classes, you'll have to use pointers. So I'll use boost shared pointers to mimick the .NET semantics.
This can be abstracted away. Here is the class I use to expose C++ classes to the .NET world:
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(); }
};
Then you can use:
ref class MyStruct
{
public:
// Expose your .NET interface here, make it use the handle variable.
internal:
Handle<Native::MyStruct> handle;
};
and use the handle
member variable in your C++ code with no restrictions. It will not be shown in .NET. Then you can expose properties, accessors, operators, etc. in the .NET fashion.
I found another solution which is very easy, short and does not need copying data. You could call native functions which want a C SDATUM in this way:
//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);
}
I tested it and it works because both SDATUM Structs have the same bit structure. Because I only call short native functions I think fragmentation is no problem.
精彩评论