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:
parent
9bf8799bf3
commit
8e446b28c3
@ -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); \
|
||||
} \
|
||||
|
@ -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
147
sourcehook/sh_listcat.h
Normal 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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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); \
|
||||
} \
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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[])
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)));
|
||||
|
@ -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));
|
||||
|
266
sourcehook/test/testvphooks.cpp
Normal file
266
sourcehook/test/testvphooks.cpp
Normal 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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user