簡體   English   中英

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;
};

我正在嘗試從文件中讀取字節並使用Marshal和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

我不知道為什么拋出這個異常。

我沒有立即看到這個錯誤並寫了一個小測試程序來重現這個問題。 使用二進制搜索來查找問題,重復注釋一半字段,直到我將其縮小到:

[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;
};

如有必要,請使用十六進制查看器來確定SizeConst的正確值。 如果編碼異常(不是系統默認頁面),則必須將其聲明為byte []並使用正確的編碼進行轉換。

您可以理解的訪問沖突是由於嘗試讀取未分配的內存或正在釋放的內存,您可能需要檢查以下堆棧溢出發布:

觸發Marshal.PtrToStructure時的AccessViolationException

這是指托管和本機結構的大小之間的差異作為問題的原因,基本上您需要在編組期間提供偏移以匹配結構的托管和本機分配之間的差異。

也檢查此帖子,用戶添加了偏移量

在循環中使用方法Marshal.PtrToStructure時訪問沖突異常

另一個解決方案的鏈接:

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

如果這沒有用,那么使用windbg很容易調試這些問題,我可以列出細節,以防你需要這樣做。 同樣在VS中啟用Win32 Aces違例異常,它會在拋出異常行時打破一些額外的信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM