如何在C ++中构建动态数组并将其返回给C#/。NET

时间:2015-06-05 15:38:12

标签: c# c++ .net arrays winapi

我必须找到在C ++ Win32端构建结构数组的方法。我没有最初的项目数。调整该数组的速度应该非常快。

构建列表时,我需要将其返回给.NET。因此,数组(列表)应该转换为可以在.NET端轻松读取的传输,或者初始列表可以“按原样”使用,只需传递指针。

先谢谢你给我一个提示!

2 个答案:

答案 0 :(得分:3)

通常,如果使用CLI支持编译C ++ dll,则只需使用托管容器即可。如果您不希望使用CLI选项编译您的dll,那么您可以编写小型C ++ / CLI包装器DLL,它将从本机C ++ DLL调用方法并在托管容器中存储对象。 另一种可能的解决方案是更改C ++ lib的接口以通过索引返回对象,支持插入和/或删除。

std::vector<CFoo> vec;

void init() {
    //read data to vec
}

CFoo getIthElement(int i) {
    return vec[i];
}

int getElementCount() {
    return vec.size();
}

因此,您将在C#端使用getIthElementgetElementCount函数。

答案 1 :(得分:3)

实现&#34;动态数组的一种非常常见的方式&#34;在C ++中使用STL的 std::vector 。在您的情况下,您可以定义vector<SomeData>std::vector可以根据您的请求动态更改动态(即在运行时):您可以将push_backemplace_back方法用于此目的,向矢量添加新项目。

然而,C#并没有理解&#34; std::vector

要将其内容整理到C#,您可以使用 SAFEARRAY ,这是CLR非常了解的。 SAFEARRAY的好处在于它除了数组内容之外还存储了数组大小:它是一个独立的数据结构。 因此,您可以创建一个适当大小的SAFEARRAY,用向量中动态创建的内容填充它,并将该SAFEARRAY传递给C#。

请注意,您也可以直接构建SAFEARRAY,而不传递std :: vector。但STL的矢量具有更强大的编程接口;所以如果你想在运行时通过push_back或emplace_back做几个项目的添加,首先构建std :: vector,然后&#34; marshalling&#34;进入SAFEARRAY,可能是更好的选择。无论如何,这取决于您的特定需求和背景。

作为替代方案,您可以使用C ++ / CLI作为C ++端和C#端之间的桥接层。在这种情况下,您可以使用gcnew来创建.NET&#34;托管&#34;的 array

另外,作为另一种选择,您可以使用C接口从本机C ++ DLL导出几个函数:

  • 获取数组中项目数的函数

  • 另一个函数,用于在输出调用者分配的缓冲区中获取实际的数组数据(其大小由前一个函数返回)

在C#中,使用IntPtr输出参数传递输出缓冲区指针 然后,您可以使用Marshal.PtrToStructure编组单个数据项,并且可以使用Marshal.SizeOf增加指针,使其指向数组中的下一个项目。

这样的事情:

// In C++:

struct SomeData
{
    /* your data fields */
};

// Export these two functions from your native DLL:
extern "C" int GetSomeDataCount( /* some params */ );
extern "C" void GetSomeData( SomeData* ptr, /* some other params */ );


// In C#:    

public struct SomeData
{
    // Map C++ data structure fields to C#
}

static extern int GetSomeDataCount( /* some params */ );
static extern void GetSomeData( [Out] out IntPtr ptr, /* some other params */ );

SomeData[] GetSomeData( /* some params */ )
{
    // Allocate an array of proper size
    SomeData[] dataArray = new SomeData[ GetSomeDataCount( /* some params */ ) ];

    // Fill the array with content from GetSomeData
    IntPtr dataPtr;
    GetSomeData( out dataPtr, /* some other params */ );
    for (int i = 0; i < dataArray.Length; i++)
    {
        dataArray[i] = Marshal.PtrToStructure(dataPtr, typeof(SomeData));
        dataPtr += Marshal.SizeOf(typeof(SomeData));
    }
    return dataArray;
}