Marshal.PtrToStructure 中的访问冲突

发布于 2024-08-04 11:24:41 字数 1580 浏览 3 评论 0原文

我正在尝试反序列化一个结构,但在 PtrToStructure 中遇到 AV 异常。唯一的问题是这是一个可变长度结构,因此我需要在反序列化之前调整长度。这是我的代码,有什么明显的错误吗?该结构仅包含整数/短/字节数组,没有什么花哨的。

传入的数据是 374 字节,我需要调整它以匹配 576 字节的数据结构。基本上,传入数据包的最后一个字段比最大可能字段短,这是正常的。

public static ... FromByteArray(byte[] receivedData)
    {
        int rawsize = Marshal.SizeOf(typeof(MyPacket));
    // allocate a new buffer of the maximum size, to help deserialization
    byte[] newBuffer = new byte[rawsize]; 
    Array.Copy(receivedData, newBuffer, receivedData.Length);

    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(newBuffer, 0, buffer, rawsize);

/// CRASHES ON NEXT LINE
    MyPacketDefinition def = (MyPacketDefinition ) Marshal.PtrToStructure(buffer, typeof(MyPacketDefinition ));   
    Marshal.FreeHGlobal(buffer);

    //...
}

我的结构看起来像这样:

 [StructLayout (LayoutKind.Explicit, Pack=1, Size=576, CharSet=CharSet.Ansi)]
 public struct MyPacket
    {

    [FieldOffset(0)]
    public System.Byte Type;

    .
    . // a few more INT/SHORT fields
    .

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        [FieldOffset(28)]  public System.Byte[] Address;


        [MarshalAs(UnmanagedType.LPStr, SizeConst=64)]
        [FieldOffset(44)] public System.String Name;


        [MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
        [FieldOffset(108)] public System.String SystemData;


        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 340)]
        [FieldOffset(236)] public System.Byte[] Options;

}

最后一个参数(选项)是最大 340 字节的可变长度字段(通常更短)

I am trying to deserialize a structure, and I'm getting an AV exception in PtrToStructure. The only wrinkle is that this is a variable length structure, so I need to adjust the length before deserializing. Here's my code, is there anything obviously wrong? The structure contains only integer/short/byte arrays, nothing fancy.

the incoming data is 374 bytes, and I need to adjust it to match the 576 bytes data structure. Basically the incoming packet has a shorter last field than the max possible, which is normal.

public static ... FromByteArray(byte[] receivedData)
    {
        int rawsize = Marshal.SizeOf(typeof(MyPacket));
    // allocate a new buffer of the maximum size, to help deserialization
    byte[] newBuffer = new byte[rawsize]; 
    Array.Copy(receivedData, newBuffer, receivedData.Length);

    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(newBuffer, 0, buffer, rawsize);

/// CRASHES ON NEXT LINE
    MyPacketDefinition def = (MyPacketDefinition ) Marshal.PtrToStructure(buffer, typeof(MyPacketDefinition ));   
    Marshal.FreeHGlobal(buffer);

    //...
}

My structure looks something like this:

 [StructLayout (LayoutKind.Explicit, Pack=1, Size=576, CharSet=CharSet.Ansi)]
 public struct MyPacket
    {

    [FieldOffset(0)]
    public System.Byte Type;

    .
    . // a few more INT/SHORT fields
    .

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        [FieldOffset(28)]  public System.Byte[] Address;


        [MarshalAs(UnmanagedType.LPStr, SizeConst=64)]
        [FieldOffset(44)] public System.String Name;


        [MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
        [FieldOffset(108)] public System.String SystemData;


        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 340)]
        [FieldOffset(236)] public System.Byte[] Options;

}

With the last parameter (Option) being a variable length field of maximum 340 bytes (normally shorter)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柠北森屋 2024-08-11 11:24:41

有点晚了,但是……

为了在结构体内部使用 C# 编组数组,您必须将它们声明为“固定”,否则它们只是指向托管内存的指针,这会造成混乱。

值得注意的是,出于某种原因,“修复”是一个不安全的选项,需要您将代码标记为不安全。

A little late but....

In order to use C# marshalling with arrays inside structs you have to declare them as "fixed", otherwise they are just pointers out to managed memory which will make a mess.

Its worth noting that "fixed" for some reason is an unsafe option and requires you flag your code as unsafe.

绻影浮沉 2024-08-11 11:24:41

正如弗朗西在评论中所建议的那样,我能够使用这种方法让它工作(尽管我不确定这是否是他的意思)。

我不知道为什么另一种方法是提出 AV,我以前用过这种方法,没有任何问题。

    byte[] mem = new byte[Marshal.SizeOf(typeof(MyPacketDefinition))];
    Marshal.Copy(receivedData, 0, mem, mem.Length);
    using (MemoryStream ms = new MemoryStream(mem))
    {
        using (BinaryReader br = new BinaryReader(ms))
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(MyPacketDefinition )));

            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            try
            {
                MyPacketDefinition s = (MyPacketDefinition )Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MyPacketDefinition ));
            }
            finally
            {
                handle.Free();
            }
            
        }
   }

I was able to get it to work using this method, as suggested by Franci in the comments (although I'm not sure if this is what he meant).

I do not know why the other way was raising an AV, I've used that method before with no issues.

    byte[] mem = new byte[Marshal.SizeOf(typeof(MyPacketDefinition))];
    Marshal.Copy(receivedData, 0, mem, mem.Length);
    using (MemoryStream ms = new MemoryStream(mem))
    {
        using (BinaryReader br = new BinaryReader(ms))
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(MyPacketDefinition )));

            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            try
            {
                MyPacketDefinition s = (MyPacketDefinition )Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MyPacketDefinition ));
            }
            finally
            {
                handle.Free();
            }
            
        }
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文