15

I have the following C++ structs

struct InnerStruct
{
   int A;
   int B;
};

struct OuterStruct
{
   int numberStructs;
   InnerStruct* innerStructs;
};

And a C++ function

OuterStruct getStructs();

How can I marshal this to C#? Where the C# definitions is

struct OuterStruct {
   InnerStruct[] innerStructs;
};
DevDevDev
  • 5,107
  • 7
  • 55
  • 87

1 Answers1

23

You'll have to do this manually, since there's no way to tell the P/Invoke layer how much data to marshal from your C++ return value.

struct OuterStruct {
   int numberStructs;
   IntPtr innerStructs;
};

OuterStruct s = getStructs(); // using DllImport
var structSize = Marshal.SizeOf(typeof(InnerStruct));
var innerStructs = new List<InnerStruct>();
var ptr = s.innerStructs;

for (int i = 0; i < s.numberStructs; i++)
{
    innerStructs.Add((InnerStruct)Marshal.PtrToStructure(ptr, 
        typeof(InnerStruct));
    ptr = ptr + structSize;
}

Note that if you want to free the memory for innerStructs from your C# code, you have to use the standard allocator CoTaskMemAlloc in your C++ code--then you can call Marshal.CoTaskMemFree to free innerStructs.

Ben M
  • 22,262
  • 3
  • 67
  • 71
  • Cool man, thanks a lot. Also, as a quick question, is it possible to Marshal a vector, so that I could just have OuterStruct have a vector of InnerStructs? I know you can't marshal classes, but I thought that perhaps someone had written something tricky to do this. – DevDevDev Jul 28 '09 at 23:22
  • Not that I know of, but I've never looked. :-) – Ben M Jul 28 '09 at 23:27
  • You cast the pointer to `int`? What if it is running in a 64-bit process?! [You don't need the casts](https://msdn.microsoft.com/en-us/library/system.intptr.op_addition(v=vs.110).aspx) – doug65536 Oct 05 '16 at 23:04
  • Please note that's really extremely bad idea to cast `IntPtr` to `int` in a case such that. Please don't! – ForNeVeR Dec 17 '16 at 07:18
  • 1
    @doug65536 Yes, oops! Fixed! (8 years later) – Ben M Feb 17 '17 at 16:24