1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-02-20 13:54:14 +01:00

Added hook ids

Added VP hooks and VP Hook test
New macro syntax (SH_ADD_HOOK + SH_STATIC/SH_MEMBER)

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40385
This commit is contained in:
Pavol Marko 2007-05-07 18:35:59 +00:00
parent 9bf8799bf3
commit 8e446b28c3
21 changed files with 1453 additions and 372 deletions

View File

@ -22,7 +22,12 @@
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Impl versions:
// ???
// 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!
#define SH_IMPL_VERSION 4
// Hookman version:
// 1 - Support for recalls, performance optimisations
@ -479,7 +484,40 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
/**
* @brief Modes for the new AddHook
*/
enum AddHookMode
{
Hook_Normal,
Hook_VP
};
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @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 iface The interface pointer
* @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
@ -651,37 +689,67 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_GET_MCALLCLASS(ptr, size) SH_GET_MCALLCLASS_R(SH_GLOB_SHPTR, reinterpret_cast<SourceHook::EmptyClass*>(ptr), size)
#define SH_RELEASE_CALLCLASS(ptr) SH_RELEASE_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
// New ADD / REMOVE macros.
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
#define SH_MEMBER(inst, func) fastdelegate::MakeDelegate(inst, func)
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHRemove##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
post, handler)
#define SH_ADD_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_HOOK_ID(hookid) \
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
// Old macros
// !! These are now deprecated. Instead, use one of these:
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
#define SH_NOATTRIB
@ -716,6 +784,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -760,7 +830,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
int __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
@ -769,7 +839,20 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
@ -811,6 +894,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -843,10 +928,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_MFHCls(hookname) SH_MFHCls(hookname)::ms_Inst; \
::SourceHook::MemFuncInfo SH_MFHCls(hookname)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_MFHCls(hookname)::ms_HI; \
bool __SourceHook_FHMAdd##hookname(void *iface, bool post, \
int __SourceHook_FHMAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, pthisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \

View File

@ -22,7 +22,12 @@
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Impl versions:
// ???
// 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!
#define SH_IMPL_VERSION 4
// Hookman version:
// 1 - Support for recalls, performance optimisations
@ -479,7 +484,40 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
/**
* @brief Modes for the new AddHook
*/
enum AddHookMode
{
Hook_Normal,
Hook_VP
};
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @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 iface The interface pointer
* @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
@ -651,37 +689,67 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_GET_MCALLCLASS(ptr, size) SH_GET_MCALLCLASS_R(SH_GLOB_SHPTR, reinterpret_cast<SourceHook::EmptyClass*>(ptr), size)
#define SH_RELEASE_CALLCLASS(ptr) SH_RELEASE_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
// New ADD / REMOVE macros.
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
#define SH_MEMBER(inst, func) fastdelegate::MakeDelegate(inst, func)
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHRemove##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
post, handler)
#define SH_ADD_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_HOOK_ID(hookid) \
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
// Old macros
// !! These are now deprecated. Instead, use one of these:
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
#define SH_NOATTRIB
@ -716,6 +784,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -760,7 +830,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
int __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
@ -769,7 +839,20 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
@ -811,6 +894,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -843,10 +928,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_MFHCls(hookname) SH_MFHCls(hookname)::ms_Inst; \
::SourceHook::MemFuncInfo SH_MFHCls(hookname)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_MFHCls(hookname)::ms_HI; \
bool __SourceHook_FHMAdd##hookname(void *iface, bool post, \
int __SourceHook_FHMAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, pthisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \

147
sourcehook/sh_listcat.h Normal file
View File

@ -0,0 +1,147 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
// Used for VP-Hooks
#ifndef _INCLUDE_SMM_LISTCAT_H
#define _INCLUDE_SMM_LISTCAT_H
#include "sh_list.h"
namespace SourceHook
{
// Only a very special-case forward iterator!
template <typename T>
class ListCatIterator
{
List<T> *m_pListLeft;
List<T> *m_pListRight;
typename List<T>::iterator m_Iter;
void CheckLeftEmptyOnBegin()
{
// If the left list is empty and right is valid, GoToBegin sets m_Iter to m_Left
// End() checks for equality to m_Right.end() so it returns false
// then Next() corrupts by incrementing!
// To avoid this, we skip left if it's empty.
if (m_pListLeft && m_pListLeft->empty() && m_pListRight)
{
m_Iter = m_pListRight->begin();
}
}
public:
// At least one list has to be non-null!
ListCatIterator(List<T> *pListLeft, List<T> *pListRight) : m_pListLeft(pListLeft), m_pListRight(pListRight),
m_Iter(pListLeft ? pListLeft->begin() : pListRight->begin())
{
CheckLeftEmptyOnBegin();
}
void GoToBegin()
{
m_Iter = m_pListLeft ? m_pListLeft->begin() : m_pListRight->begin();
CheckLeftEmptyOnBegin();
}
bool End()
{
return m_pListRight ? (m_Iter == m_pListRight->end())
: (m_Iter == m_pListLeft->end());
}
//pre increment
ListCatIterator & operator++()
{
++m_Iter;
if (m_pListLeft && m_Iter == m_pListLeft->end())
{
if (m_pListRight)
m_Iter = m_pListRight->begin();
}
return *this;
}
//post increment
ListCatIterator operator++(int)
{
ListCatIterator old(*this);
++m_Iter;
if (m_pListLeft && m_Iter == m_pListLeft->end())
{
if (m_pListRight)
m_Iter = m_pListRight->begin();
}
return old;
}
const T & operator * () const
{
return *m_Iter;
}
T & operator * ()
{
return *m_Iter;
}
T * operator -> ()
{
return &(*m_Iter);
}
const T * operator -> () const
{
return &(*m_Iter);
}
bool operator != (const typename List<T>::iterator &where) const
{
return (m_Iter != where);
}
bool operator ==(const typename List<T>::iterator &where) const
{
return (m_Iter == where);
}
ListCatIterator & operator = (const typename List<T>::iterator &where)
{
m_Iter = where;
if (m_pListLeft && m_Iter == m_pListLeft->end())
{
if (m_pListRight)
m_Iter = m_pListRight->begin();
// :HACK HACK: RemoveHookById is not aware of ListCatIterator (yet? :TODO: Change it!)
// So we have to do this here... (look for the "Move all iterators pointing at this" section)
--m_Iter;
}
return *this;
}
ListCatIterator & operator = (const ListCatIterator<T> &other)
{
m_Iter = other.m_Iter;
m_pListLeft = other.m_pListLeft;
m_pListRight = other.m_pListRight;
return *this;
}
void SetListLeft(List<T> *pList)
{
m_pListLeft = pList;
}
};
}
#endif

View File

