Search code examples
c#cpinvoke

Porting C struct to C#


I'm Porting C code to C# and I have some doubts.

Consider this structure:

typedef struct
{
  uint32_t       w;
  uint32_t       h;
  uint32_t       f_cc;
  uint32_t       st;
  unsigned char *pl[4];
  int32_t        strd[4];
  void         (*done)(void *thisobj);
  void          *e_cc;
  uint32_t       rsrvd2;
  uint32_t       rsrvd3;
} f_tt;

I've done this and it does not work (probably because it's wrong :-/ ):

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct f_tt
{
    public uint w;
    public uint h;
    public uint f_cc;
    public uint st;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public Byte[] pl;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public int[] strd;
    public delegate void done(IntPtr thisobj);
    public delegate void e_cc();
    public uint rsrvd2;
    public uint rsrvd3;
}

Can someone advise me how to do this i c#?

  void         (*done)(void *thisobj);
  void          *e_cc;

Thank you!


Solution

  • Before we come to the delegates, I suspect that you are wrong to pack the struct. It's very unusual to do so. Only do that if you find the pack #pragma in the C code.

    The e_cc field is not a function pointer. It's just a void pointer. In C# that is IntPtr.

    The pl member is an array of 4 pointers. I'm not quite sure what they contain, but for sure you can marshal that like this:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public IntPtr[] pl;
    

    That leaves you with manual intervention to populate the array, or read its contents. It's possible that could be done by the marshaller, but without knowing the semantics of the interop, I can't say how to do that.

    As for done, you should declare the delegate outside the struct. Like this:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void doneDelegate(IntPtr thisobj);
    

    Here I am assuming that the calling convention is cdecl since there's nothing in the C code to say otherwise.

    Putting it all together you have:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void doneFunc(IntPtr thisobj);
    
    [StructLayout(LayoutKind.Sequential)]
    public struct f_tt
    {
        public uint w;
        public uint h;
        public uint f_cc;
        public uint st;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public IntPtr[] pl;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public int[] strd;
        public doneDelegate done;
        public IntPtr e_cc;
        public uint rsrvd2;
        public uint rsrvd3;
    }