Marshal.StructureToPtr fails with bool and fixed s

2019-03-26 12:27发布

If I marshal this struct with StructureToPtr and then unmarshal it again with PtrToStructure, my first node has y = {1,2} whilst my second node has y = {1,0}.

I've no idea why, perhaps my struct is bad somehow? Removing the bool from the struct makes it work.

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);
        }
    }
}

2条回答
Anthone
2楼-- · 2019-03-26 13:08

You should also pack the struct or class before you use it. That works for me, almost as good as memcpy

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class SomeClass
{
}
查看更多
唯我独甜
3楼-- · 2019-03-26 13:14

This indeed goes wrong. It is the StructureToPtr() call that fails to copy enough bytes. You can see this by using Debug + Windows + Memory + Memory1 and putting "ptr" in the address box. Using the sizeof operator isn't correct but not actually the source of the problem. Only the first element of the array is copied, regardless of the array length. Not sure what causes this problem, I never use fixed in pinvoke. I can only recommend the traditional pinvoke way which works fine:

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);
    }

You can post to connect.microsoft.com if you want to bring this to the attention of the CLR interop masters.

查看更多
登录 后发表回答