RasmusW
RasmusW

Reputation: 3461

C to C# PInvoke with structs with pointers

I'm trying to create a C# interface which receives a callback from an external C DLL. The callback's parameters contain pointers to C structs, which themselves have a pointer to a different struct.

The callback signature:

typedef application_event_result (*application_event_ptr)(abuffertype* read_buffer, abuffertype* write_buffer);

The buffer struct definitions in C:

typedef struct {
    uint16 size;   
    uint8* data; 
} anotherbuffertype;

typedef struct {
    anotherbuffertype *buffer; 
    uint16 position; 
} abuffertype;

I know that the C# signature of the callback should use "ref" for the pointer type of the parameter. But how can the pointer inside the "abuffertype" struct be defined in C#?

So far I have this definition of the two structs in C#:

    [StructLayout(LayoutKind.Sequential)]
    public struct anotherbuffer
    {
        UInt16 size;
        IntPtr data;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct abuffer
    {
        anotherbuffer buffer;
        UInt16 position;
    } 

But that doesn't work. The contents of "abuffer" in C# is not what was there before the callback in the C code.

Do I need to unmarshal the internal struct pointer manually, and if so, how?

Upvotes: 4

Views: 993

Answers (1)

Hans Passant
Hans Passant

Reputation: 941277

You will not get help from the marshaller, this normally causes a major memory management problem. But can work in the specific case of a callback since it is the calling C program that manages the data.

You have to convert the data yourself. Declare the pointers as IntPtr and use Marshal.PtrToStructure() to retrieve the data.

The anotherbuffertype.data member looks like an array, use Marshal.Copy() to copy its content into your own byte[] array. If you don't mind the unsafe keyword then you can keep it declared as byte* and access the elements with data[index], avoids the cost of the copy. It is not very unsafe, pretty easy to keep index constrained to [0..size).

Upvotes: 4

Related Questions