Marshal.PtrToStructure抛出AccessViolationException

我有这个结构:

[StructLayout(LayoutKind.Sequential)] public struct IS { public UInt32 ID; public UInt32 Quality; public UInt32 Flags; public UInt32 Flags2; public UInt32 ContainerSlots; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public Int32[] ItemStatType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public UInt32[] ItemStatValue; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public Int32[] ItemStatUnk1; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public Int32[] ItemStatUnk2; public UInt32 ScalingStatDistribution; public UInt32 DamageType; public UInt32 Delay; public float RangedModRange; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellId; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellTrigger; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellCharges; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellCooldown; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellCategory; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public Int32[] SpellCategoryCooldown; public UInt32 Bonding; public string Name; public string Name2; public string Name3; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public UInt32[] Color; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public UInt32[] Content; }; 

我正在尝试从文件中读取字节并使用Marshal和GCHandle将这些字节复制到上面的struct ,我的代码如下:

 reader = BinaryReader.FromFile(fileName); m_rows = new List(); int size = Marshal.SizeOf(typeof(IS)); if(reader.BaseStream.Length < size) return; byte[] buffer = new byte[size]; buffer = reader.ReadBytes(size); GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); m_rows.Add((IS)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(IS))); handle.Free(); 

但我得到一个AccessViolationException : attempt to read or write protected memory

我不知道为什么抛出这个exception。

我没有立即看到这个错误并写了一个小测试程序来重现这个问题。 使用二进制搜索来查找问题,重复注释一半字段,直到我将其缩小到:

 [StructLayout(LayoutKind.Sequential)] public struct IS { public string Name; } 

这不起作用,pinvoke marshaller假定字符串的默认封送来自C字符串char* 。 这不可能纠正您从文件中读取的数据,它永远不会包含有效的指针。 尝试取消引用指针时会触发AccessViolation。

问题中没有任何提示可以猜测字符串是如何实际序列化到文件中的。 通常的方法是:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct IS { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)] public string Name; }; 

如有必要,请使用hex查看器来确定SizeConst的正确值。 如果编码exception(不是系统默认页面),则必须将其声明为byte []并使用正确的编码进行转换。

您可以理解的访问冲突是由于尝试读取未分配的内存或正在释放的内存,您可能需要检查以下堆栈溢出发布:

触发Marshal.PtrToStructure时的AccessViolationException

这是指托管和本机结构的大小之间的差异作为问题的原因,基本上您需要在编组期间提供偏移以匹配结构的托管和本机分配之间的差异。

也检查此post,用户添加了偏移量

在循环中使用方法Marshal.PtrToStructure时访问冲突exception 。

另一个解决方案的链接:

http://www.codeproject.com/Questions/585390/AccessplusViolationplusException

如果这没有帮助,那么使用windbg很容易调试这些问题,我可以列出详细信息,以防你需要这样做。 同样在VS中启用Win32 Aces违例exception,它会在抛出exception行时会有一些额外的信息