Sorry for first post, lil problem with my marshalling (ooopsy). Here's working code.
If folks can contribute to the layout of the SpellInfo struct, that would be very helpful.
Code:
[StructLayout(LayoutKind.Explicit, Size = (int)ObjectOffsets.DBSpellCache_BlockSize)]
public class SpellInfo
{
[FieldOffset(0x238)]
IntPtr _nameBytes;
// note that I should decode these as UTF-8 since they're not technically ANSI, but that's a ton more work. Why doesn't Marshal.PtrToString take a Text.Encoding object??
public string Name
{
get
{
return Marshal.PtrToStringAnsi(_nameBytes);
}
}
[FieldOffset(0x23c)]
public IntPtr _secondaryNameBytes;
public string SecondaryName
{
get
{
return Marshal.PtrToStringAnsi(_secondaryNameBytes);
}
}
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate bool GetCachedSpellInfo(IntPtr spellCache, int spellID, IntPtr buffer);
static GetCachedSpellInfo s_getCachedSpellInfo = null;
public static SpellInfo GetSpellInfo(int spellID)
{
if (s_getCachedSpellInfo == null)
{
s_getCachedSpellInfo = Utilities.RegisterDelegate<GetCachedSpellInfo>((IntPtr)GlobalOffsets.DBSpellCache_GetInfoBlockByID);
}
IntPtr DBSpellCache = (IntPtr)GlobalOffsets.DBSpellCache;
IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SpellInfo)));
try
{
if (s_getCachedSpellInfo(DBSpellCache, spellID, buffer))
{
return (SpellInfo)Marshal.PtrToStructure(buffer, typeof(SpellInfo));
}
else
{
return null;
}
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
}
Relevant offsets:
Code:
CGSpell__CreateSpellLink = 0x005B4280, // 3.3.0 (RE: look for the spell link string (aSHspellDHSHS)
DBSpellCache_GetInfoBlockByID = 0x00476630, // 3.3.0 (RE: second call in CGSpell__CreateSpellLink)
DBSpellCache = 0x00A751FC, // 3.3.0 (RE: move ecx, [static] right before GetInfoBlockByID in CreateSpellLink above)
DBSpellCache_BlockSize = 0x2c0, // see DBSpellCache_GetInfoBlockByID, the only call, 2nd param)