Возврат вектора из собственной библиотеки DLL C ++ в управляемую dll C ++ / CLI

Я пишу оболочку CLI / C ++ вокруг собственной библиотеки DLL C ++, которую нельзя изменить. Одна из функций собственной библиотеки DLL возвращает вектор неуправляемых объектов. Как лучше всего поместить этот вектор в оболочку CLI? Оболочка CLI будет использоваться приложением C #.

class __declspec(dllexport) Instrument
{
  public:
        Instrument();
        ~Instrument();
        string _type;
        unsigned int _depth;
}

В собственной DLL есть функция getInstruments (), которую я пытаюсь обернуть.

 class __declspec(dllexport) InstrumentList
   {
       InstrumentList();
       ~InstrumentList();
       vector<Instrument*> getInstruments();
   }

Поэтому мне нужно обернуть класс инструмента в управляемый класс, а класс InstrumentList - в управляемый класс. У меня есть упакованный класс Instrument, но мне нужно преобразовать вектор, возвращаемый getInstruments (), в нечто эквивалентное, которое может вернуть оболочка CLI для InstrumentList.


person JonF    schedule 19.05.2011    source источник
comment
Может быть, просто преобразовать вектор в указатель и вернуть указатель?   -  person Seth Carnegie    schedule 20.05.2011
comment
Когда вы хотите маршалировать данные? Каждый раз при обращении к Instrument::_type или один раз при вызове InstrumentList::getInstruments()?   -  person ildjarn    schedule 20.05.2011
comment
@SethCarnegie: C # не имеет понятия, что такое std::vector<> или std::string, так что это было бы не очень полезно.   -  person ildjarn    schedule 20.05.2011
comment
@ildjarn - я могу обернуть инструмент уже в класс, который я назову manInstrument. Я хочу максимально эффективно упорядочить вектор инструмента. Я думаю, мне нужно обернуть каждый объект Instrument как manInstrument и вернуть некоторый объект векторного типа из управляемого getInstrument   -  person JonF    schedule 20.05.2011
comment
когда вы говорите обертывание, вы имеете в виду, что у вас есть ссылочный класс (управляемый) с неуправляемым (Instrument) объектом в нем, или у вас есть ссылочный класс, который отражает исходный класс Instrument, и вы создаете его экземпляр, когда вам нужно работать с инструментами в C ++ / CLI   -  person Marius Bancila    schedule 20.05.2011
comment
Ваша собственная DLL неисправна, std::vector не гарантируется наличие совместимых определений в разных библиотеках DLL, поэтому ее экспорт через границы DLL - очень плохая идея. То же для std::string. Помещение собственного кода и управляемой оболочки в одну DLL было бы хорошо, детали C ++ скрыты внутри одной DLL, а объекты .NET имеют стандартные двоичные интерфейсы, которые могут пересекать границы DLL.   -  person Ben Voigt    schedule 20.05.2011
comment
@ildjarn Я имею в виду, взять указатель на начало элементов, которые вектор хранил (поскольку он должен хранить их в последовательных ячейках памяти), и дать C # указатель на элементы (и количество имеющихся элементов). Я не говорил о передаче указателя на вектор.   -  person Seth Carnegie    schedule 20.05.2011


Ответы (2)


Если вы не хотите отложить маршалинг Instrument::_type до получения доступа к его управляемому фасаду, это должно помочь вам начать:

public ref class InstrumentM
{
    String^ _type;
    unsigned _depth;

internal:
    explicit InstrumentM(Instrument const& i)
      : _type(gcnew String(i._type.c_str())),
        _depth(i._depth)
    { }

public:
    property String^ Type { String^ get() { return _type; } }
    property unsigned Depth { unsigned get() { return _depth; } }
};

public ref class InstrumentListM
{
    InstrumentList* _list;

public:
    InstrumentListM() : _list(new InstrumentList()) { }
    ~InstrumentListM() { this->!InstrumentListM(); }
    !InstrumentListM()
    {
        delete _list;
        _list = nullptr;
    }

    array<InstrumentM^>^ GetInstruments()
    {
        if (!_list)
            throw gcnew ObjectDisposedException(L"_list");

        vector<Instrument*> const& v = _list->getInstruments();
        array<InstrumentM^>^ ret = gcnew array<InstrumentM^>(v.size());
        for (int i = 0, i_max = ret->Length; i != i_max; ++i)
            if (v[i])
                ret[i] = gcnew InstrumentM(*v[i])
        return ret;
    }
};
person ildjarn    schedule 19.05.2011

Возможно, вы вообще не захотите оборачивать InstrumentList.

Просто используйте одну из стандартных коллекций .NET (к которой вы можете получить доступ из C ++ / CLI) и создайте коллекцию ваших оболочек инструментов. Я использую ObservableCollection, так как хочу привязать данные к своим коллекциям.

Пример:

public ref class MyManagedType
{
    public:
        MyManagedType(MyNativeType* pObject) { m_pObject = pObject };

    private:
        MyNativeType* m_pObject;
}

Затем создайте управляемую коллекцию следующим образом:

ObservableCollection<MyManagedType^>^ managedCollection = gcnew ObservableCollection<MyManagedType^>();

Наконец, добавьте объекты в коллекцию:

managedCollection->Add(gcnew MyManagedType(pNativeObject));

Синхронизировать собственные и управляемые коллекции требует немного усилий, но это хорошо работает.

person 17 of 26    schedule 19.05.2011