mans
mans

Reputation: 18228

marshaling structure in C#

I have this piece of code and it generates an error:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct MyItem
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string Name;
        public int ID;
        public double ID1;

    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {

        MyItem[] items = new MyItem[6];
        items[0].Name = "JFK";
        items[0].ID = 35;
        items[1].Name = "LBJ";
        items[1].ID = 36;
        items[2].Name = "Tricky Dicky";
        items[2].ID = 37;
        items[3].Name = "Gerald Ford";
        items[3].ID = 38;
        items[4].Name = "Jimmy Carter";
        items[4].ID = 39;
        items[5].Name = "Ronald Reagan";
        items[5].ID = 40;

        IntPtr itemsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyItem)) * 
           items.Length);
        try
        {
            IntPtr item = new IntPtr(itemsPtr.ToInt32());
            for (int i = 0; i < items.Length; i++)
            {
                Marshal.StructureToPtr(items[i], item, true);
                item = new IntPtr(item.ToInt32() + Marshal.SizeOf(typeof(MyItem)));
            }         
        }
        finally
        {
            Marshal.FreeHGlobal(itemsPtr);
        }

When I run this code, I am getting write protection error in Marshal.StructureToPtr(items[i], item, true);

What is the problem and how do I solve it?

Upvotes: 0

Views: 451

Answers (1)

David Heffernan
David Heffernan

Reputation: 613541

You should be passing false to the fDeleteOld parameter of StructureToPtr().

By passing true you are asking the marshaller to delete the contents of item. Since you are filling this out for the first time, this results in a memory access failure because the memory is not yet valid.

The documentation states:

StructureToPtr copies the contents of structure to the pre-allocated block of memory that the ptr parameter points to. If the fDeleteOld parameter is true, the pre-allocated buffer is deleted with the appropriate deletion method on the embedded pointer, but the buffer must contain valid data.

The emphasis is mine.

Incidentally I think the loop code looks neater like this:

Int32 addr = itemsPtr.ToInt32();
for (int i = 0; i < items.Length; i++)
{
    Marshal.StructureToPtr(items[i], new IntPtr(addr), false);
    addr += Marshal.SizeOf(typeof(MyItem));
}

Upvotes: 4

Related Questions