2010-11-22 37 views
0

由於遊戲使用的DBC文件包含關於遊戲中可用法術的記錄和信息。 :) (如ID,名稱,損壞等等等)Marshaling.PtrToStructure丟棄異常 - 將字節讀取到結構中

更復雜的是,字符串數據存儲在記錄之後的一個塊中。在記錄字符串數據包含偏移到字符串,(所以它不是一個真正的字符串)

我有DBC文件結構,看起來像這樣:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct SpellEntry 
    { 
     private const int MAX_EFFECT_INDEX = 3; 
     public uint ID; 
     public uint Category; 
     public uint Dispel; 
     public uint Mechanic; 
     public uint Attributes; 
     public uint AttributesEx; 
     public uint AttributesEx2; 
     public uint AttributesEx3; 
     public uint AttributesEx4; 
     public uint AttributesEx5; 
     public uint AttributesEx6; 
     public uint AttributesEx7; 
     public uint Stances; 
     public uint unk_320_2; 
     public uint StancesNot; 
     public uint unk_320_3; 
     public uint Targets; 
     public uint TargetCreatureType; 
     public uint RequiresSpellFocus; 
     public uint FacingCasterFlags; 
     public uint CasterAuraState; 
     public uint TargetAuraState; 
     public uint CasterAuraStateNot; 
     public uint TargetAuraStateNot; 
     public uint casterAuraSpell; 
     public uint targetAuraSpell; 
     public uint excludeCasterAuraSpell; 
     public uint excludeTargetAuraSpell; 
     public uint CastingTimeIndex; 
     public uint RecoveryTime; 
     public uint CategoryRecoveryTime; 
     public uint InterruptFlags; 
     public uint AuraInterruptFlags; 
     public uint ChannelInterruptFlags; 
     public uint procFlags; 
     public uint procChance; 
     public uint procCharges; 
     public uint maxLevel; 
     public uint baseLevel; 
     public uint spellLevel; 
     public uint DurationIndex; 
     public uint powerType; 
     public uint manaCost; 
     public uint manaCostPerlevel; 
     public uint manaPerSecond; 
     public uint manaPerSecondPerLevel; 
     public uint rangeIndex; 
     public float speed; 
     public uint modalNextSpell; 
     public uint StackAmount; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] 
     public uint[] Totem; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.I4)] 
     public int[] Reagent; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] 
     public uint[] ReagentCount; 
     public int EquippedItemClass; 
     public int EquippedItemSubClassMask; 
     public int EquippedItemInventoryTypeMask; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] Effect; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.I4)] 
     public int[] EffectDieSides; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.I4)] 
     public int[] EffectBaseDice; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.R4)] 
     public float[] EffectDicePerLevel; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.R4)] 
     public float[] EffectRealPointsPerLevel; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.I4)] 
     public int[] EffectBasePoints; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectMechanic; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectImplicitTargetA; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectImplicitTargetB; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectRadiusIndex; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectApplyAuraName; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectAmplitude; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.R4)] 
     public float[] EffectMultipleValue; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectChainTarget; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectItemType; 
     //[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.I4)] 
     //public int[] EffectMiscValue; 
     //[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.I4)] 
     //public int[] EffectMiscValueB; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.U4)] 
     public uint[] EffectTriggerSpell; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.R4)] 
     public float[] EffectPointsPerComboPoint; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX)] 
     public Flag96[] EffectSpellClassMask; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] 
     public uint[] SpellVisual; 
     public uint SpellIconID; 
     public uint activeIconID; 
     public uint spellPriority; 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string SpellName; 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string Rank; 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string Description; 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string ToolTip; 
     public uint ManaCostPercentage; 
     public uint StartRecoveryCategory; 
     public uint StartRecoveryTime; 
     public uint MaxTargetLevel; 
     public uint SpellFamilyName; 
     public Flag96 SpellFamilyFlags; 
     public uint MaxAffectedTargets; 
     public uint DmgClass; 
     public uint PreventionType; 
     public uint StanceBarOrder; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_EFFECT_INDEX, ArraySubType = UnmanagedType.R4)] 
     public float[] DmgMultiplier; 
     public uint MinFactionId; 
     public uint MinReputation; 
     public uint RequiredAuraVision; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] 
     public uint[] TotemCategory; 
     public int AreaGroupId; 
     public int SchoolMask; 
     public uint runeCostID; 
     public uint spellMissileID; 
     public uint PowerDisplayId; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.R4)] 
     public float[] unk_320_4; 
     public uint spellDescriptionVariableID; 
     public uint SpellDifficultyId; 
    } 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Flag96 
    { 
     public uint DwA; 
     public uint DwB; 
     public uint DwC; 

     public override string ToString() 
     { 
      return string.Format("DwA: {0} - DwB: {1} - DwC: {2}", DwA, DwB, DwC); 
     } 
    } 

所以,我嘗試做的是編組字節這個結構用下面的代碼:

   byte[] buff = new byte[Marshal.SizeOf(typeof(Spell.SpellEntry))]; 
       binReader.BaseStream.Seek(DBCFile.HEADER_SIZE + (index * 4 * 234), SeekOrigin.Begin); 
       var bytes = binReader.ReadBytes(buff.Length); 
       var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
       var obj = (Spell.SpellEntry)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(Spell.SpellEntry)); 
       handle.Free(); 

這使我對Marshal.PtrToStructure線的AccessViolationException。 我懷疑我的結構是無效的,不知何故,你能糾正我,還是給一個提示? 有趣的是,當我在IDE中調試時,它看起來像它正確地讀取結構,但給這個例外......怪異。

我也tryed讀入結構一個接一個,像

    spell[index].ID = BitConverter.ToUInt32(binReader.ReadBytes(4), 0); 
        spell[index].Category = BitConverter.ToUInt32(binReader.ReadBytes(4), 0); 
        spell[index].Dispel = BitConverter.ToUInt32(binReader.ReadBytes(4), 0); 
        spell[index].Mechanic = BitConverter.ToUInt32(binReader.ReadBytes(4), 0); 

這是工作的100%爲我好,但它的外觀跛腳,其很長的代碼。編組看起來更親:)所以,你的意見是什麼,編組速度比一個一個閱讀更快,如果是的話,我應該如何解決它? 感謝

+0

編組是用於在託管代碼和非託管代碼之間編組數據,而不是提供將數據讀入結構的便捷方式。一個[BinaryReader](http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx)在這裏是適當的。 – dtb 2010-11-22 19:53:19

+0

是的,那是我做的另一種方式,但是在這樣的大結構上,它是正確的方法嗎? – 2010-11-22 19:59:31

回答

1
var bytes = binReader.ReadBytes(buff.Length); 

buff.Length落在該片段的天空。它至少一樣大,如果不是正好大到Marshal.SizeOf(typeof(Spell.SpellEntry))。此外,如果BitConverter工作,則必須將[StructLayout]屬性的Pack屬性設置爲1.一旦解決了緩衝區長度問題,您可以通過檢查第一個損壞值的字段來找到聲明問題。

通用解決方案可在my answer here