Search code examples
c#pinvoke

C# calling C function that returns struct with fixed size char array


So, there have been many variants of this question, and after looking at several I still can't figure it out.

This is the C code:

typedef struct
{
    unsigned long Identifier;
    char Name[128];
} Frame;

Frame GetFrame(int index);

This is the C# code:

struct Frame
{
    public ulong Identifier;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 128)]
    public char[] Name;
}

[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern Frame GetFrame(int index);

This is the last attempt I tried in C#, and it seems pretty logical, but I get the error "Method's signature is not PInvoke compatible." So, I'm kind of lost on what to try next. Any help is appreciated.

Thanks, Kevin

Updated Kevin added this as an edit to my answer

I should instead change my C code:

void GetFrame(int index, Frame * f);

and use instead for C#:

struct Frame
{
    public uint Identifier;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string Name;
}

[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern void GetFrame(int index, ref Frame f);

Solution

  • The problem is that the native function returns a non-blittable type as a return value.

    http://msdn.microsoft.com/en-us/library/ef4c3t39.aspx

    P/Invoke cannot have non-blittable types as a return value.

    You cannot p/Invoke that method. [EDIT It is actually possible, see JaredPar's answer]

    Returning 132 bytes by value is a bad idea. If this native code is yours, I would fix it. You can fix it by allocating the 132 bytes and returning a pointer. Then add a FreeFrame method to release that memory. Now it can be p/Invoked.

    Alternately, you could change it to accept a pointer to the Frame memory that it will fill in.