Wrapper for DOTNET to native written in C++ CLI BestWay to pass structures?

本小妞迷上赌 提交于 2019-12-07 19:41:23

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/5375370/wrapper-for-dotnet-to-native-written-in-c-cli-bestway-to-pass-structures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!