2010-11-22 24 views
0

ゲームで使用されるDBCファイルには、使用可能なスペルのゲームに関する情報が含まれています。 :) (ID、名前、ダメージなど...)Marshaling.PtrToStructureが例外を落とす - 構造体にバイトを読み込む

もっと複雑になるために、文字列データはレコードの後のブロックに格納されます。私がしようとしているものを、そう

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

:レコード内の文字列データは、私はこのようになりますDBCファイルの構造体を、持っている文字列、(そう、そのことは本当に文字列)

にオフセットを含みます行うには、次のコードで、この構造体へのバイトをマーシャリングされます。

   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でデバッグすると構造が正しく読み込まれているように見えますが、この例外があります。

は、私も私のために100%良い取り組んでいる

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

のように、1によって構造体1への読み込みしようと試みたが、そのルックスラメ、およびその本当に長いコードインチマーシャリングはもっとプロに見えます:)あなたの意見はどうですか?マーシャリングは、1つ1つを読むよりも早く、もしあれば、どうすれば修正できますか?そのスニペットに空から落ちるbuff.Length

おかげ
+0

マーシャルは、管理コードと非管理コードの間でデータをマーシャリングするためのもので、データを構造体に読み込む便利な方法を提供するものではありません。ここでは[BinaryReader](http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx)が適切です。 – dtb

+0

はい、それは私がそれを行う他の方法ですが、このような大きな構造体で、それは正しい、断食方法ですか? –

+0

私はここでBinaryReaderが適切な解決策であると言います。私はより速いものをチェックしていない。マーシャリングはコードの行数を減らす必要があるため、速くなければならないわけではありません(マーシャリングは単なるmemcpyではありません)。プロファイラを使用します。 – dtb

答えて

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

と少なくとも同じ大きさでなければなりません。正確に Marshal.SizeOf(typeof(Spell.SpellEntry))と同じ大きさです。さらに、BitConverterが動作する場合は、[StructLayout]属性のPackプロパティを1に設定する必要があります。バッファ長の問題が分類されると、最初に取り消された値のフィールドを調べて宣言の問題を見つけることができます。

汎用ソリューションはmy answer hereです。

+0

申し訳ありません、この行を忘れてしまった。 byte [] buff =新しいバイト[Marshal.SizeOf(typeof(Spell.SpellEntry))]; –

+0

あなたのアドバイスを試みます、私は報告します:) THanks –

+0

Btw、[MarshalAs(UnmanagedType.LPStr)]は決して働くことはできません、ファイルはポインタを含むことができません。それは爆弾です。 –

関連する問題