2014-10-09 77 views
1

我有这样的结构: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; 
}; 

而且我想从文件中读取字节,这些字节复制到使用元帅和的GCHandle上述struct,我的代码是如下:

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 : attempt to read or write protected memory

我不知道为什么这会抛出异常。

回答

5

我没有立即看到该错误,并编写了一个测试程序来重现问题。使用二进制搜索来查找问题,评论一半的领域了,直到我把范围缩小到:

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

可不行,PInvoke的编组假设默认编组为是从C字符串,char* 。对于从文件读取的数据,这不可能是正确的,它永远不能包含有效的指针。 AccessViolation在它试图解引用指针时被触发。

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

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

必要时使用十六进制查看器找出SizeConst的正确价值。如果编码不正常(不是系统默认页面),则必须将其声明为byte []并使用正确的编码进行转换。

1

访问冲突,你会明白的是由于试图读取未分配的内存或者被释放的内存,您可能需要检查以下堆栈溢出发帖:

AccessViolationException when Marshal.PtrToStructure fires

其中提到的区别作为问题的原因,托管和本机结构的大小基本上需要在编组时提供偏移以匹配结构的托管和本地分配之间的差异。

入住此张贴过,其中偏移已被用户

Access violation exception when use method Marshal.PtrToStructure in a loop增加。

与解决方案的另一个链接:你需要做的

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

在这种情况下,不那么帮助它很容易使用WinDbg的这样的问题,我可以列出的细节进行调试,以防它。同时在VS中启用Win32 Aces违例异常,它会在行中抛出异常并附带一些额外信息