【问题标题】:Returning a vector from a native C++ dll into a managed C++/CLI dll将本机 C++ dll 中的向量返回到托管 C++/CLI dll
【发布时间】:2011-08-29 04:35:11
【问题描述】:

我正在围绕无法更改的本机 C++ dll 编写 CLI/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() 返回的向量转换为 InstrumentList 的 CLI 包装器可以返回的等效值。

【问题讨论】:

  • 也许只是将向量转换为指针并返回指针?
  • 您希望何时封送数据?每次访问Instrument::_type 还是调用一次InstrumentList::getInstruments()
  • @SethCarnegie : C# 不知道 std::vector&lt;&gt;std::string 是什么,所以这不是很有用。
  • 您的本地 DLL 已损坏,std::vector 不能保证在不同的 DLL 中具有兼容的定义,因此跨 DLL 边界导出它是一个非常糟糕的主意。 std::string 同上。将本机代码和托管包装器放入单个 DLL 就可以了,C++ 细节隐藏在单个 DLL 中,.NET 对象被设计为具有可以跨 DLL 边界的标准二进制接口。
  • @ildjarn 我的意思是将指针指向向量存储的元素的开头(因为它必须将它们存储在连续的内存位置中)并给 C# 指向元素的指针(以及元素的数量有)。我不是在谈论将指针传递给向量。

标签: visual-c++ dll c++-cli interop mixed-mode


【解决方案1】:

除非您想延迟 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;
    }
};

【讨论】:

    【解决方案2】:

    您可能根本不想包装 InstrumentList。

    只需使用一个现有的 .NET 集合(您可以从 C++/CLI 访问)并制作您的 Instrument 包装器集合。我一直在使用 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));
    

    让原生集合和托管集合保持同步需要付出一些努力,但效果很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-14
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多