如何建立一个动态数组C ++编写,将其返回到C#/。NET将其、数组、建立一个、动态

2023-09-03 06:49:43 作者:童话再美终是假的ヽ

我必须找到建立在C ++的Win32侧结构的阵列的方式。我没有项目的初始数量。它应该是非常快的,以调整该数组。

I have to find the way to build the array of structs on C++ Win32 side. I don't have the initial number of items. It should be very fast to resize that array.

在列表构建的,我需要将其返回到.NET。使数组(清单)应转换为可用于这就容易可以读取.NET一侧或初始列表中的运输原样刚好路过的指针。

When the list is build, I need to return it back to .NET. So That array(list) should be converted to the transport which easily can be read on .NET side or the initial list can be used "as is" just passing the pointer.

在此先感谢给我一个提示!

Thanks in advance for giving me a hint!

推荐答案

在C ++中实施动态数组的一个很常见的方法是使用STL的 的std :: vector的 。你的情况,你可以定义一个矢量< SomeData> 的std ::矢量可以改变其大小的动态的(即在运行时),按你的要求:你可以使用它的的push_back emplace_back 方法为目的,添加新项目的载体。

A very common way of implementing "dynamic arrays" in C++ is to use STL's std::vector. In your case, you can define a vector<SomeData>. std::vector can change its size dynamically (i.e. at run-time), as per your request: you can use its push_back or emplace_back methods for that purpose, adding new items to the vector.

不过,C#不​​理解的std ::矢量

However, C# doesn't "understand" std::vector.

要编组的内容到C#,你可以使用 SAFEARRAY ,这对CLR的理解非常好。关于SAFEARRAY的好处是,它也存储数组的大小,除了阵列的内容:这是一个自包含的数据结构。 所以,你可以创建一个适当大小的SAFEARRAY,在载体动态创建的内容填充它,并SAFEARRAY传递到C#。

To marshal its content to C#, you could use a SAFEARRAY, which the CLR understands very well. The good thing about SAFEARRAY is that it stores also the array size, besides the array content: it's a self-contained data structure. So, you can create a SAFEARRAY of proper size, fill it with the content dynamically created in the vector, and pass that SAFEARRAY to C#.

请注意,您也可以建立一个SAFEARRAY直接,无需通过为标准::向量。但是,STL的载体具有更强大的编程接口;所以,如果你想要做的项目数增加通过的push_back或emplace_back在运行时,首先构建的std ::向量,然后编组到一个SAFEARRAY,可能是一个更好的选择。无论如何,这要看你的具体需求和环境。

Note that you could also build a SAFEARRAY directly, without passing for std::vector. But STL's vector has a more powerful programming interface; so if you want to do several additions of items via push_back or emplace_back at run-time, building the std::vector first, and then "marshalling" it into a SAFEARRAY, could be a better option. Anyway, that depends on your particular needs and context.

作为替代方案,你可以使用C ++ / CLI为C ++侧和C#侧之间的桥接层。在这种情况下,你可以使用 gcnew 来创建一个.NET管理 阵列

As an alternative, you could use C++/CLI as a bridging layer between the C++ side and the C# side. In this case you could use gcnew to create a .NET "managed" array.

和,作为另一种选择,你可以用一个C接口输出几个功能从本地C ++ DLL:

And, as another option, you could export a couple of functions from your native C++ DLL with a C interface:

一个函数来获取项目的数量阵列中

a function to get the count of items in the array

另一个函数来获得在输出调用者分配的缓冲区内的实际数组数据(其大小是由previous函数返回)

another function to get the actual array data in an output caller-allocated buffer (the size of which is returned by the previous function)

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

In C#, the output buffer pointer is passed using an IntPtr output parameter. You can then use Marshal.PtrToStructure to marshal a single data item, and you can increase the pointer using Marshal.SizeOf, to make it point to the next item in the array.

事情是这样的:

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