@ -277,14 +277,21 @@ namespace SourceHook
m_HookMans.clear();
}
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{
return AddHookNew(plug, Hook_Normal, iface, thisptr_offs, myHookMan, handler, post) != 0 ? true : false;
}
int CSourceHookImpl::AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post)
{
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
// 1) Get info about the hook manager
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
return 0;
tmp.m_Func = myHookMan;
tmp.m_Plug = plug;
@ -320,7 +327,7 @@ namespace SourceHook
hmil_iter != hmcl_iter2->end(); ++hmil_iter)
{
if (hmil_iter->m_VfnPtrs.find(cur_vfnptr) != hmil_iter->m_VfnPtrs.end())
return false;
return 0;
}
}
}
@ -338,7 +345,7 @@ namespace SourceHook
// Alter vtable entry
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
return false;
return 0;
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->m_HookfuncVfnptr);
@ -352,6 +359,10 @@ namespace SourceHook
ApplyCallClassPatches(adjustediface, tmp.m_VtblOffs, tmp.m_VtblIdx, vfp.m_OrigEntry);
}
// If it's a VP hook, set adjustediface to NULL now ( see the comments at the beginning of sourcehook_impl.h )
if (mode == Hook_VP)
adjustediface = NULL;
CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(adjustediface);
if (iface_iter == vfnptr_iter->m_Ifaces.end())
{
@ -361,6 +372,34 @@ namespace SourceHook
// Make iface_iter point to the new element
iface_iter = vfnptr_iter->m_Ifaces.end();
--iface_iter;
// If this is a VP-Hook-NULL interface, go through all other interfaces of this vfnptr and tell them!
if (adjustediface == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 != NULL)
{
iface_iter2->m_PreHooks.SetVPList(&iface_iter->m_PreHooks.m_List);
iface_iter2->m_PostHooks.SetVPList(&iface_iter->m_PostHooks.m_List);
}
}
}
else
{
// If this is a new non-VP-Hook-NULL interface, look for a non-VP-Hook-NULL interface!
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 == NULL)
{
iface_iter->m_PreHooks.SetVPList(&iface_iter2->m_PreHooks.m_List);
iface_iter->m_PostHooks.SetVPList(&iface_iter2->m_PostHooks.m_List);
break; // There can only be one!
}
}
}
}
// Add the hook
@ -369,11 +408,136 @@ namespace SourceHook
hookinfo.plug = plug;
hookinfo.paused = false;
hookinfo.thisptr_offs = thisptr_offs;
hookinfo.hookid = m_HookIDMan.New(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx, cur_vfnptr,
adjustediface, plug, thisptr_offs, handler, post);
if (post)
iface_iter->m_PostHooks.m_List.push_back(hookinfo);
else
iface_iter->m_PreHooks.m_List.push_back(hookinfo);
return hookinfo.hookid;
}
bool CSourceHookImpl::RemoveHookByID(Plugin plug, int hookid)
{
const CHookIDManager::Entry *hentry;
hentry = m_HookIDMan.QueryHook(hookid);
if (!hentry)
{
// hookid doesn't exist !
return false;
}
HookManContList::iterator hmcl_iter = m_HookMans.find(
CHookManagerContainer::HMCI(hentry->proto.GetProto(), hentry->vtbl_offs, hentry->vtbl_idx));
if (hmcl_iter == m_HookMans.end() || hmcl_iter->empty())
return false;
CHookManagerContainer::iterator hookman = hmcl_iter->begin();
// Find vfnptr
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(hentry->vfnptr);
if (vfnptr_iter == hookman->m_VfnPtrs.end())
return false;
// Find iface
CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(hentry->adjustediface);
if (iface_iter == vfnptr_iter->m_Ifaces.end())
return false;
// Find hook
List<HookInfo> &hooks = hentry->post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
List<HookInfo>::iterator hookiter = hooks.find(hookid);
if (hookiter == hooks.end())
return false;
hookiter->handler->DeleteThis();
// Move all iterators pointing at this
List<HookInfo>::iterator oldhookiter = hookiter;
hookiter = hooks.erase(hookiter);
List<HookInfo>::iterator newhookiter = hookiter;
--newhookiter; // The hook loop will ++ it then
CHookList::CIter *pItIter;
for (pItIter = iface_iter->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
// If this is VP-Hook-NULL interface, also check all other interfaces of this vfnptr
if (*iface_iter == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 != NULL)
{
for (pItIter = iface_iter2->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
}
}
}
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
// If this is a VP-Hook-NULL interface, go through all other interfaces of this vfnptr and tell them!
if (*iface_iter == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (iface_iter2->m_Ptr != NULL)
{
iface_iter2->m_PreHooks.ClearVPList();
iface_iter2->m_PostHooks.ClearVPList();
}
}
}
// There are no hooks on this iface anymore...
for (HookLoopInfoStack::iterator hli_iter = m_HLIStack.begin();
hli_iter != m_HLIStack.end(); ++hli_iter)
{
if (hli_iter->pCurIface == static_cast<IIface*>(&(*iface_iter)))
hli_iter->shouldContinue = false;
}
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
{
// No ifaces at all -> Deactivate the hook
// Only patch the vfnptr back if the module is still in memory
// If it's not, do not remove stuff like we did before
// First off we did it wrong (shutdown the whole hookman, uh..) and secondly applications may be
// confused by RemoveHook returning false then (yeah, I know, I made this one up, no one checks for RemoveHook error)
if (ModuleInMemory(reinterpret_cast<char*>(vfnptr_iter->m_Ptr), SH_PTRSIZE))
{
*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->m_Ptr == hentry->adjustediface)
cciter->RemoveCallClassPatch(hentry->vtbl_offs, hentry->vtbl_idx);
if (hookman->m_VfnPtrs.empty())
{
// Unregister the hook manager
hookman->m_Func(HA_Unregister, NULL);
}
}
}
// Don't forget to remove the hookid from m_HookIDMan
m_HookIDMan.Remove(hookid);
return true;
}
@ -384,110 +548,29 @@ 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);
// Get info about hook manager and compute adjustediface
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Find the hook manager and the hook
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs);
HookManContList::iterator hmcl_iter = m_HookMans.find(
CHookManagerContainer::HMCI(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx));
if (hmcl_iter == m_HookMans.end() || hmcl_iter->empty())
return false;
CHookManagerContainer::iterator hookman = hmcl_iter->begin();
// Loop through all hooks and remove those which match:
// hookman, vfnptr, iface, plug, adjusted iface, this ptr offs, handler, post
CVector<int> removehooks;
m_HookIDMan.FindAllHooks(removehooks, tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx, adjustediface, plug, thisptr_offs, handler, post);
if (!ModuleInMemory(reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs,
sizeof(void*) * (tmp.m_VtblIdx + 1)))
{
// 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.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->m_VfnPtrs.end())
if (removehooks.empty())
return false;
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end();)
bool status = false;
for (CVector<int>::iterator iter = removehooks.begin(); iter != removehooks.end(); ++iter)
{
if (iface_iter->m_Ptr != adjustediface)
{
iface_iter++;
continue;
}
List<HookInfo> &hooks =
post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
bool erase;
for (List<HookInfo>::iterator hookiter = hooks.begin();
hookiter != hooks.end(); )
{
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler) &&
hookiter->thisptr_offs == thisptr_offs;
if (erase)
{
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
// Move all iterators pointing at this
List<HookInfo>::iterator oldhookiter = hookiter;
hookiter = hooks.erase(hookiter);
List<HookInfo>::iterator newhookiter = hookiter;
--newhookiter; // The hook loop will ++ it then
CHookList::CIter *pItIter;
for (pItIter = iface_iter->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
}
else
++hookiter;
}
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
// There are no hooks on this iface anymore...
for (HookLoopInfoStack::iterator hli_iter = m_HLIStack.begin();
hli_iter != m_HLIStack.end(); ++hli_iter)
{
if (hli_iter->pCurIface == static_cast<IIface*>(&(*iface_iter)))
hli_iter->shouldContinue = false;
}
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->m_Ptr == adjustediface)
cciter->RemoveCallClassPatch(tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman->m_VfnPtrs.empty())
{
// Unregister the hook manager
hookman->m_Func(HA_Unregister, NULL);
}
// Don't try to continue looping through ifaces
// - the list is already invalid
return true;
}
}
else
++iface_iter;
if (RemoveHookByID(plug, *iter))
status = true;
}
return true;
return status;
}
GenericCallClass *CSourceHookImpl::GetCallClass(void *iface, size_t size)
@ -614,7 +697,7 @@ namespace SourceHook
void CSourceHookImpl::HookLoopBegin(IIface *pIface)
{
HookLoopInfo hli;
HookLoopInfo hli = {0};
hli.pCurIface = pIface;
hli.shouldContinue = true;
hli.recall = HookLoopInfo::Recall_No;
@ -917,7 +1000,17 @@ namespace SourceHook
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
{
IfaceListIter iter = m_Ifaces.find(ptr);
return iter == m_Ifaces.end() ? NULL : &(*iter);
// If nothing is found, check for a NULL-interface (VP hooks only)
if (iter == m_Ifaces.end())
{
iter = m_Ifaces.find((void*)0);
return iter == m_Ifaces.end() ? NULL : &(*iter);
}
else
{
return &(*iter);
}
}
////////////////////////////
@ -948,11 +1041,11 @@ namespace SourceHook
// CHookList
////////////////////////////
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL), m_UsedIters(NULL),
CSourceHookImpl::CHookList::CHookList() : m_VPList(NULL), m_FreeIters(NULL), m_UsedIters(NULL),
m_Recall(false)
{
}
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List),
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_VPList(other.m_VPList), m_List(other.m_List),
m_FreeIters(NULL), m_UsedIters(NULL), m_Recall(false)
{
}
@ -1029,9 +1122,36 @@ namespace SourceHook
m_Recall = false;
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList), m_pNext(NULL)
void CSourceHookImpl::CHookList::SetVPList(List<HookInfo> *newList)
{
m_VPList = newList;
// Update cached CIter objects
CIter *pTmp;
pTmp = m_FreeIters;
while (pTmp)
{
pTmp->m_Iter.SetListLeft(m_VPList);
pTmp = pTmp->m_pNext;
}
pTmp = m_UsedIters;
while (pTmp)
{
pTmp->m_Iter.SetListLeft(m_VPList);
pTmp = pTmp->m_pNext;
}
}
void CSourceHookImpl::CHookList::ClearVPList()
{
SetVPList(NULL);
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList),
m_Iter(pList->m_VPList, &m_pList->m_List), m_pNext(NULL)
{
GoToBegin();
}
CSourceHookImpl::CHookList::CIter::~CIter()
{
@ -1044,7 +1164,7 @@ namespace SourceHook
void CSourceHookImpl::CHookList::CIter::GoToBegin()
{
m_Iter = m_pList->m_List.begin();
m_Iter.GoToBegin();
SkipPaused();
}
@ -1052,7 +1172,7 @@ namespace SourceHook
{
if (!m_pList)
return false;
return m_Iter == m_pList->m_List.end();
return m_Iter.End();;
}
void CSourceHookImpl::CHookList::CIter::Next()
{
@ -1067,7 +1187,7 @@ namespace SourceHook
}
void CSourceHookImpl::CHookList::CIter::SkipPaused()
{
while (m_Iter != m_pList->m_List.end() && m_Iter->paused)
while (!m_Iter.End() && m_Iter->paused)
++m_Iter;
}
@ -1085,6 +1205,9 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
char *CSourceHookImpl::CProto::DupProto(const char *p)
{
if (!p)
return NULL;
char *newproto;
if (*p)
{
@ -1105,6 +1228,9 @@ namespace SourceHook
void CSourceHookImpl::CProto::FreeProto(char *prot)
{
if (!prot)
return;
if (*prot)
{
delete [] prot;
@ -1117,6 +1243,9 @@ namespace SourceHook
bool CSourceHookImpl::CProto::Equal(const char *p1, const char *p2)
{
if (!p1 || !p2)
return false;
if (*p1 && *p2) // Case1: Both old
{
// As in old versions
@ -1209,4 +1338,68 @@ namespace SourceHook
}
}
}
//////////////////////////////////////////////////////////////////////////
// CHookIDManager
//////////////////////////////////////////////////////////////////////////
CSourceHookImpl::CHookIDManager::CHookIDManager()
{
}
int CSourceHookImpl::CHookIDManager::New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr,
void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
{
Entry tmp(proto, vtbl_offs, vtbl_idx, vfnptr, adjustediface, plug, thisptr_offs, handler, post);
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (m_Entries[i].isfree)
{
m_Entries[i] = tmp;
return static_cast<int>(i) + 1;
}
}
m_Entries.push_back(tmp);
return static_cast<int>(m_Entries.size()); // return size() because hookid = id+1 anyway
}
bool CSourceHookImpl::CHookIDManager::Remove(int hookid)
{
int realid = hookid - 1;
if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
return false;
m_Entries[realid].isfree = true;
// :TODO: remove free ids from back sometimes ??
return true;
}
const CSourceHookImpl::CHookIDManager::Entry * CSourceHookImpl::CHookIDManager::QueryHook(int hookid)
{
int realid = hookid - 1;
if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
return NULL;
return &m_Entries[realid];
}
void CSourceHookImpl::CHookIDManager::FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs,
int vtbl_idx, void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
{
// oh my god, a lot of parameters...
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs &&
m_Entries[i].vtbl_idx == vtbl_idx && m_Entries[i].adjustediface == adjustediface && m_Entries[i].plug == plug &&
m_Entries[i].thisptr_offs == thisptr_offs && m_Entries[i].handler->IsEqual(handler) && m_Entries[i].post == post)
{
output.push_back(static_cast<int>(i) + 1);
}
}
}
}

