开发者

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

开发者 https://www.devze.com 2023-02-18 12:36 出处:网络
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++.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号