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

One bugfix, addition of META_RETURN_(VALUE_)NEWPARAMS (implemented using recalls), tests now support compiling against an older version of sourcehook.h (through the sourcehook_test.h file) while main.cpp which now also acts as a CSourceHookImpl factory compiles against the new version.

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40163
This commit is contained in:
Pavol Marko 2005-12-23 11:58:11 +00:00
parent 196071466b
commit 9eb35c8830
20 changed files with 1001 additions and 274 deletions

View File

@ -372,7 +372,7 @@ namespace SourceHook
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual void SetOverrideRetPtr(void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
/**
@ -382,22 +382,89 @@ namespace SourceHook
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) = 0;
virtual void DoRecall() = 0; //!< Initiates a recall sequence
/*
HOW RECALLS WORK:
The problem:
Users want the ability to change parameters of the called function
from inside their handler.
The solution:
1) Mark as "recall"
2) Recall the function
3) => SH's hook func gets called:
4) The first iterator points at the first hook the last hookfunc didn't execute yet
5) does all iteration and returns normally
6) The user's handler returns immediately
7) The hook func returns immediately as well
Also note that the recalled hookfunc starts with the status the recalling hookfunc
ended with. The last handler (doing the recall) is also able to specify its own
META_RES.
*/
virtual void *GetOverrideRetPtr() = 0; //!< Returns the pointer set by SetOverrideRetPtr
/**
* @brief Set up the hook loop. Equivalent to calling:
* SetStatusPtr, SetPrevResPtr, SetCurResPtr, SetIfacePtrPtr, SetOrigRetPtr, Get/SetOverrideRetPtr
*
* @param statusPtr pointer to status variable
* @param prevResPtr pointer to previous result variable
* @param curResPtr pointer to current result variable
* @param ifacePtrPtr pointer to interface this pointer variable
* @param origRetPr pointer to original return value variable. NULL for void funcs
* @param overrideRetPtr pointer to override return value variable. NULL for void funcs
*
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
};
}
/************************************************************************/
/* High level interface */
/************************************************************************/
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
#define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOrigRet())
#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOverrideRet())
#define META_IFACEPTR(type) reinterpret_cast<type*>(SH_GLOB_SHPTR->GetIfacePtr())
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
// NEVER-EVER call these from post hooks!
// also, only call it from the hook handlers directly!
// :TODO: enforce it
// :TODO: problems with SetOverrideResult and overloaded iface::func ?
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
if ((result) >= MRES_OVERRIDE) \
{ \
/* meh, set the override result here because we don't get a chance to return */ \
/* before continuing the hook loop through the recall */ \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, &iface::func, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
} while (0)
/**
* @brief Get/generate callclass for an interface pointer
@ -542,8 +609,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0) \
return false; /* No virtual inheritance supported */ \
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, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
@ -659,16 +726,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
rettype *pOverrideRet = reinterpret_cast<rettype*>(SH_GLOB_SHPTR->SetupHookLoop( \
&status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret));
#define SH_CALL_HOOKS(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -683,10 +746,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res > status) \
status = cur_res; \
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
*pOverrideRet = plugin_ret; \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
@ -703,11 +763,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
else \
orig_ret = override_ret;
orig_ret = override_ret; \
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
return status >= MRES_OVERRIDE ? *pOverrideRet : orig_ret;
#define SH_HANDLEFUNC(paramtypes, params, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params) \
@ -743,13 +803,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
SH_GLOB_SHPTR->SetupHookLoop(&status, &prev_res, &cur_res, &ifptr, NULL, NULL); \
#define SH_CALL_HOOKS_void(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -791,6 +846,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
// Special vafmt handlers
// :TODO: what
#define SH_HANDLEFUNC_vafmt(paramtypes, params_orig, params_plug, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params_orig) \
SH_CALL_HOOKS(pre, params_plug) \
@ -3497,6 +3553,121 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// These take a ISourceHook pointer instead of using SH_GLOB_SHPTR directly
// The reason is that the user may want to redefine SH_GLOB_SHPTR - then the macros
// (META_RETURN_VALUE_NEWPARAMS) should obey the new pointer.
namespace SourceHook
{
template <class Iface, class RetType>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
}
#endif
// The pope is dead. -> :(

View File

@ -372,7 +372,7 @@ namespace SourceHook
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual void SetOverrideRetPtr(void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
/**
@ -382,22 +382,89 @@ namespace SourceHook
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) = 0;
virtual void DoRecall() = 0; //!< Initiates a recall sequence
/*
HOW RECALLS WORK:
The problem:
Users want the ability to change parameters of the called function
from inside their handler.
The solution:
1) Mark as "recall"
2) Recall the function
3) => SH's hook func gets called:
4) The first iterator points at the first hook the last hookfunc didn't execute yet
5) does all iteration and returns normally
6) The user's handler returns immediately
7) The hook func returns immediately as well
Also note that the recalled hookfunc starts with the status the recalling hookfunc
ended with. The last handler (doing the recall) is also able to specify its own
META_RES.
*/
virtual void *GetOverrideRetPtr() = 0; //!< Returns the pointer set by SetOverrideRetPtr
/**
* @brief Set up the hook loop. Equivalent to calling:
* SetStatusPtr, SetPrevResPtr, SetCurResPtr, SetIfacePtrPtr, SetOrigRetPtr, Get/SetOverrideRetPtr
*
* @param statusPtr pointer to status variable
* @param prevResPtr pointer to previous result variable
* @param curResPtr pointer to current result variable
* @param ifacePtrPtr pointer to interface this pointer variable
* @param origRetPr pointer to original return value variable. NULL for void funcs
* @param overrideRetPtr pointer to override return value variable. NULL for void funcs
*
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
};
}
/************************************************************************/
/* High level interface */
/************************************************************************/
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
#define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOrigRet())
#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOverrideRet())
#define META_IFACEPTR(type) reinterpret_cast<type*>(SH_GLOB_SHPTR->GetIfacePtr())
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
// NEVER-EVER call these from post hooks!
// also, only call it from the hook handlers directly!
// :TODO: enforce it
// :TODO: problems with SetOverrideResult and overloaded iface::func ?
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
if ((result) >= MRES_OVERRIDE) \
{ \
/* meh, set the override result here because we don't get a chance to return */ \
/* before continuing the hook loop through the recall */ \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, &iface::func, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
} while (0)
/**
* @brief Get/generate callclass for an interface pointer
@ -542,8 +609,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0) \
return false; /* No virtual inheritance supported */ \
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, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
@ -659,16 +726,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
rettype *pOverrideRet = reinterpret_cast<rettype*>(SH_GLOB_SHPTR->SetupHookLoop( \
&status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret));
#define SH_CALL_HOOKS(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -683,10 +746,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res > status) \
status = cur_res; \
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
*pOverrideRet = plugin_ret; \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
@ -703,11 +763,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
else \
orig_ret = override_ret;
orig_ret = override_ret; \
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
return status >= MRES_OVERRIDE ? *pOverrideRet : orig_ret;
#define SH_HANDLEFUNC(paramtypes, params, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params) \
@ -743,13 +803,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
SH_GLOB_SHPTR->SetupHookLoop(&status, &prev_res, &cur_res, &ifptr, NULL, NULL); \
#define SH_CALL_HOOKS_void(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -791,6 +846,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
// Special vafmt handlers
// :TODO: what
#define SH_HANDLEFUNC_vafmt(paramtypes, params_orig, params_plug, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params_orig) \
SH_CALL_HOOKS(pre, params_plug) \
@ -1025,5 +1081,22 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@Param%%|, @@
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// These take a ISourceHook pointer instead of using SH_GLOB_SHPTR directly
// The reason is that the user may want to redefine SH_GLOB_SHPTR - then the macros
// (META_RETURN_VALUE_NEWPARAMS) should obey the new pointer.
namespace SourceHook
{
@VARARGS@
template <class Iface, class RetType@, class Param%%@>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(@Param%%|, @), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
@ENDARGS@
}
#endif
// The pope is dead. -> :(

View File

@ -174,6 +174,16 @@ namespace SourceHook
return m_Elements[m_UsedSize - 1];
}
T &second()
{
return m_Elements[m_UsedSize - 2];
}
const T &second() const
{
return m_Elements[m_UsedSize - 2];
}
iterator begin()
{
return iterator(this, 0);

View File

@ -627,6 +627,7 @@ namespace SourceHook
HookLoopInfo hli;
hli.pCurIface = pIface;
hli.shouldContinue = true;
hli.recall = false;
m_HLIStack.push(hli);
}
@ -657,6 +658,20 @@ namespace SourceHook
const void *CSourceHookImpl::GetOverrideRet()
{
// pOverrideRet is always set since recalls were introduced
// GetOverrideRetPtr was added; a function which always returns pOverrideRet
// so that RETURN_META_VALUE_NEWPARAMS can provide an override result
// This means that we have to filter GetOverrideRet:
// If the status variable is < MRES_OVERRIDE, return NULL.
return (*m_HLIStack.front().pStatus < MRES_OVERRIDE) ?
NULL : m_HLIStack.front().pOverrideRet;
}
void *CSourceHookImpl::GetOverrideRetPtr()
{
// As described in the comment above: always return pOverrideRet
return m_HLIStack.front().pOverrideRet;
}
@ -673,11 +688,19 @@ namespace SourceHook
void CSourceHookImpl::SetPrevResPtr(META_RES *mres)
{
m_HLIStack.front().pPrevRes = mres;
// If we're recalling, drag the previous mres value to the new hookfunc
if (m_HLIStack.size() > 1 && m_HLIStack.second().recall)
*mres = *m_HLIStack.second().pPrevRes;
}
void CSourceHookImpl::SetStatusPtr(META_RES *mres)
{
m_HLIStack.front().pStatus = mres;
// If we're recalling, drag the previous mres value to the new hookfunc
if (m_HLIStack.size() > 1 && m_HLIStack.second().recall)
*mres = *m_HLIStack.second().pStatus;
}
void CSourceHookImpl::SetIfacePtrPtr(void **pp)
@ -689,13 +712,61 @@ namespace SourceHook
{
m_HLIStack.front().pOrigRet = ptr;
}
void CSourceHookImpl::SetOverrideRetPtr(const void *ptr)
void CSourceHookImpl::SetOverrideRetPtr(void *ptr)
{
m_HLIStack.front().pOverrideRet = ptr;
}
// New function which does all of the above + more :)
void *CSourceHookImpl::SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr)
{
HookLoopInfo &hli = m_HLIStack.front();
hli.pStatus = statusPtr;
hli.pPrevRes = prevResPtr;
hli.pCurRes = curResPtr;
hli.pIfacePtrPtr = ifacePtrPtr;
hli.pOrigRet = origRetPtr;
// Handle some recall stuff
if (m_HLIStack.size() > 1 && m_HLIStack.second().recall)
{
HookLoopInfo &other = m_HLIStack.second();
*statusPtr = *other.pStatus;
*prevResPtr = *other.pStatus;
hli.pOverrideRet = other.pOverrideRet;
}
else
hli.pOverrideRet = overrideRetPtr;
// Tell the hook func which override ret ptr to use
return hli.pOverrideRet;
}
bool CSourceHookImpl::ShouldContinue()
{
return m_HLIStack.front().shouldContinue;
// If recall is true, we shall not continue either.
// This is because, if it's true and ShouldContinue is called, it suggests that the
// actual recall is done and that we are back in the original handler which shall return
// immediately.
return m_HLIStack.front().shouldContinue && !m_HLIStack.front().recall;
}
void CSourceHookImpl::DoRecall()
{
if (!m_HLIStack.empty())
{
m_HLIStack.front().recall = true;
CHookList *mlist = static_cast<CHookList*>(m_HLIStack.front().pCurIface->GetPreHooks());
mlist->m_Recall = true;
// The hookfunc usually do this, but it won't have a chance to see it,
// so for recalls, we update status here if it's required
if (*m_HLIStack.front().pCurRes > *m_HLIStack.front().pStatus)
*m_HLIStack.front().pStatus = *m_HLIStack.front().pCurRes;
}
}
////////////////////////////
@ -897,12 +968,15 @@ namespace SourceHook
// CHookList
////////////////////////////
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL), m_UsedIters(NULL)
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL), m_UsedIters(NULL),
m_Recall(false)
{
}
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List), m_FreeIters(NULL), m_UsedIters(NULL)
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List),
m_FreeIters(NULL), m_UsedIters(NULL), m_Recall(false)
{
}
CSourceHookImpl::CHookList::~CHookList()
{
while (m_FreeIters)
@ -932,12 +1006,22 @@ namespace SourceHook
ret = new CIter(this);
}
// Muuuh, if we're recalling, it shall be a copy of the last iterator, incremented by one
if (m_Recall && m_UsedIters)
{
ret->Set(m_UsedIters); // m_UsedIters is the last returned and not released iterator
ret->Next(); // Use next instead of directly incrementing its m_Iter:
// skips paused plugins
}
ret->m_pNext = m_UsedIters;
ret->m_pPrev = NULL;
if (m_UsedIters)
m_UsedIters->m_pPrev = ret;
m_UsedIters = ret;
m_Recall = false;
return ret;
}
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
@ -958,6 +1042,9 @@ namespace SourceHook
pIter2->m_pNext = m_FreeIters;
m_FreeIters = pIter2;
// Reset recall state.
m_Recall = false;
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList), m_pNext(NULL)
@ -968,6 +1055,11 @@ namespace SourceHook
{
}
void CSourceHookImpl::CHookList::CIter::Set(CIter *pOther)
{
m_Iter = pOther->m_Iter;
}
void CSourceHookImpl::CHookList::CIter::GoToBegin()
{
m_Iter = m_pList->m_List.begin();

View File

@ -372,7 +372,7 @@ namespace SourceHook
virtual void SetStatusPtr(META_RES *mres) = 0; //!< Sets pointer to the status variable
virtual void SetIfacePtrPtr(void **pp) = 0; //!< Sets pointer to the interface this pointer
virtual void SetOrigRetPtr(const void *ptr) = 0; //!< Sets the original return pointer
virtual void SetOverrideRetPtr(const void *ptr) = 0; //!< Sets the override result pointer
virtual void SetOverrideRetPtr(void *ptr) = 0; //!< Sets the override result pointer
virtual bool ShouldContinue() = 0; //!< Returns false if the hook loop should exit
/**
@ -382,22 +382,89 @@ namespace SourceHook
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) = 0;
virtual void DoRecall() = 0; //!< Initiates a recall sequence
/*
HOW RECALLS WORK:
The problem:
Users want the ability to change parameters of the called function
from inside their handler.
The solution:
1) Mark as "recall"
2) Recall the function
3) => SH's hook func gets called:
4) The first iterator points at the first hook the last hookfunc didn't execute yet
5) does all iteration and returns normally
6) The user's handler returns immediately
7) The hook func returns immediately as well
Also note that the recalled hookfunc starts with the status the recalling hookfunc
ended with. The last handler (doing the recall) is also able to specify its own
META_RES.
*/
virtual void *GetOverrideRetPtr() = 0; //!< Returns the pointer set by SetOverrideRetPtr
/**
* @brief Set up the hook loop. Equivalent to calling:
* SetStatusPtr, SetPrevResPtr, SetCurResPtr, SetIfacePtrPtr, SetOrigRetPtr, Get/SetOverrideRetPtr
*
* @param statusPtr pointer to status variable
* @param prevResPtr pointer to previous result variable
* @param curResPtr pointer to current result variable
* @param ifacePtrPtr pointer to interface this pointer variable
* @param origRetPr pointer to original return value variable. NULL for void funcs
* @param overrideRetPtr pointer to override return value variable. NULL for void funcs
*
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
};
}
/************************************************************************/
/* High level interface */
/************************************************************************/
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
#define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOrigRet())
#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast<const type*>(SH_GLOB_SHPTR->GetOverrideRet())
#define META_IFACEPTR(type) reinterpret_cast<type*>(SH_GLOB_SHPTR->GetIfacePtr())
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0)
// NEVER-EVER call these from post hooks!
// also, only call it from the hook handlers directly!
// :TODO: enforce it
// :TODO: problems with SetOverrideResult and overloaded iface::func ?
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
if ((result) >= MRES_OVERRIDE) \
{ \
/* meh, set the override result here because we don't get a chance to return */ \
/* before continuing the hook loop through the recall */ \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, &iface::func, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
} while (0)
/**
* @brief Get/generate callclass for an interface pointer
@ -542,8 +609,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
using namespace ::SourceHook; \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0) \
return false; /* No virtual inheritance supported */ \
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, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
@ -659,16 +726,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
rettype orig_ret; \
rettype override_ret; \
rettype plugin_ret; \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOrigRetPtr(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL);
rettype *pOverrideRet = reinterpret_cast<rettype*>(SH_GLOB_SHPTR->SetupHookLoop( \
&status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret));
#define SH_CALL_HOOKS(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -683,10 +746,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (cur_res > status) \
status = cur_res; \
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
SH_GLOB_SHPTR->SetOverrideRetPtr(&override_ret); \
} \
*pOverrideRet = plugin_ret; \
if (!SH_GLOB_SHPTR->ShouldContinue()) \
{ \
iter.SetToZero(); \
@ -703,11 +763,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
orig_ret = (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \
else \
orig_ret = override_ret;
orig_ret = override_ret; \
#define SH_RETURN() \
SH_GLOB_SHPTR->HookLoopEnd(); \
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
return status >= MRES_OVERRIDE ? *pOverrideRet : orig_ret;
#define SH_HANDLEFUNC(paramtypes, params, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params) \
@ -743,13 +803,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
META_RES status = MRES_IGNORED; \
META_RES prev_res; \
META_RES cur_res; \
SH_GLOB_SHPTR->SetStatusPtr(&status); \
SH_GLOB_SHPTR->SetPrevResPtr(&prev_res); \
SH_GLOB_SHPTR->SetCurResPtr(&cur_res); \
void* ifptr; \
SH_GLOB_SHPTR->SetIfacePtrPtr(&ifptr); \
SH_GLOB_SHPTR->SetOverrideRetPtr(NULL); \
SH_GLOB_SHPTR->SetOrigRetPtr(NULL);
SH_GLOB_SHPTR->SetupHookLoop(&status, &prev_res, &cur_res, &ifptr, NULL, NULL); \
#define SH_CALL_HOOKS_void(post, params) \
if (SH_GLOB_SHPTR->ShouldContinue()) \
@ -791,6 +846,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
// Special vafmt handlers
// :TODO: what
#define SH_HANDLEFUNC_vafmt(paramtypes, params_orig, params_plug, rettype) \
SH_SETUPCALLS(rettype, paramtypes, params_orig) \
SH_CALL_HOOKS(pre, params_plug) \
@ -3497,6 +3553,121 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// These take a ISourceHook pointer instead of using SH_GLOB_SHPTR directly
// The reason is that the user may want to redefine SH_GLOB_SHPTR - then the macros
// (META_RETURN_VALUE_NEWPARAMS) should obey the new pointer.
namespace SourceHook
{
template <class Iface, class RetType>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20), const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
}
#endif
// The pope is dead. -> :(

View File

@ -76,6 +76,7 @@ namespace SourceHook
virtual ~CIter();
void GoToBegin();
void Set(CIter *pOther);
bool End();
void Next();
@ -89,7 +90,16 @@ namespace SourceHook
};
CIter *m_FreeIters;
CIter *m_UsedIters;
CIter *m_UsedIters; // The last returned and not-yet-released iter is always m_UsedIters
// For recalls
bool m_Recall;
void SetRecallState(); // Sets the list into a state where the next returned
// iterator (from GetIter) will be a copy of the last
// returned iterator, incremented by one. This is used in Recalls.
// The hook resets this state automatically on:
// GetIter, ReleaseIter
CHookList();
CHookList(const CHookList &other);
@ -165,6 +175,8 @@ namespace SourceHook
VfnPtrList m_VfnPtrs;
int m_HookFuncVersion;
public:
virtual ~CHookManagerInfo();
@ -221,10 +233,11 @@ namespace SourceHook
META_RES *pCurRes;
bool shouldContinue;
bool recall; //!< True if we're in a recall, eh.
IIface *pCurIface;
const void *pOrigRet;
const void *pOverrideRet;
void *pOverrideRet;
void **pIfacePtrPtr;
};
typedef CStack<HookLoopInfo> HookLoopInfoStack;
@ -357,7 +370,7 @@ namespace SourceHook
void SetStatusPtr(META_RES *mres); //!< Sets pointer to the status variable
void SetIfacePtrPtr(void **pp); //!< Sets pointer to the interface this pointer
void SetOrigRetPtr(const void *ptr); //!< Sets the original return pointer
void SetOverrideRetPtr(const void *ptr); //!< Sets the override result pointer
void SetOverrideRetPtr(void *ptr); //!< Sets the override result pointer
bool ShouldContinue(); //!< Returns false if the hook loop should exit
/**
@ -367,6 +380,11 @@ namespace SourceHook
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc);
virtual void DoRecall(); //!< Initiates a recall sequence
virtual void *GetOverrideRetPtr(); //!< Returns the pointer set by SetOverrideRetPtr
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr);
};
}

View File

@ -2,6 +2,7 @@
// hello pm how are you
// I'm fine, what about you?
// not bad, just looking for mem leaks
// mem leaks in my code!? never! I have to preserve binary compatibility :(
// This is a test file
#include <stdio.h>
@ -75,6 +76,7 @@ DO_TEST(PlugSys);
DO_TEST(Bail);
DO_TEST(Reentr);
DO_TEST(Manual);
DO_TEST(Recall);
int main(int argc, char *argv[])
{
@ -90,3 +92,37 @@ int main(int argc, char *argv[])
cin.read(&x, 1);
}
SourceHook::ISourceHook *Test_Factory()
{
return new SourceHook::CSourceHookImpl();
}
void Test_Delete(SourceHook::ISourceHook *shptr)
{
delete static_cast<SourceHook::CSourceHookImpl *>(shptr);
}
void Test_CompleteShutdown(SourceHook::ISourceHook *shptr)
{
static_cast<SourceHook::CSourceHookImpl *>(shptr)->CompleteShutdown();
}
bool Test_IsPluginInUse(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return static_cast<SourceHook::CSourceHookImpl *>(shptr)->IsPluginInUse(plug);
}
void Test_UnloadPlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
static_cast<SourceHook::CSourceHookImpl *>(shptr)->UnloadPlugin(plug);
}
void Test_PausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
static_cast<SourceHook::CSourceHookImpl *>(shptr)->PausePlugin(plug);
}
void Test_UnpausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
static_cast<SourceHook::CSourceHookImpl *>(shptr)->UnpausePlugin(plug);
}

View File

@ -0,0 +1,27 @@
// This file is used for backwards compatibility testing
// It allows us to test binary backwards compatibility by using an older include file HERE:
#include "sourcehook.h" // <-- here
// There. main.cpp which implements all of the following function is always usign sourcehook.h
// and the up-to-date sourcehook_impl.h/sourcehook.cpp. The tests use this file however.
// If the test needs an up-to-date version (like the recall test), it can simply
// #include "sourcehook.h" before including this, thus overriding our decision.
SourceHook::ISourceHook *Test_Factory();
void Test_Delete(SourceHook::ISourceHook *shptr);
struct CSHPtrAutoDestruction
{
SourceHook::ISourceHook *m_SHPtr;
CSHPtrAutoDestruction(SourceHook::ISourceHook *shptr) : m_SHPtr(shptr) {}
~CSHPtrAutoDestruction() { Test_Delete(m_SHPtr); }
};
#define GET_SHPTR(var) var = Test_Factory(); CSHPtrAutoDestruction ___autodestruction(var);
// Access to CSourceHookImpl functions
void Test_CompleteShutdown(SourceHook::ISourceHook *shptr);
bool Test_IsPluginInUse(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
void Test_UnloadPlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
void Test_PausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
void Test_UnpausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);

View File

@ -262,6 +262,9 @@
<File
RelativePath=".\testbail.cpp">
</File>
<File
RelativePath=".\testbail.h">
</File>
<File
RelativePath=".\testbail2.cpp">
</File>
@ -277,6 +280,9 @@
GeneratePreprocessedFile="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\testrecall.cpp">
</File>
<File
RelativePath=".\testreentr.cpp">
</File>
@ -305,6 +311,9 @@
<File
RelativePath="..\sourcehook_impl.h">
</File>
<File
RelativePath=".\sourcehook_test.h">
</File>
<File
RelativePath="testevents.h">
</File>

View File

@ -1,5 +1,5 @@
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook_test.h"
#include "testevents.h"
#include "sh_memory.h"
@ -92,7 +92,7 @@ namespace
virtual void F57(){}
virtual void F58(){}
virtual void F59(){}
virtual void F60(){}
virtual void F60(int &hello){}
virtual void F61(){}
virtual void F62(){}
virtual void F63(){}
@ -350,6 +350,8 @@ namespace
SH_DECL_HOOK0_void(Test, F9, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, F10, SH_NOATTRIB, 0);
SH_DECL_HOOK1_void(Test, F60, SH_NOATTRIB, 0, int&);
META_RES g_F1Pre_WhatToDo;
META_RES g_F1Post_WhatToDo;
@ -384,8 +386,18 @@ namespace
!META_RESULT_ORIG_RET(bool));
}
void F60_Pre(int &hello)
{
hello = 10;
}
}
template <class T> T func(T a)
{
return a;
}
bool TestBasic(std::string &error)
{
// Simple test for ModuleInMemory
@ -399,8 +411,7 @@ bool TestBasic(std::string &error)
new State_ModuleInMemory(false),
NULL), "ModuleInMemory");
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
HandlersF1 f1_handlers;
@ -676,7 +687,13 @@ bool TestBasic(std::string &error)
SH_REMOVE_HOOK_MEMFUNC(Test, F9, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F10, pTest, &f1_handlers, &HandlersF1::Pre, false);
g_SHImpl.CompleteShutdown();
SH_ADD_HOOK_STATICFUNC(Test, F60, pTest, F60_Pre, false);
int a = 0;
pTest->F60(a);
Test_CompleteShutdown(g_SHPtr);
CHECK_COND(a == 10, "Part12.a");
return true;
}

View File

@ -1,5 +1,5 @@
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook_test.h"
#include "testevents.h"
#include <stdarg.h>
@ -89,8 +89,7 @@ namespace
bool TestVafmtAndOverload(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
IGaben gabgab;

View File

@ -1,5 +1,5 @@
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook_test.h"
#include "testevents.h"
// TEST3
@ -69,8 +69,7 @@ namespace
bool TestThisPtrOffs(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Derived inst;

View File

@ -1,5 +1,5 @@
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook_test.h"
#include "testevents.h"
// TEST4
@ -60,8 +60,7 @@ namespace
bool TestPlugSys(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test inst;
@ -86,7 +85,7 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 1.1");
g_SHImpl.CompleteShutdown();
Test_CompleteShutdown(g_SHPtr);
pInst->Func1();
pInst->Func2();
@ -139,10 +138,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 2.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -152,7 +151,7 @@ bool TestPlugSys(std::string &error)
NULL), "Part 2.2");
// Unload plugins one by one
g_SHImpl.UnloadPlugin(3);
Test_UnloadPlugin(g_SHPtr, 3);
pInst->Func1();
pInst->Func2();
@ -170,10 +169,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 2.3.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -182,7 +181,7 @@ bool TestPlugSys(std::string &error)
new State_PluginInUse(4, false),
NULL), "Part 2.3.2");
g_SHImpl.UnloadPlugin(2);
Test_UnloadPlugin(g_SHPtr, 2);
pInst->Func1();
pInst->Func2();
@ -197,10 +196,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 2.4.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -209,7 +208,7 @@ bool TestPlugSys(std::string &error)
new State_PluginInUse(4, false),
NULL), "Part 2.4.2");
g_SHImpl.UnloadPlugin(1);
Test_UnloadPlugin(g_SHPtr, 1);
pInst->Func1();
pInst->Func2();
@ -221,10 +220,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 2.5.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, false),
@ -275,10 +274,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 3.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -288,7 +287,7 @@ bool TestPlugSys(std::string &error)
NULL), "Part 3.2");
// Unload plugins one by one
g_SHImpl.PausePlugin(3);
Test_PausePlugin(g_SHPtr, 3);
pInst->Func1();
pInst->Func2();
@ -306,10 +305,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 3.3.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -318,7 +317,7 @@ bool TestPlugSys(std::string &error)
new State_PluginInUse(4, false),
NULL), "Part 3.3.2");
g_SHImpl.PausePlugin(2);
Test_PausePlugin(g_SHPtr, 2);
pInst->Func1();
pInst->Func2();
@ -333,10 +332,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 3.4.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -345,7 +344,7 @@ bool TestPlugSys(std::string &error)
new State_PluginInUse(4, false),
NULL), "Part 3.4.2");
g_SHImpl.PausePlugin(1);
Test_PausePlugin(g_SHPtr, 1);
pInst->Func1();
pInst->Func2();
@ -357,10 +356,10 @@ bool TestPlugSys(std::string &error)
new State_Func3_Called,
NULL), "Part 3.5.1");
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -369,14 +368,14 @@ bool TestPlugSys(std::string &error)
new State_PluginInUse(4, false),
NULL), "Part 3.5.2");
g_SHImpl.UnpausePlugin(1);
g_SHImpl.UnpausePlugin(2);
g_SHImpl.UnpausePlugin(3);
Test_UnpausePlugin(g_SHPtr, 1);
Test_UnpausePlugin(g_SHPtr, 2);
Test_UnpausePlugin(g_SHPtr, 3);
ADD_STATE(State_PluginInUse(1, g_SHImpl.IsPluginInUse(1)));
ADD_STATE(State_PluginInUse(2, g_SHImpl.IsPluginInUse(2)));
ADD_STATE(State_PluginInUse(3, g_SHImpl.IsPluginInUse(3)));
ADD_STATE(State_PluginInUse(4, g_SHImpl.IsPluginInUse(4)));
ADD_STATE(State_PluginInUse(1, Test_IsPluginInUse(g_SHPtr, 1)));
ADD_STATE(State_PluginInUse(2, Test_IsPluginInUse(g_SHPtr, 2)));
ADD_STATE(State_PluginInUse(3, Test_IsPluginInUse(g_SHPtr, 3)));
ADD_STATE(State_PluginInUse(4, Test_IsPluginInUse(g_SHPtr, 4)));
CHECK_STATES((&g_States,
new State_PluginInUse(1, true),
@ -405,7 +404,7 @@ bool TestPlugSys(std::string &error)
NULL), "Part 3.7");
// 4) Shutdown :)
g_SHImpl.CompleteShutdown();
Test_CompleteShutdown(g_SHPtr);
pInst->Func1();
pInst->Func2();

View File

@ -1,74 +1,103 @@
// TESTBAIL
// Test for a bug Bail has found
// This test used to be a test for a bug BAIL found.
// That bug is now fixed so I've granted BAIL the pleasure of being a test for
// the correct priority ordering of hook managers based on their version.
/*
THE PROBLEM:
Old hook funcs don't work right when you combine override returns and recalls.
THE SOLUTION:
Always use a new hook func when possible. For this, hook funcs have to be able to say
" HELLO I'M NEW! "
This file tests that functionality.
How it works:
testbail.cpp compiles with old version of sourcehook.h.
It sets everything up, adds a hook on a function
Then testbail2.cpp which has the new version adds a hook on the same function and
does a recall and overrides the value in it.
*/
#include "sourcehook_test.h"
#include "testbail.h"
void *___testbail_gabgab;
SourceHook::ISourceHook *___testbail_shptr;
namespace
{
class zomg_lolz
{
public:
virtual void zomg()
{
}
};
SH_DECL_HOOK0_void(zomg_lolz, zomg, SH_NOATTRIB, 0);
void Handler()
{
SH_REMOVE_HOOK_STATICFUNC(zomg_lolz, zomg, META_IFACEPTR(zomg_lolz),
Handler, false);
}
void Handler2()
int EatYams_Handler1(int a)
{
ADD_STATE(State_EatYams_Handler1_Called(a));
RETURN_META_VALUE(MRES_IGNORED, 0);
}
}
// These are here so they can access this CU's g_States
int ___testbail_EatYams_Handler2(int a)
{
ADD_STATE(State_EatYams_Handler2_Called(a));
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, 6, IGaben, EatYams, (0xBEEF));
}
int ___testbail_EatYams_Handler3(int a)
{
ADD_STATE(State_EatYams_Handler3_Called(a));
RETURN_META_VALUE(MRES_IGNORED, 0);
}
bool TestBail(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1;
g_Gabgab = new IGaben;
___testbail_gabgab = (void*)g_Gabgab;
___testbail_shptr = g_SHPtr;
g_Gabgab->EatYams();
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams0_Handler, false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
g_Gabgab->EatYams();
CHECK_STATES((&g_States,
new State_EatYams_Handler1_Called(0xDEAD),
new State_EatYams_Called(0xDEAD),
new State_EatYams_Return(5),
NULL), "Part 1");
___TestBail2();
g_Gabgab->EatYams();
if (!___TestBail2(error))
return false;
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams0_Handler, false);
CHECK_STATES((&g_States,
new State_EatYams_Handler1_Called(0xDEAD),
new State_EatYams_Handler2_Called(0xDEAD),
new State_EatYams_Handler3_Called(0xBEEF),
new State_EatYams_Called(0xBEEF),
NULL), "Part 2.1");
g_Gabgab->EatYams();
// WHAT IF NOW SOMEONE UNLOADS PLUGIN 2 !?!?!?!?
Test_UnloadPlugin(g_SHPtr, 2);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
CHECK_STATES((&g_States,
new State_EatYams_Handler1_Called(0xDEAD),
new State_EatYams_Called(0xDEAD),
new State_EatYams_Return(5),
NULL), "Part 3");
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
CHECK_STATES((&g_States,
new State_EatYams_Called(0xDEAD),
new State_EatYams_Return(5),
NULL), "Part 4");
delete g_Gabgab;
// If it didn't crash, it's ok
// NEW TEST: Remove hook from handler
zomg_lolz inst;
SH_ADD_HOOK_STATICFUNC(zomg_lolz, zomg, &inst, Handler, false);
SH_ADD_HOOK_STATICFUNC(zomg_lolz, zomg, &inst, Handler2, false);
zomg_lolz *mwah = &inst;
mwah->zomg();
mwah->zomg();
SH_ADD_HOOK_STATICFUNC(zomg_lolz, zomg, &inst, Handler, false);
SH_REMOVE_HOOK_STATICFUNC(zomg_lolz, zomg, &inst, Handler2, false);
mwah->zomg();
mwah->zomg();
// Shouldn't crash again...
return true;
}

