How to build a dynamic array in C ++ and return it back to C # /. NET

I need to find a way to build an array of structures on the C ++ Win32 side. I do not have an initial number of elements. To resize this array must be very fast.

When the list is created, I need to return it back to .NET. Thus, an array (list) must be converted to a transport that can easily be read on the .NET side, or the original list can be used "as is", simply by passing a pointer.

Thanks in advance for the tip!

+2
source share
2 answers

A very common way to implement "dynamic arrays" in C ++ is to use STL std::vector . In your case, you can define vector<SomeData> . std::vector can change its size dynamically (i.e. at runtime) according to your request: you can use its push_back or emplace_back for this purpose, adding new elements to the vector.

However, C # does not understand std::vector .

To streamline its contents to C #, you can use SAFEARRAY , which the CLR understands perfectly. The good thing about SAFEARRAY is that it also stores the size of the array, in addition to the contents of the array: it is an autonomous data structure. That way you can create a SAFEARRAY of the correct size, fill it with content dynamically created in the vector, and pass that SAFEARRAY to C #.

Note that you can also create SAFEARRAY directly, without passing for std :: vector. But the STL vector has a more powerful programming interface; therefore, if you want to do multiple item additions via push_back or emplace_back at run time, first create std :: vector and then "marshalling" in SAFEARRAY, might be a better option. In any case, it depends on your specific needs and context.


Alternatively, you can use C ++ / CLI as a tie layer between C ++ and C #. In this case, you can use gcnew to create managed .NET. array


And, as another option, you can export several functions from your native C ++ library with the C interface:

  • function to get the number of elements in an array

  • one more function to get the actual data of the array in the buffer allocated by the output (the size of which is returned by the previous function)

In C #, the output buffer pointer is passed using the IntPtr output parameter.
Then you can use Marshal.PtrToStructure to marshal one data item, and you can increase the pointer with Marshal.SizeOf so that it points to the next item in the array.

Something like that:

 // 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; } 
+3
source

Usually, if your C ++ dll is compiled with CLI support, you can just use managed containers. If you do not want your dll to be compiled with the CLI option, you can write a small C ++ / CLI DLL wrapper that will call methods from the native C ++ dll and store the objects in a managed container. Another possible solution is to change the C ++ library interface to return objects by index, support for insertion and / or deletion.

 std::vector<CFoo> vec; void init() { //read data to vec } CFoo getIthElement(int i) { return vec[i]; } int getElementCount() { return vec.size(); } 

This way you will use the getIthElement and getElementCount functions on the C # side.

+2
source

All Articles