Reputation: 503
I try to call the code int size = Marshal.SizeOf(typeof(MyStruct))
but it throws the following exception:
Type 'MyStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
My struct is as follows:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 version;
[MarshalAs(UnmanagedType.FunctionPtr)]
public IntPtr Start;
[MarshalAs(UnmanagedType.FunctionPtr)]
public IntPtr Stop;
// And a bunch more IntPtr, all declared the same way.
}
The struct is supposed to be passed to C-land, where the C code will use its contents as function pointers. I can't see how computing a size would fail, can anyone help?
Upvotes: 0
Views: 5999
Reputation: 941545
UnmanagedType.FunctionPtr requires the field to be a delegate type. It will be a function pointer on the C-side after the structure is marshaled. Using [MarshalAs] is superfluous, a delegate already gets marshaled like that. So, roughly:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 version;
public Action Start;
public Func<bool> Stop;
// etc..
}
Change the delegate types to match the function signature of the corresponding C function pointer. You often have to declare your own delegate type so you can give it the [UnmanagedFunctionPointer] attribute to match the calling convention of the C function. Usually CallingConvention.Cdecl, not the default of Stdcall.
You have to be very careful when you initialize a structure like this. The delegate objects you create and assign to the fields must be referenced elsewhere to prevent them from getting garbage collected. Either by storing them in a class object that's guaranteed to live as long as the C code can make calls, by storing them in a static variable or by explicitly adding a reference with GCHandle.Alloc()
Lots of ways to shoot your foot, good luck with it :)
Upvotes: 4