Wrapper для DOTNET на родной написано в C ++ CLI BestWay для передачи структур? - PullRequest
2 голосов
/ 21 марта 2011

Тем не менее я пишу оболочку в 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, которые принимают этот тип как тип dotnet SDATUM в формепередачи по значению, по ссылке (sdatum%) и по указателю sdatum *, как там, где соответствующие нативные функции.Что мне нужно для преобразования / приведения этих структур?

Ответы [ 3 ]

2 голосов
/ 21 марта 2011

Остерегайтесь того, что семантика копирования в C ++ и .NET принципиально отличается: .NET использует общие ссылки для сбора мусора, а C ++ использует конструкторы копирования.

C ++ / CLI не позволит использовать собственные объекты в качестве членов управляемых классов, вам придется использовать указатели.Поэтому я буду использовать общие указатели boost для имитации семантики .NET.

Это можно абстрагировать.Вот класс, который я использую для представления классов C ++ в мире .NET:

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;
};

и использовать переменную-член handle в вашем C ++Код без ограничений.Это не будет показано в .NET.Затем вы можете выставлять свойства, методы доступа, операторы и т. Д. В стиле .NET.

2 голосов
/ 21 марта 2011

Я бы не стал кастоваться.Скорее напишите класс ref, который содержит SDATUM.Предоставьте методы и свойства, которые устанавливают базовый SDATUM.Со стороны C # работайте с этим классом ref (или, что еще лучше, создайте интерфейс, который реализует этот класс, и сделайте так, чтобы сторона C # работала с этим интерфейсом).В C ++ / CLI вы можете получить доступ к собственной версии класса и при необходимости передать ее нативным методам.

0 голосов
/ 30 марта 2011

Я нашел другое решение, которое очень просто, коротко и не требует копирования данных. Вы можете вызывать нативные функции, которые хотят SDATUM C, следующим образом:

//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 имеют одинаковую структуру битов. Потому что я звоню только короткие родные функции, я думаю, что фрагментация не проблема.

...