View File

@ -22,7 +22,12 @@
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Impl versions:
// ???
// 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!
#define SH_IMPL_VERSION 4
// Hookman version:
// 1 - Support for recalls, performance optimisations
@ -479,7 +484,40 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
/**
* @brief Modes for the new AddHook
*/
enum AddHookMode
{
Hook_Normal,
Hook_VP
};
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @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 iface The interface pointer
* @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
@ -651,37 +689,67 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_GET_MCALLCLASS(ptr, size) SH_GET_MCALLCLASS_R(SH_GLOB_SHPTR, reinterpret_cast<SourceHook::EmptyClass*>(ptr), size)
#define SH_RELEASE_CALLCLASS(ptr) SH_RELEASE_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
// New ADD / REMOVE macros.
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
#define SH_MEMBER(inst, func) fastdelegate::MakeDelegate(inst, func)
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHRemove##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
post, handler)
#define SH_ADD_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_HOOK_ID(hookid) \
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
// Old macros
// !! These are now deprecated. Instead, use one of these:
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
#define SH_NOATTRIB
@ -716,6 +784,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -760,7 +830,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
int __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
@ -769,7 +839,20 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
@ -811,6 +894,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -843,10 +928,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_MFHCls(hookname) SH_MFHCls(hookname)::ms_Inst; \
::SourceHook::MemFuncInfo SH_MFHCls(hookname)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_MFHCls(hookname)::ms_HI; \
bool __SourceHook_FHMAdd##hookname(void *iface, bool post, \
int __SourceHook_FHMAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, pthisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_VP, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \

