James Wilkins
James Wilkins

Reputation: 7367

What is the difference between C# marshaled struct pointers?

Ok, this is working:

[StructLayout(LayoutKind.Explicit, Size = 28)]
public unsafe struct HandleProxy
{
    [FieldOffset(0), MarshalAs(UnmanagedType.I4)]
    public JSValueType _ValueType; // JSValueType is an enum

    [FieldOffset(4), MarshalAs(UnmanagedType.I4)]
    public Int32 _ManagedObjectID; 

    [FieldOffset(8)]
    public void* _NativeEngineProxy;

    [FieldOffset(16), MarshalAs(UnmanagedType.I4)]
    public Int32 _EngineID;

    [FieldOffset(20)]
    public void* _Handle;
}

[DllImport("Proxy")]
public static extern void DisposeHandleProxy(HandleProxy* handle);

... and this does not ...

[StructLayout(LayoutKind.Explicit, Size = 20)]
public unsafe struct ValueProxy
{
    [FieldOffset(0), MarshalAs(UnmanagedType.I4)]
    public JSValueType _ValueType; // 32-bit type value.

    [FieldOffset(4), MarshalAs(UnmanagedType.Bool)]
    public bool _Boolean;

    [FieldOffset(4), MarshalAs(UnmanagedType.I4)]
    public Int32 _Integer;

    [FieldOffset(4)]
    public double _Number;

    [FieldOffset(12)]
    public void* _String;
}

[DllImport("Proxy")]
public static extern void DisposeValueProxy(ValueProxy* valueProxy);

So, what's the difference? I'm missing something. A call to "DisposeValueProxy() gives the following error:

"Cannot marshal 'parameter #1': Pointers cannot reference marshaled structures. Use ByRef instead."

(and yes, I can simply use IntPtr/void* instead of "ValueProxy*" but that's not my point).

A call to "DisposeHandleProxy()" works fine.

Let's see if someone can figure this one out. ;)

Upvotes: 7

Views: 1497

Answers (1)

Hans Passant
Hans Passant

Reputation: 941545

A struct must be blittable to create a pointer to it. The second struct is not blittable, the bool field is the troublemaker. You'd have to make it a byte or int instead, depending on the intention.

An overview of what types are blittable in .NET is available here.

The exception message's advice is a very sound one, declare the argument as ref ValueProxy instead to leave it up to the pinvoke marshaller to create a copy of the struct with the desired layout.

Upvotes: 9

Related Questions