开发者

Marshaling.PtrToStructure drops Exception - Read bytes to structures

Given a DBC file, used by a game, contains records, infos about ingame usable Spells. :) (like ID, name, damage, etc etc...)

To be more complex, the string data is stored in a block after the records. String data in records contain an offset to the string, (so its not really a string)

I have a struct for DBC file, that looks like this:

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

So, what I'm trying to do is marshaling bytes to this struct with the following code:

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

Which gives me an AccessViolationException on the Marshal.PtrToStructure line. I suspect my struct is invalid, somehow, could you correct me, or give a hint? What's interesting that when I debug in the IDE, it looks like its reads the structure correctly, but gives this exception... weird.

I also tryed reading into struct one by one, like

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

which is working 100% good for me, but its looks lame, and its really long in the code. Marshaling looks more pro :) So, whats your opinion, Is marshal开发者_如何学编程ing faster than reading one by one, if yes, how should I fix it? THanks


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

buff.Length falls from the sky in that snippet. It has to be at least as large, if not exactly as large as Marshal.SizeOf(typeof(Spell.SpellEntry)). Furthermore, if BitConverter works then you have to set the Pack property of the [StructLayout] attribute to 1. Once you've got the buffer length problem sorted out you can find declaration problems by checking the fields for the first mangled value.

A generic solution is available in my answer here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