【问题标题】:Marshal.StructureToPtr fails with bool and fixed size array?Marshal.StructureToPtr 因 bool 和固定大小的数组而失败?
【发布时间】:2013-05-07 15:41:31
【问题描述】:

如果我用StructureToPtr 编组这个结构,然后用PtrToStructure 再次解组它,我的第一个节点有 y = {1,2} 而我的第二个节点有 y = {1,0}。

我不知道为什么,也许我的结构在某种程度上是坏的?从结构中删除bool 使其工作。

using System;
using System.Runtime.InteropServices;

namespace csharp_test
{
    unsafe class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct Node
        {
            public bool boolVar;
            public fixed int y[2];
        }

        unsafe static void Main(string[] args)
        {
            Node node = new Node();

            node.y[0] = 1;
            node.y[1] = 2;
            node.boolVar = true;

            int size = sizeof(Node);
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(node, ptr, false);
            Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node));
            Marshal.FreeHGlobal(ptr);
        }
    }
}

【问题讨论】:

  • 也许它与 bool 被编组为 4 个字节 (BOOL) 而不是 1 个字节有关?但我想不出确切的原因......
  • 此外,它会忽略第一个元素之后的所有数组元素(将它们作为零写入非托管内存中)。 bool 是在数组之前还是在结构之后也没关系。

标签: c# marshalling


【解决方案1】:

这确实出错了。是 StructureToPtr() 调用未能复制足够的字节。您可以通过使用 Debug + Windows + Memory + Memory1 并将“ptr”放入地址框中来看到这一点。使用 sizeof 运算符 isn't correct 但实际上并不是问题的根源。无论数组长度如何,只复制数组的第一个元素。不知道是什么导致了这个问题,我从不在 pinvoke 中使用 fixed。我只能推荐效果很好的传统 pinvoke 方式:

unsafe class Program {
    [StructLayout(LayoutKind.Sequential)]
    public struct Node {
        public bool boolVar;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public int[] y;
    }

    unsafe static void Main(string[] args) {
        Node node = new Node();
        node.y = new int[2];

        node.y[0] = 1;
        node.y[1] = 2;
        node.boolVar = true;

        int size = Marshal.SizeOf(node);
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(node, ptr, false);
        Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node));
        Marshal.FreeHGlobal(ptr);
    }

如果您想引起 CLR 互操作大师的注意,您可以发布到 connect.microsoft.com。

【讨论】:

  • 谢谢,您发布的链接中的评论确实解释了问题,但实际上真正的答案是我根本不应该使用固定大小的缓冲区,而应该只使用 MarshalAs 属性,如你演示。我已经知道你不应该真正使用 sizeof(),只是我不确定在现实世界中它是否有任何区别。但无论如何,我现在已经更改了我的代码以使用 Marshal.SizeOf 无论如何。
  • @Hans 您的链接中缺少一个 cmets ☹
  • 只是补充一点:PtrToStructure() 也只会复制固定数组的第一个字节,即使内存位置包含更多信息。即使结构使用 LayoutKind.Explicit 它仍然失败:(
【解决方案2】:

您还应该在使用之前打包结构或类。这对我有用,几乎和 memcpy 一样好

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SomeClass
{
}

【讨论】:

    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2018-10-20
    • 1970-01-01
    • 2021-12-07
    相关资源
    最近更新 更多