Converting a structure to an intptr

4.1k views Asked by At

I have a class definition as follows:

[StructLayout(LayoutKind.Sequential)]
public class OUR_MEM_STR
            {
                public byte[] p;
                public int  len;
            };

This is an equivalent defintion of the C structure below:

typedef struct
{
    void *p;
    int  len;
} OUR_MEM_STR;

I used byte[] instead of IntPtr type for member p becuase of the way it was being used thorughout c# project.

I have defined an object obj with len = 10 and p = new byte[10]

I want to make it an intptr. How do I get the size of the object for that?

 IntPtr pObj = Marshal.AllocHGlobal(obj.len + sizeof(int));
 Marshal.StructureToPtr(obj, pObj, true);

See what I did there. It seems too hard coded. If I do the below snippet;

IntPtr pObj = Marshal.AllocHGlobal(Marshal.SizeOf(obj));

Doing this returns the wrong size because obj.p returns a size of 4 and not 10. Because of the memory taken by the pointer pointing to the byte array is 4 bytes.

Is there a better way?

1

There are 1 answers

5
Hans Passant On BEST ANSWER

The return value is correct, p is a pointer, it takes 4 bytes.

You cannot leave it this way, there are two memory allocations. The marshaller allocated the memory for the array. It created a SAFEARRAY, a COM array type. Pretty unlikely that your C code is going to be happy with that. Declare it like this instead:

[StructLayout(LayoutKind.Sequential)]
public class OUR_MEM_STR {
    public IntPtr p;
    public int len;
};

And use Marshal.AllocHGlobal(10) to assign p. Don't forget to clean-up again.

Don't pass true to StructureToPtr(), the memory allocated by AllocHGlobal() isn't initialized. That's going to randomly crash your program. You must pass false.