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.
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!
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.
However, C# doesn't "understand" std::vector.
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#.
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.
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.
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
another function to get the actual array data in an output caller-allocated buffer (the size of which is returned by the previous function)
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.
Something like this:
// 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With