1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-12-01 13:24:25 +01:00
sh_memory.h: Added ModuleInMemory; first checks /proc/self/maps OR /proc/curproc/map; if not available tries DS's sigsegv trapping method
sh_tinyhash: Added simple erase function(s)
test/Makefile: New makefile
Changed internal interface: sourcehook.hxx now doesn't need to know about implementation details like vectors etc.

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40118
This commit is contained in:
Pavol Marko 2005-10-03 17:20:22 +00:00
parent 71d74c6722
commit 2790931701
12 changed files with 2173 additions and 921 deletions

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1
#define SH_IMPL_VERSION 1
#define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID
#endif
#ifdef SH_DEBUG
# include <stdio.h>
# include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0)
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__)
# define SH_ASSERT(x, info) \
do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else
# define SH_ASSERT(x, info)
#endif
@ -70,10 +78,6 @@
#include "FastDelegate.h"
#include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook
{
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/**
* @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/
class EmptyClass
{
@ -111,29 +118,33 @@ namespace SourceHook
/**
* @brief A plugin typedef
*
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it
* and every plugin has a unique identifier, everything is ok.
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/
typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction
{
HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference
HA_Unregister // -> Clear the saved pointer
HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister //!< Clear the saved pointer
};
struct HookManagerInfo;
class IHookManagerInfo;
/**
* @brief Pointer to hook manager type
* @brief Pointer to hook manager interface function
*
* A "hook manager" is a the only thing that knows the actual protoype of the function at compile time.
*
* @param hi A pointer to a HookManagerInfo structure. The hook manager should fill it and store it for
* future reference (mainly if something should get hooked to its hookfunc)
* @param ha What the hook manager should do
* @param hi A pointer to IHookManagerInfo
*/
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi);
typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate
{
@ -170,65 +181,83 @@ namespace SourceHook
}
};
/**
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
struct IHookList
{
struct VfnPtr
struct IIter
{
struct Iface
{
struct Hook
{
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
virtual bool End() = 0;
virtual void Next() = 0;
virtual ISHDelegate *Handler() = 0;
virtual int ThisPtrOffs() = 0;
};
Plugin plug; //!< The owner plugin
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
virtual IIter *GetIter() = 0;
virtual void ReleaseIter(IIter *pIter) = 0;
};
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
struct IIface
{
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass
{
B *ptr; //!< Pointer to the actual object
size_t objsize; //!< Size of the instance
OrigVTables vt; //!< Info about vtables & functions
virtual B *GetThisPtr() = 0;
virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
};
typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook
{
public:
virtual ~ISourceHook()
{ }
/**
* @brief Return interface version
*/
@ -263,7 +290,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual const void *GetOrigRet() = 0; //!< Gets the original result.
//!< If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result.
//!< If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry;
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0;
#else
# error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \
SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \
using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
\
if (action == ::SourceHook::HA_GetInfo) \
{ \
param->proto = ms_Proto; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
\
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \
param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \
} \
else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static ::SourceHook::HookManagerInfo *ms_HI; \
static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \
else \
orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
//////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
}
#define SH_RETURN_void()
@ -1490,6 +1514,210 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 17 arguments *********
#define SH_DECL_HOOK17(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 18 arguments *********
#define SH_DECL_HOOK18(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 19 arguments *********
#define SH_DECL_HOOK19(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 20 arguments *********
#define SH_DECL_HOOK20(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
//////////////////////////////////////////////////////////////////////////
@ -1497,14 +1725,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -1512,9 +1742,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \
void *addr; \
} u; \
u.addr = iter->val[mfi.vtblindex]; \
u.addr = origfunc; \
\
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
}
@ -1524,10 +1754,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -1539,10 +1769,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \
} s; \
} u; \
u.s.addr = iter->val[mfi.vtblindex]; \
u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \
\
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \
return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
}
#endif
@ -1626,6 +1856,22 @@ namespace SourceHook
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
// Support for 17 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
// Support for 18 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
// Support for 19 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
// Support for 20 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19, Param20 p20) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
};
}
@ -1888,6 +2134,66 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300
// GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it
@ -2147,12 +2453,72 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#endif
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY
#undef SH_MAKE_EXECUTABLECLASS_OB
#endif
// The pope is dead. -> :(

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1
#define SH_IMPL_VERSION 1
#define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID
#endif
#ifdef SH_DEBUG
# include <stdio.h>
# include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0)
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__)
# define SH_ASSERT(x, info) \
do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else
# define SH_ASSERT(x, info)
#endif
@ -70,10 +78,6 @@
#include "FastDelegate.h"
#include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook
{
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/**
* @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/
class EmptyClass
{
@ -111,29 +118,33 @@ namespace SourceHook
/**
* @brief A plugin typedef
*
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it
* and every plugin has a unique identifier, everything is ok.
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/
typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction
{
HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference
HA_Unregister // -> Clear the saved pointer
HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister //!< Clear the saved pointer
};
struct HookManagerInfo;
class IHookManagerInfo;
/**
* @brief Pointer to hook manager type
* @brief Pointer to hook manager interface function
*
* A "hook manager" is a the only thing that knows the actual protoype of the function at compile time.
*
* @param hi A pointer to a HookManagerInfo structure. The hook manager should fill it and store it for
* future reference (mainly if something should get hooked to its hookfunc)
* @param ha What the hook manager should do
* @param hi A pointer to IHookManagerInfo
*/
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi);
typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate
{
@ -170,65 +181,83 @@ namespace SourceHook
}
};
/**
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
struct IHookList
{
struct VfnPtr
struct IIter
{
struct Iface
{
struct Hook
{
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
virtual bool End() = 0;
virtual void Next() = 0;
virtual ISHDelegate *Handler() = 0;
virtual int ThisPtrOffs() = 0;
};
Plugin plug; //!< The owner plugin
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
virtual IIter *GetIter() = 0;
virtual void ReleaseIter(IIter *pIter) = 0;
};
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
struct IIface
{
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass
{
B *ptr; //!< Pointer to the actual object
size_t objsize; //!< Size of the instance
OrigVTables vt; //!< Info about vtables & functions
virtual B *GetThisPtr() = 0;
virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
};
typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook
{
public:
virtual ~ISourceHook()
{ }
/**
* @brief Return interface version
*/
@ -263,7 +290,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual const void *GetOrigRet() = 0; //!< Gets the original result.
//!< If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result.
//!< If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry;
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0;
#else
# error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \
SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \
using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
\
if (action == ::SourceHook::HA_GetInfo) \
{ \
param->proto = ms_Proto; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
\
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \
param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \
} \
else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static ::SourceHook::HookManagerInfo *ms_HI; \
static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \
else \
orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
//////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
}
#define SH_RETURN_void()
@ -683,14 +707,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -698,9 +724,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \
void *addr; \
} u; \
u.addr = iter->val[mfi.vtblindex]; \
u.addr = origfunc; \
\
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
}
@ -710,10 +736,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -725,10 +751,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \
} s; \
} u; \
u.s.addr = iter->val[mfi.vtblindex]; \
u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \
\
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \
return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
}
#endif
@ -800,7 +826,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@Param%%|, @@
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY
#undef SH_MAKE_EXECUTABLECLASS_OB
#endif
// The pope is dead. -> :(

