【问题标题】:Why can't I do Marshal.SizeOf() for this C# struct?为什么我不能为此 C# 结构执行 Marshal.SizeOf() ?
【发布时间】:2013-10-16 16:11:03
【问题描述】:

我尝试调用代码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 代码将使用其内容作为函数指针。我看不出计算大小会如何失败,有人可以帮忙吗?

【问题讨论】:

    标签: c# .net interop


    【解决方案1】:

    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() 显式添加引用

    射脚的方法很多,祝你好运:)

    【讨论】:

    • 感谢您的反馈。我目前正在通过Marshal.GetFunctionPointerForDelegate(whatever) 填充结构。出于各种原因,我想将结构成员保留为 IntPtr - 如果我只是删除 [MarshalAs(UnmanagedType.FunctionPtr)] 会兼容吗?
    • 使用 GetFunctionPointerForDelegate() 不会改变答案中的任何内容,完全相同的问题也适用。是的,就像将字段声明为委托类型一样,您也不需要在 IntPtr 上使用 [MarshalAs]。
    猜你喜欢
    • 2010-10-08
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    相关资源
    最近更新 更多