View File

@ -2,13 +2,9 @@
// Shared data for testbail
#include <string>
#include "sourcehook_impl.h"
#include "testevents.h"
#include <stdarg.h>
#include <list>
#include <algorithm>
void ___TestBail2();
bool ___TestBail2(std::string &error);
namespace
{
@ -16,79 +12,28 @@ namespace
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
MAKE_STATE(State_EatYams_Called);
MAKE_STATE(State_EatYams_Handler_Called);
MAKE_STATE_1(State_EatYams_Called, int);
MAKE_STATE_1(State_EatYams_Handler1_Called, int);
MAKE_STATE_1(State_EatYams_Handler2_Called, int);
MAKE_STATE_1(State_EatYams_Handler3_Called, int);
MAKE_STATE_1(State_EatYams_Return, int);
class IGaben
{
public:
virtual void EatYams()
virtual int EatYams(int a)
{
ADD_STATE(State_EatYams_Called);
ADD_STATE(State_EatYams_Called(a));
return 5;
}
};
SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0);
/*
SHINT_MAKE_GENERICSTUFF_BEGIN(IGaben, EatYams, 0, (static_cast<void (IGaben::*)() SH_NOATTRIB>
(&IGaben::EatYams)))
typedef fastdelegate::FastDelegate0<> FD;
virtual void Func()
{
// SH_HANDLEFUNC_void(IGaben, EatYams, (), ());
SH_SETUPCALLS_void((), ())
SH_CALL_HOOKS_void(pre, ())
if (status != MRES_SUPERCEDE)
{
void (EmptyClass::*mfp)();
SH_SETUP_MFP(mfp);
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)();
}
SH_CALL_HOOKS_void(post, ())
SH_RETURN_void()
}
};
SH_FHCls(IGaben,EatYams,0) SH_FHCls(IGaben,EatYams,0)::ms_Inst;
::SourceHook::MemFuncInfo SH_FHCls(IGaben,EatYams,0)::ms_MFI;
::SourceHook::IHookManagerInfo *SH_FHCls(IGaben,EatYams,0)::ms_HI;
const char *SH_FHCls(IGaben,EatYams,0)::ms_Proto = "SH_NOATTRIB";
bool __SourceHook_FHAddIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc,
new CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD>(handler), post);
}
bool __SourceHook_FHRemoveIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD> tmp(handler);
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc, &tmp, post);
}
*/
void EatYams0_Handler()
{
ADD_STATE(State_EatYams_Handler_Called);
}
SH_DECL_HOOK1(IGaben, EatYams, SH_NOATTRIB, 0, int, int);
IGaben *g_Gabgab;
}
extern void *___testbail_gabgab;
extern SourceHook::ISourceHook *___testbail_shptr;
extern int ___testbail_EatYams_Handler2(int a);
extern int ___testbail_EatYams_Handler3(int a);