View File

@ -16,6 +16,7 @@
#include "sh_vector.h"
#include "sh_tinyhash.h"
#include "sh_stack.h"
#include "sh_listcat.h"
/*
@ -142,6 +143,15 @@ Return Values in Post Recalls
HookLoopEnd we make sure that status is high enough so that the override return will be returned. crazy.
All this stuff could be much less complicated if I didn't try to preserve binary compatibility :)
VP Hooks
VP hooks are hooks which are called on a vfnptr, regardless of the this pointer with which it was called. They are
implemented as a special CIface instance with m_Ptr = NULL. All Hook Lists have a new "ListCatIterator" which
virtually concatenates the NULL-interface-hook-list with their normal hook list.
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 :)
*/
namespace SourceHook
@ -160,6 +170,10 @@ namespace SourceHook
char *DupProto(const char *src);
void FreeProto(char *prot);
public:
CProto() : m_Proto(NULL)
{
}
CProto(const char *szProto) : m_Proto(DupProto(szProto))
{
}
@ -192,6 +206,11 @@ namespace SourceHook
{
return Equal(other.m_Proto, m_Proto);
}
const char *GetProto() const
{
return m_Proto;
}
};
@ -226,17 +245,79 @@ namespace SourceHook
HookManagerPubFunc hookman;
};
// Associates hook ids with info about the hooks
// Also used to keep track of used hook ids
class CHookIDManager
{
public:
struct Entry
{
bool isfree;
// hookman info
CProto proto;
int vtbl_offs;
int vtbl_idx;
// vfnptr
void *vfnptr;
// iface
void* adjustediface;
// hook
Plugin plug;
int thisptr_offs;
ISHDelegate *handler;
bool post;
Entry(const CProto &pprt, int pvo, int pvi, void *pvp, void *pai, Plugin pplug, int pto,
ISHDelegate *ph, bool ppost)
: isfree(false), proto(pprt), vtbl_offs(pvo), vtbl_idx(pvi), vfnptr(pvp),
adjustediface(pai), plug(pplug), thisptr_offs(pto), handler(ph), post(ppost)
{
}
Entry()
{
}
};
private:
// Internally, hookid 1 is stored as m_Entries[0]
CVector<Entry> m_Entries;
public:
CHookIDManager();
int New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr, void *adjustediface,
Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post);
bool Remove(int hookid);
const Entry * QueryHook(int hookid);
// Finds all hooks with the given info, and fills the hookids into output.
void FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs, int vtbl_idx,
void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post);
// Removes all hooks with a specified vfnptr
bool RemoveAll(void *vfnptr);
};
struct HookInfo
{
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
int hookid; //!< Unique ID given by CHookIDManager
bool operator==(int otherid)
{
return hookid == otherid;
}
};
class CHookList : public IHookList
{
public:
List<HookInfo> *m_VPList; // left-hand list for ListCatIterator -> for VP hooks
List<HookInfo> m_List;
friend class CIter;
@ -250,7 +331,7 @@ namespace SourceHook
void SkipPaused();
public:
List<HookInfo>::iterator m_Iter;
ListCatIterator<HookInfo> m_Iter;
CIter(CHookList *pList);
@ -293,6 +374,9 @@ namespace SourceHook
IIter *GetIter();
void ReleaseIter(IIter *pIter);
void SetVPList(List<HookInfo> *newList);
void ClearVPList();
};
// I know, data hiding... But I'm a lazy bastard!
@ -315,6 +399,10 @@ namespace SourceHook
{
return m_Ptr == ptr;
}
bool operator!=(void *ptr)
{
return m_Ptr != ptr;
}
};
class CVfnPtr : public IVfnPtr
@ -520,6 +608,7 @@ namespace SourceHook
void SetPluginPaused(Plugin plug, bool paused);
HookLoopInfoStack m_HLIStack;
CHookIDManager m_HookIDMan;
public:
CSourceHookImpl();
virtual ~CSourceHookImpl();
@ -650,6 +739,32 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr);
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @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 iface The interface pointer
* @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post);
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid);
};
}

View File

@ -80,6 +80,7 @@ DO_TEST(Recall);
DO_TEST(Multi);
DO_TEST(Ref);
DO_TEST(RefRet);
DO_TEST(VPHooks);
int main(int argc, char *argv[])
{

View File

@ -289,6 +289,12 @@
<File
RelativePath="..\testref.cpp">
</File>
<File
RelativePath="..\testrefret.cpp">
</File>
<File
RelativePath="..\testvphooks.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
@ -296,6 +302,9 @@
<File
RelativePath="..\..\sh_list.h">
</File>
<File
RelativePath="..\..\sh_listcat.h">
</File>
<File
RelativePath="..\..\sh_stack.h">
</File>

View File

@ -338,6 +338,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public Test
{
};
SH_DECL_HOOK1(Test, F299, SH_NOATTRIB, 0, bool, const char *);
SH_DECL_HOOK0_void(Test, F1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, F2, SH_NOATTRIB, 0);
@ -416,7 +421,7 @@ bool TestBasic(std::string &error)
g_PLID = 1337;
HandlersF1 f1_handlers;
Test test;
Whatever test;
Test *pTest = &test;
// 1) Get a call class and call the member through it and normally
@ -458,8 +463,9 @@ bool TestBasic(std::string &error)
NULL), "Part 2");
// 3) Add a pre hook
// (one add memfunc in old format)
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, 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)();
pTest->F1();
@ -505,6 +511,7 @@ bool TestBasic(std::string &error)
NULL), "Part 5");
// 6) remove the hook again
// (one remove memfunc in old format)
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
ADD_STATE(State_F1_HookRemoved);
@ -519,7 +526,7 @@ bool TestBasic(std::string &error)
// 7) add a post hook now
g_F1Post_WhatToDo = MRES_IGNORED;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Post, true)));
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)();
pTest->F1();
@ -533,7 +540,7 @@ bool TestBasic(std::string &error)
// 8) And a pre hook again
g_F1Pre_WhatToDo = MRES_IGNORED;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, 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)();
pTest->F1();
@ -554,9 +561,9 @@ bool TestBasic(std::string &error)
NULL), "Part 8");
// 9) Remove all hooks
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
ADD_STATE(State_F1_HookRemoved);
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Post, true);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
ADD_STATE(State_F1_HookRemoved);
SH_CALL(cc, &Test::F1)();
@ -583,6 +590,7 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.1");
// (one add staticfunc in old format)
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
@ -595,7 +603,7 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.2");
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, 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(SH_CALL(cc, &Test::F299)("hi")));
@ -633,6 +641,7 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.5");
// (one remove staticfunc in old format)
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
@ -645,7 +654,7 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.6");
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, 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(SH_CALL(cc, &Test::F299)("hi")));
@ -665,30 +674,58 @@ bool TestBasic(std::string &error)
new State_F1_CallClassReleased,
NULL), "Part 11");
// 11 1/2) Test removing hook by id
g_F1Pre_WhatToDo = MRES_IGNORED;
pTest->F1();
int hookPre = SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
int hookPost = SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
pTest->F1();
SH_REMOVE_HOOK_ID(hookPost);
pTest->F1();
SH_REMOVE_HOOK_ID(hookPre);
pTest->F1();
CHECK_STATES((&g_States,
new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers),
new State_F1_Called,
new State_F1_PostHandler_Called(&f1_handlers),
new State_F1_PreHandler_Called(&f1_handlers),
new State_F1_Called,
new State_F1_Called,
NULL), "Part 11 1/2");
// 12) Test? Test.
SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F2, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F3, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F4, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F5, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F6, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F7, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F8, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F9, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F10, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F2, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F3, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F4, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F5, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F6, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F7, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F8, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F9, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F10, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F2, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F3, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F4, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F5, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F6, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F7, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F8, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F9, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F10, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F2, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F3, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F4, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F5, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F6, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F7, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F8, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F9, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F10, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK_STATICFUNC(Test, F60, pTest, F60_Pre, false);
SH_ADD_HOOK(Test, F60, pTest, SH_STATIC(F60_Pre), false);
int a = 0;
pTest->F60(a);

