Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marshal.StructureToPtr fails with bool and fixed size array?

Tags:

c#

marshalling

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);
        }
    }
}
like image 670
junichiro Avatar asked Feb 05 '12 19:02

junichiro


1 Answers

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.

like image 138
Hans Passant Avatar answered Sep 25 '22 11:09

Hans Passant