2013-10-16 193 views
0

我尝试调用代码int size = Marshal.SizeOf(typeof(MyStruct)),但它抛出以下异常:为什么我不能为此C#结构执行Marshal.SizeOf()?

类型“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-土地,那里的C代码将使用其内容作为函数指针。我看不到如何计算大小会失败,任何人都可以帮忙?

回答

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()的引用,就可以保证这些类对象能够正常播放。类别对象有许多拍摄方式你的脚,祝你好运:) :)

+0

感谢您的反馈。我目前通过执行'Marshal.GetFunctionPointerForDelegate(无论)'来填充结构体。由于各种原因,我想保留结构成员为'IntPtr' - 如果我只是删除'[MarshalAs(UnmanagedType.FunctionPtr)]'将兼容? – FusterCluck

+1

使用GetFunctionPointerForDelegate()不会改变答案中的任何内容,但同样的问题也适用。是的,就像将该字段声明为委托类型一样,您也不需要IntPtr上的[MarshalAs]。 –

相关问题