View File

@ -23,6 +23,9 @@
# define SH_MEM_EXEC 4
# elif /******/ defined __linux__
# include <sys/mman.h>
# include <stdio.h>
# include <signal.h>
# include <setjmp.h>
// http://www.die.net/doc/linux/man/man2/mprotect.2.html
# include <limits.h>
# ifndef PAGESIZE
@ -66,6 +69,118 @@ namespace SourceHook
# endif
}
#ifdef __linux__
namespace
{
bool g_BadReadCalled;
jmp_buf g_BadReadJmpBuf;
static void BadReadHandler(int sig)
{
if (g_BadReadCalled)
longjmp(g_BadReadJmpBuf, 1);
}
}
#endif
/**
* @brief Checks whether the specified memory region is (still) accessible
*
* @param addr The lower boundary
* @param len Length of the region to be checked
*/
namespace
{
bool ModuleInMemory(char *addr, size_t len)
{
#ifdef __linux__
// On linux, first check /proc/self/maps
long lower = reinterpret_cast<long>(addr);
long upper = lower + len;
FILE *pF = fopen("/proc/self/maps", "r");
if (pF)
{
// Linux /proc/self/maps -> parse
// Format:
// lower upper prot stuff path
// 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat
long rlower, rupper;
while (fscanf(pF, "%lx-%lx", &rlower, &rupper) != EOF)
{
// Check whether we're IN THERE!
if (lower >= rlower && upper <= rupper)
{
fclose(pF);
return true;
}
// Read to end of line
int c;
while ((c = fgetc(pF)) != '\n')
{
if (c == EOF)
break;
}
if (c == EOF)
break;
}
fclose(pF);
return false;
}
pF = fopen("/proc/curproc/map", "r");
if (pF)
{
// FreeBSD /proc/curproc/map -> parse
// 0x804800 0x805500 13 15 0xc6e18960 r-x 21 0x0 COW NC vnode
long rlower, rupper;
while (fscanf(pF, "0x%lx 0x%lx", &rlower, &rupper) != EOF)
{
// Check whether we're IN THERE!
if (lower >= rlower && upper <= rupper)
{
fclose(pF);
return true;
}
// Read to end of line
int c;
while ((c = fgetc(pF)) != '\n')
{
if (c == EOF)
break;
}
if (c == EOF)
break;
}
fclose(pF);
return false;
}
// Both of the above failed, try to actually read and trap sigsegv (implemented by Damaged Soul)
void(*prevHandler)(int sig);
g_BadReadCalled = true;
if (setjmp(g_BadReadJmpBuf))
return true;
prevHandler = signal(SIGSEGV, BadReadHandler);
volatile const char *p = reinterpret_cast<const char*>(addr);
char dummy;
for (size_t i = 0; i < len; i++)
dummy = p[i];
g_BadReadCalled = false;
signal(SIGSEGV, prevHandler);
return false;
#else
// On Win32, simply use IsBadReadPtr
return !IsBadReadPtr(addr, len);
#endif
}
}
}
#endif

View File

@ -139,7 +139,7 @@ namespace SourceHook
typename List<THashNode *>::iterator iter;
size_t place;
THashNode *pHashNode;
NodePtr *temp = new NodePtr[m_numBuckets];
NodePtr *temp = new NodePtr[m_numBuckets];
for (size_t i=0; i<m_numBuckets; i++)
temp[i] = NULL;
//look in old hash table
@ -225,7 +225,7 @@ namespace SourceHook
&&
(this->end ||
((where.curbucket == this->curbucket)
&& (where.iter == iter))
&& (where.iter == iter))
))
return true;
return false;
@ -234,6 +234,20 @@ namespace SourceHook
{
return !( (*this) == where );
}
void erase()
{
if (end || !hash || curbucket < 0 || curbucket >= static_cast<int>(hash->m_numBuckets))
return;
// Remove this element and move to the next one
iterator tmp = *this;
++tmp;
hash->m_Buckets[curbucket]->erase(iter);
*this = tmp;
// :TODO: Maybe refactor to a lower size if required
}
private:
void _Inc()
{
@ -324,7 +338,7 @@ namespace SourceHook
&&
(this->end ||
((where.curbucket == this->curbucket)
&& (where.iter == iter))
&& (where.iter == iter))
))
return true;
return false;
@ -428,6 +442,20 @@ namespace SourceHook
}
return end();
}
iterator erase(iterator where)
{
where.erase();
return where;
}
template <typename U>
void erase(const U & u)
{
iterator iter = find(u);
if (iter == end())
return;
iter.erase();
}
private:
NodePtr *m_Buckets;
size_t m_numBuckets;

View File