View File

@ -50,6 +50,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public IGaben
{
};
SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0);
SH_DECL_HOOK1(IGaben, EatYams, const, 1, bool, const char *);
SH_DECL_HOOK2_void_vafmt(IGaben, Vafmt1, SH_NOATTRIB, 0, bool, int);
@ -92,7 +97,7 @@ bool TestVafmtAndOverload(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
IGaben gabgab;
Whatever gabgab;
IGaben *pGab = &gabgab;
SourceHook::CallClass<IGaben> *cc = SH_GET_CALLCLASS(pGab);

View File

@ -47,6 +47,8 @@ namespace
}
};
class DerivedDerived : public Derived { };
SH_DECL_HOOK0_void(Derived, Func1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Derived, Func2, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Derived, Func3, SH_NOATTRIB, 0);
@ -72,7 +74,7 @@ bool TestThisPtrOffs(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Derived inst;
DerivedDerived inst;
Derived *pD = &inst;
Base1 *pB1 = pD;
Base2 *pB2 = pD;
@ -129,9 +131,9 @@ bool TestThisPtrOffs(std::string &error)
// 3) Add hooks on them (referring to them through pD1 / Derived)
// Check whether the hooks are called with the correct this pointer
SH_ADD_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -153,17 +155,17 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 3");
SH_REMOVE_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_REMOVE_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
// 4)
// Now add the hooks on Base1 and Base2 and check again
// Note that the new implicit_cast should convert the pD to Base1*/Base2* :)
SH_ADD_HOOK_STATICFUNC(Base1, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Base2, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Base1, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Base2, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -186,18 +188,18 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 4");
SH_REMOVE_HOOK_STATICFUNC(Base1, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Base2, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_REMOVE_HOOK(Base1, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Base2, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
// 5)
// Add some hooks, and use callclasses
// 5.1) First off, add all of them on pD
SH_ADD_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -226,9 +228,9 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 5.2");
SH_REMOVE_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_REMOVE_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
SH_RELEASE_CALLCLASS(pB1_CC);
SH_RELEASE_CALLCLASS(pB2_CC);

View File

@ -40,6 +40,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public Test
{
};
SH_DECL_HOOK0_void(Test, Func1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, Func2, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, Func3, SH_NOATTRIB, 0);
@ -63,14 +68,14 @@ bool TestPlugSys(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test inst;
Whatever inst;
Test *pInst = &inst;
// 1)
// Add hooks, then issue a complete shutdown
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
pInst->Func1();
pInst->Func2();
@ -101,23 +106,23 @@ bool TestPlugSys(std::string &error)
// Add hooks from "different plugins", then shutdown the plugins
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
pInst->Func1();
pInst->Func2();
@ -237,23 +242,23 @@ bool TestPlugSys(std::string &error)
// Add hooks from "different plugins", then pause the plugins
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
pInst->Func1();
pInst->Func2();

View File

@ -44,7 +44,7 @@ bool TestBail(std::string &error)
g_Gabgab = new IGaben;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
@ -75,7 +75,7 @@ bool TestBail(std::string &error)
new State_EatYams_Return(5),
NULL), "Part 3");
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_REMOVE_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
@ -97,7 +97,7 @@ bool TestBail(std::string &error)
new State_EatYams_Called(0xBEEF),
NULL), "Part 5");
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));

View File

@ -24,8 +24,8 @@ namespace N_TestBail
{
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler2, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler3, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler2), false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler3), false);
int ret = g_Gabgab->EatYams(0xDEAD);

View File

@ -52,6 +52,11 @@ namespace
{
ADD_STATE(State_Func5_Called(reinterpret_cast<void*>(this)));
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public TheWall
{
};
SH_DECL_HOOK0_void(TheWall, Func1, SH_NOATTRIB, 0);
@ -106,7 +111,7 @@ bool TestManual(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
TheWall inst;
Whatever inst;
TheWall *p = &inst;
SourceHook::ManualCallClass *cc = SH_GET_MCALLCLASS(p, sizeof(void*));
@ -155,10 +160,10 @@ bool TestManual(std::string &error)
// 2)
// Hook each function normally, call them
SH_ADD_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -206,18 +211,18 @@ bool TestManual(std::string &error)
NULL), "Part 2.1");
// Unhook them
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_REMOVE_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
// 3)
// Hook each function manually, call them
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -267,10 +272,10 @@ bool TestManual(std::string &error)
NULL), "Part 3.1");
// Unhook them
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_REMOVE_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
// 4)
// Hook each function manually, then normally, call, unhook
@ -278,7 +283,7 @@ bool TestManual(std::string &error)
AnotherBrick handler_inst;
// Why this?
// 1) tests sh_add_manualhook_memfunc
// 1) tests sh_add_manualhook
// 2) in my tests, the proto of the manual hook was not equal to the proto of the auto hook
// (because there are no attribs for manual hooks).
// sourcehook.cpp did a !strcmp(..), so it assigned a new hook manager even though there
@ -287,15 +292,15 @@ bool TestManual(std::string &error)
// The problem with this is that returning MRES_SUPERCEDE (as AnotherBrick::Handler_Func1
// does) will supercede the second hook func from being called - thus bypassing the call
// of the auto hook here.
SH_ADD_MANUALHOOK_MEMFUNC(TheWall_Func1, p, &handler_inst, &AnotherBrick::Handler_Func1, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_MEMBER(&handler_inst, &AnotherBrick::Handler_Func1), false);
SH_ADD_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -319,19 +324,19 @@ bool TestManual(std::string &error)
new State_Return(4),
NULL), "Part 4");
SH_REMOVE_MANUALHOOK_MEMFUNC(TheWall_Func1, p, &handler_inst, &AnotherBrick::Handler_Func1, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_REMOVE_MANUALHOOK(TheWall_Func1, p, SH_MEMBER(&handler_inst, &AnotherBrick::Handler_Func1), false);
SH_REMOVE_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_REMOVE_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
// 5) Reconfigure TheWall_Func1 to actually hook Func5:
SH_MANUALHOOK_RECONFIGURE(TheWall_Func1, 4, 0, 0);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
p->Func5();

View File

@ -53,7 +53,7 @@ bool TestMulti(std::string &error)
for (unsigned int i=0; i<10; i++)
SH_ADD_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[i], HookFunction, false);
SH_ADD_HOOK(VMultiTest, HookTarget, pv[i], SH_STATIC(HookFunction), false);
pv[0]->HookTarget();
@ -72,7 +72,7 @@ bool TestMulti(std::string &error)
}
}
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[0], HookFunction, false);
SH_REMOVE_HOOK(VMultiTest, HookTarget, pv[0], SH_STATIC(HookFunction), false);
for (unsigned int i=1; i<10; i++)
pv[i]->HookTarget();
@ -96,7 +96,7 @@ bool TestMulti(std::string &error)
for (unsigned int i=1; i<10; i++)
{
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[1], HookFunction, false);
SH_REMOVE_HOOK(VMultiTest, HookTarget, pv[1], SH_STATIC(HookFunction), false);
delete pv[i];
}

