views:

469

answers:

2

Hi,

I have an unmanaged struct I'd like to marshal to c sharp that looks basically like this:

struct MyStruct{  
    /* ... some stuff ... */
    int numChilds;  
    MyStruct *childs;
}

I believe that I have to write a custom marshaller but I'm not sure on how to proceed.

A: 

If you want just to pass it to some unmanaged function, you could just use unsafe code and stackalloc / fix an array to get a pointer to the array of objects.

        unsafe struct Foo
        {
            public int value;
      public int fooCount;
      public Foo* foos;
        }

     [DllImport("dll_natv.dll")]
     static extern void PrintFoos(Foo f);

     public unsafe static void Main()
     {
      Foo* foos = stackalloc Foo[10];

      for (int i = 0; i < 10; ++i)
       foos[i].value = i;

      Foo mainFoo = new Foo();
      mainFoo.fooCount = 10;
      mainFoo.value = 100;
      mainFoo.foos = foos;

      PrintFoos(mainFoo);


     }
Ravadre
+3  A: 

I like to use a setup like this when I don't need to directly index children:

struct MyStruct
{
    /* ... some stuff ... */
    int numChilds;
    IntPtr childData;

    public IEnumerable<MyStruct> Children
    {
        get
        {
            int elementSize = Marshal.SizeOf(typeof(MyStruct));
            for (int i = 0; i < this.numChilds; i++)
            {
                IntPtr data = new IntPtr(this.childData.ToInt64() + elementSize * i);
                MyStruct child = (MyStruct)Marshal.PtrToStructure(data, typeof(MyStruct));
                yield return child;
            }
        }
    }
}

If you do need to directly index children, the easiest thing is creating a method GetChild (shown below). The harder way is creating a helper/wrapper class that implements IList<MyStruct>. An instance would be returned from the Children property, and its internal would work by calling the GetChild method. This is left as an exercise to the reader should he need it.

public MyStruct GetChild(int index)
{
    if (index < 0)
        throw new ArgumentOutOfRangeException("index", "The index must be >= 0.");
    if (index >= this.numChilds)
        throw new ArgumentException("The index must be less than the number of children", "index");

    int elementSize = Marshal.SizeOf(typeof(MyStruct));
    IntPtr data = new IntPtr(childData.ToInt64() + elementSize * index);
    MyStruct child = (MyStruct)Marshal.PtrToStructure(data, typeof(MyStruct));
    return child;
}
280Z28