@ -17,8 +17,9 @@
#if defined __GNUC__
#include <stdint.h>
#endif
#include "sourcehook_impl.h"
#include "sh_tinyhash.h"
#include "sh_memory.h"
namespace SourceHook
{
@ -41,7 +42,6 @@ namespace SourceHook
CSourceHookImpl::CSourceHookImpl()
{
}
CSourceHookImpl::~CSourceHookImpl()
{
}
@ -63,23 +63,23 @@ namespace SourceHook
// If a hook from an other plugin is found, return true
// Return false otherwise
#define TMP_CHECK_LIST(name) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
if (hook_iter->plug == plug) \
return true;
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{
if (hmil_iter->plug != plug)
if (hmil_iter->m_Plug != plug)
continue;
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre);
TMP_CHECK_LIST(hooks_post);
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks);
TMP_CHECK_LIST(m_PostHooks);
}
}
}
@ -94,21 +94,22 @@ namespace SourceHook
HookManInfoList::iterator hmil_iter;
#define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
if (hook_iter->plug == plug) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \
hook_iter->thisptr_offs, hmil_iter->func, hook_iter->handler, ispost))
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre, false);
TMP_CHECK_LIST(hooks_post, true);
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
}
}
}
@ -126,9 +127,9 @@ namespace SourceHook
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end();
erase ? hmil_iter=m_HookMans.erase(hmil_iter) : ++hmil_iter)
{
if (hmil_iter->plug == plug)
if (hmil_iter->m_Plug == plug)
{
if (!hmil_iter->vfnptrs.empty())
if (!hmil_iter->m_VfnPtrs.empty())
{
// All hooks by this plugin are already removed
// So if there is a vfnptr, it has to be used by an other plugin
@ -140,41 +141,41 @@ namespace SourceHook
erase = false;
}
// For each hook manager:
// For each hook manager that is used in an other plugin:
for (hmil_iter = tmphookmans.begin(); hmil_iter != tmphookmans.end(); ++hmil_iter)
{
// Find a suitable hook manager in an other plugin
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
hmil_iter->proto, hmil_iter->vtbl_offs, hmil_iter->vtbl_idx);
hmil_iter->m_Proto, hmil_iter->m_VtblOffs, hmil_iter->m_VtblIdx);
// This should _never_ happen.
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
SH_ASSERT(newHookMan != m_HookMans.end(),
"Could not find a suitable hook manager in an other plugin!");
("Could not find a suitable hook manager in an other plugin!"));
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo
SH_ASSERT(newHookMan->plug != plug, "New hook manager from same plugin!");
SH_ASSERT(newHookMan->m_Plug != plug, ("New hook manager from same plugin!"));
// The first hook manager should be always used - so the new hook manager has to be empty
SH_ASSERT(newHookMan->vfnptrs.empty(), "New hook manager not empty!");
SH_ASSERT(newHookMan->m_VfnPtrs.empty(), ("New hook manager not empty!"));
// Move the vfnptrs from the old hook manager to the new one
newHookMan->vfnptrs = hmil_iter->vfnptrs;
newHookMan->m_VfnPtrs = hmil_iter->m_VfnPtrs;
// Unregister the old one, register the new one
hmil_iter->func(HA_Unregister, NULL);
newHookMan->func(HA_Register, &(*newHookMan));
hmil_iter->m_Func(HA_Unregister, NULL);
newHookMan->m_Func(HA_Register, &(*newHookMan));
// zOMG BAIL, here is part of what you wanted:
// Go through all vfnptrs in this hookman and patch them to point to the new manager's handler!
// or whatever
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->vfnptrs.begin();
vfnptr_iter != newHookMan->vfnptrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->m_VfnPtrs.begin();
vfnptr_iter != newHookMan->m_VfnPtrs.end(); ++vfnptr_iter)
{
// And DEREFERENCE newHookMan->hookfunc_vfnptr!
// And DEREFERENCE newHookMan->m_HookfuncVfnptr!
// otherwise it will be executing the vtable... had to find out the hard way
*reinterpret_cast<void**>(vfnptr_iter->vfnptr) = *reinterpret_cast<void**>(newHookMan->hookfunc_vfnptr);
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(newHookMan->m_HookfuncVfnptr);
}
// That should fix it, bail!
@ -185,20 +186,20 @@ namespace SourceHook
{
List<RemoveHookInfo> hookstoremove;
#define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \
hook_iter->thisptr_offs, hmil_iter->func, hook_iter->handler, ispost))
for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre, false);
TMP_CHECK_LIST(hooks_post, true);
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
}
}
}
@ -214,87 +215,84 @@ namespace SourceHook
{
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
// 1) Get info about the hook manager
HookManagerInfo tmp;
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager with this proto/vo/vi registered
// Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager
// with this proto/vo/vi registered
HookManInfoList::iterator hkmi_iter;
for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter)
{
if (hkmi_iter->plug == plug && strcmp(hkmi_iter->proto, tmp.proto) == 0 &&
hkmi_iter->vtbl_offs == tmp.vtbl_offs && hkmi_iter->vtbl_idx == tmp.vtbl_idx)
if (hkmi_iter->m_Plug == plug && strcmp(hkmi_iter->m_Proto, tmp.m_Proto) == 0 &&
hkmi_iter->m_VtblOffs == tmp.m_VtblOffs && hkmi_iter->m_VtblIdx == tmp.m_VtblIdx)
break;
}
if (hkmi_iter == m_HookMans.end())
{
// No such hook manager from this plugin yet, add it!
tmp.func = myHookMan;
tmp.plug = plug;
tmp.m_Func = myHookMan;
tmp.m_Plug = plug;
m_HookMans.push_back(tmp);
}
// Then, search for a suitable hook manager (from the beginning)
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx);
SH_ASSERT(hookman != m_HookMans.end(), "No hookman found - but if there was none, we've just added one!");
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.m_Proto,
tmp.m_VtblOffs, tmp.m_VtblIdx);
SH_ASSERT(hookman != m_HookMans.end(), ("No hookman found - but if there was none, we've just added one!"));
// Tell it to store the pointer if it's not already active
if (hookman->vfnptrs.empty())
hookman->func(HA_Register, &(*hookman));
if (hookman->m_VfnPtrs.empty())
hookman->m_Func(HA_Register, &(*hookman));
void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx);
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.find(cur_vfnptr);
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->vfnptrs.end())
if (vfnptr_iter == hookman->m_VfnPtrs.end())
{
// Add a new one
HookManagerInfo::VfnPtr vfp;
vfp.vfnptr = cur_vfnptr;
vfp.orig_entry = *reinterpret_cast<void**>(cur_vfnptr);
CVfnPtr vfp(cur_vfnptr);
// Alter vtable entry
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.vtbl_idx + 1), SH_MEM_READ | SH_MEM_WRITE))
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
return false;
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->hookfunc_vfnptr);
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->m_HookfuncVfnptr);
hookman->vfnptrs.push_back(vfp);
hookman->m_VfnPtrs.push_back(vfp);
// Make vfnptr_iter point to the new element
vfnptr_iter = hookman->vfnptrs.end();
vfnptr_iter = hookman->m_VfnPtrs.end();
--vfnptr_iter;
// Now that it is done, check whether we have to update any callclasses
ApplyCallClassPatches(adjustediface, tmp.vtbl_offs, tmp.vtbl_idx, vfp.orig_entry);
ApplyCallClassPatches(adjustediface, tmp.m_VtblOffs, tmp.m_VtblIdx, vfp.m_OrigEntry);
}
HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.find(adjustediface);
if (iface_iter == vfnptr_iter->ifaces.end())
CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(adjustediface);
if (iface_iter == vfnptr_iter->m_Ifaces.end())
{
// Add a new one
HookManagerInfo::VfnPtr::Iface ifs;
ifs.ptr = adjustediface;
vfnptr_iter->ifaces.push_back(ifs);
vfnptr_iter->m_Ifaces.push_back(CIface(adjustediface));
// Make iface_iter point to the new element
iface_iter = vfnptr_iter->ifaces.end();
iface_iter = vfnptr_iter->m_Ifaces.end();
--iface_iter;
}
// Add the hook
HookManagerInfo::VfnPtr::Iface::Hook hookinfo;
HookInfo hookinfo;
hookinfo.handler = handler;
hookinfo.plug = plug;
hookinfo.paused = false;
hookinfo.thisptr_offs = thisptr_offs;
if (post)
iface_iter->hooks_post.push_back(hookinfo);
iface_iter->m_PostHooks.m_List.push_back(hookinfo);
else
iface_iter->hooks_pre.push_back(hookinfo);
iface_iter->m_PreHooks.m_List.push_back(hookinfo);
return true;
}
@ -307,40 +305,42 @@ namespace SourceHook
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs);
HookManagerInfo tmp;
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Find the hook manager and the hook
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx);
tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman == m_HookMans.end())
return false;
if (IsBadReadPtr(reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs, sizeof(char)))
if (!ModuleInMemory(reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs,
sizeof(void*) * (tmp.m_VtblIdx + 1)))
{
hookman->vfnptrs.clear();
hookman->func(HA_Unregister, NULL);
// The module the vtable was in is already unloaded.
hookman->m_VfnPtrs.clear();
hookman->m_Func(HA_Unregister, NULL);
return true;
}
void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx);
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.find(cur_vfnptr);
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->vfnptrs.end())
if (vfnptr_iter == hookman->m_VfnPtrs.end())
return false;
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end();)
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end();)
{
List<HookManagerInfo::VfnPtr::Iface::Hook> &hooks =
post ? iface_iter->hooks_post : iface_iter->hooks_pre;
List<HookInfo> &hooks =
post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
bool erase;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = hooks.begin();
for (List<HookInfo>::iterator hookiter = hooks.begin();
hookiter != hooks.end(); erase ? hookiter = hooks.erase(hookiter) : ++hookiter)
{
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler) &&
@ -348,25 +348,27 @@ namespace SourceHook
if (erase)
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
}
if (iface_iter->hooks_post.empty() && iface_iter->hooks_pre.empty())
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
iface_iter = vfnptr_iter->ifaces.erase(iface_iter);
if (vfnptr_iter->ifaces.empty())
{
// Deactivate the hook
*reinterpret_cast<void**>(vfnptr_iter->vfnptr) = vfnptr_iter->orig_entry;
// There are no hooks on this iface anymore...
hookman->vfnptrs.erase(vfnptr_iter);
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
{
// No ifaces at all -> Deactivate the hook
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = vfnptr_iter->m_OrigEntry;
hookman->m_VfnPtrs.erase(vfnptr_iter);
// Remove callclass patch
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
if (cciter->cc.ptr == adjustediface)
RemoveCallClassPatch(*cciter, tmp.vtbl_offs, tmp.vtbl_idx);
if (cciter->m_Ptr == adjustediface)
cciter->RemoveCallClassPatch(tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman->vfnptrs.empty())
if (hookman->m_VfnPtrs.empty())
{
// Unregister the hook manager
hookman->func(HA_Unregister, NULL);
hookman->m_Func(HA_Unregister, NULL);
}
// Don't try to continue looping through ifaces
@ -384,22 +386,19 @@ namespace SourceHook
{
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
{
if (cciter->cc.ptr == iface && cciter->cc.objsize == size)
if (cciter->m_Ptr == iface && cciter->m_ObjSize == size)
{
++cciter->refcounter;
return &cciter->cc;
++cciter->m_RefCounter;
return &(*cciter);
}
}
CallClassInfo tmp;
tmp.refcounter = 1;
tmp.cc.ptr = iface;
tmp.cc.objsize = size;
// Make a new one
CCallClassImpl tmp(iface, size);
ApplyCallClassPatches(tmp);
m_CallClasses.push_back(tmp);
return &m_CallClasses.back().cc;
return &m_CallClasses.back();
}
void CSourceHookImpl::ReleaseCallClass(GenericCallClass *ptr)
@ -407,35 +406,27 @@ namespace SourceHook
Impl_CallClassList::iterator iter = m_CallClasses.find(ptr);
if (iter == m_CallClasses.end())
return;
--iter->refcounter;
if (iter->refcounter < 1)
--iter->m_RefCounter;
if (iter->m_RefCounter < 1)
m_CallClasses.erase(iter);
}
void CSourceHookImpl::ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry)
{
OrigFuncs &tmpvec = cc.cc.vt[vtbl_offs];
if (tmpvec.size() <= (size_t)vtbl_idx)
tmpvec.resize(vtbl_idx+1);
tmpvec[vtbl_idx] = orig_entry;
}
void CSourceHookImpl::ApplyCallClassPatches(CallClassInfo &cc)
void CSourceHookImpl::ApplyCallClassPatches(CCallClassImpl &cc)
{
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
{
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.begin();
vfnptr_iter != hookman->vfnptrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.begin();
vfnptr_iter != hookman->m_VfnPtrs.end(); ++vfnptr_iter)
{
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter)
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
if (iface_iter->ptr >= cc.cc.ptr &&
iface_iter->ptr < (reinterpret_cast<char*>(cc.cc.ptr) + cc.cc.objsize))
if (iface_iter->m_Ptr >= cc.m_Ptr &&
iface_iter->m_Ptr < (reinterpret_cast<char*>(cc.m_Ptr) + cc.m_ObjSize))
{
ApplyCallClassPatch(cc, static_cast<int>(reinterpret_cast<char*>(iface_iter->ptr) -
reinterpret_cast<char*>(cc.cc.ptr)) + hookman->vtbl_offs,
hookman->vtbl_idx, vfnptr_iter->orig_entry);
cc.ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(iface_iter->m_Ptr) -
reinterpret_cast<char*>(cc.m_Ptr)) + hookman->m_VtblOffs,
hookman->m_VtblIdx, vfnptr_iter->m_OrigEntry);
}
}
}
@ -447,11 +438,11 @@ namespace SourceHook
for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end();
++cc_iter)
{
if (ifaceptr >= cc_iter->cc.ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->cc.ptr) + cc_iter->cc.objsize))
if (ifaceptr >= cc_iter->m_Ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->m_Ptr) + cc_iter->m_ObjSize))
{
ApplyCallClassPatch(*cc_iter, static_cast<int>(reinterpret_cast<char*>(ifaceptr) -
reinterpret_cast<char*>(cc_iter->cc.ptr)) + vtbl_offs, vtbl_idx, orig_entry);
cc_iter->ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(ifaceptr) -
reinterpret_cast<char*>(cc_iter->m_Ptr)) + vtbl_offs, vtbl_idx, orig_entry);
}
}
}
@ -461,34 +452,10 @@ namespace SourceHook
for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end();
++cc_iter)
{
if (ifaceptr >= cc_iter->cc.ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->cc.ptr) + cc_iter->cc.objsize))
if (ifaceptr >= cc_iter->m_Ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->m_Ptr) + cc_iter->m_ObjSize))
{
RemoveCallClassPatch(*cc_iter, vtbl_offs, vtbl_idx);
}
}
}
void CSourceHookImpl::RemoveCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx)
{
OrigVTables::iterator iter = cc.cc.vt.find(vtbl_offs);
if (iter != cc.cc.vt.end())
{
if (iter->val.size() > (size_t)vtbl_idx)
{
iter->val[vtbl_idx] = 0;
// Free some memory if possible
// :TODO: add this back in!
/*
OrigFuncs::reverse_iterator riter;
for (riter = iter->second.rbegin(); riter != iter->second.rend(); ++riter)
{
if (*riter != 0)
break;
}
iter->second.resize(iter->second.size() - (riter - iter->second.rbegin()));
if (!iter->second.size())
cc.cc.vt.erase(iter);*/
cc_iter->RemoveCallClassPatch(vtbl_offs, vtbl_idx);
}
}
}
@ -499,53 +466,41 @@ namespace SourceHook
HookManInfoList::iterator hookmaniter;
for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
{
if (strcmp(hookmaniter->proto, proto) == 0 && hookmaniter->vtbl_offs == vtblofs &&
hookmaniter->vtbl_idx == vtblidx)
if (strcmp(hookmaniter->m_Proto, proto) == 0 && hookmaniter->m_VtblOffs == vtblofs &&
hookmaniter->m_VtblIdx == vtblidx)
break;
}
return hookmaniter;
}
void CSourceHookImpl::PausePlugin(Plugin plug)
void CSourceHookImpl::SetPluginPaused(Plugin plug, bool paused)
{
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin();
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter)
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin();
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin();
vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter)
for (CVfnPtr::IfaceListIter ifaceiter = vfnptr_iter->m_Ifaces.begin();
ifaceiter != vfnptr_iter->m_Ifaces.end(); ++ifaceiter)
{
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PreHooks.m_List.begin();
hookiter != ifaceiter->m_PreHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = true;
hookiter->paused = paused;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PostHooks.m_List.begin();
hookiter != ifaceiter->m_PostHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = true;
hookiter->paused = paused;
}
}
void CSourceHookImpl::PausePlugin(Plugin plug)
{
SetPluginPaused(plug, true);
}
void CSourceHookImpl::UnpausePlugin(Plugin plug)
{
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin();
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter)
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin();
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter)
{
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = false;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = false;
}
SetPluginPaused(plug, false);
}
void CSourceHookImpl::SetRes(META_RES res)
@ -608,38 +563,212 @@ namespace SourceHook
return m_IfacePtr;
}
#ifdef __linux__
bool g_BadReadCalled;
jmp_buf g_BadReadJmpBuf;
// Windows has an implementation for this already, but Linux does not :(
bool IsBadReadPtr(const void *ptr, size_t len)
////////////////////////////
// CCallClassImpl
////////////////////////////
CSourceHookImpl::CCallClassImpl::CCallClassImpl(void *ptr, size_t size)
: m_Ptr(ptr), m_ObjSize(size), m_RefCounter(1)
{
}
CSourceHookImpl::CCallClassImpl::~CCallClassImpl()
{
void(*prevHandler)(int sig);
g_BadReadCalled = true;
if (setjmp(g_BadReadJmpBuf))
return true;
prevHandler = signal(SIGSEGV, BadReadHandler);
volatile const char *p = reinterpret_cast<const char*>(ptr);
char dummy;
for (size_t i = 0; i < len; i++)
dummy = p[i];
g_BadReadCalled = false;
signal(SIGSEGV, prevHandler);
return false;
}
void BadReadHandler(int sig)
void *CSourceHookImpl::CCallClassImpl::GetThisPtr()
{
if (g_BadReadCalled)
longjmp(g_BadReadJmpBuf, 1);
return m_Ptr;
}
void *CSourceHookImpl::CCallClassImpl::GetOrigFunc(int vtbloffs, int vtblidx)
{
OrigVTables::iterator iter = m_VT.find(vtbloffs);
if (iter != m_VT.end() && iter->val.size() > (size_t)vtblidx)
{
return iter->val[vtblidx];
}
return NULL;
}
void CSourceHookImpl::CCallClassImpl::ApplyCallClassPatch(int vtbl_offs, int vtbl_idx, void *orig_entry)
{
OrigFuncs &tmpvec = m_VT[vtbl_offs];
if (tmpvec.size() <= (size_t)vtbl_idx)
tmpvec.resize(vtbl_idx+1);
tmpvec[vtbl_idx] = orig_entry;
}
void CSourceHookImpl::CCallClassImpl::RemoveCallClassPatch(int vtbl_offs, int vtbl_idx)
{
OrigVTables::iterator iter = m_VT.find(vtbl_offs);
if (iter != m_VT.end())
{
if (iter->val.size() > (size_t)vtbl_idx)
{
iter->val[vtbl_idx] = 0;
OrigFuncs &of = iter->val;
OrigFuncs::iterator lastused = of.end();
for (OrigFuncs::iterator viter = of.begin(); viter != of.end(); ++viter)
{
if (*viter)
lastused = viter;
}
if (lastused == of.end())
{
// No used element => Remove the whole vector
m_VT.erase(iter);
return;
}
of.resize(lastused - of.begin() + 1);
}
}
}
////////////////////////////
// CHookManagerInfo
////////////////////////////
CSourceHookImpl::CHookManagerInfo::~CHookManagerInfo()
{
}
IVfnPtr *CSourceHookImpl::CHookManagerInfo::FindVfnPtr(void *vfnptr)
{
VfnPtrListIter iter = m_VfnPtrs.find(vfnptr);
return iter == m_VfnPtrs.end() ? NULL : &(*iter);
}
void CSourceHookImpl::CHookManagerInfo::SetInfo(int vtbl_offs, int vtbl_idx, const char *proto)
{
m_VtblOffs = vtbl_offs;
m_VtblIdx = vtbl_idx;
m_Proto = proto;
}
void CSourceHookImpl::CHookManagerInfo::SetHookfuncVfnptr(void *hookfunc_vfnptr)
{
m_HookfuncVfnptr = hookfunc_vfnptr;
}
////////////////////////////
// CVfnPtr
////////////////////////////
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr) : m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(ptr))
{
}
CSourceHookImpl::CVfnPtr::~CVfnPtr()
{
}
void *CSourceHookImpl::CVfnPtr::GetVfnPtr()
{
return m_Ptr;
}
void *CSourceHookImpl::CVfnPtr::GetOrigEntry()
{
return m_OrigEntry;
}
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
{
IfaceListIter iter = m_Ifaces.find(ptr);
return iter == m_Ifaces.end() ? NULL : &(*iter);
}
////////////////////////////
// CIface
////////////////////////////
CSourceHookImpl::CIface::CIface(void *ptr) : m_Ptr(ptr)
{
}
CSourceHookImpl::CIface::~CIface()
{
}
void *CSourceHookImpl::CIface::GetPtr()
{
return m_Ptr;
}
IHookList *CSourceHookImpl::CIface::GetPreHooks()
{
return &m_PreHooks;
}
IHookList *CSourceHookImpl::CIface::GetPostHooks()
{
return &m_PostHooks;
}
////////////////////////////
// CHookList
////////////////////////////
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL)
{
}
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List), m_FreeIters(NULL)
{
}
CSourceHookImpl::CHookList::~CHookList()
{
while (m_FreeIters)
{
CIter *iter = m_FreeIters->m_pNext;
delete m_FreeIters;
m_FreeIters = iter;
}
}
IHookList::IIter *CSourceHookImpl::CHookList::GetIter()
{
if (m_FreeIters)
{
CIter *ret = m_FreeIters;
m_FreeIters = ret->m_pNext;
ret->GoToBegin();
return ret;
}
return new CIter(this);
}
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
{
CIter *pIter2 = static_cast<CIter*>(pIter);
pIter2->m_pNext = m_FreeIters;
m_FreeIters = pIter2;
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList), m_pNext(NULL)
{
GoToBegin();
}
CSourceHookImpl::CHookList::CIter::~CIter()
{
}
void CSourceHookImpl::CHookList::CIter::GoToBegin()
{
m_Iter = m_pList->m_List.begin();
SkipPaused();
}
bool CSourceHookImpl::CHookList::CIter::End()
{
return m_Iter == m_pList->m_List.end();
}
void CSourceHookImpl::CHookList::CIter::Next()
{
++m_Iter;
SkipPaused();
}
void CSourceHookImpl::CHookList::CIter::SkipPaused()
{
while (m_Iter != m_pList->m_List.end() && m_Iter->paused)
++m_Iter;
}
ISHDelegate *CSourceHookImpl::CHookList::CIter::Handler()
{
return m_Iter->handler;
}
int CSourceHookImpl::CHookList::CIter::ThisPtrOffs()
{
return m_Iter->thisptr_offs;
}
#endif
}

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1
#define SH_IMPL_VERSION 1
#define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID
#endif
#ifdef SH_DEBUG
# include <stdio.h>
# include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0)
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__)
# define SH_ASSERT(x, info) \
do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else
# define SH_ASSERT(x, info)
#endif
@ -70,10 +78,6 @@
#include "FastDelegate.h"
#include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook
{
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/**
* @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/
class EmptyClass
{
@ -111,29 +118,33 @@ namespace SourceHook
/**
* @brief A plugin typedef
*
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it
* and every plugin has a unique identifier, everything is ok.
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/
typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction
{
HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference
HA_Unregister // -> Clear the saved pointer
HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister //!< Clear the saved pointer
};
struct HookManagerInfo;
class IHookManagerInfo;
/**
* @brief Pointer to hook manager type
* @brief Pointer to hook manager interface function
*
* A "hook manager" is a the only thing that knows the actual protoype of the function at compile time.
*
* @param hi A pointer to a HookManagerInfo structure. The hook manager should fill it and store it for
* future reference (mainly if something should get hooked to its hookfunc)
* @param ha What the hook manager should do
* @param hi A pointer to IHookManagerInfo
*/
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi);
typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate
{
@ -170,65 +181,83 @@ namespace SourceHook
}
};
/**
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
struct IHookList
{
struct VfnPtr
struct IIter
{
struct Iface
{
struct Hook
{
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
virtual bool End() = 0;
virtual void Next() = 0;
virtual ISHDelegate *Handler() = 0;
virtual int ThisPtrOffs() = 0;
};
Plugin plug; //!< The owner plugin
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
virtual IIter *GetIter() = 0;
virtual void ReleaseIter(IIter *pIter) = 0;
};
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
struct IIface
{
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass
{
B *ptr; //!< Pointer to the actual object
size_t objsize; //!< Size of the instance
OrigVTables vt; //!< Info about vtables & functions
virtual B *GetThisPtr() = 0;
virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
};
typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook
{
public:
virtual ~ISourceHook()
{ }
/**
* @brief Return interface version
*/
@ -263,7 +290,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual const void *GetOrigRet() = 0; //!< Gets the original result.
//!< If not in post function, undefined
virtual const void *GetOverrideRet() = 0; //!< Gets the override result.
//!< If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry;
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \
reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0;
#else
# error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \
SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \
using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
\
if (action == ::SourceHook::HA_GetInfo) \
{ \
param->proto = ms_Proto; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
\
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \
param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \
} \
else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static ::SourceHook::HookManagerInfo *ms_HI; \
static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \
else \
orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
//////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \
if (vfptriter == ms_HI->vfnptrs.end()) \
{ \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
/* ... and the iface */ \
IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
if (!ifinfo) \
{ \
/* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \
} \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \
IHookList *prelist = ifinfo->GetPreHooks(); \
IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \
if (cur_res > status) \
status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
}
#define SH_RETURN_void()
@ -1490,6 +1514,210 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 17 arguments *********
#define SH_DECL_HOOK17(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 18 arguments *********
#define SH_DECL_HOOK18(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 19 arguments *********
#define SH_DECL_HOOK19(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 20 arguments *********
#define SH_DECL_HOOK20(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
//////////////////////////////////////////////////////////////////////////
@ -1497,14 +1725,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -1512,9 +1742,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \
void *addr; \
} u; \
u.addr = iter->val[mfi.vtblindex]; \
u.addr = origfunc; \
\
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
}
@ -1524,10 +1754,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \
return (m_CC->ptr->*m_MFP)call; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
@ -1539,10 +1769,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \
} s; \
} u; \
u.s.addr = iter->val[mfi.vtblindex]; \
u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \
\
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \
return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
}
#endif
@ -1626,6 +1856,22 @@ namespace SourceHook
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
// Support for 17 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
// Support for 18 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
// Support for 19 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
// Support for 20 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19, Param20 p20) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
};
}
@ -1888,6 +2134,66 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300
// GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it
@ -2147,12 +2453,72 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#endif
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY
#undef SH_MAKE_EXECUTABLECLASS_OB
#endif
// The pope is dead. -> :(

View File

@ -12,13 +12,12 @@
#define __SOURCEHOOK_IMPL_H__
#include "sourcehook.h"
#ifdef __linux__
#include <signal.h>
#include <setjmp.h>
#endif
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Set this to 1 to enable runtime code generation (faster)
// (unused at the moment, but may come back, so I'm leaving it in here!)
#define SH_RUNTIME_CODEGEN 1
namespace SourceHook
@ -28,6 +27,7 @@ namespace SourceHook
*/
class CSourceHookImpl : public ISourceHook
{
private:
/**
* @brief A hook can be removed if you have this information
*/
@ -48,24 +48,165 @@ namespace SourceHook
bool post;
};
/**
* @brief A list of HookManagerInfo structures
*/
typedef List<HookManagerInfo> HookManInfoList;
struct CallClassInfo
struct HookInfo
{
GenericCallClass cc;
int refcounter;
bool operator==(void *other)
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
class CHookList : public IHookList
{
public:
List<HookInfo> m_List;
friend class CIter;
class CIter : public IHookList::IIter
{
return cc.ptr == other;
friend class CHookList;
CHookList *m_pList;
List<HookInfo>::iterator m_Iter;
void SkipPaused();
public:
CIter(CHookList *pList);
virtual ~CIter();
void GoToBegin();
bool End();
void Next();
ISHDelegate *Handler();
int ThisPtrOffs();
CIter *m_pNext; // When stored in m_FreeIters
};
CIter *m_FreeIters;
CHookList();
CHookList(const CHookList &other);
virtual ~CHookList();
void operator=(const CHookList &other);
IIter *GetIter();
void ReleaseIter(IIter *pIter);
};
// I know, data hiding... But I'm a lazy bastard!
class CIface : public IIface
{
public:
void *m_Ptr;
CHookList m_PreHooks;
CHookList m_PostHooks;
public:
CIface(void *ptr);
virtual ~CIface();
void *GetPtr();
IHookList *GetPreHooks();
IHookList *GetPostHooks();
bool operator==(void *ptr)
{
return m_Ptr == ptr;
}
};
class CVfnPtr : public IVfnPtr
{
public:
typedef List<CIface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
void *m_Ptr;
void *m_OrigEntry;
IfaceList m_Ifaces;
public:
CVfnPtr(void *ptr);
virtual ~CVfnPtr();
void *GetVfnPtr();
void *GetOrigEntry();
virtual IIface *FindIface(void *ptr);
bool operator==(void *ptr)
{
return m_Ptr == ptr;
}
};
class CHookManagerInfo : public IHookManagerInfo
{
public:
typedef List<CVfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
Plugin m_Plug;
HookManagerPubFunc m_Func;
int m_VtblOffs;
int m_VtblIdx;
const char *m_Proto;
void *m_HookfuncVfnptr;
VfnPtrList m_VfnPtrs;
public:
virtual ~CHookManagerInfo();
IVfnPtr *FindVfnPtr(void *vfnptr);
void SetInfo(int vtbl_offs, int vtbl_idx, const char *proto);
void SetHookfuncVfnptr(void *hookfunc_vfnptr);
};
/**
* @brief A list of CHookManagerInfo classes
*/
typedef List<CHookManagerInfo> HookManInfoList;
class CCallClassImpl : public GenericCallClass
{
public:
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
void *m_Ptr; //!< Pointer to the actual object
size_t m_ObjSize; //!< Size of the instance
OrigVTables m_VT; //!< Info about vtables & functions
int m_RefCounter;
CCallClassImpl(void *ptr, size_t size);
virtual ~CCallClassImpl();
bool operator==(void *other)
{
return m_Ptr == other;
}
void *GetThisPtr();
void *GetOrigFunc(int vtbloffs, int vtblidx);
void ApplyCallClassPatch(int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatch(int vtbl_offs, int vtbl_idx);
};
/**
* @brief A list of CallClass structures
*/
typedef List<CallClassInfo> Impl_CallClassList;
typedef List<CCallClassImpl> Impl_CallClassList;
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
HookManInfoList m_HookMans; //!< A list of hook managers
@ -76,19 +217,19 @@ namespace SourceHook
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
const char *proto, int vtblofs, int vtblidx);
void ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry);
void ApplyCallClassPatches(CallClassInfo &cc);
void ApplyCallClassPatches(CCallClassImpl &cc);
void ApplyCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx);
void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx);
void SetPluginPaused(Plugin plug, bool paused);
META_RES m_Status, m_PrevRes, m_CurRes;
const void *m_OrigRet;
const void *m_OverrideRet;
void *m_IfacePtr;
public:
CSourceHookImpl();
~CSourceHookImpl();
virtual ~CSourceHookImpl();
/**
* @brief Returns the interface version
@ -199,19 +340,6 @@ namespace SourceHook
virtual void SetOrigRet(const void *ptr); //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr); //!< Sets the override result pointer
};
#ifdef __linux__
/**
* @brief Checks to see if a memory value can be read from a given pointer.
*
* @return True if the value can be read and false if it cannot.
*
* @param ptr The pointer to the memory value.
* @param len The length of the memory value to be read from the pointer.
*/
bool IsBadReadPtr(const void *ptr, size_t len);
void BadReadHandler(int sig);
#endif
}
#endif

