Your code have several problems and suboptimal points.
You have an infinite loop for(unsigned int i = 0; result.size(); i++)
You do not need to copy your array (in native), instead you want to keep your array as a global object, and return the pointer to the data()
of the vector and then marshal it. This is the most general schema, in particular, if you have unblittable types and arrays, you can't do it differently.
You are actually not just passing a struct from native to managed, but an array of struct, which is a bit more demanding.
If you are passing just one struct from native to managed, you only only need Marshal.PtrToStructure<myStruct>(pointer);
If you need to get a vector of structures, I advise you to marshal the structs one at a time on the managed side.
Here a functionnal revised code:
native:
struct myStruct
{
int cid;
float c;
float r;
};
std::vector<myStruct> SomeFunction(const char* path_2d)
{
std::vector<myStruct> lresult{};
for (int i=0; i <10; i++)
{
myStruct o{};
o.cid = i;
o.c = 1.f / (float)i;
o.r = 1.f - o.c;
lresult.push_back(o);
}
return lresult;
}
std::vector<myStruct> result{};
extern "C" __declspec(dllexport) myStruct* Predict(int* size, const char* path2D)
{
result = SomeFunction(path2D);
*size = result.size();
return result.data();
}
managed:
[StructLayout(LayoutKind.Sequential)]
public struct myStruct
{
public int cid;
public float c;
public float r;
public override string ToString() => $"cid,r,c: {cid} - {r} - {c}";
}
public static class NativeLibrary
{
[DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Predict(out int size, [MarshalAs(UnmanagedType.LPStr)] string path2Image);
public static List<myStruct> GetPredict(string path = "somepath")
{
var ptr = Predict(out int size, path);
List<myStruct> results = new List<myStruct>();
var structSize = Marshal.SizeOf(typeof(myStruct));
for (var i = 0; i < size; i++)
{
var o = Marshal.PtrToStructure<myStruct>(ptr);
results.Add(o);
ptr += structSize;
}
return results;
}
}
class Program
{
static void Main()
{
var result = NativeLibrary.GetPredict();
Console.WriteLine($"list of {result.Count} structures");
foreach (var o in result)
Console.WriteLine(o);
}
}
result:
list of 10 structures
cid,r,c: 0 - -∞ - ∞
cid,r,c: 1 - 0 - 1
cid,r,c: 2 - 0,5 - 0,5
cid,r,c: 3 - 0,6666666 - 0,33333334
cid,r,c: 4 - 0,75 - 0,25
cid,r,c: 5 - 0,8 - 0,2
cid,r,c: 6 - 0,8333333 - 0,16666667
cid,r,c: 7 - 0,85714287 - 0,14285715
cid,r,c: 8 - 0,875 - 0,125
cid,r,c: 9 - 0,8888889 - 0,11111111
remarks:
you need to have a global instance, in order to keep the object alive; the alternative is to use the pointer of a class instance created by new MyClass()
.
the functions of your managed structure are not taken into account for your structure size; and with blittable types, the structure size is the same in managed and native.