为什么我不能为这个C#结构做Marshal.SizeOf()?

时间:2013-10-16 16:11:03

标签: c# .net interop

我尝试调用代码int size = Marshal.SizeOf(typeof(MyStruct)),但它抛出以下异常:

  

类型'MyStruct'不能作为非托管结构封送;没有有意义的大小或偏移量可以计算出来。

我的结构如下:

[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.
}

结构应该传递给C-land,C代码将把它的内容用作函数指针。我无法看到计算大小会失败,任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:3)

UnmanagedType.FunctionPtr要求该字段为委托类型。在封送结构之后,它将是C端的函数指针。使用[MarshalAs]是多余的,代表已经被这样封送了。所以,粗略地说:

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 version;
    public Action Start;
    public Func<bool> Stop;
    // etc..
}

更改委托类型以匹配相应C函数指针的函数签名。您经常需要声明自己的委托类型,以便为其提供[UnmanagedFunctionPointer]属性以匹配C函数的调用约定。通常是CallingConvention.Cdecl,而不是默认的Stdcall。

初始化这样的结构时必须非常小心。您创建并分配给字段的委托对象必须在别处引用,以防止它们被垃圾收集。通过将它们存储在C代码可以进行调用的类对象中,通过将它们存储在静态变量中或通过使用GCHandle.Alloc()显式添加引用来保存它们。

有很多方法可以拍脚,祝你好运:)