View File

@ -1,16 +1,16 @@
#(C)2004-2005 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson
# Makefile written by David "BAILOPAN" Anderson and Pavol Marko
OPT_FLAGS = -O3 -funroll-loops -s -pipe
DEBUG_FLAGS = -g -ggdb3
CPP = gcc
BINARY = sourcehook_test
OBJECTS = test1.cpp test2.cpp test3.cpp test4.cpp testbail.cpp testbail2.cpp testlist.cpp main.cpp sourcehook.cpp
LINK = -lstdc++
INCLUDE = -I. -I..
MAX_PARAMS=20
BINARY = sourcehook_test
OBJECTS = main.cpp sourcehook.cpp $(shell ls -t test*.cpp)
HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
@ -20,27 +20,41 @@ else
CFLAGS = $(OPT_FLAGS)
endif
# CFLAGS +=
CFLAGS += -Wall
# Also, enable SH_ASSERT
CFLAGS += -DSH_DEBUG
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
default: all
$(BIN_DIR)/%.o: %.cpp $(HEADERS)
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)
ln -sf ../sourcehook.cpp sourcehook.cpp
$(MAKE) sourcehook_test
rm -f $(BINARY)
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
../sourcehook.h: ../generate/sourcehook.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) sourcehook.hxx sourcehook.h; cp sourcehook.h ..)
sourcehook_test: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(BINARY)
../sourcehook.hxx: ../generate/sh_memfuncinfo.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) sh_memfuncinfo.hxx sh_memfuncinfo.h; cp sh_memfuncino.h ..)
../FastDelegate.hxx: ../generate/FastDelegate.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) FastDelegate.hxx FastDelegate.h; cp FastDelegate.h ..)
debug:
$(MAKE) all DEBUG=true
default: all
all:
mkdir -p $(BIN_DIR)
ln -sf ../sourcehook.cpp sourcehook.cpp
$(MAKE) $(BINARY)
rm -f $(BINARY)
rm -f sourcehook.cpp
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
$(BINARY): $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(BINARY)
clean:
rm -rf Release/*.o

View File

@ -2,6 +2,8 @@
#include "sourcehook_impl.h"
#include "testevents.h"
#include "sh_memory.h"
namespace
{
StateList g_States;
@ -12,6 +14,7 @@ namespace
// Basic tests
// Hooking and callclass
MAKE_STATE_1(State_ModuleInMemory, bool);
MAKE_STATE(State_F1_Called);
MAKE_STATE_1(State_F1_PreHandler_Called, void*);
MAKE_STATE_1(State_F1_PostHandler_Called, void*);
@ -385,6 +388,22 @@ namespace
bool TestBasic(std::string &error)
{
// Simple test for ModuleInMemory:
// 1) &error should on the stack
// 2) 0 should not be mapped
// 3) &error to -1 should not be mapped
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(reinterpret_cast<char*>(&error), sizeof(error))));
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(0, 1)));
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(reinterpret_cast<char*>(&error),
(reinterpret_cast<std::string*>(-1) - &error) - 1)));
CHECK_STATES((&g_States,
new State_ModuleInMemory(true),
new State_ModuleInMemory(false),
new State_ModuleInMemory(false),
NULL), "ModuleInMemory");
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
g_PLID = 1337;

View File

@ -31,6 +31,58 @@ namespace
SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0);
/*
SHINT_MAKE_GENERICSTUFF_BEGIN(IGaben, EatYams, 0, (static_cast<void (IGaben::*)() SH_NOATTRIB>
(&IGaben::EatYams)))
typedef fastdelegate::FastDelegate0<> FD;
virtual void Func()
{
// SH_HANDLEFUNC_void(IGaben, EatYams, (), ());
SH_SETUPCALLS_void((), ())
SH_CALL_HOOKS_void(pre, ())
if (status != MRES_SUPERCEDE)
{
void (EmptyClass::*mfp)();
SH_SETUP_MFP(mfp);
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)();
}
SH_CALL_HOOKS_void(post, ())
SH_RETURN_void()
}
};
SH_FHCls(IGaben,EatYams,0) SH_FHCls(IGaben,EatYams,0)::ms_Inst;
::SourceHook::MemFuncInfo SH_FHCls(IGaben,EatYams,0)::ms_MFI;
::SourceHook::IHookManagerInfo *SH_FHCls(IGaben,EatYams,0)::ms_HI;
const char *SH_FHCls(IGaben,EatYams,0)::ms_Proto = "SH_NOATTRIB";
bool __SourceHook_FHAddIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc,
new CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD>(handler), post);
}
bool __SourceHook_FHRemoveIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD> tmp(handler);
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc, &tmp, post);
}
*/
void EatYams0_Handler()
{
ADD_STATE(State_EatYams_Handler_Called);

View File

@ -148,6 +148,15 @@ namespace
for (int i = 1; i <= mymax; ++i)
hash2[i] = i + 5000;
hash2.erase(mymax - 100);
CHECK_COND(hash2.find(mymax - 101) != hash2.end(), "Part 4.1");
CHECK_COND(hash2.find(mymax - 99) != hash2.end(), "Part 4.2");
CHECK_COND(hash2.find(mymax - 100) == hash2.end(), "Part 4.3");
hash2.erase(mymax - 99);
CHECK_COND(hash2.find(mymax - 101) != hash2.end(), "Part 4.4");
CHECK_COND(hash2.find(mymax - 99) == hash2.end(), "Part 4.5");
CHECK_COND(hash2.find(mymax - 100) == hash2.end(), "Part 4.6");
return true;
}
}