mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-12-07 10:28:30 +00:00
Direct VP hooks, new SH_CALL
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40389
This commit is contained in:
parent
499e6359f0
commit
50926ce4e6
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,9 @@
|
|||||||
// ???
|
// ???
|
||||||
// 4 - addition of hook ids and vp hooks (with them, AddHookNew and RemoveHookNew)
|
// 4 - addition of hook ids and vp hooks (with them, AddHookNew and RemoveHookNew)
|
||||||
// This is not a SH_IFACE_VERSION change so that old plugins continue working!
|
// This is not a SH_IFACE_VERSION change so that old plugins continue working!
|
||||||
#define SH_IMPL_VERSION 4
|
// 5 - addition of direct vp hooks (new hook mode; from now on AddHookNew checks for
|
||||||
|
// invalid hookmode -> impl version won't have to change because of things like this)
|
||||||
|
#define SH_IMPL_VERSION 5
|
||||||
|
|
||||||
// Hookman version:
|
// Hookman version:
|
||||||
// 1 - Support for recalls, performance optimisations
|
// 1 - Support for recalls, performance optimisations
|
||||||
@ -490,7 +492,8 @@ namespace SourceHook
|
|||||||
enum AddHookMode
|
enum AddHookMode
|
||||||
{
|
{
|
||||||
Hook_Normal,
|
Hook_Normal,
|
||||||
Hook_VP
|
Hook_VP,
|
||||||
|
Hook_DVP
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -518,6 +521,22 @@ namespace SourceHook
|
|||||||
* @param hookid The hook id (returned by AddHookNew)
|
* @param hookid The hook id (returned by AddHookNew)
|
||||||
*/
|
*/
|
||||||
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
|
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Makes sure that hooks are going to be ignored on the next call of vfnptr
|
||||||
|
*
|
||||||
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
|
* @param vfnptr The virtual function pointer of the function in question
|
||||||
|
*/
|
||||||
|
virtual void SetIgnoreHooks(Plugin plug, void *vfnptr) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverses SetIgnoreHooks' effect
|
||||||
|
*
|
||||||
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
|
* @param vfnptr The virtual function pointer of the function in question
|
||||||
|
*/
|
||||||
|
virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
|
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
|
||||||
@ -548,6 +567,33 @@ namespace SourceHook
|
|||||||
return &ref;
|
return &ref;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For source-level compatibility
|
||||||
|
template <class T> struct LegacyCallClass
|
||||||
|
{
|
||||||
|
T *ptr;
|
||||||
|
|
||||||
|
LegacyCallClass(T *p) : ptr(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T*()
|
||||||
|
{
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
LegacyCallClass<T> *GetLegacyCallClass(T *p)
|
||||||
|
{
|
||||||
|
return new LegacyCallClass<T>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void ReleaseLegacyCallClass(LegacyCallClass<T> *p)
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
@ -652,31 +698,6 @@ namespace SourceHook
|
|||||||
RETURN_META_VALUE(MRES_SUPERCEDE, (thisptr->*(u.mfp)) newparams); \
|
RETURN_META_VALUE(MRES_SUPERCEDE, (thisptr->*(u.mfp)) newparams); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get/generate callclass for an interface pointer
|
|
||||||
*
|
|
||||||
* @param ifaceptr The interface pointer
|
|
||||||
*/
|
|
||||||
template<class ifacetype>
|
|
||||||
inline SourceHook::CallClass<ifacetype> *SH_GET_CALLCLASS_R(SourceHook::ISourceHook *shptr, ifacetype *ptr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<SourceHook::CallClass<ifacetype>*>(
|
|
||||||
shptr->GetCallClass(reinterpret_cast<void*>(ptr), sizeof(ifacetype)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ifacetype>
|
|
||||||
inline SourceHook::CallClass<ifacetype> *SH_GET_MCALLCLASS_R(SourceHook::ISourceHook *shptr, ifacetype *ptr, int ifacesize)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<SourceHook::CallClass<ifacetype>*>(
|
|
||||||
shptr->GetCallClass(reinterpret_cast<void*>(ptr), ifacesize));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ifacetype>
|
|
||||||
inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::CallClass<ifacetype> *ptr)
|
|
||||||
{
|
|
||||||
shptr->ReleaseCallClass(reinterpret_cast<SourceHook::GenericCallClass*>(ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SH_MANUALHOOK_RECONFIGURE(hookname, pvtblindex, pvtbloffs, pthisptroffs) \
|
#define SH_MANUALHOOK_RECONFIGURE(hookname, pvtblindex, pvtbloffs, pthisptroffs) \
|
||||||
do { \
|
do { \
|
||||||
SH_GLOB_SHPTR->RemoveHookManager(SH_GLOB_PLUGPTR, SH_MFHCls(hookname)::HookManPubFunc); \
|
SH_GLOB_SHPTR->RemoveHookManager(SH_GLOB_PLUGPTR, SH_MFHCls(hookname)::HookManPubFunc); \
|
||||||
@ -685,9 +706,13 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \
|
SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SH_GET_CALLCLASS(ptr) SH_GET_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
|
// For source-level compatibility
|
||||||
#define SH_GET_MCALLCLASS(ptr, size) SH_GET_MCALLCLASS_R(SH_GLOB_SHPTR, reinterpret_cast<SourceHook::EmptyClass*>(ptr), size)
|
#define CallClass LegacyCallClass
|
||||||
#define SH_RELEASE_CALLCLASS(ptr) SH_RELEASE_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
|
#define ManualCallClass LegacyCallClass<SourceHook::EmptyClass>
|
||||||
|
|
||||||
|
#define SH_GET_CALLCLASS(ptr) SourceHook::GetLegacyCallClass(ptr)
|
||||||
|
#define SH_GET_MCALLCLASS(ptr, size) SourceHook::GetLegacyCallClass(reinterpret_cast<SourceHook::EmptyClass*>(ptr))
|
||||||
|
#define SH_RELEASE_CALLCLASS(ptr) SourceHook::ReleaseLegacyCallClass(ptr)
|
||||||
|
|
||||||
// New ADD / REMOVE macros.
|
// New ADD / REMOVE macros.
|
||||||
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
|
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
|
||||||
@ -709,10 +734,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
|
|
||||||
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
||||||
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
|
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
|
||||||
post, handler)
|
post, handler, false)
|
||||||
|
|
||||||
|
#define SH_ADD_DVPHOOK(ifacetype, ifacefunc, vtableptr, handler, post) \
|
||||||
|
__SourceHook_FHVPAdd##ifacetype##ifacefunc(reinterpret_cast<void*>(vtableptr), \
|
||||||
|
post, handler, true)
|
||||||
|
|
||||||
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
|
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
|
||||||
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
|
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler, false)
|
||||||
|
|
||||||
|
#define SH_ADD_MANUALDVPHOOK(hookname, vtableptr, handler, post) \
|
||||||
|
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(vtableptr), post, handler, true)
|
||||||
|
|
||||||
#define SH_REMOVE_HOOK_ID(hookid) \
|
#define SH_REMOVE_HOOK_ID(hookid) \
|
||||||
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
|
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
|
||||||
@ -844,7 +876,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
||||||
} \
|
} \
|
||||||
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
|
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler, bool direct) \
|
||||||
{ \
|
{ \
|
||||||
using namespace ::SourceHook; \
|
using namespace ::SourceHook; \
|
||||||
MemFuncInfo mfi = {true, -1, 0, 0}; \
|
MemFuncInfo mfi = {true, -1, 0, 0}; \
|
||||||
@ -852,8 +884,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
|
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
|
||||||
return false; /* No non-virtual functions / virtual inheritance supported */ \
|
return false; /* No non-virtual functions / virtual inheritance supported */ \
|
||||||
\
|
\
|
||||||
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, mfi.thisptroffs, \
|
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, \
|
||||||
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
|
direct ? ::SourceHook::ISourceHook::Hook_DVP : ::SourceHook::ISourceHook::Hook_VP, \
|
||||||
|
iface, mfi.thisptroffs, SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
|
||||||
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
||||||
} \
|
} \
|
||||||
bool __SourceHook_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
|
bool __SourceHook_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
|
||||||
@ -936,10 +969,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
|
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
|
||||||
} \
|
} \
|
||||||
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
|
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
|
||||||
SH_MFHCls(hookname)::FD handler) \
|
SH_MFHCls(hookname)::FD handler, bool direct) \
|
||||||
{ \
|
{ \
|
||||||
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, pthisptroffs, \
|
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, \
|
||||||
SH_MFHCls(hookname)::HookManPubFunc, \
|
direct ? ::SourceHook::ISourceHook::Hook_DVP : ::SourceHook::ISourceHook::Hook_VP, \
|
||||||
|
iface, pthisptroffs, SH_MFHCls(hookname)::HookManPubFunc, \
|
||||||
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
|
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
|
||||||
} \
|
} \
|
||||||
bool __SourceHook_FHMRemove##hookname(void *iface, bool post, \
|
bool __SourceHook_FHMRemove##hookname(void *iface, bool post, \
|
||||||
@ -1219,136 +1253,103 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// SH_CALL
|
// SH_CALL
|
||||||
|
|
||||||
#if SH_COMP == SH_COMP_MSVC
|
#define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
|
||||||
|
|
||||||
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
|
|
||||||
{ \
|
{ \
|
||||||
using namespace ::SourceHook; \
|
using namespace ::SourceHook; \
|
||||||
MemFuncInfo mfi = {true, -1, 0, 0}; \
|
|
||||||
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. */ \
|
SH_GLOB_SHPTR->SetIgnoreHooks(SH_GLOB_PLUGPTR, m_VfnPtr); \
|
||||||
union \
|
RetType tmpret = (m_ThisPtr->*m_MFP)call; \
|
||||||
{ \
|
SH_GLOB_SHPTR->ResetIgnoreHooks(SH_GLOB_PLUGPTR, m_VfnPtr); \
|
||||||
RetType(EmptyClass::*mfpnew)prms; \
|
return tmpret; \
|
||||||
void *addr; \
|
|
||||||
} u; \
|
|
||||||
u.addr = origfunc; \
|
|
||||||
\
|
|
||||||
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
|
|
||||||
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# define SH_MAKE_MEXECUTABLECLASS_OB(call, prms) \
|
#define SH_MAKE_EXECUTABLECLASS_OB_void(call, prms) \
|
||||||
{ \
|
{ \
|
||||||
using namespace ::SourceHook; \
|
using namespace ::SourceHook; \
|
||||||
char *adjustedthisptr = reinterpret_cast<char*>(m_CC->GetThisPtr()) + m_ThisPtrOffs; \
|
|
||||||
union \
|
|
||||||
{ \
|
|
||||||
RetType(EmptyClass::*mfpnew)prms; \
|
|
||||||
void *addr; \
|
|
||||||
} u; \
|
|
||||||
u.addr = m_CC->GetOrigFunc(m_ThisPtrOffs + m_VtblOffs, m_VtblIdx); \
|
|
||||||
if (!u.addr) \
|
|
||||||
u.addr = (*reinterpret_cast<void***>(adjustedthisptr + m_VtblOffs))[m_VtblIdx]; \
|
|
||||||
\
|
\
|
||||||
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
|
SH_GLOB_SHPTR->SetIgnoreHooks(SH_GLOB_PLUGPTR, m_VfnPtr); \
|
||||||
|
(m_ThisPtr->*m_MFP)call; \
|
||||||
|
SH_GLOB_SHPTR->ResetIgnoreHooks(SH_GLOB_PLUGPTR, m_VfnPtr); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif SH_COMP == SH_COMP_GCC
|
|
||||||
|
|
||||||
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
|
|
||||||
{ \
|
|
||||||
using namespace ::SourceHook; \
|
|
||||||
MemFuncInfo mfi = {true, -1, 0, 0}; \
|
|
||||||
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 \
|
|
||||||
{ \
|
|
||||||
RetType(EmptyClass::*mfpnew)prms; \
|
|
||||||
struct \
|
|
||||||
{ \
|
|
||||||
void *addr; \
|
|
||||||
intptr_t adjustor; \
|
|
||||||
} s; \
|
|
||||||
} u; \
|
|
||||||
u.s.addr = origfunc; \
|
|
||||||
u.s.adjustor = mfi.thisptroffs; \
|
|
||||||
\
|
|
||||||
return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
|
|
||||||
}
|
|
||||||
|
|
||||||
# define SH_MAKE_MEXECUTABLECLASS_OB(call, prms) \
|
|
||||||
{ \
|
|
||||||
using namespace ::SourceHook; \
|
|
||||||
char *thisptr = reinterpret_cast<char*>(m_CC->GetThisPtr()); \
|
|
||||||
union \
|
|
||||||
{ \
|
|
||||||
RetType(EmptyClass::*mfpnew)prms; \
|
|
||||||
struct { \
|
|
||||||
void *addr; \
|
|
||||||
intptr_t adjustor; \
|
|
||||||
} s; \
|
|
||||||
} u; \
|
|
||||||
u.s.addr = m_CC->GetOrigFunc(m_ThisPtrOffs + m_VtblOffs, m_VtblIdx); \
|
|
||||||
if (!u.s.addr) \
|
|
||||||
u.s.addr = (*reinterpret_cast<void***>(thisptr + m_ThisPtrOffs + m_VtblOffs))[m_VtblIdx]; \
|
|
||||||
\
|
|
||||||
u.s.adjustor = m_ThisPtrOffs; \
|
|
||||||
return (reinterpret_cast<EmptyClass*>(thisptr)->*u.mfpnew)call; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace SourceHook
|
namespace SourceHook
|
||||||
{
|
{
|
||||||
@[$1,0,$a:
|
// Call Class Wrapper!
|
||||||
// Support for $1 arguments
|
template <class T> struct CCW
|
||||||
template<class CCType, class MFPType, class RetType@[$2,1,$1:, class Param$2@]> class ExecutableClass$1
|
|
||||||
{
|
{
|
||||||
CCType *m_CC;
|
typedef T type;
|
||||||
MFPType m_MFP;
|
|
||||||
public:
|
|
||||||
ExecutableClass$1(CCType *cc, MFPType mfp) : m_CC(cc), m_MFP(mfp) { }
|
|
||||||
|
|
||||||
RetType operator()(@[$2,1,$1|, :Param$2 p$2@]) const
|
// Get Real Pointer!
|
||||||
SH_MAKE_EXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
|
static inline T *GRP(T *p)
|
||||||
|
{
|
||||||
@[$2,$1+1,$a:
|
return p;
|
||||||
template <@[$3,$1+1,$2|, :class Param$3@]> RetType operator()(@[$3,1,$2|, :Param$3 p$3@]) const
|
}
|
||||||
SH_MAKE_EXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
|
|
||||||
@]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class RetType@[$2,1,$1:, class Param$2@]> class MExecutableClass$1
|
template <class T> struct CCW< LegacyCallClass<T> >
|
||||||
{
|
{
|
||||||
ManualCallClass *m_CC;
|
typedef T type;
|
||||||
int m_ThisPtrOffs;
|
|
||||||
int m_VtblIdx;
|
// Get Real Pointer!
|
||||||
int m_VtblOffs;
|
static inline T *GRP(LegacyCallClass<T> *p)
|
||||||
|
{
|
||||||
|
return p->ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@[$1,0,$a:
|
||||||
|
// Support for $1 arguments
|
||||||
|
template<class ObjType, class MFP, class RetType@[$2,1,$1:, class Param$2@]> class ExecutableClass$1
|
||||||
|
{
|
||||||
|
ObjType *m_ThisPtr;
|
||||||
|
void *m_VfnPtr;
|
||||||
|
MFP m_MFP;
|
||||||
public:
|
public:
|
||||||
MExecutableClass$1(ManualCallClass *cc, int vtbloffs, int vtblidx, int thisptroffs) : m_CC(cc),
|
ExecutableClass$1(ObjType *tp, MFP mfp, void *vp) : m_ThisPtr(tp), m_MFP(mfp), m_VfnPtr(vp) { }
|
||||||
m_ThisPtrOffs(thisptroffs), m_VtblIdx(vtblidx), m_VtblOffs(vtbloffs) { }
|
|
||||||
|
|
||||||
RetType operator()(@[$2,1,$1|, :Param$2 p$2@]) const
|
RetType operator()(@[$2,1,$1|, :Param$2 p$2@]) const
|
||||||
SH_MAKE_MEXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
|
SH_MAKE_EXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
|
||||||
|
|
||||||
@[$2,$1+1,$a:
|
@[$2,$1+1,$a:
|
||||||
template <@[$3,$1+1,$2|, :class Param$3@]> RetType operator()(@[$3,1,$2|, :Param$3 p$3@]) const
|
template <@[$3,$1+1,$2|, :class Param$3@]> RetType operator()(@[$3,1,$2|, :Param$3 p$3@]) const
|
||||||
SH_MAKE_MEXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
|
SH_MAKE_EXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
|
||||||
@]
|
@]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class ObjType, class MFP@[$2,1,$1:, class Param$2@]> class ExecutableClass$1<ObjType, MFP, void@[$2,1,$1:, Param$2@]>
|
||||||
|
{
|
||||||
|
ObjType *m_ThisPtr;
|
||||||
|
void *m_VfnPtr;
|
||||||
|
MFP m_MFP;
|
||||||
|
public:
|
||||||
|
ExecutableClass$1(ObjType *tp, MFP mfp, void *vp) : m_ThisPtr(tp), m_MFP(mfp), m_VfnPtr(vp) { }
|
||||||
|
|
||||||
|
void operator()(@[$2,1,$1|, :Param$2 p$2@]) const
|
||||||
|
SH_MAKE_EXECUTABLECLASS_OB_void((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
|
||||||
|
|
||||||
|
@[$2,$1+1,$a:
|
||||||
|
template <@[$3,$1+1,$2|, :class Param$3@]> void operator()(@[$3,1,$2|, :Param$3 p$3@]) const
|
||||||
|
SH_MAKE_EXECUTABLECLASS_OB_void((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
|
||||||
|
@]
|
||||||
|
};
|
||||||
@]
|
@]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SH__CALL_GET_VFNPTR_NORMAL \
|
||||||
|
using namespace ::SourceHook; \
|
||||||
|
MemFuncInfo mfi = {true, -1, 0, 0}; \
|
||||||
|
GetFuncInfo(CCW<Y>::GRP(ptr), mfp, mfi); \
|
||||||
|
void *vfnptr = reinterpret_cast<void*>( \
|
||||||
|
*reinterpret_cast<void***>(reinterpret_cast<char*>(ptr) + mfi.thisptroffs + mfi.vtbloffs) + mfi.vtblindex);
|
||||||
|
|
||||||
|
#define SH__CALL_GET_VFNPTR_MANUAL \
|
||||||
|
using namespace ::SourceHook; \
|
||||||
|
void *vfnptr = reinterpret_cast<void*>( \
|
||||||
|
*reinterpret_cast<void***>( (reinterpret_cast<char*>(CCW<Y>::GRP(ptr)) + thisptroffs + vtbloffs) ) + vtblidx); \
|
||||||
|
/* patch mfp */ \
|
||||||
|
*reinterpret_cast<void**>(&mfp) = *reinterpret_cast<void**>(vfnptr);
|
||||||
|
|
||||||
// SH_CALL needs to deduce the return type -> it uses templates and function overloading
|
// SH_CALL needs to deduce the return type -> it uses templates and function overloading
|
||||||
// That's why SH_CALL takes two parameters: "mfp2" of type RetType(X::*mfp)(params), and "mfp" of type MFP
|
// That's why SH_CALL takes two parameters: "mfp2" of type RetType(X::*mfp)(params), and "mfp" of type MFP
|
||||||
// The only purpose of the mfp2 parameter is to extract the return type
|
// The only purpose of the mfp2 parameter is to extract the return type
|
||||||
@ -1356,24 +1357,28 @@ namespace SourceHook
|
|||||||
@[$1,0,$a:
|
@[$1,0,$a:
|
||||||
// Support for $1 arguments
|
// Support for $1 arguments
|
||||||
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
||||||
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
|
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
|
||||||
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]))
|
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]))
|
||||||
{
|
{
|
||||||
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
|
SH__CALL_GET_VFNPTR_NORMAL
|
||||||
|
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr), mfp, vfnptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
||||||
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
|
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
|
||||||
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@])const)
|
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@])const)
|
||||||
{
|
{
|
||||||
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
|
SH__CALL_GET_VFNPTR_NORMAL
|
||||||
|
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr), mfp, vfnptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class RetType@[$2,1,$1:, class Param$2@]>
|
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
||||||
SourceHook::MExecutableClass$1<RetType@[$2,1,$1:, Param$2@]>
|
SourceHook::ExecutableClass$1<SourceHook::EmptyClass, MFP, RetType@[$2,1,$1:, Param$2@]>
|
||||||
SH_MCALL2(SourceHook::ManualCallClass *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]), int vtblidx, int vtbloffs, int thisptroffs)
|
SH_MCALL3(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]), int vtblidx, int vtbloffs, int thisptroffs)
|
||||||
{
|
{
|
||||||
return SourceHook::MExecutableClass$1<RetType@[$2,1,$1:, Param$2@]>(ptr, vtbloffs, vtblidx, thisptroffs);
|
SH__CALL_GET_VFNPTR_MANUAL
|
||||||
|
return SourceHook::ExecutableClass$1<EmptyClass, MFP, RetType@[$2,1,$1:, Param$2@]>(
|
||||||
|
reinterpret_cast<SourceHook::EmptyClass*>(CCW<Y>::GRP(ptr)), mfp, vfnptr);
|
||||||
}
|
}
|
||||||
@]
|
@]
|
||||||
|
|
||||||
@ -1383,17 +1388,19 @@ SH_MCALL2(SourceHook::ManualCallClass *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$
|
|||||||
@[$1,0,$a:
|
@[$1,0,$a:
|
||||||
// Support for $1 arguments
|
// Support for $1 arguments
|
||||||
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
||||||
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
|
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
|
||||||
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...))
|
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...))
|
||||||
{
|
{
|
||||||
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
|
SH__CALL_GET_VFNPTR_NORMAL
|
||||||
|
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr), mfp, vfnptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
|
||||||
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
|
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
|
||||||
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...)const)
|
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...)const)
|
||||||
{
|
{
|
||||||
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
|
SH__CALL_GET_VFNPTR_NORMAL
|
||||||
|
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr), mfp, vfnptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@]
|
@]
|
||||||
@ -1401,6 +1408,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
|
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
|
||||||
|
#define SH_MCALL2(ptr, mfp, vtblidx, vtbloffs, thisptroffs) SH_MCALL3((ptr), (mfp), (mfp), (vtblidx), (vtbloffs), (thisptroffs))
|
||||||
#define SH_MCALL(ptr, mhookname) SH_MCALL2((ptr), SH_MFHCls(mhookname)::ECMFP(), SH_MFHCls(mhookname)::ms_MFI.vtblindex, \
|
#define SH_MCALL(ptr, mhookname) SH_MCALL2((ptr), SH_MFHCls(mhookname)::ECMFP(), SH_MFHCls(mhookname)::ms_MFI.vtblindex, \
|
||||||
SH_MFHCls(mhookname)::ms_MFI.vtbloffs, SH_MFHCls(mhookname)::ms_MFI.thisptroffs)
|
SH_MFHCls(mhookname)::ms_MFI.vtbloffs, SH_MFHCls(mhookname)::ms_MFI.thisptroffs)
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@ namespace SourceHook
|
|||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
CSourceHookImpl::CSourceHookImpl()
|
CSourceHookImpl::CSourceHookImpl() : m_OneIgnore(NULL), m_IgnoreActive(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
CSourceHookImpl::~CSourceHookImpl()
|
CSourceHookImpl::~CSourceHookImpl()
|
||||||
@ -286,7 +286,12 @@ namespace SourceHook
|
|||||||
int CSourceHookImpl::AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
|
int CSourceHookImpl::AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
|
||||||
ISHDelegate *handler, bool post)
|
ISHDelegate *handler, bool post)
|
||||||
{
|
{
|
||||||
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
|
void *adjustediface = NULL;
|
||||||
|
void **cur_vtptr = NULL;
|
||||||
|
void *cur_vfnptr = NULL;
|
||||||
|
|
||||||
|
if (mode != Hook_Normal && mode != Hook_VP && mode != Hook_DVP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// 1) Get info about the hook manager
|
// 1) Get info about the hook manager
|
||||||
CHookManagerInfo tmp;
|
CHookManagerInfo tmp;
|
||||||
@ -298,10 +303,6 @@ namespace SourceHook
|
|||||||
|
|
||||||
CHookManagerContainer::HMCI hmci(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
|
CHookManagerContainer::HMCI hmci(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
|
||||||
|
|
||||||
void **cur_vtptr = *reinterpret_cast<void***>(
|
|
||||||
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
|
|
||||||
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
|
|
||||||
|
|
||||||
// Add the container if not already added
|
// Add the container if not already added
|
||||||
HookManContList::iterator hmcl_iter = m_HookMans.find(hmci);
|
HookManContList::iterator hmcl_iter = m_HookMans.find(hmci);
|
||||||
if (hmcl_iter == m_HookMans.end())
|
if (hmcl_iter == m_HookMans.end())
|
||||||
@ -336,12 +337,33 @@ namespace SourceHook
|
|||||||
if (hookman->m_VfnPtrs.empty())
|
if (hookman->m_VfnPtrs.empty())
|
||||||
hookman->m_Func(HA_Register, &(*hookman));
|
hookman->m_Func(HA_Register, &(*hookman));
|
||||||
|
|
||||||
|
|
||||||
|
// find vfnptr
|
||||||
|
if (mode == Hook_Normal || mode == Hook_VP)
|
||||||
|
{
|
||||||
|
adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
|
||||||
|
|
||||||
|
cur_vtptr = *reinterpret_cast<void***>(
|
||||||
|
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
|
||||||
|
cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
|
||||||
|
|
||||||
|
// For Hook_VP, adjustediface will be set to NULL later
|
||||||
|
// because we first have to patch callclasses (callclasses are deprecated but left in for backwards compat)
|
||||||
|
}
|
||||||
|
else if (mode == Hook_DVP)
|
||||||
|
{
|
||||||
|
adjustediface = NULL;
|
||||||
|
|
||||||
|
cur_vtptr = reinterpret_cast<void**>(iface);
|
||||||
|
cur_vfnptr = cur_vtptr + tmp.m_VtblIdx;
|
||||||
|
}
|
||||||
|
|
||||||
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
|
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
|
||||||
|
|
||||||
if (vfnptr_iter == hookman->m_VfnPtrs.end())
|
if (vfnptr_iter == hookman->m_VfnPtrs.end())
|
||||||
{
|
{
|
||||||
// Add a new one
|
// Add a new one
|
||||||
CVfnPtr vfp(cur_vfnptr);
|
CVfnPtr vfp(cur_vfnptr, &m_OneIgnore);
|
||||||
|
|
||||||
// Alter vtable entry
|
// Alter vtable entry
|
||||||
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
|
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
|
||||||
@ -885,6 +907,16 @@ namespace SourceHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSourceHookImpl::SetIgnoreHooks(Plugin plug, void *vfnptr)
|
||||||
|
{
|
||||||
|
m_OneIgnore = vfnptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSourceHookImpl::ResetIgnoreHooks(Plugin plug, void *vfnptr)
|
||||||
|
{
|
||||||
|
m_OneIgnore = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
// CCallClassImpl
|
// CCallClassImpl
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
@ -980,7 +1012,8 @@ namespace SourceHook
|
|||||||
|
|
||||||
// If you get a crash here, the ptr passed is invalid
|
// If you get a crash here, the ptr passed is invalid
|
||||||
// This usually means a SH_DECL_MANUALHOOK* with wrong thisptroffs/vtbloffs/vtblidx
|
// This usually means a SH_DECL_MANUALHOOK* with wrong thisptroffs/vtbloffs/vtblidx
|
||||||
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr) : m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(ptr))
|
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr, void **pOneIgnore) : m_Ptr(ptr),
|
||||||
|
m_pOneIgnore(pOneIgnore), m_OrigEntry(*reinterpret_cast<void**>(ptr))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
CSourceHookImpl::CVfnPtr::~CVfnPtr()
|
CSourceHookImpl::CVfnPtr::~CVfnPtr()
|
||||||
@ -999,6 +1032,12 @@ namespace SourceHook
|
|||||||
|
|
||||||
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
|
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
|
||||||
{
|
{
|
||||||
|
if (m_Ptr == *m_pOneIgnore)
|
||||||
|
{
|
||||||
|
*m_pOneIgnore = NULL; // Only once!
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
IfaceListIter iter = m_Ifaces.find(ptr);
|
IfaceListIter iter = m_Ifaces.find(ptr);
|
||||||
|
|
||||||
// If nothing is found, check for a NULL-interface (VP hooks only)
|
// If nothing is found, check for a NULL-interface (VP hooks only)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -90,6 +90,9 @@ Hooks
|
|||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
Call classes
|
Call classes
|
||||||
|
|
||||||
|
!! deprecated !! - see below (new SH_CALL)
|
||||||
|
|
||||||
Call classes are identified by a this pointer and an instance size
|
Call classes are identified by a this pointer and an instance size
|
||||||
|
|
||||||
We use the instance size because a derived class instance and a base class instance could
|
We use the instance size because a derived class instance and a base class instance could
|
||||||
@ -152,8 +155,25 @@ VP Hooks
|
|||||||
|
|
||||||
I'm afraid that with the addition of Recalls and VP Hooks, SourceHook is now a pretty complex and hacked-together
|
I'm afraid that with the addition of Recalls and VP Hooks, SourceHook is now a pretty complex and hacked-together
|
||||||
binary compatible beast which is pretty hard to maintain unless you've written it :)
|
binary compatible beast which is pretty hard to maintain unless you've written it :)
|
||||||
|
|
||||||
|
New SH_CALL
|
||||||
|
The addition of VP hooks messed up the Call Classes concept (see above) - call classes are bound to an
|
||||||
|
instance pointer; they only work on one of the hooked instances. But VP hooks are called on all instances.
|
||||||
|
|
||||||
|
That's why now, SH_CALL takes an instance pointer instead of a callclass pointer. It basically does this:
|
||||||
|
1) call SH_GLOB_PTR->SetIgnoreHooks(vfnptr)
|
||||||
|
2) call this->*mfp
|
||||||
|
3) call SH_GLOB_PTR->ResetIgnoreHooks(vfnptr)
|
||||||
|
|
||||||
|
SourceHook stroes the "ignored vfnptr" and makes CVfnPtr::FindIface return NULL if the CVfnPtr instance
|
||||||
|
corresponds to the ignored vfnptr. This way the hook manager thinks that the instance isn't hooked, and calls
|
||||||
|
the original function. Everything works fine. This works even for VP hooks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// See sourcehook.hxx :)
|
||||||
|
#undef CallClass
|
||||||
|
#undef ManualCallClass
|
||||||
|
|
||||||
namespace SourceHook
|
namespace SourceHook
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -416,8 +436,9 @@ namespace SourceHook
|
|||||||
|
|
||||||
IfaceList m_Ifaces;
|
IfaceList m_Ifaces;
|
||||||
|
|
||||||
|
void **m_pOneIgnore;
|
||||||
public:
|
public:
|
||||||
CVfnPtr(void *ptr);
|
CVfnPtr(void *ptr, void **pOneIgnore);
|
||||||
virtual ~CVfnPtr();
|
virtual ~CVfnPtr();
|
||||||
|
|
||||||
void *GetVfnPtr();
|
void *GetVfnPtr();
|
||||||
@ -609,6 +630,9 @@ namespace SourceHook
|
|||||||
|
|
||||||
HookLoopInfoStack m_HLIStack;
|
HookLoopInfoStack m_HLIStack;
|
||||||
CHookIDManager m_HookIDMan;
|
CHookIDManager m_HookIDMan;
|
||||||
|
|
||||||
|
void *m_OneIgnore; //:TODO:
|
||||||
|
bool m_IgnoreActive;
|
||||||
public:
|
public:
|
||||||
CSourceHookImpl();
|
CSourceHookImpl();
|
||||||
virtual ~CSourceHookImpl();
|
virtual ~CSourceHookImpl();
|
||||||
@ -748,6 +772,8 @@ namespace SourceHook
|
|||||||
* @param plug The unique identifier of the plugin that calls this function
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
* @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook)
|
* @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook)
|
||||||
* @param iface The interface pointer
|
* @param iface The interface pointer
|
||||||
|
* The representative interface pointer for VP hooks
|
||||||
|
* The vtable pointer for direct VP hooks !!!
|
||||||
* @param ifacesize The size of the class iface points to
|
* @param ifacesize The size of the class iface points to
|
||||||
* @param myHookMan A hook manager function that should be capable of handling the function
|
* @param myHookMan A hook manager function that should be capable of handling the function
|
||||||
* @param handler A pointer to a FastDelegate containing the hook handler
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
||||||
@ -765,6 +791,22 @@ namespace SourceHook
|
|||||||
* @param hookid The hook id (returned by AddHookNew)
|
* @param hookid The hook id (returned by AddHookNew)
|
||||||
*/
|
*/
|
||||||
virtual bool RemoveHookByID(Plugin plug, int hookid);
|
virtual bool RemoveHookByID(Plugin plug, int hookid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Makes sure that hooks are going to be ignored on the next call of vfnptr
|
||||||
|
*
|
||||||
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
|
* @param vfnptr The virtual function pointer of the function in question
|
||||||
|
*/
|
||||||
|
virtual void SetIgnoreHooks(Plugin plug, void *vfnptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverses SetIgnoreHooks' effect
|
||||||
|
*
|
||||||
|
* @param plug The unique identifier of the plugin that calls this function
|
||||||
|
* @param vfnptr The virtual function pointer of the function in question
|
||||||
|
*/
|
||||||
|
virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -305,6 +305,12 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\..\sh_listcat.h">
|
RelativePath="..\..\sh_listcat.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\sh_memfuncinfo.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\sh_memory.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\sh_stack.h">
|
RelativePath="..\..\sh_stack.h">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@ -424,40 +424,33 @@ bool TestBasic(std::string &error)
|
|||||||
Whatever test;
|
Whatever test;
|
||||||
Test *pTest = &test;
|
Test *pTest = &test;
|
||||||
|
|
||||||
// 1) Get a call class and call the member through it and normally
|
// 1) SH_CALL it and call it normally
|
||||||
SourceHook::CallClass<Test> *cc = SH_GET_CALLCLASS(pTest);
|
|
||||||
|
return true;
|
||||||
|
SH_CALL(pTest, &Test::F1)();
|
||||||
|
|
||||||
ADD_STATE(State_F1_CallClassGenerated);
|
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F1_CallClassGenerated,
|
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
NULL), "Part 1");
|
NULL), "Part 1");
|
||||||
|
|
||||||
// 2) Request a call class again
|
// 2) Request a call class again
|
||||||
SourceHook::CallClass<Test> *cc2 = SH_GET_CALLCLASS(pTest);
|
|
||||||
ADD_STATE(State_F1_CallClassGenerated);
|
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
SH_CALL(cc2, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(cc2);
|
SH_CALL(pTest, &Test::F1)();
|
||||||
ADD_STATE(State_F1_CallClassReleased);
|
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F1_CallClassGenerated,
|
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_CallClassReleased,
|
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
NULL), "Part 2");
|
NULL), "Part 2");
|
||||||
@ -467,7 +460,7 @@ bool TestBasic(std::string &error)
|
|||||||
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
||||||
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false) ? true : false));
|
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false) ? true : false));
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -476,30 +469,26 @@ bool TestBasic(std::string &error)
|
|||||||
new State_F1_PreHandler_Called(&f1_handlers),
|
new State_F1_PreHandler_Called(&f1_handlers),
|
||||||
NULL), "Part 3");
|
NULL), "Part 3");
|
||||||
|
|
||||||
// 4) Rerequest the callclass
|
// 4) Test source-level compat with callclasses
|
||||||
SH_RELEASE_CALLCLASS(cc);
|
SourceHook::CallClass<Test> *pCC = SH_GET_CALLCLASS(pTest);
|
||||||
|
|
||||||
ADD_STATE(State_F1_CallClassReleased);
|
SH_CALL(pCC, &Test::F1)();
|
||||||
cc2 = SH_GET_CALLCLASS(pTest);
|
|
||||||
ADD_STATE(State_F1_CallClassGenerated);
|
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
|
SH_RELEASE_CALLCLASS(pCC);
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F1_CallClassReleased,
|
|
||||||
new State_F1_CallClassGenerated,
|
|
||||||
new State_F1_Called,
|
new State_F1_Called,
|
||||||
new State_F1_PreHandler_Called(&f1_handlers),
|
new State_F1_PreHandler_Called(&f1_handlers),
|
||||||
NULL), "Part 4");
|
NULL), "Part 4");
|
||||||
|
|
||||||
// 5) Check ignore / supercede
|
// 5) Check ignore / supercede
|
||||||
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
g_F1Pre_WhatToDo = MRES_IGNORED;
|
g_F1Pre_WhatToDo = MRES_IGNORED;
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -515,7 +504,7 @@ bool TestBasic(std::string &error)
|
|||||||
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
|
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
|
||||||
ADD_STATE(State_F1_HookRemoved);
|
ADD_STATE(State_F1_HookRemoved);
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -528,7 +517,7 @@ bool TestBasic(std::string &error)
|
|||||||
g_F1Post_WhatToDo = MRES_IGNORED;
|
g_F1Post_WhatToDo = MRES_IGNORED;
|
||||||
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true) ? true : false));
|
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true) ? true : false));
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -542,11 +531,11 @@ bool TestBasic(std::string &error)
|
|||||||
g_F1Pre_WhatToDo = MRES_IGNORED;
|
g_F1Pre_WhatToDo = MRES_IGNORED;
|
||||||
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false) ? true : false));
|
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false) ? true : false));
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -566,7 +555,7 @@ bool TestBasic(std::string &error)
|
|||||||
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
|
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
|
||||||
ADD_STATE(State_F1_HookRemoved);
|
ADD_STATE(State_F1_HookRemoved);
|
||||||
|
|
||||||
SH_CALL(cc, &Test::F1)();
|
SH_CALL(pTest, &Test::F1)();
|
||||||
pTest->F1();
|
pTest->F1();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -581,7 +570,7 @@ bool TestBasic(std::string &error)
|
|||||||
g_F299Pre_WhatToRet = false;
|
g_F299Pre_WhatToRet = false;
|
||||||
|
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_Called("hi"),
|
new State_F299_Called("hi"),
|
||||||
@ -593,7 +582,7 @@ bool TestBasic(std::string &error)
|
|||||||
// (one add staticfunc in old format)
|
// (one add staticfunc in old format)
|
||||||
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
|
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_PreHandlerCalled("hi"),
|
new State_F299_PreHandlerCalled("hi"),
|
||||||
@ -605,7 +594,7 @@ bool TestBasic(std::string &error)
|
|||||||
|
|
||||||
SH_ADD_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
|
SH_ADD_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_PreHandlerCalled("hi"),
|
new State_F299_PreHandlerCalled("hi"),
|
||||||
@ -618,7 +607,7 @@ bool TestBasic(std::string &error)
|
|||||||
|
|
||||||
g_F299Pre_WhatToDo = MRES_OVERRIDE;
|
g_F299Pre_WhatToDo = MRES_OVERRIDE;
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_PreHandlerCalled("hi"),
|
new State_F299_PreHandlerCalled("hi"),
|
||||||
@ -631,7 +620,7 @@ bool TestBasic(std::string &error)
|
|||||||
|
|
||||||
g_F299Pre_WhatToDo = MRES_SUPERCEDE;
|
g_F299Pre_WhatToDo = MRES_SUPERCEDE;
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_PreHandlerCalled("hi"),
|
new State_F299_PreHandlerCalled("hi"),
|
||||||
@ -644,7 +633,7 @@ bool TestBasic(std::string &error)
|
|||||||
// (one remove staticfunc in old format)
|
// (one remove staticfunc in old format)
|
||||||
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
|
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_Called("hi"),
|
new State_F299_Called("hi"),
|
||||||
@ -656,7 +645,7 @@ bool TestBasic(std::string &error)
|
|||||||
|
|
||||||
SH_REMOVE_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
|
SH_REMOVE_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
|
||||||
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
ADD_STATE(State_F299Ret(pTest->F299("hi")));
|
||||||
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
|
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_F299_Called("hi"),
|
new State_F299_Called("hi"),
|
||||||
@ -665,14 +654,6 @@ bool TestBasic(std::string &error)
|
|||||||
new State_F299Ret(true),
|
new State_F299Ret(true),
|
||||||
NULL), "Part 10.7");
|
NULL), "Part 10.7");
|
||||||
|
|
||||||
// 11) Release callclass
|
|
||||||
SH_RELEASE_CALLCLASS(cc);
|
|
||||||
ADD_STATE(State_F1_CallClassReleased);
|
|
||||||
|
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
|
||||||
new State_F1_CallClassReleased,
|
|
||||||
NULL), "Part 11");
|
|
||||||
|
|
||||||
// 11 1/2) Test removing hook by id
|
// 11 1/2) Test removing hook by id
|
||||||
|
|
||||||
|
|||||||
@ -100,11 +100,9 @@ bool TestVafmtAndOverload(std::string &error)
|
|||||||
Whatever gabgab;
|
Whatever gabgab;
|
||||||
IGaben *pGab = &gabgab;
|
IGaben *pGab = &gabgab;
|
||||||
|
|
||||||
SourceHook::CallClass<IGaben> *cc = SH_GET_CALLCLASS(pGab);
|
|
||||||
|
|
||||||
// Part 1
|
// Part 1
|
||||||
SH_CALL(cc, static_cast<void (IGaben::*)()>(&IGaben::EatYams))();
|
SH_CALL(pGab, static_cast<void (IGaben::*)()>(&IGaben::EatYams))();
|
||||||
SH_CALL(cc, static_cast<bool (IGaben::*)(const char *) const>(&IGaben::EatYams))("Here!");
|
SH_CALL(pGab, static_cast<bool (IGaben::*)(const char *) const>(&IGaben::EatYams))("Here!");
|
||||||
|
|
||||||
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams0_Handler, false);
|
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams0_Handler, false);
|
||||||
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams1_Handler, false);
|
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams1_Handler, false);
|
||||||
@ -126,9 +124,9 @@ bool TestVafmtAndOverload(std::string &error)
|
|||||||
|
|
||||||
// Part 2
|
// Part 2
|
||||||
pGab->Vafmt1(true, 55, "Hello %s%d%s", "BA", 1, "L");
|
pGab->Vafmt1(true, 55, "Hello %s%d%s", "BA", 1, "L");
|
||||||
SH_CALL(cc, &IGaben::Vafmt1)(true, 55, "Hello %s%d%s", "BA", 1, "L");
|
SH_CALL(pGab, &IGaben::Vafmt1)(true, 55, "Hello %s%d%s", "BA", 1, "L");
|
||||||
pGab->Vafmt2("Hello %s%d%s", "BA", 1, "LOPAN");
|
pGab->Vafmt2("Hello %s%d%s", "BA", 1, "LOPAN");
|
||||||
SH_CALL(cc, &IGaben::Vafmt2)("Hello %s%d%s", "BA", 1, "LOPAN");
|
SH_CALL(pGab, &IGaben::Vafmt2)("Hello %s%d%s", "BA", 1, "LOPAN");
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Vafmt_Called(1, "Hello BA1L"),
|
new State_Vafmt_Called(1, "Hello BA1L"),
|
||||||
@ -170,7 +168,5 @@ bool TestVafmtAndOverload(std::string &error)
|
|||||||
new State_Vafmt_Called(2, "Hello BA1LOPAN"),
|
new State_Vafmt_Called(2, "Hello BA1LOPAN"),
|
||||||
NULL), "Part 4");
|
NULL), "Part 4");
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(cc);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,11 +87,10 @@ bool TestThisPtrOffs(std::string &error)
|
|||||||
// Get a callclass for pD
|
// Get a callclass for pD
|
||||||
// Verify whether the this pointers are correct
|
// Verify whether the this pointers are correct
|
||||||
// Also call them normally to make sure that we aren't messing it up ;)
|
// Also call them normally to make sure that we aren't messing it up ;)
|
||||||
SourceHook::CallClass<Derived> *pD_CC = SH_GET_CALLCLASS(pD);
|
|
||||||
|
|
||||||
SH_CALL(pD_CC, &Derived::Func1)();
|
SH_CALL(pD, &Derived::Func1)();
|
||||||
SH_CALL(pD_CC, &Derived::Func2)();
|
SH_CALL(pD, &Derived::Func2)();
|
||||||
SH_CALL(pD_CC, &Derived::Func3)();
|
SH_CALL(pD, &Derived::Func3)();
|
||||||
pD->Func1();
|
pD->Func1();
|
||||||
pD->Func2();
|
pD->Func2();
|
||||||
pD->Func3();
|
pD->Func3();
|
||||||
@ -105,8 +104,8 @@ bool TestThisPtrOffs(std::string &error)
|
|||||||
new State_Func3_Called(pD),
|
new State_Func3_Called(pD),
|
||||||
NULL), "Part 1");
|
NULL), "Part 1");
|
||||||
|
|
||||||
SH_CALL(pD_CC, &Base1::Func1)();
|
SH_CALL(pD, &Base1::Func1)();
|
||||||
SH_CALL(pD_CC, &Base2::Func2)();
|
SH_CALL(pD, &Base2::Func2)();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(pB1),
|
new State_Func1_Called(pB1),
|
||||||
@ -116,11 +115,8 @@ bool TestThisPtrOffs(std::string &error)
|
|||||||
// 2)
|
// 2)
|
||||||
// Get callclasses for the other ones and verify it as well
|
// Get callclasses for the other ones and verify it as well
|
||||||
|
|
||||||
SourceHook::CallClass<Base1> *pB1_CC = SH_GET_CALLCLASS(pB1);
|
SH_CALL(pB1, &Base1::Func1)();
|
||||||
SourceHook::CallClass<Base2> *pB2_CC = SH_GET_CALLCLASS(pB2);
|
SH_CALL(pB2, &Base2::Func2)();
|
||||||
|
|
||||||
SH_CALL(pB1_CC, &Base1::Func1)();
|
|
||||||
SH_CALL(pB2_CC, &Base2::Func2)();
|
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(pB1),
|
new State_Func1_Called(pB1),
|
||||||
@ -214,11 +210,11 @@ bool TestThisPtrOffs(std::string &error)
|
|||||||
new State_Func3_Called(pD),
|
new State_Func3_Called(pD),
|
||||||
NULL), "Part 5.1");
|
NULL), "Part 5.1");
|
||||||
|
|
||||||
SH_CALL(pD_CC, &Derived::Func1)();
|
SH_CALL(pD, &Derived::Func1)();
|
||||||
SH_CALL(pD_CC, &Derived::Func2)();
|
SH_CALL(pD, &Derived::Func2)();
|
||||||
SH_CALL(pD_CC, &Derived::Func3)();
|
SH_CALL(pD, &Derived::Func3)();
|
||||||
SH_CALL(pB1_CC, &Base1::Func1)();
|
SH_CALL(pB1, &Base1::Func1)();
|
||||||
SH_CALL(pB2_CC, &Base2::Func2)();
|
SH_CALL(pB2, &Base2::Func2)();
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(pB1),
|
new State_Func1_Called(pB1),
|
||||||
@ -232,9 +228,5 @@ bool TestThisPtrOffs(std::string &error)
|
|||||||
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
|
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
|
||||||
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
|
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(pB1_CC);
|
|
||||||
SH_RELEASE_CALLCLASS(pB2_CC);
|
|
||||||
SH_RELEASE_CALLCLASS(pD_CC);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,8 +114,6 @@ bool TestManual(std::string &error)
|
|||||||
Whatever inst;
|
Whatever inst;
|
||||||
TheWall *p = &inst;
|
TheWall *p = &inst;
|
||||||
|
|
||||||
SourceHook::ManualCallClass *cc = SH_GET_MCALLCLASS(p, sizeof(void*));
|
|
||||||
|
|
||||||
// 1)
|
// 1)
|
||||||
// Call each function
|
// Call each function
|
||||||
p->Func1();
|
p->Func1();
|
||||||
@ -134,14 +132,14 @@ bool TestManual(std::string &error)
|
|||||||
|
|
||||||
// 1.1)
|
// 1.1)
|
||||||
// Now call each function through the manual call class, using the hook decl and manually
|
// Now call each function through the manual call class, using the hook decl and manually
|
||||||
SH_MCALL(cc, TheWall_Func1)();
|
SH_MCALL(p, TheWall_Func1)();
|
||||||
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
|
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
|
||||||
SH_MCALL(cc, TheWall_Func2)(200);
|
SH_MCALL(p, TheWall_Func2)(200);
|
||||||
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
|
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(p),
|
new State_Func1_Called(p),
|
||||||
@ -158,6 +156,17 @@ bool TestManual(std::string &error)
|
|||||||
new State_Return(4),
|
new State_Return(4),
|
||||||
NULL), "Part 1.1");
|
NULL), "Part 1.1");
|
||||||
|
|
||||||
|
// Compat: really get a manual call class!
|
||||||
|
SourceHook::ManualCallClass *pCC = SH_GET_MCALLCLASS(p, sizeof(void*));
|
||||||
|
SH_MCALL(pCC, TheWall_Func1)();
|
||||||
|
SH_MCALL2(pCC, MFP_Func1(), 0, 0, 0)();
|
||||||
|
CHECK_STATES((&g_States,
|
||||||
|
new State_Func1_Called(p),
|
||||||
|
new State_Func1_Called(p),
|
||||||
|
NULL), "Part 1.2");
|
||||||
|
|
||||||
|
SH_RELEASE_CALLCLASS(pCC);
|
||||||
|
|
||||||
// 2)
|
// 2)
|
||||||
// Hook each function normally, call them
|
// Hook each function normally, call them
|
||||||
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
|
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
|
||||||
@ -186,14 +195,14 @@ bool TestManual(std::string &error)
|
|||||||
// Call them through the mcallclass
|
// Call them through the mcallclass
|
||||||
// 2.1)
|
// 2.1)
|
||||||
// Now call each function through the manual call class, using the hook decl and manually
|
// Now call each function through the manual call class, using the hook decl and manually
|
||||||
SH_MCALL(cc, TheWall_Func1)();
|
SH_MCALL(p, TheWall_Func1)();
|
||||||
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
|
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
|
||||||
SH_MCALL(cc, TheWall_Func2)(200);
|
SH_MCALL(p, TheWall_Func2)(200);
|
||||||
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
|
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(p),
|
new State_Func1_Called(p),
|
||||||
@ -247,14 +256,14 @@ bool TestManual(std::string &error)
|
|||||||
// Call them through the mcallclass
|
// Call them through the mcallclass
|
||||||
// 3.1)
|
// 3.1)
|
||||||
// Now call each function through the manual call class, using the hook decl and manually
|
// Now call each function through the manual call class, using the hook decl and manually
|
||||||
SH_MCALL(cc, TheWall_Func1)();
|
SH_MCALL(p, TheWall_Func1)();
|
||||||
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
|
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
|
||||||
SH_MCALL(cc, TheWall_Func2)(200);
|
SH_MCALL(p, TheWall_Func2)(200);
|
||||||
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
|
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
|
||||||
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
|
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
|
||||||
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
|
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Func1_Called(p),
|
new State_Func1_Called(p),
|
||||||
|
|||||||
@ -104,8 +104,6 @@ bool TestRef(std::string &error)
|
|||||||
CHello *pHello = &hello;
|
CHello *pHello = &hello;
|
||||||
CHook hook;
|
CHook hook;
|
||||||
|
|
||||||
SourceHook::CallClass<CHello> *cc = SH_GET_CALLCLASS(pHello);
|
|
||||||
|
|
||||||
ADD_STATE(State_Result(pHello->Func(base)));
|
ADD_STATE(State_Result(pHello->Func(base)));
|
||||||
ADD_STATE(State_Result(pHello->Func(der)));
|
ADD_STATE(State_Result(pHello->Func(der)));
|
||||||
ADD_STATE(State_Result(pHello->Func(der2)));
|
ADD_STATE(State_Result(pHello->Func(der2)));
|
||||||
@ -118,10 +116,10 @@ bool TestRef(std::string &error)
|
|||||||
new State_Result(12),
|
new State_Result(12),
|
||||||
NULL), "Part 1");
|
NULL), "Part 1");
|
||||||
|
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(base)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(base)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der2)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der2)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der3)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der3)));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Result(0),
|
new State_Result(0),
|
||||||
@ -148,10 +146,10 @@ bool TestRef(std::string &error)
|
|||||||
new State_Result(20),
|
new State_Result(20),
|
||||||
NULL), "Part 3");
|
NULL), "Part 3");
|
||||||
|
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(base)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(base)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der2)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der2)));
|
||||||
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der3)));
|
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der3)));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
new State_Result(0),
|
new State_Result(0),
|
||||||
|
|||||||
@ -164,8 +164,7 @@ bool TestRefRet(std::string &error)
|
|||||||
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
|
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
|
||||||
|
|
||||||
// Through a callclass
|
// Through a callclass
|
||||||
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
|
int &ret5 = SH_CALL(pTest, &Test::Func1)();
|
||||||
int &ret5 = SH_CALL(cc1, &Test::Func1)();
|
|
||||||
ADD_STATE(State_Func1_Ret(&ret5));
|
ADD_STATE(State_Func1_Ret(&ret5));
|
||||||
|
|
||||||
CHECK_STATES((&g_States,
|
CHECK_STATES((&g_States,
|
||||||
@ -173,7 +172,6 @@ bool TestRefRet(std::string &error)
|
|||||||
new State_Func1_Ret(&test.m_Var1),
|
new State_Func1_Ret(&test.m_Var1),
|
||||||
NULL), "Part 5");
|
NULL), "Part 5");
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(cc1);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Func2 tests
|
// Func2 tests
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
// TEST VP HOOKS
|
// TEST VP HOOKS
|
||||||
// Test vfnptr-wide hooks
|
// Test vfnptr-wide hooks
|
||||||
|
// Also contains a test for removing hooks on deleted instances (by id)
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -138,6 +139,18 @@ bool TestVPHooks(std::string &error)
|
|||||||
new State_D2_Func1(p_d2i1),
|
new State_D2_Func1(p_d2i1),
|
||||||
NULL), "Part 1");
|
NULL), "Part 1");
|
||||||
|
|
||||||
|
SH_CALL(p_d1i1, &IBase::Func1)();
|
||||||
|
SH_CALL(p_d1i2, &IBase::Func1)();
|
||||||
|
SH_CALL(p_d2i1, &IBase::Func1)();
|
||||||
|
|
||||||
|
CHECK_STATES((&g_States,
|
||||||
|
new State_D1_Func1(p_d1i1),
|
||||||
|
|
||||||
|
new State_D1_Func1(p_d1i2),
|
||||||
|
|
||||||
|
new State_D2_Func1(p_d2i1),
|
||||||
|
NULL), "Part 1.1");
|
||||||
|
|
||||||
SH_REMOVE_HOOK_ID(hook1);
|
SH_REMOVE_HOOK_ID(hook1);
|
||||||
|
|
||||||
p_d1i1->Func1();
|
p_d1i1->Func1();
|
||||||
@ -261,6 +274,60 @@ bool TestVPHooks(std::string &error)
|
|||||||
SH_REMOVE_HOOK_ID(hook2);
|
SH_REMOVE_HOOK_ID(hook2);
|
||||||
SH_REMOVE_HOOK_ID(hook3);
|
SH_REMOVE_HOOK_ID(hook3);
|
||||||
|
|
||||||
|
// Test direct VP hook
|
||||||
|
|
||||||
|
p_d1i1->Func1();
|
||||||
|
p_d1i2->Func1();
|
||||||
|
|
||||||
|
// get vtable manually
|
||||||
|
void *pVtable = *reinterpret_cast<void**>(p_d1i1);
|
||||||
|
|
||||||
|
hook1 = SH_ADD_DVPHOOK(IBase, Func1, pVtable, SH_STATIC(Handler_Func1_Pre), false);
|
||||||
|
|
||||||
|
p_d1i1->Func1();
|
||||||
|
p_d1i2->Func1();
|
||||||
|
|
||||||
|
CHECK_STATES((&g_States,
|
||||||
|
new State_D1_Func1(p_d1i1),
|
||||||
|
new State_D1_Func1(p_d1i2),
|
||||||
|
|
||||||
|
new State_Func1_Pre(p_d1i1),
|
||||||
|
new State_D1_Func1(p_d1i1),
|
||||||
|
new State_Func1_Pre(p_d1i2),
|
||||||
|
new State_D1_Func1(p_d1i2),
|
||||||
|
NULL), "Part 8.1");
|
||||||
|
|
||||||
|
SH_REMOVE_HOOK_ID(hook1);
|
||||||
|
|
||||||
|
// Now try manual dvp hooks
|
||||||
|
p_d1i1->Func3(1);
|
||||||
|
p_d1i2->Func3(1);
|
||||||
|
|
||||||
|
hook1 = SH_ADD_MANUALDVPHOOK(IBase_Func3_Manual, pVtable, SH_STATIC(Handler_Func3_Pre), false);
|
||||||
|
|
||||||
|
p_d1i1->Func3(1);
|
||||||
|
p_d1i2->Func3(1);
|
||||||
|
|
||||||
|
CHECK_STATES((&g_States,
|
||||||
|
new State_D1_Func3(p_d1i1, 1),
|
||||||
|
new State_D1_Func3(p_d1i2, 1),
|
||||||
|
|
||||||
|
new State_Func3_Pre(p_d1i1, 1), // manual vp hook
|
||||||
|
new State_D1_Func3(p_d1i1, 2), // function
|
||||||
|
|
||||||
|
new State_Func3_Pre(p_d1i2, 1), // normal vp hook
|
||||||
|
new State_D1_Func3(p_d1i2, 2), // function
|
||||||
|
|
||||||
|
NULL), "Part 8.2");
|
||||||
|
|
||||||
|
|
||||||
|
// Test removing normal hooks even though the instance is deleted
|
||||||
|
p_d1i1 = new CDerived1;
|
||||||
|
SH_ADD_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false);
|
||||||
|
delete p_d1i1;
|
||||||
|
// The following line may not crash!
|
||||||
|
SH_REMOVE_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user