View File

@ -1,23 +1,25 @@
// TESTBAIL
// Different compilation unit
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testbail.h"
void ___TestBail2()
// :TODO: Test new-old proto system compa
bool ___TestBail2(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
g_SHPtr = ___testbail_shptr;
g_PLID = 2;
g_Gabgab = (IGaben*)___testbail_gabgab;
g_Gabgab->EatYams();
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, ___testbail_EatYams_Handler2, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, ___testbail_EatYams_Handler3, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams0_Handler, false);
g_Gabgab->EatYams();
int ret = g_Gabgab->EatYams(0xDEAD);
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams0_Handler, false);
g_Gabgab->EatYams();
CHECK_COND(ret == 6, "Part 2.1");
return true;
}

View File

@ -39,9 +39,6 @@ namespace
typedef std::list<State*> StateList;
#define ADD_STATE(name) g_States.push_back(new name)
void DumpStates(StateList *sl)
{
for (StateList::iterator iter = sl->begin(); iter != sl->end(); ++iter)
@ -101,6 +98,9 @@ namespace
}
}
#define ADD_STATE(name) g_States.push_back(new name)
#define ADD_STATE_PTR(statesptr, name) statesptr->push_back(new name)
#define CHECK_STATES(mwah, myerr) if (!StatesOk mwah) { error=myerr; return false; } else if (g_Verbose) { std::cout << "No error: " << myerr << std::endl; }
#define MAKE_STATE(name) struct name : State { \

