Marshal.PtrToStructure抛出AccessViolationException [英] Marshal.PtrToStructure throwing 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;
};
我试图从文件中读取字节并将这些字节复制到上面的 struct
使用Marshal和GCHandle,我的代码如下:
And I'm trying to read bytes from a file and copy those bytes to the above struct
using Marshal and a GCHandle, my code is as follows:
reader = BinaryReader.FromFile(fileName);
m_rows = new List<IS>();
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:尝试读或写受保护的内存
But I'm getting an AccessViolationException : attempt to read or write protected memory
我不知道为什么会抛出此异常。
I have no idea why this exception is thrown.
推荐答案
我没有立即看到错误,并写了一个测试程序来重现问题。使用二进制搜索找到问题,重复注释一半字段,直到我把它缩小到:
I didn't see the bug immediately and wrote a little test program to repro the problem. Using binary search to find the issue, commenting half the fields out repeatedly until I narrowed it down to:
[StructLayout(LayoutKind.Sequential)]
public struct IS {
public string Name;
}
这不能工作,pinvoke marshaller假定为 string 来自C字符串, char *
。这不可能纠正从文件读取的数据,它不能包含有效的指针。 AccessViolation在尝试解除引用指针时被触发。
That cannot work, the pinvoke marshaller assumes the default marshaling for string is from a C string, char*
. That cannot possibly correct for data that you read from a file, it can never contain valid pointers. The AccessViolation is triggered when it tries to dereference the pointer.
问题中没有提示猜测字符串是如何实际序列化到文件中的。 正常方式是:
There are no hints in the question to guess how the string was actually serialized to the file. The normal way is:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IS {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string Name;
};
如有必要,使用十六进制查看器来找出SizeConst的正确值。如果编码是不寻常的(不是系统默认页面),那么你必须声明它为byte []并使用正确的编码转换它。
Use a hex viewer if necessary to figure out the proper value of SizeConst. If the encoding is unusual (not the system default page) then you have to declare it as byte[] and use the proper Encoding to convert it.
这篇关于Marshal.PtrToStructure抛出AccessViolationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!