3

在下面的代码中,我观察到编组器正在读取 3 字节源数组以填充另外 8 字节的数据。随着时间的推移,代码最终会引发内存访问冲突。有没有办法告诉编组器在将指针转换为结构时只编组前 3 个字节?如果我将 Articulations 数组设为“NonSerialized”,那么构造函数在处理 11 个字节的源数组时将引发访问冲突。

using System;
using System.Runtime.InteropServices;

namespace MarshallingTest
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct Articulation
    {
        public const int BaseSize = 8;
        public byte attribute1;
        public byte attribute2;
        public byte attribute3;
        public byte attribute4;
        public byte attribute5;
        public byte attribute6;
        public byte attribute7;
        public byte attribute8;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class TestEntity
    {
        public const int BaseSize = 3;

        public byte EntityId;         //  1 byte
        public byte Variable;         //  1 byte
        public byte NumArticulations; //  1 byte

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct)]
        public Articulation[] Articulations;   // 8 bytes each

        public TestEntity(byte[] rawData)
        {
            unsafe
            {
                fixed (byte* pData = rawData)
                {
                    // I am observing that the marshaler is reading past the 3 bytes
                    // to populate another 8 bytes of data.  With time, the code
                    // will eventually throw a memory access violation.
                    //
                    // Is there a way to tell the marshaller to only marshal the 
                    // first 3 bytes when converting a pointer to a structure?
                    Marshal.PtrToStructure((IntPtr) pData, this);

                    for (int i = 0; i < BaseSize + Articulation.BaseSize; i++)
                    {
                        Console.WriteLine("pData + " + i + " = " + *(pData + i));
                    }
                }
            }
        }

        public byte[] ToRaw()
        {
            byte[] byteArray = new byte[BaseSize + Articulation.BaseSize*Articulations.Length];
            unsafe
            {
                fixed (byte* pData = byteArray)
                {
                    Marshal.StructureToPtr(this, (IntPtr) pData, false);
                }
            }
            return byteArray;
        }
    }

    internal class Program
    {
        private const int TestDataSize = TestEntity.BaseSize;

        private static void Main()
        {
            byte[] testData = new byte[TestDataSize];
            for (int i = 0; i < TestDataSize; i++)
            {
                testData[i] = (byte) (i + 1);
            }
            TestEntity test = new TestEntity(testData);

            // Print resulting array.  You'll see that data outside the source
            // byte array was marshalled into the test structure.
            Console.WriteLine(test.EntityId);
            Console.WriteLine(test.Variable);
            Console.WriteLine(test.NumArticulations);
            Console.WriteLine(test.Articulations[0].attribute1);
            Console.WriteLine(test.Articulations[0].attribute2);
            Console.WriteLine(test.Articulations[0].attribute3);
            Console.WriteLine(test.Articulations[0].attribute4);
            Console.WriteLine(test.Articulations[0].attribute5);
            Console.WriteLine(test.Articulations[0].attribute6);
            Console.WriteLine(test.Articulations[0].attribute7);
            Console.WriteLine(test.Articulations[0].attribute8);

            Console.WriteLine("Test complete.");
        }
    }
}
4

0 回答 0