View File

@ -48,6 +48,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
struct Whatever : Test
{
};
void Handler1_Func1(int a)
{
ADD_STATE(State_H1_Func1(a));
@ -119,12 +124,12 @@ bool TestRecall(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Test inst;
Whatever inst;
Test *ptr = &inst;
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler1_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, HandlerPost_Func1, true);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler1_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(HandlerPost_Func1), true);
ptr->Func1(77);
@ -135,10 +140,10 @@ bool TestRecall(std::string &error)
new State_HP_Func1(0, ptr),
NULL), "Part 1");
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, Handler1_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(Handler1_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
ptr->Func1(77);
@ -151,8 +156,8 @@ bool TestRecall(std::string &error)
new State_HP_Func1(57, ptr),
NULL), "Part 2");
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, HandlerPost_Func1, true);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(HandlerPost_Func1), true);
ptr->Func1(77);
@ -162,8 +167,8 @@ bool TestRecall(std::string &error)
// Func2
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func2, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost_Func2, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func2), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost_Func2), true);
int a = ptr->Func2(77);
CHECK_STATES((&g_States,
@ -175,8 +180,8 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 500, "Part 4.1");
// Func2, with other handler
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func2, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler2_Func2, false);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func2), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler2_Func2), false);
a = ptr->Func2(77);
CHECK_STATES((&g_States,
@ -191,9 +196,9 @@ bool TestRecall(std::string &error)
// 1) WITH OVERRIDE
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func22, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1A_Func22, true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func22), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1A_Func22), true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
a = ptr->Func2(10, 11);
CHECK_STATES((&g_States,
@ -206,11 +211,11 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 0, "Part 5.1");
// 2) WITH IGNORE
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1A_Func22, true);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1A_Func22), true);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1_Func22, true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1_Func22), true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
a = ptr->Func2(10, 11);
CHECK_STATES((&g_States,

View File

@ -82,6 +82,7 @@ namespace
return 1;
}
};
struct C2
{
virtual void F()
@ -167,6 +168,15 @@ namespace
}
};
struct C1_Derived : public C1 {};
struct C2_Derived : public C2 {};
struct C3_Derived : public C3 {};
struct C4_Derived : public C4 {};
struct C5_Derived : public C5 {};
struct C6_Derived : public C6 {};
struct C7_Derived : public C7 {};
struct C8_Derived : public C8 {};
SH_DECL_HOOK0_void(C1, F, SH_NOATTRIB, 0);
SH_DECL_HOOK0(C1, G, SH_NOATTRIB, 0, int);
SH_DECL_HOOK0_void(C2, F, SH_NOATTRIB, 0);
@ -258,9 +268,9 @@ namespace
void Handler_C7_F()
{
if (g_TestID == 1 || g_TestID == 2)
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
if (g_TestID == 2)
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
ADD_STATE(State_H_C7_F(META_IFACEPTR(C7)));
g_pC7->G();
@ -282,14 +292,14 @@ namespace
return 8;
}
C1 g_C1;
C2 g_C2;
C3 g_C3;
C4 g_C4;
C5 g_C5;
C6 g_C6;
C7 g_C7;
C8 g_C8;
C1_Derived g_C1;
C2_Derived g_C2;
C3_Derived g_C3;
C4_Derived g_C4;
C5_Derived g_C5;
C6_Derived g_C6;
C7_Derived g_C7;
C8_Derived g_C8;
}
bool TestReentr(std::string &error)
@ -306,22 +316,22 @@ bool TestReentr(std::string &error)
g_pC7 = &g_C7;
g_pC8 = &g_C8;
SH_ADD_HOOK_STATICFUNC(C1, F, g_pC1, Handler_C1_F, false);
SH_ADD_HOOK_STATICFUNC(C1, G, g_pC1, Handler_C1_G, false);
SH_ADD_HOOK_STATICFUNC(C2, F, g_pC2, Handler_C2_F, false);
SH_ADD_HOOK_STATICFUNC(C2, G, g_pC2, Handler_C2_G, false);
SH_ADD_HOOK_STATICFUNC(C3, F, g_pC3, Handler_C3_F, false);
SH_ADD_HOOK_STATICFUNC(C3, G, g_pC3, Handler_C3_G, false);
SH_ADD_HOOK_STATICFUNC(C4, F, g_pC4, Handler_C4_F, false);
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_ADD_HOOK_STATICFUNC(C5, F, g_pC5, Handler_C5_F, false);
SH_ADD_HOOK_STATICFUNC(C5, G, g_pC5, Handler_C5_G, false);
SH_ADD_HOOK_STATICFUNC(C6, F, g_pC6, Handler_C6_F, false);
SH_ADD_HOOK_STATICFUNC(C6, G, g_pC6, Handler_C6_G, false);
SH_ADD_HOOK_STATICFUNC(C7, F, g_pC7, Handler_C7_F, false);
SH_ADD_HOOK_STATICFUNC(C7, G, g_pC7, Handler_C7_G, false);
SH_ADD_HOOK_STATICFUNC(C8, F, g_pC8, Handler_C8_F, false);
SH_ADD_HOOK_STATICFUNC(C8, G, g_pC8, Handler_C8_G, false);
SH_ADD_HOOK(C1, F, g_pC1, SH_STATIC(Handler_C1_F), false);
SH_ADD_HOOK(C1, G, g_pC1, SH_STATIC(Handler_C1_G), false);
SH_ADD_HOOK(C2, F, g_pC2, SH_STATIC(Handler_C2_F), false);
SH_ADD_HOOK(C2, G, g_pC2, SH_STATIC(Handler_C2_G), false);
SH_ADD_HOOK(C3, F, g_pC3, SH_STATIC(Handler_C3_F), false);
SH_ADD_HOOK(C3, G, g_pC3, SH_STATIC(Handler_C3_G), false);
SH_ADD_HOOK(C4, F, g_pC4, SH_STATIC(Handler_C4_F), false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
SH_ADD_HOOK(C5, F, g_pC5, SH_STATIC(Handler_C5_F), false);
SH_ADD_HOOK(C5, G, g_pC5, SH_STATIC(Handler_C5_G), false);
SH_ADD_HOOK(C6, F, g_pC6, SH_STATIC(Handler_C6_F), false);
SH_ADD_HOOK(C6, G, g_pC6, SH_STATIC(Handler_C6_G), false);
SH_ADD_HOOK(C7, F, g_pC7, SH_STATIC(Handler_C7_F), false);
SH_ADD_HOOK(C7, G, g_pC7, SH_STATIC(Handler_C7_G), false);
SH_ADD_HOOK(C8, F, g_pC8, SH_STATIC(Handler_C8_F), false);
SH_ADD_HOOK(C8, G, g_pC8, SH_STATIC(Handler_C8_G), false);
g_pC1->F();
@ -361,7 +371,7 @@ bool TestReentr(std::string &error)
NULL), "1");
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
g_pC1->F();
@ -517,7 +527,7 @@ bool TestReentr(std::string &error)
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
g_TestID = 2;
@ -578,22 +588,22 @@ bool TestReentr(std::string &error)
new State_C1_F(g_pC1),
NULL), "7");
SH_REMOVE_HOOK_STATICFUNC(C1, F, g_pC1, Handler_C1_F, false);
SH_REMOVE_HOOK_STATICFUNC(C1, G, g_pC1, Handler_C1_G, false);
SH_REMOVE_HOOK_STATICFUNC(C2, F, g_pC2, Handler_C2_F, false);
SH_REMOVE_HOOK_STATICFUNC(C2, G, g_pC2, Handler_C2_G, false);
SH_REMOVE_HOOK_STATICFUNC(C3, F, g_pC3, Handler_C3_F, false);
SH_REMOVE_HOOK_STATICFUNC(C3, G, g_pC3, Handler_C3_G, false);
SH_REMOVE_HOOK_STATICFUNC(C4, F, g_pC4, Handler_C4_F, false);
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_REMOVE_HOOK_STATICFUNC(C5, F, g_pC5, Handler_C5_F, false);
SH_REMOVE_HOOK_STATICFUNC(C5, G, g_pC5, Handler_C5_G, false);
SH_REMOVE_HOOK_STATICFUNC(C6, F, g_pC6, Handler_C6_F, false);
SH_REMOVE_HOOK_STATICFUNC(C6, G, g_pC6, Handler_C6_G, false);
SH_REMOVE_HOOK_STATICFUNC(C7, F, g_pC7, Handler_C7_F, false);
SH_REMOVE_HOOK_STATICFUNC(C7, G, g_pC7, Handler_C7_G, false);
SH_REMOVE_HOOK_STATICFUNC(C8, F, g_pC8, Handler_C8_F, false);
SH_REMOVE_HOOK_STATICFUNC(C8, G, g_pC8, Handler_C8_G, false);
SH_REMOVE_HOOK(C1, F, g_pC1, SH_STATIC(Handler_C1_F), false);
SH_REMOVE_HOOK(C1, G, g_pC1, SH_STATIC(Handler_C1_G), false);
SH_REMOVE_HOOK(C2, F, g_pC2, SH_STATIC(Handler_C2_F), false);
SH_REMOVE_HOOK(C2, G, g_pC2, SH_STATIC(Handler_C2_G), false);
SH_REMOVE_HOOK(C3, F, g_pC3, SH_STATIC(Handler_C3_F), false);
SH_REMOVE_HOOK(C3, G, g_pC3, SH_STATIC(Handler_C3_G), false);
SH_REMOVE_HOOK(C4, F, g_pC4, SH_STATIC(Handler_C4_F), false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
SH_REMOVE_HOOK(C5, F, g_pC5, SH_STATIC(Handler_C5_F), false);
SH_REMOVE_HOOK(C5, G, g_pC5, SH_STATIC(Handler_C5_G), false);
SH_REMOVE_HOOK(C6, F, g_pC6, SH_STATIC(Handler_C6_F), false);
SH_REMOVE_HOOK(C6, G, g_pC6, SH_STATIC(Handler_C6_G), false);
SH_REMOVE_HOOK(C7, F, g_pC7, SH_STATIC(Handler_C7_F), false);
SH_REMOVE_HOOK(C7, G, g_pC7, SH_STATIC(Handler_C7_G), false);
SH_REMOVE_HOOK(C8, F, g_pC8, SH_STATIC(Handler_C8_F), false);
SH_REMOVE_HOOK(C8, G, g_pC8, SH_STATIC(Handler_C8_G), false);
return true;
}

