2014-10-09 56 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違例異常,它會在行中拋出異常並附帶一些額外信息