tags:

views:

92

answers:

3

I'm p-invoking into a DLL that returns a void** list of struct pointers, all of the same type. From what I've read, in order to cast and get my structure out of that list, the struct needs to be considered unmanaged. The main culprits to the struct I'm trying to marshal over are the following two fields from the C side:

char name[1024];
int crop[4];

Most guides suggest using string or int[] on the corresponding struct on the managed side, but that having those fields makes it into a managed struct and thus incapable of extracting from the void** list.

What's another way I can marshal these fields that gives me an unmanaged struct?

+1  A: 

You can use the fixed keyword to create a buffer with a fixed size array in a data structure:

unsafe struct Foo
{
    public fixed byte name[1024];
    public fixed int crop[4];
}

static unsafe void DumpCrops(void** ptr, int count)
{
    Foo** p = (Foo**)ptr;

    for (int i = 0; i < count; i++)
    {
        Foo* f = p[i];

        for (int j = 0; j < 4; j++)
        {
            Console.WriteLine(f->crop[j]);
        }
    }
}
dtb
Thanks, that did the trick.
RandomEngy
A: 

You need to add a line in that point on the struct as shown...


[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct _FOOBAR {
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 1024, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I2)]
char name[1024];
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)]
int crop[4];
};

You need to double check on the last bit in the attribute bit, UnmanagedType...

Hope that helps, Best regards, Tom.

tommieb75
+1  A: 

The structure will marshal without help or need for the unsafe keyword if you declare it like this:

using System.Runtime.InteropServices;
...
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct Example {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string name;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    int[] crop;
  }

Convert the void* to the structure with Marshal.PtrToStructure().

Hans Passant
That's useful for making the struct a bit friendlier, though I still needed unsafe code to access all of the structs in the list.
RandomEngy
It shouldn't be necessary, it ought to be covered by Marshal.ReadIntPtr() if it is a void**. There isn't enough detail in your post to tell how the list was implemented, linked list vs array of pointers.
Hans Passant
Ahh, right you are.
RandomEngy