View File

@ -76,6 +76,7 @@ namespace
return sth.Func();
}
};
class CHelloDerived : public CHello { };
class CHook
{
@ -99,11 +100,11 @@ bool TestRef(std::string &error)
CDerived der;
CDerived2 der2(11);
CDerived2 der3(12);
CHello hello;
CHelloDerived hello;
CHello *pHello = &hello;
CHook hook;
SourceHook::CallClass<CHello> *cc = SH_GET_CALLCLASS(&hello);
SourceHook::CallClass<CHello> *cc = SH_GET_CALLCLASS(pHello);
ADD_STATE(State_Result(pHello->Func(base)));
ADD_STATE(State_Result(pHello->Func(der)));
@ -129,7 +130,7 @@ bool TestRef(std::string &error)
new State_Result(12),
NULL), "Part 2");
SH_ADD_HOOK_MEMFUNC(CHello, Func, &hello, &hook, &CHook::Func, false);
SH_ADD_HOOK(CHello, Func, &hello, SH_MEMBER(&hook, &CHook::Func), false);
ADD_STATE(State_Result(pHello->Func(base)));
ADD_STATE(State_Result(pHello->Func(der)));

View File

@ -48,6 +48,10 @@ namespace
return m_Var2;
}
};
class Whatever : public Test
{
};
class CHook
{
@ -98,7 +102,7 @@ bool TestRefRet(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test test;
Whatever test;
Test *pTest = &test;
CHook hook;
@ -111,7 +115,7 @@ bool TestRefRet(std::string &error)
NULL), "Part 1");
// Now add Func1_Pre1, which supercedes and returns hook.m_Var
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre1, false);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
int &ret2 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret2));
@ -123,7 +127,7 @@ bool TestRefRet(std::string &error)
NULL), "Part 2");
// Now add Func1_Post1, which only reports orig ret and override ret
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post1, true);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
int &ret3 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret3));
@ -139,8 +143,8 @@ bool TestRefRet(std::string &error)
// Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337)
// and add Func1_Post2, which overrides and returns hook.m_Var again.
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre2, false);
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post2, true);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
int &ret4 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret4));
@ -160,7 +164,7 @@ bool TestRefRet(std::string &error)
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
// Through a callclass
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(&test);
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
int &ret5 = SH_CALL(cc1, &Test::Func1)();
ADD_STATE(State_Func1_Ret(&ret5));
@ -181,8 +185,8 @@ bool TestRefRet(std::string &error)
new State_Func2_Ret(&test.m_Var2),
NULL), "Part 6");
SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Pre1, false);
SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Post1, true);
SH_ADD_HOOK(Test, Func2, &test, SH_MEMBER(&hook, &CHook::Func2_Pre1), false);
SH_ADD_HOOK(Test, Func2, &test, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
const int &ret22 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret22));

View File

