开发者

marshaling structure in C#

开发者 https://www.devze.com 2023-03-09 01:57 出处:网络
I have this piece of code and it generates an error: [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MyItem

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";
     开发者_如何学Go   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?


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

精彩评论

暂无评论...
验证码 换一张
取 消