4

I am trying to use pinvoke to marshall an array of structures inside another structure from C to C#. AFAIK, no can do.
So instead, in the C structure I declare a ptr to my array, and malloc. Problems: 1) How do I declare the equivalent on the C# side? 2) How do I allocate and use the equivalent on the C# side?

//The C code
typedef struct {
       int a;
       int b; } A;
typedef struct {
      int c;
      // A myStruct[100];    // can't do this, so:
      A *myStruct; } B;

//The c# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class A{
    int a;
    int b;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class B{
      int c;
      // can't declare array of [100] A structures...
     ?
 }

[EDIT]: Somehow I misinterpreted what I read elsewhere about fixed array of objects on the c# side. And I can fix the array size in C So compiled ok, but then I get "object reference not set to an instance of an object" when using:

data.B[3].a = 4567; So, reading elsewhere about what this error might be, I added this method:

public void initA()
        {
          for (int i = 0; i < 100; i++) { B[i] = new A(); }
        }

Again, compiled OK, but same error msg.

3
  • Have you tried A[] myStruct? Commented Aug 15, 2012 at 12:13
  • That compiles ok. But how do I allocate storage and use it (I'm still learning c#). Thanks. Commented Aug 15, 2012 at 12:20
  • just curious: why can't you use A myStruct[100]; in C? That would make things much easier on the C# side... Commented Aug 15, 2012 at 13:21

1 Answer 1

5

To marshal "complex" structures like this between C and C#, you have a couple of options.

In this case, I would highly recommend that you try to embed a fixed array into your C-side structure, as it will simplify the C# side a lot. You can use the MarshalAs attribute to tell C# how much space it needs to allocate in the array at run-time:

// In C:
typedef struct
{
 int a;
 int b;
} A;

typedef struct
{
 int c;
 A data[100];
} B;

// In C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct A 
{
  int a;
  int b;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct B
{
  int c;
  [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
  A[] data = new data[100];
}

If you don't know, or can't specify, a fixed size for your array, then you'll need to do what you did and declare it as a pointer in C. In this case, you cannot tell C# how much memory the array is going to use at run-time, so you're pretty much stuck with doing all of the marshalling by hand. This question has a good rundown of how that works, but the basic idea is:

  1. You should add a field to your structure that includes a count of the array elements (this will make your life much easier)
  2. Declare the field in C# as: IntPtr data; with no attributes.
  3. Use Marshal.SizeOf(typeof(A)) to get the size of the struct in unmanaged memory.
  4. Use Marshal.PtrToStructure to convert a single unmanaged structure to C#
  5. Use IntPtr.Add(ptr, sizeofA) to move to the next structure in the array
  6. Loop until you run out.
Sign up to request clarification or add additional context in comments.

2 Comments

object reference not set to an instance of an objec
On the C# size, you still need to assign an array to the field, since arrays are reference types. You should be able to do this inline, I've edited my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.