@ -0,0 +1,266 @@
#include <string>
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testevents.h"
// TEST VP HOOKS
// Test vfnptr-wide hooks
namespace
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
class IBase;
MAKE_STATE_1(State_D1_Func1, IBase *);
MAKE_STATE_1(State_D2_Func1, IBase *);
MAKE_STATE_1(State_Func1_Pre, IBase *);
MAKE_STATE_1(State_Func1_Post, IBase *);
MAKE_STATE_1(State_D1_Func2, IBase *);
MAKE_STATE_1(State_D2_Func2, IBase *);
MAKE_STATE_1(State_Func2_Pre, IBase *);
MAKE_STATE_1(State_Func2_Post, IBase *);
MAKE_STATE_2(State_D1_Func3, IBase *, int);
MAKE_STATE_2(State_D2_Func3, IBase *, int);
MAKE_STATE_2(State_Func3_Pre, IBase *, int);
MAKE_STATE_2(State_Func3_Post, IBase *, int);
class IBase
{
public:
virtual void Func1() = 0;
virtual void Func2() = 0;
virtual void Func3(int x) = 0;
};
class CDerived1 : public IBase
{
public:
virtual void Func1()
{
ADD_STATE(State_D1_Func1(this));
}
virtual void Func2()
{
ADD_STATE(State_D1_Func2(this));
}
virtual void Func3(int x)
{
ADD_STATE(State_D1_Func3(this, x));
}
};
class CDerived2 : public IBase
{
public:
virtual void Func1()
{
ADD_STATE(State_D2_Func1(this));
}
virtual void Func2()
{
ADD_STATE(State_D2_Func2(this));
}
virtual void Func3(int x)
{
ADD_STATE(State_D2_Func3(this, x));
}
};
void Handler_Func1_Pre()
{
ADD_STATE(State_Func1_Pre(META_IFACEPTR(IBase)));
}
void Handler_Func1_Post()
{
ADD_STATE(State_Func1_Post(META_IFACEPTR(IBase)));
}
int g_F2_Pre_HookToRemove = 0;
void Handler_Func2_Pre()
{
ADD_STATE(State_Func2_Pre(META_IFACEPTR(IBase)));
SH_REMOVE_HOOK_ID(g_F2_Pre_HookToRemove);
}
void Handler_Func2_Post()
{
ADD_STATE(State_Func2_Post(META_IFACEPTR(IBase)));
}
void Handler_Func3_Pre(int x)
{
ADD_STATE(State_Func3_Pre(META_IFACEPTR(IBase), x));
RETURN_META_NEWPARAMS(MRES_IGNORED, &IBase::Func3, (x+1));
}
void Handler_Func3_Post(int x)
{
ADD_STATE(State_Func3_Post(META_IFACEPTR(IBase), x));
}
SH_DECL_HOOK0_void(IBase, Func1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(IBase, Func2, SH_NOATTRIB, 0);
SH_DECL_HOOK1_void(IBase, Func3, SH_NOATTRIB, 0, int);
SH_DECL_MANUALHOOK1_void(IBase_Func3_Manual, 2, 0, 0, int);
}
bool TestVPHooks(std::string &error)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
CDerived1 d1i1;
CDerived1 d1i2;
CDerived2 d2i1;
IBase *p_d1i1 = &d1i1;
IBase *p_d1i2 = &d1i2;
IBase *p_d2i1 = &d2i1;
int hook1 = SH_ADD_VPHOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false);
p_d1i1->Func1();
p_d1i2->Func1();
p_d2i1->Func1();
CHECK_STATES((&g_States,
new State_Func1_Pre(p_d1i1),
new State_D1_Func1(p_d1i1),
new State_Func1_Pre(p_d1i2),
new State_D1_Func1(p_d1i2),
new State_D2_Func1(p_d2i1),
NULL), "Part 1");
SH_REMOVE_HOOK_ID(hook1);
p_d1i1->Func1();
p_d1i2->Func1();
p_d2i1->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 2");
// Normal hook, then vp hook
int hook2 = SH_ADD_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false);
hook1 = SH_ADD_VPHOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false);
p_d1i1->Func1();
p_d1i2->Func1();
p_d2i1->Func1();
CHECK_STATES((&g_States,
new State_Func1_Pre(p_d1i1),
new State_Func1_Pre(p_d1i1),
new State_D1_Func1(p_d1i1),
new State_Func1_Pre(p_d1i2),
new State_D1_Func1(p_d1i2),
new State_D2_Func1(p_d2i1),
NULL), "Part 3");
SH_REMOVE_HOOK_ID(hook1);
p_d1i1->Func1();
p_d1i2->Func1();
p_d2i1->Func1();
CHECK_STATES((&g_States,
new State_Func1_Pre(p_d1i1),
new State_D1_Func1(p_d1i1),
new State_D1_Func1(p_d1i2),
new State_D2_Func1(p_d2i1),
NULL), "Part 4");
SH_REMOVE_HOOK_ID(hook2);
p_d1i1->Func1();
p_d1i2->Func1();
p_d2i1->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 5");
// Test this:
// Normal hook AND vp hook on Func2
// Func2's pre handler removes the VP hook. It has to work anyway :)
hook1 = SH_ADD_VPHOOK(IBase, Func2, p_d1i1, SH_STATIC(Handler_Func2_Pre), false);
hook2 = SH_ADD_HOOK(IBase, Func2, p_d1i1, SH_STATIC(Handler_Func2_Pre), false);
g_F2_Pre_HookToRemove = hook1;
p_d1i1->Func2();
p_d1i1->Func2();
CHECK_STATES((&g_States,
new State_Func2_Pre(p_d1i1),
new State_Func2_Pre(p_d1i1),
new State_D1_Func2(p_d1i1),
new State_Func2_Pre(p_d1i1),
new State_D1_Func2(p_d1i1),
NULL), "Part 6");
SH_REMOVE_HOOK_ID(hook1);
// Hook function 3:
// Using manualhook, VP
hook1 = SH_ADD_MANUALVPHOOK(IBase_Func3_Manual, p_d1i1, SH_STATIC(Handler_Func3_Pre), false);
// Normally, VP
hook2 = SH_ADD_VPHOOK(IBase, Func3, p_d1i1, SH_STATIC(Handler_Func3_Pre), false);
// Normally, no VP
int hook3 = SH_ADD_HOOK(IBase, Func3, p_d1i1, SH_STATIC(Handler_Func3_Pre), false);
p_d1i1->Func3(1);
CHECK_STATES((&g_States,
new State_Func3_Pre(p_d1i1, 1), // manual vp hook
new State_Func3_Pre(p_d1i1, 2), // normal vp hook
new State_Func3_Pre(p_d1i1, 3), // normal non-vp hook
new State_D1_Func3(p_d1i1, 4), // function
NULL), "Part 7.1");
p_d1i2->Func3(1);
CHECK_STATES((&g_States,
new State_Func3_Pre(p_d1i2, 1), // manual vp hook
new State_Func3_Pre(p_d1i2, 2), // normal vp hook
new State_D1_Func3(p_d1i2, 3), // function
NULL), "Part 7.2");
SH_REMOVE_HOOK_ID(hook1);
SH_REMOVE_HOOK_ID(hook2);
SH_REMOVE_HOOK_ID(hook3);
return true;
}