View File

@ -1,5 +1,6 @@
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testevents.h"
// TESTMANUAL
@ -94,8 +95,7 @@ namespace
bool TestManual(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
TheWall inst;

View File

@ -0,0 +1,131 @@
#include <string>
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testevents.h"
// TESTRECALL
// Test modifying parameters from hook handlers
namespace
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
MAKE_STATE_1(State_Func1, int);
MAKE_STATE_1(State_H1_Func1, int);
MAKE_STATE_1(State_H2_Func1, int);
MAKE_STATE_2(State_HP_Func1, int, void*);
MAKE_STATE_1(State_Func2, int);
MAKE_STATE_1(State_H1_Func2, int);
MAKE_STATE_2(State_HP_Func2, int, int);
struct Test
{
virtual void Func1(int a)
{
ADD_STATE(State_Func1(a));
}
virtual int Func2(int a)
{
ADD_STATE(State_Func2(a));
return 1000;
}
};
void Handler1_Func1(int a)
{
ADD_STATE(State_H1_Func1(a));
RETURN_META_NEWPARAMS(MRES_IGNORED, Test, Func1, (5));
}
void Handler2_Func1(int a)
{
ADD_STATE(State_H2_Func1(a));
RETURN_META_NEWPARAMS(MRES_IGNORED, Test, Func1, (a - 5));
}
void HandlerPost_Func1(int a)
{
ADD_STATE(State_HP_Func1(a, META_IFACEPTR(void)));
}
int Handler1_Func2(int a)
{
ADD_STATE(State_H1_Func2(a));
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, 500, Test, Func2, (a - 10));
}
int HandlerPost_Func2(int a)
{
ADD_STATE(State_HP_Func2(a, META_RESULT_ORIG_RET(int)));
RETURN_META_VALUE(MRES_IGNORED, 0);
}
SH_DECL_HOOK1_void(Test, Func1, SH_NOATTRIB, 0, int);
SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, int, int);
}
bool TestRecall(std::string &error)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Test 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);
ptr->Func1(77);
CHECK_STATES((&g_States,
new State_H1_Func1(77),
new State_H2_Func1(5),
new State_Func1(0),
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);
ptr->Func1(77);
CHECK_STATES((&g_States,
new State_H2_Func1(77),
new State_H2_Func1(72),
new State_H2_Func1(67),
new State_H2_Func1(62),
new State_Func1(57),
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);
ptr->Func1(77);
CHECK_STATES((&g_States,
new State_Func1(77),
NULL), "Part 3");
// Func2
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func2, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost_Func2, true);
int a = ptr->Func2(77);
CHECK_STATES((&g_States,
new State_H1_Func2(77),
new State_Func2(67),
new State_HP_Func2(67, 1000), // 1000 because it's the ORIG_RET
NULL), "Part 4");
CHECK_COND(a == 500, "Part 4.1");
return true;
}

View File

@ -2,7 +2,7 @@
// = calling hooks from hook handlers, etc
#include <string>
#include "sourcehook_impl.h"
#include "sourcehook_test.h"
#include "testevents.h"
namespace
@ -294,8 +294,7 @@ namespace
bool TestReentr(std::string &error)
{
SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl;
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
g_pC1 = &g_C1;