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

Added insert(iterator where, const T &what) to sh_list and simplified it on the occasion, hook managers now have (optional) version numbers, everything somehow works! Also changed _NEWPARAMS macro syntax a bit

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40164
This commit is contained in:
Pavol Marko 2005-12-23 23:00:55 +00:00
parent 9eb35c8830
commit 27de459d8f
13 changed files with 1156 additions and 550 deletions

View File

@ -21,10 +21,13 @@
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Hookman version:
// 1 - Support for recalls, performance optimisations
#define SH_HOOKMAN_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -235,6 +238,11 @@ namespace SourceHook
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
// Added 23.12.2005 (yup! I'm coding RIGHT BEFORE CHRISTMAS!)
// If the hookman doesn't set this, it defaults 0
// SourceHook prefers hookmans with higher version numbers
virtual void SetVersion(int version) = 0;
};
class AutoHookIter
@ -422,6 +430,8 @@ namespace SourceHook
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
};
}
@ -442,18 +452,20 @@ namespace SourceHook
// 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 ?
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
#define RETURN_META_NEWPARAMS(result, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
#define RETURN_META_VALUE_NEWPARAMS(result, value, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
@ -461,9 +473,10 @@ namespace SourceHook
{ \
/* 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); \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
RETURN_META_VALUE(MRES_SUPERCEDE, \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \
} while (0)
/**
@ -563,6 +576,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -657,6 +671,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -3554,7 +3569,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// SetOverrideRet and RecallGetIface 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.
@ -3566,106 +3581,232 @@ namespace SourceHook
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)())
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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;
}
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>
Iface *RecallGetIface(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))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
}
#endif

View File

@ -21,10 +21,13 @@
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Hookman version:
// 1 - Support for recalls, performance optimisations
#define SH_HOOKMAN_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -235,6 +238,11 @@ namespace SourceHook
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
// Added 23.12.2005 (yup! I'm coding RIGHT BEFORE CHRISTMAS!)
// If the hookman doesn't set this, it defaults 0
// SourceHook prefers hookmans with higher version numbers
virtual void SetVersion(int version) = 0;
};
class AutoHookIter
@ -422,6 +430,8 @@ namespace SourceHook
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
};
}
@ -442,18 +452,20 @@ namespace SourceHook
// 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 ?
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
#define RETURN_META_NEWPARAMS(result, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
#define RETURN_META_VALUE_NEWPARAMS(result, value, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
@ -461,9 +473,10 @@ namespace SourceHook
{ \
/* 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); \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
RETURN_META_VALUE(MRES_SUPERCEDE, \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \
} while (0)
/**
@ -563,6 +576,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -657,6 +671,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -1082,7 +1097,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@Param%%|, @@
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// SetOverrideRet and RecallGetIface 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.
@ -1095,6 +1110,12 @@ namespace SourceHook
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType@, class Param%%@>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(@Param%%|, @))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
@ENDARGS@
}

View File

@ -16,253 +16,276 @@
namespace SourceHook
{
//This class is from CSDM for AMX Mod X
template <class T>
class List
{
public:
class iterator;
friend class iterator;
class ListNode
//This class is from CSDM for AMX Mod X
/*
A circular, doubly-linked list with one sentinel node
Empty:
m_Head = sentinel
m_Head->next = m_Head;
m_Head->prev = m_Head;
One element:
m_Head = sentinel
m_Head->next = node1
m_Head->prev = node1
node1->next = m_Head
node1->prev = m_Head
Two elements:
m_Head = sentinel
m_Head->next = node1
m_Head->prev = node2
node1->next = node2
node1->prev = m_Head
node2->next = m_Head
node2->prev = node1
*/
template <class T>
class List
{
public:
ListNode(const T & o) : obj(o) { };
ListNode() { };
T obj;
ListNode *next;
ListNode *prev;
};
private:
ListNode *_Initialize()
{
ListNode *n = (ListNode *)malloc(sizeof(ListNode));
n->next = NULL;
n->prev = NULL;
return n;
}
public:
List() : m_Head(_Initialize()), m_Size(0)
{
}
List(const List &src) : m_Head(_Initialize()), m_Size(0)
{
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
}
~List()
{
clear();
if (m_Head)
class iterator;
friend class iterator;
class ListNode
{
free(m_Head);
m_Head = NULL;
public:
ListNode(const T & o) : obj(o) { };
ListNode() { };
T obj;
ListNode *next;
ListNode *prev;
};
private:
// Initializes the sentinel node.
// BAIL used malloc instead of new in order to bypass the need for a constructor.
ListNode *_Initialize()
{
ListNode *n = (ListNode *)malloc(sizeof(ListNode));
n->next = n;
n->prev = n;
return n;
}
}
void push_back(const T &obj)
{
ListNode *node = new ListNode(obj);
if (!m_Head->prev)
public:
List() : m_Head(_Initialize()), m_Size(0)
{
//link in the node as the first item
node->next = m_Head;
node->prev = m_Head;
m_Head->prev = node;
m_Head->next = node;
} else {
}
List(const List &src) : m_Head(_Initialize()), m_Size(0)
{
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
}
~List()
{
clear();
// Don't forget to free the sentinel
if (m_Head)
{
free(m_Head);
m_Head = NULL;
}
}
void push_back(const T &obj)
{
ListNode *node = new ListNode(obj);
node->prev = m_Head->prev;
node->next = m_Head;
m_Head->prev->next = node;
m_Head->prev = node;
m_Size++;
}
m_Size++;
}
size_t size()
{
return m_Size;
}
void clear()
{
ListNode *node = m_Head->next;
ListNode *temp;
m_Head->next = NULL;
m_Head->prev = NULL;
while (node && node != m_Head)
size_t size()
{
temp = node->next;
delete node;
node = temp;
return m_Size;
}
m_Size = 0;
}
bool empty()
{
return (m_Head->next == NULL);
}
T & back()
{
return m_Head->prev->obj;
}
private:
ListNode *m_Head;
size_t m_Size;
public:
class iterator
{
friend class List;
public:
iterator()
void clear()
{
m_This = NULL;
ListNode *node = m_Head->next;
ListNode *temp;
m_Head->next = m_Head;
m_Head->prev = m_Head;
// Iterate through the nodes until we find g_Head (the sentinel) again
while (node != m_Head)
{
temp = node->next;
delete node;
node = temp;
}
m_Size = 0;
}
iterator(const List &src)
bool empty()
{
m_This = src.m_Head;
return (m_Size == 0);
}
iterator(ListNode *n) : m_This(n)
T & back()
{
}
iterator(const iterator &where)
{
m_This = where.m_This;
}
//pre decrement
iterator & operator--()
{
if (m_This)
m_This = m_This->prev;
return *this;
}
//post decrement
iterator operator--(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->prev;
return old;
}
//pre increment
iterator & operator++()
{
if (m_This)
m_This = m_This->next;
return *this;
}
//post increment
iterator operator++(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->next;
return old;
}
const T & operator * () const
{
return m_This->obj;
}
T & operator * ()
{
return m_This->obj;
}
T * operator -> ()
{
return &(m_This->obj);
}
const T * operator -> () const
{
return &(m_This->obj);
}
bool operator != (const iterator &where) const
{
return (m_This != where.m_This);
}
bool operator ==(const iterator &where) const
{
return (m_This == where.m_This);
return m_Head->prev->obj;
}
private:
ListNode *m_This;
};
public:
iterator begin() const
{
if (m_Size)
return iterator(m_Head->next);
else
return iterator(m_Head);
}
iterator end() const
{
return iterator(m_Head);
}
iterator erase(iterator &where)
{
ListNode *pNode = where.m_This;
iterator iter(where);
iter++;
//If we are both the head and tail...
if (m_Head->next == pNode && m_Head->prev == pNode)
ListNode *m_Head;
size_t m_Size;
public:
class iterator
{
m_Head->next = NULL;
m_Head->prev = NULL;
} else if (m_Head->next == pNode) {
//we are only the first
pNode->next->prev = m_Head;
m_Head->next = pNode->next;
} else if (m_Head->prev == pNode) {
//we are the tail
pNode->prev->next = m_Head;
m_Head->prev = pNode->prev;
} else {
//middle unlink
friend class List;
public:
iterator()
{
m_This = NULL;
}
iterator(const List &src)
{
m_This = src.m_Head;
}
iterator(ListNode *n) : m_This(n)
{
}
iterator(const iterator &where)
{
m_This = where.m_This;
}
//pre decrement
iterator & operator--()
{
if (m_This)
m_This = m_This->prev;
return *this;
}
//post decrement
iterator operator--(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->prev;
return old;
}
//pre increment
iterator & operator++()
{
if (m_This)
m_This = m_This->next;
return *this;
}
//post increment
iterator operator++(int)
{
iterator old(*this);
if (m_This)
m_This = m_This->next;
return old;
}
const T & operator * () const
{
return m_This->obj;
}
T & operator * ()
{
return m_This->obj;
}
T * operator -> ()
{
return &(m_This->obj);
}
const T * operator -> () const
{
return &(m_This->obj);
}
bool operator != (const iterator &where) const
{
return (m_This != where.m_This);
}
bool operator ==(const iterator &where) const
{
return (m_This == where.m_This);
}
private:
ListNode *m_This;
};
public:
iterator begin() const
{
return iterator(m_Head->next);
}
iterator end() const
{
return iterator(m_Head);
}
iterator erase(iterator &where)
{
ListNode *pNode = where.m_This;
iterator iter(where);
iter++;
// Works for all cases: empty list, erasing first element, erasing tail, erasing in the middle...
pNode->prev->next = pNode->next;
pNode->next->prev = pNode->prev;
delete pNode;
m_Size--;
return iter;
}
delete pNode;
m_Size--;
return iter;
}
public:
void remove(const T & obj)
{
iterator b;
for (b=begin(); b!=end(); b++)
iterator insert(iterator where, const T &obj)
{
if ( (*b) == obj )
// Insert obj right before where
ListNode *node = new ListNode(obj);
ListNode *pWhereNode = where.m_This;
pWhereNode->prev->next = node;
node->prev = pWhereNode->prev;
pWhereNode->prev = node;
node->next = pWhereNode;
m_Size++;
return iterator(node);
}
public:
void remove(const T & obj)
{
iterator b;
for (b=begin(); b!=end(); b++)
{
erase( b );
break;
if ( (*b) == obj )
{
erase( b );
break;
}
}
}
}
template <typename U>
iterator find(const U & equ)
{
iterator iter;
for (iter=begin(); iter!=end(); iter++)
template <typename U>
iterator find(const U & equ)
{
if ( (*iter) == equ )
return iter;
iterator iter;
for (iter=begin(); iter!=end(); iter++)
{
if ( (*iter) == equ )
return iter;
}
return end();
}
return end();
}
List & operator =(const List &src)
{
clear();
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
return *this;
}
};
List & operator =(const List &src)
{
clear();
iterator iter;
for (iter=src.begin(); iter!=src.end(); iter++)
push_back( (*iter) );
return *this;
}
};
}; //NAMESPACE
#endif //_INCLUDE_CSDM_LIST_H

View File

@ -67,22 +67,28 @@ namespace SourceHook
if (hook_iter->plug == plug) \
return true;
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
if (hmil_iter->m_Plug != plug)
continue;
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
for (CHookManagerContainer::iterator hmil_iter = hmcl_iter->begin();
hmil_iter != hmcl_iter->end(); ++hmil_iter)
{
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
if (hmil_iter->m_Plug != plug)
continue;
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks);
TMP_CHECK_LIST(m_PostHooks);
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks);
TMP_CHECK_LIST(m_PostHooks);
}
}
}
}
#undef TMP_CHECK_LIST
return false;
}
@ -90,26 +96,37 @@ namespace SourceHook
void CSourceHookImpl::UnloadPlugin(Plugin plug)
{
// 1) Manually remove all hooks by this plugin
// 2) Manually remove all hook mans by this plugin
List<RemoveHookInfo> hookstoremove;
List<RemoveHookManInfo> hookmanstoremove;
HookManInfoList::iterator hmil_iter;
#define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
if (hook_iter->plug == plug) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost)); \
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
for (CHookManagerContainer::iterator hmil_iter = hmcl_iter->begin();
hmil_iter != hmcl_iter->end(); ++hmil_iter)
{
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
if (hmil_iter->m_Plug == plug)
hookmanstoremove.push_back(RemoveHookManInfo(plug, hmil_iter->m_Func));
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
}
}
}
}
@ -118,68 +135,8 @@ namespace SourceHook
for (List<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
RemoveHook(*rmiter);
// 2) Other plugins may use hook managers in this plugin.
// Get a list of hook managers that are in this plugin and are used by other plugins
// Delete all hook managers that are in this plugin
HookManInfoList tmphookmans;
bool erase = false;
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end();
erase ? hmil_iter=m_HookMans.erase(hmil_iter) : ++hmil_iter)
{
if (hmil_iter->m_Plug == plug)
{
if (!hmil_iter->m_VfnPtrs.empty())
{
// All hooks by this plugin are already removed
// So if there is a vfnptr, it has to be used by an other plugin
tmphookmans.push_back(*hmil_iter);
}
erase = true;
}
else
erase = false;
}
// For each hook manager that is used in an other plugin:
for (hmil_iter = tmphookmans.begin(); hmil_iter != tmphookmans.end(); ++hmil_iter)
{
// Find a suitable hook manager in an other plugin
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
hmil_iter->m_Proto, hmil_iter->m_VtblOffs, hmil_iter->m_VtblIdx);
// This should _never_ happen.
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
SH_ASSERT(newHookMan != m_HookMans.end(),
("Could not find a suitable hook manager in an other plugin!"));
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo
SH_ASSERT(newHookMan->m_Plug != plug, ("New hook manager from same plugin!"));
// The first hook manager should be always used - so the new hook manager has to be empty
SH_ASSERT(newHookMan->m_VfnPtrs.empty(), ("New hook manager not empty!"));
// Move the vfnptrs from the old hook manager to the new one
newHookMan->m_VfnPtrs = hmil_iter->m_VfnPtrs;
// Unregister the old one, register the new one
hmil_iter->m_Func(HA_Unregister, NULL);
newHookMan->m_Func(HA_Register, &(*newHookMan));
// zOMG BAIL, here is part of what you wanted:
// Go through all vfnptrs in this hookman and patch them to point to the new manager's handler!
// or whatever
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->m_VfnPtrs.begin();
vfnptr_iter != newHookMan->m_VfnPtrs.end(); ++vfnptr_iter)
{
// And DEREFERENCE newHookMan->m_HookfuncVfnptr!
// otherwise it will be executing the vtable... had to find out the hard way
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(newHookMan->m_HookfuncVfnptr);
}
// That should fix it, bail!
}
for (List<RemoveHookManInfo>::iterator rmiter = hookmanstoremove.begin(); rmiter != hookmanstoremove.end(); ++rmiter)
RemoveHookManager(*rmiter);
}
void CSourceHookImpl::RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc)
@ -190,12 +147,22 @@ namespace SourceHook
if (pubFunc(HA_GetInfo, &tmp) != 0)
return;
HookManInfoList::iterator hmil_iter = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
HookManContList::iterator hmcl_iter = m_HookMans.find(
CHookManagerContainer::HMCI(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx));
if (hmil_iter == m_HookMans.end())
if (hmcl_iter == m_HookMans.end())
{
// Moo ?
// Moo?
return;
}
CHookManagerContainer::iterator hmil_iter = hmcl_iter->find(
CHookManagerInfo::Descriptor(plug, pubFunc));
if (hmil_iter == hmcl_iter->end())
{
// Moo?
return;
}
@ -230,63 +197,75 @@ namespace SourceHook
CHookManagerInfo info = *hmil_iter;
// Unlink the hook manager from the list
m_HookMans.erase(hmil_iter);
hmcl_iter->erase(hmil_iter);
// If there were any hooks from other plugins, find a new suitable hook manager.
if (stillInUse)
{
// Find a suitable hook manager in an other plugin
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
info.m_Proto, info.m_VtblOffs, info.m_VtblIdx);
hmil_iter = hmcl_iter->begin();
// This should _never_ happen.
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
SH_ASSERT(newHookMan != m_HookMans.end(),
SH_ASSERT(hmil_iter != hmcl_iter->end(),
("Could not find a suitable hook manager in an other plugin!"));
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo
SH_ASSERT(newHookMan->m_Plug != plug, ("New hook manager from same plugin!"));
SH_ASSERT(hmil_iter->m_Plug != plug, ("New hook manager from same plugin!"));
// The first hook manager should be always used - so the new hook manager has to be empty
SH_ASSERT(newHookMan->m_VfnPtrs.empty(), ("New hook manager not empty!"));
SH_ASSERT(hmil_iter->m_VfnPtrs.empty(), ("New hook manager not empty!"));
// Move the vfnptrs from the old hook manager to the new one
newHookMan->m_VfnPtrs = info.m_VfnPtrs;
hmil_iter->m_VfnPtrs = info.m_VfnPtrs;
// Unregister the old one, register the new one
info.m_Func(HA_Unregister, NULL);
newHookMan->m_Func(HA_Register, &(*newHookMan));
hmil_iter->m_Func(HA_Register, &(*hmil_iter));
// Go through all vfnptrs in this hookman and patch them to point to the new manager's handler!
// or whatever
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->m_VfnPtrs.begin();
vfnptr_iter != newHookMan->m_VfnPtrs.end(); ++vfnptr_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
// And DEREFERENCE newHookMan->m_HookfuncVfnptr!
// otherwise it will be executing the vtable... had to find out the hard way
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(newHookMan->m_HookfuncVfnptr);
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(hmil_iter->m_HookfuncVfnptr);
}
}
}
void CSourceHookImpl::RemoveHookManager(RemoveHookManInfo info)
{
RemoveHookManager(info.plug, info.hookman);
}
void CSourceHookImpl::CompleteShutdown()
{
// Remove all hooks
List<RemoveHookInfo> hookstoremove;
#define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
for (CHookManagerContainer::iterator hmil_iter = hmcl_iter->begin();
hmil_iter != hmcl_iter->end(); ++hmil_iter)
{
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(m_PostHooks, true);
}
}
}
}
@ -307,40 +286,42 @@ namespace SourceHook
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
tmp.m_Func = myHookMan;
tmp.m_Plug = plug;
CHookManagerContainer::HMCI hmci(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
// Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager
// with this proto/vo/vi registered
HookManInfoList::iterator hkmi_iter;
for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter)
// Add the container if not already added
HookManContList::iterator hmcl_iter = m_HookMans.find(hmci);
if (hmcl_iter == m_HookMans.end())
{
if (hkmi_iter->m_Plug == plug && ProtosEquiv(hkmi_iter->m_Proto, tmp.m_Proto) &&
hkmi_iter->m_VtblOffs == tmp.m_VtblOffs && hkmi_iter->m_VtblIdx == tmp.m_VtblIdx)
break;
}
if (hkmi_iter == m_HookMans.end())
{
// No such hook manager from this plugin yet, add it!
tmp.m_Func = myHookMan;
tmp.m_Plug = plug;
m_HookMans.push_back(tmp);
m_HookMans.push_back(CHookManagerContainer(hmci));
hmcl_iter = m_HookMans.end();
--hmcl_iter;
}
// Then, search for a suitable hook manager (from the beginning)
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.m_Proto,
tmp.m_VtblOffs, tmp.m_VtblIdx);
SH_ASSERT(hookman != m_HookMans.end(), ("No hookman found - but if there was none, we've just added one!"));
hmcl_iter->AddHookManager(plug, tmp);
// Check whether there is already an other hook manager for the same vfnptr but with other values before
CHookManagerContainer::iterator hookman = hmcl_iter->begin();
SH_ASSERT(hookman != hmcl_iter->end(), ("No hookman found - but we've just added one!"));
// Check whether any other container holds a hook manager which holds this vfnptr
// If yes, it means that the two are incompatible, so return false.
for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter)
for (HookManContList::iterator hmcl_iter2 = m_HookMans.begin();
hmcl_iter2 != m_HookMans.end(); ++hmcl_iter2)
{
if (hkmi_iter != hookman)
if (hmcl_iter2 != hmcl_iter)
{
if (hkmi_iter->m_VfnPtrs.find(cur_vfnptr) != hkmi_iter->m_VfnPtrs.end())
return false;
for (CHookManagerContainer::iterator hmil_iter = hmcl_iter2->begin();
hmil_iter != hmcl_iter2->end(); ++hmil_iter)
{
if (hmil_iter->m_VfnPtrs.find(cur_vfnptr) != hmil_iter->m_VfnPtrs.end())
return false;
}
}
}
@ -409,10 +390,13 @@ namespace SourceHook
return false;
// Find the hook manager and the hook
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman == m_HookMans.end())
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();
if (!ModuleInMemory(reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs,
sizeof(void*) * (tmp.m_VtblIdx + 1)))
@ -532,20 +516,25 @@ namespace SourceHook
void CSourceHookImpl::ApplyCallClassPatches(CCallClassImpl &cc)
{
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.begin();
vfnptr_iter != hookman->m_VfnPtrs.end(); ++vfnptr_iter)
for (CHookManagerContainer::iterator hookman = hmcl_iter->begin();
hookman != hmcl_iter->end(); ++hookman)
{
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.begin();
vfnptr_iter != hookman->m_VfnPtrs.end(); ++vfnptr_iter)
{
if (iface_iter->m_Ptr >= cc.m_Ptr &&
iface_iter->m_Ptr < (reinterpret_cast<char*>(cc.m_Ptr) + cc.m_ObjSize))
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{
cc.ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(iface_iter->m_Ptr) -
reinterpret_cast<char*>(cc.m_Ptr)) + hookman->m_VtblOffs,
hookman->m_VtblIdx, vfnptr_iter->m_OrigEntry);
if (iface_iter->m_Ptr >= cc.m_Ptr &&
iface_iter->m_Ptr < (reinterpret_cast<char*>(cc.m_Ptr) + cc.m_ObjSize))
{
cc.ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(iface_iter->m_Ptr) -
reinterpret_cast<char*>(cc.m_Ptr)) + hookman->m_VtblOffs,
hookman->m_VtblIdx, vfnptr_iter->m_OrigEntry);
}
}
}
}
@ -579,38 +568,34 @@ namespace SourceHook
}
}
CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin,
HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx)
{
HookManInfoList::iterator hookmaniter;
for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
{
if (ProtosEquiv(hookmaniter->m_Proto, proto) && hookmaniter->m_VtblOffs == vtblofs &&
hookmaniter->m_VtblIdx == vtblidx)
break;
}
return hookmaniter;
}
void CSourceHookImpl::SetPluginPaused(Plugin plug, bool paused)
{
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin();
vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter)
for (CVfnPtr::IfaceListIter ifaceiter = vfnptr_iter->m_Ifaces.begin();
ifaceiter != vfnptr_iter->m_Ifaces.end(); ++ifaceiter)
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
for (CHookManagerContainer::iterator hookmaniter = hmcl_iter->begin();
hookmaniter != hmcl_iter->end(); ++hookmaniter)
{
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin();
vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter)
{
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PreHooks.m_List.begin();
hookiter != ifaceiter->m_PreHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = paused;
for (CVfnPtr::IfaceListIter ifaceiter = vfnptr_iter->m_Ifaces.begin();
ifaceiter != vfnptr_iter->m_Ifaces.end(); ++ifaceiter)
{
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PreHooks.m_List.begin();
hookiter != ifaceiter->m_PreHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = paused;
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PostHooks.m_List.begin();
hookiter != ifaceiter->m_PostHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = paused;
for (List<HookInfo>::iterator hookiter = ifaceiter->m_PostHooks.m_List.begin();
hookiter != ifaceiter->m_PostHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = paused;
}
}
}
}
}
void CSourceHookImpl::PausePlugin(Plugin plug)
{
@ -828,68 +813,12 @@ namespace SourceHook
}
}
bool CSourceHookImpl::ProtosEquiv(const char *p1, const char *p2)
{
/*
Old protos look like this:
0_void:
"attrib"
1_void:
"attrib|param1_type"
2_void:
"attrib|param1_type|param2_type
0:
"attrib|ret_type"
1:
"attrib|ret_type|param1_type"
2:
"attrib|ret_type|param2_type"
New protos are in fact pointers to the ProtoInfo sturcture (see sourcehook.h for details)
Old protos _never_ begin with a null character
New protos _always_ begin with a null character
*/
if (*p1 && *p2) // Case1: Both old
{
// As in old versions
return strcmp(p1, p2) == 0;
}
else if (!*p1 && !*p2) // Case2: Both new
{
const ProtoInfo *pi1 = reinterpret_cast<const ProtoInfo*>(p1);
const ProtoInfo *pi2 = reinterpret_cast<const ProtoInfo*>(p2);
if (pi1->retTypeSize == pi2->retTypeSize &&
pi1->numOfParams == pi2->numOfParams)
{
// params[0] is 0 for "normal" functions and -1 for vararg functions
// params[1] is size of first parameter
// params[2] is size of second parameter ...
for (int i = 0; i <= pi1->numOfParams; ++i)
{
if (pi1->params[i] != pi2->params[i])
return false;
}
return true;
}
else
{
return false;
}
}
else // Case3: Mixed old/new
{
// Trust the user
return true;
}
}
////////////////////////////
// CHookManagerInfo
////////////////////////////
CSourceHookImpl::CHookManagerInfo::CHookManagerInfo() : m_HookManVersion(0)
{
}
CSourceHookImpl::CHookManagerInfo::~CHookManagerInfo()
{
}
@ -909,7 +838,10 @@ namespace SourceHook
{
m_HookfuncVfnptr = hookfunc_vfnptr;
}
void CSourceHookImpl::CHookManagerInfo::SetVersion(int version)
{
m_HookManVersion = version;
}
////////////////////////////
// CVfnPtr
////////////////////////////
@ -1097,4 +1029,102 @@ namespace SourceHook
{
return m_Iter->thisptr_offs;
}
//////////////////////////////////////////////////////////////////////////
// CProto
//////////////////////////////////////////////////////////////////////////
bool CSourceHookImpl::CProto::Equal(const char *p1, const char *p2)
{
if (*p1 && *p2) // Case1: Both old
{
// As in old versions
return strcmp(p1, p2) == 0;
}
else if (!*p1 && !*p2) // Case2: Both new
{
const ProtoInfo *pi1 = reinterpret_cast<const ProtoInfo*>(p1);
const ProtoInfo *pi2 = reinterpret_cast<const ProtoInfo*>(p2);
if (pi1->retTypeSize == pi2->retTypeSize &&
pi1->numOfParams == pi2->numOfParams)
{
// params[0] is 0 for "normal" functions and -1 for vararg functions
// params[1] is size of first parameter
// params[2] is size of second parameter ...
for (int i = 0; i <= pi1->numOfParams; ++i)
{
if (pi1->params[i] != pi2->params[i])
return false;
}
return true;
}
else
{
return false;
}
}
else // Case3: Mixed old/new
{
// Trust the user
return true;
}
}
//////////////////////////////////////////////////////////////////////////
// CHookManagerContainer
//////////////////////////////////////////////////////////////////////////
void CSourceHookImpl::CHookManagerContainer::AddHookManager(Plugin plug, const CHookManagerInfo &hookman)
{
iterator iter;
// Check whether such a hook manager already exists; if yes, ignore.
for (iter = begin(); iter != end(); ++iter)
{
if (iter->m_Plug == plug && iter->m_Func == hookman.m_Func)
return;
}
// It doesn't -> add it. Add it to the end of its version group.
for (iter = begin(); iter != end(); ++iter)
{
if (iter->m_HookManVersion < hookman.m_HookManVersion)
break;
}
bool isBeginning = iter == begin();
insert(iter, hookman);
// If we inserted it at the beginning and if the dam breaks open many years too soon
// and if there is more than one hookman and if the second one isn't empty, transfer
// hooks from second to first
if (isBeginning && size() > 1)
{
iter = begin();
iterator second = iter;
++second;
if (!second->m_VfnPtrs.empty())
{
// Move the vfnptrs from the old hook manager to the new one
iter->m_VfnPtrs = second->m_VfnPtrs;
second->m_VfnPtrs.clear();
// Unregister the old one, register the new one
second->m_Func(HA_Unregister, NULL);
iter->m_Func(HA_Register, &(*iter));
// Go through all vfnptrs in this hookman and patch them to point to the new manager's handler!
// or whatever
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = iter->m_VfnPtrs.begin();
vfnptr_iter != iter->m_VfnPtrs.end(); ++vfnptr_iter)
{
// And DEREFERENCE newHookMan->m_HookfuncVfnptr!
// otherwise it will be executing the vtable... had to find out the hard way
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(iter->m_HookfuncVfnptr);
}
}
}
}
}

View File

@ -21,10 +21,13 @@
// 2 - Changed to virtual functions for iterators and all queries
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Hookman version:
// 1 - Support for recalls, performance optimisations
#define SH_HOOKMAN_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -235,6 +238,11 @@ namespace SourceHook
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
// Added 23.12.2005 (yup! I'm coding RIGHT BEFORE CHRISTMAS!)
// If the hookman doesn't set this, it defaults 0
// SourceHook prefers hookmans with higher version numbers
virtual void SetVersion(int version) = 0;
};
class AutoHookIter
@ -422,6 +430,8 @@ namespace SourceHook
*/
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
};
}
@ -442,18 +452,20 @@ namespace SourceHook
// 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 ?
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
// SourceHook::SetOverrideRet is defined later.
#define RETURN_META_NEWPARAMS(result, iface, func, newparams) \
#define RETURN_META_NEWPARAMS(result, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
META_IFACEPTR(iface)->func newparams; \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams; \
RETURN_META(MRES_SUPERCEDE); \
} while (0)
#define RETURN_META_VALUE_NEWPARAMS(result, value, iface, func, newparams) \
#define RETURN_META_VALUE_NEWPARAMS(result, value, memfuncptr, newparams) \
do { \
SET_META_RESULT(result); \
SH_GLOB_SHPTR->DoRecall(); \
@ -461,9 +473,10 @@ namespace SourceHook
{ \
/* 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); \
SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \
} \
RETURN_META_VALUE(MRES_SUPERCEDE, META_IFACEPTR(iface)->func newparams); \
RETURN_META_VALUE(MRES_SUPERCEDE, \
(SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \
} while (0)
/**
@ -563,6 +576,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -657,6 +671,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
\
if (action == HA_GetInfo) \
{ \
param->SetVersion(SH_HOOKMAN_VERSION); \
param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, \
reinterpret_cast<const char*>(&ms_Proto)); \
\
@ -3554,7 +3569,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
#undef SH_MAKE_EXECUTABLECLASS_OB
//////////////////////////////////////////////////////////////////////////
// SetOverrideRet for recalls
// SetOverrideRet and RecallGetIface 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.
@ -3566,106 +3581,232 @@ namespace SourceHook
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)())
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
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;
}
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>
Iface *RecallGetIface(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))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
}
#endif

View File

@ -17,6 +17,107 @@
#include "sh_tinyhash.h"
#include "sh_stack.h"
/*
IMPLEMENTATION INFO
---------------------------------------
Protos ("Prototypes")
The purpose of protos is to provide the amount of type information about a function
which is required to be able to execute a function call without corrupting the stack.
Our protos do not fully do this, but they provide the size of the return value, the amount of
parameters, and the size of each parameter, which is enough for most situations,
There are two version of protos:
OLD:
C-Style strings.
0_void:
"attrib"
1_void:
"attrib|param1_type"
2_void:
"attrib|param1_type|param2_type
0:
"attrib|ret_type"
1:
"attrib|ret_type|param1_type"
2:
"attrib|ret_type|param2_type"
Old protos are deprecated.
NEW:
New protos are in fact pointers to the ProtoInfo structure (see sourcehook.h)
Old protos begin with a non-zero byte, new protos begin with a zero byte.
Protos are usually stored in a CProto instance.
---------------------------------------
Hook managers and hook manager containers
Each hookman container is tied to _one_ proto/vtable index/vtable offset info.
Hookman containers then contain a list of hook managers provided by plugins, sorted by version.
(higher versions come first)
Duplicate hook managers are ignored (ie. hook managers where proto, vtable index, vtable offset,
plugin, version are the same as in an already exisiting hook manager)
A new hook manager is always added to the end of the version group in the corresponding
hook container.
If the new hook manager was added to the beginning of the container (which only happens if
it is the first one or if it has a higher version than the previously first hook manager),
the now second hook manager is shut down and the new hook manager takes its job.
A "hook manager container id" (HMCI) consits of three values: proto, vtbl index, vtbl offset.
---------------------------------------
Hooks
When adding a hook, first the proposed hook manager is added to the corresponding
hook manager container as described above.
Then the first hook manager in the the manhook container is chosen to handle the function.
Removing a hook does not neccessarily unreigster the plugin's hook manager. In order to do this,
use RemoveHookManager or UnloadPlugin/
Hooks can be paused - they remain in memory but they are not called. In SH, the hook iterator
classes handle pausing transparently.
The hook loop is supposed to call ShouldContinue before each iteration. This makes hook handlers
able to remove themselves.
---------------------------------------
Call classes
Call classes are identified by a this pointer and an instance size
We use the instance size because a derived class instance and a base class instance could
have the same this pointers, and we want to avoid that the derived class
(which could be bigger) gets the same callclass as the base class (mainly if the
base class' callclass was requested first).
Call classes are reference counted.
The original function pointers are stored in a vector (in order to allow fast random access).
These vectors are stored as the value type of a hash. The key type is int and represents the
vtable offset.
If the hash key doesn't exist or the vtblidx is out of range or the corresponding element in the
vector is NULL, there is no hook on that function.
---------------------------------------
Recalls
Recalls are used for the META_RETURN_(VALUE_)NEWPARAMS macros, ie. to change the parameters
in the hook loop on the fly.
First, the macro calls DoRecall(), then it calls the function the hook is attached to -> it
calls the hookfunc. SourceHook makes sure that the newly invoked hook loop starts where the last
one left off and that status variables like status, previous result, override return are kept.
When this recurisvely called hookfunc returns, the macro returns what it returned
(using MRES_SUPERCEDE). CSourceHookImpl returns false from ShouldContinue so the original hook loop
is abandonned.
*/
namespace SourceHook
{
/**
@ -25,6 +126,40 @@ namespace SourceHook
class CSourceHookImpl : public ISourceHook
{
private:
class CProto
{
const char *m_Proto;
static bool Equal(const char *p1, const char *p2);
public:
CProto(const char *szProto) : m_Proto(szProto)
{
}
CProto(const CProto &other) : m_Proto(other.m_Proto)
{
}
void operator = (const char *szProto)
{
m_Proto = szProto;
}
void operator = (const CProto &other)
{
m_Proto = other.m_Proto;
}
bool operator == (const char *szProto) const
{
return Equal(szProto, m_Proto);
}
bool operator == (const CProto &other) const
{
return Equal(other.m_Proto, m_Proto);
}
};
/**
* @brief A hook can be removed if you have this information
*/
@ -45,6 +180,17 @@ namespace SourceHook
bool post;
};
struct RemoveHookManInfo
{
RemoveHookManInfo(Plugin pplug, HookManagerPubFunc phookman)
: plug(pplug), hookman(phookman)
{
}
Plugin plug;
HookManagerPubFunc hookman;
};
struct HookInfo
{
ISHDelegate *handler; //!< Pointer to the handler
@ -175,21 +321,93 @@ namespace SourceHook
VfnPtrList m_VfnPtrs;
int m_HookFuncVersion;
int m_HookManVersion;
public:
CHookManagerInfo();
virtual ~CHookManagerInfo();
IVfnPtr *FindVfnPtr(void *vfnptr);
void SetInfo(int vtbl_offs, int vtbl_idx, const char *proto);
void SetHookfuncVfnptr(void *hookfunc_vfnptr);
void SetVersion(int version);
bool operator < (const CHookManagerInfo &other)
{
return m_HookManVersion < other.m_HookManVersion;
}
struct Descriptor
{
Descriptor(Plugin pplug, HookManagerPubFunc ppubFunc) : plug(pplug), pubFunc(ppubFunc)
{
}
Plugin plug;
HookManagerPubFunc pubFunc;
};
bool operator == (const Descriptor desc)
{
return m_Func == desc.pubFunc && m_Plug == desc.plug;
}
};
/**
* @brief A list of CHookManagerInfo classes
*/
typedef List<CHookManagerInfo> HookManInfoList;
class CHookManagerContainer : public HookManInfoList
{
public:
// HMCI (Hook Manager Container Identification)
class HMCI
{
CProto m_Proto;
int m_VtableOffset;
int m_VtableIndex;
public:
HMCI(const char *proto, int vtbloffs, int vtblidx) :
m_Proto(proto), m_VtableOffset(vtbloffs), m_VtableIndex(vtblidx)
{
}
~HMCI()
{
}
bool operator==(const HMCI &other) const
{
return
other.m_VtableIndex == m_VtableIndex &&
other.m_Proto == m_Proto &&
other.m_VtableOffset == m_VtableOffset;
}
const CProto &GetProto() const
{
return m_Proto;
}
int GetVtableOffset() const
{
return m_VtableOffset;
}
int GetVtableIndex() const
{
return m_VtableIndex;
}
};
HMCI m_HCMI;
public:
CHookManagerContainer(const HMCI &hmci) : m_HCMI(hmci)
{
}
bool operator == (const HMCI &other) const
{
return m_HCMI == other;
}
void AddHookManager(Plugin plug, const CHookManagerInfo &hookman);
};
class CCallClassImpl : public GenericCallClass
{
public:
@ -224,7 +442,13 @@ namespace SourceHook
typedef List<CCallClassImpl> Impl_CallClassList;
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
HookManInfoList m_HookMans; //!< A list of hook managers
/**
* @brief A list of CHookManagerContainers
*/
typedef List<CHookManagerContainer> HookManContList;
HookManContList m_HookMans; //!< A list of hook managers
struct HookLoopInfo
{
@ -242,20 +466,12 @@ namespace SourceHook
};
typedef CStack<HookLoopInfo> HookLoopInfoStack;
/**
* @brief Finds a hook manager for a function based on a text-prototype, a vtable offset and a vtable index
*/
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
const char *proto, int vtblofs, int vtblidx);
void ApplyCallClassPatches(CCallClassImpl &cc);
void ApplyCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx);
void SetPluginPaused(Plugin plug, bool paused);
bool ProtosEquiv(const char *p1, const char *p2);
HookLoopInfoStack m_HLIStack;
public:
CSourceHookImpl();
@ -380,6 +596,8 @@ namespace SourceHook
* @param pubFunc The hook manager's info function
*/
virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc);
virtual void RemoveHookManager(RemoveHookManInfo info);
virtual void DoRecall(); //!< Initiates a recall sequence
virtual void *GetOverrideRetPtr(); //!< Returns the pointer set by SetOverrideRetPtr

View File

@ -22,7 +22,7 @@
Optimization="0"
FavorSizeOrSpeed="0"
AdditionalIncludeDirectories=".."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;SH_DEBUG"
StringPooling="TRUE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"

View File

@ -22,8 +22,12 @@
#include "sourcehook_test.h"
#include "testbail.h"
void *___testbail_gabgab;
SourceHook::ISourceHook *___testbail_shptr;
namespace N_TestBail
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
IGaben *g_Gabgab;
}
namespace
{
@ -34,27 +38,12 @@ namespace
}
}
// 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)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1;
g_Gabgab = new IGaben;
___testbail_gabgab = (void*)g_Gabgab;
___testbail_shptr = g_SHPtr;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
@ -66,7 +55,7 @@ bool TestBail(std::string &error)
new State_EatYams_Return(5),
NULL), "Part 1");
if (!___TestBail2(error))
if (!TestBail2(error))
return false;
CHECK_STATES((&g_States,
@ -96,6 +85,31 @@ bool TestBail(std::string &error)
new State_EatYams_Return(5),
NULL), "Part 4");
// Now, heh, try it the other way round.
Test_CompleteShutdown(g_SHPtr);
if (!TestBail2(error))
return false;
CHECK_STATES((&g_States,
new State_EatYams_Handler2_Called(0xDEAD),
new State_EatYams_Handler3_Called(0xBEEF),
new State_EatYams_Called(0xBEEF),
NULL), "Part 5");
SH_ADD_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_Handler2_Called(0xDEAD),
new State_EatYams_Handler3_Called(0xBEEF),
new State_EatYams_Handler1_Called(0xBEEF),
new State_EatYams_Called(0xBEEF),
new State_EatYams_Return(6),
NULL), "Part 6");
delete g_Gabgab;
return true;

View File

@ -4,14 +4,11 @@
#include <string>
#include "testevents.h"
bool ___TestBail2(std::string &error);
namespace
namespace N_TestBail
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
extern StateList g_States;
extern SourceHook::ISourceHook *g_SHPtr;
MAKE_STATE_1(State_EatYams_Called, int);
MAKE_STATE_1(State_EatYams_Handler1_Called, int);
MAKE_STATE_1(State_EatYams_Handler2_Called, int);
@ -28,12 +25,15 @@ namespace
}
};
SH_DECL_HOOK1(IGaben, EatYams, SH_NOATTRIB, 0, int, int);
extern IGaben *g_Gabgab;
IGaben *g_Gabgab;
bool TestBail2(std::string &error);
}
extern void *___testbail_gabgab;
extern SourceHook::ISourceHook *___testbail_shptr;
extern int ___testbail_EatYams_Handler2(int a);
extern int ___testbail_EatYams_Handler3(int a);
using namespace N_TestBail;
namespace
{
SourceHook::Plugin g_PLID;
SH_DECL_HOOK1(IGaben, EatYams, SH_NOATTRIB, 0, int, int);
}

View File

@ -5,21 +5,33 @@
#include "sourcehook_test.h"
#include "testbail.h"
// :TODO: Test new-old proto system compa
bool ___TestBail2(std::string &error)
int EatYams_Handler2(int a)
{
g_SHPtr = ___testbail_shptr;
g_PLID = 2;
g_Gabgab = (IGaben*)___testbail_gabgab;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, ___testbail_EatYams_Handler2, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, ___testbail_EatYams_Handler3, false);
int ret = g_Gabgab->EatYams(0xDEAD);
CHECK_COND(ret == 6, "Part 2.1");
return true;
ADD_STATE(State_EatYams_Handler2_Called(a));
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, 6, &IGaben::EatYams, (0xBEEF));
}
int EatYams_Handler3(int a)
{
ADD_STATE(State_EatYams_Handler3_Called(a));
RETURN_META_VALUE(MRES_IGNORED, 0);
}
namespace N_TestBail
{
bool TestBail2(std::string &error)
{
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);
int ret = g_Gabgab->EatYams(0xDEAD);
CHECK_COND(ret == 6, "Part 2.1");
return true;
}
}

View File

@ -19,26 +19,24 @@
extern bool g_Verbose;
struct State
{
virtual ~State()
{
}
virtual bool IsEqual(State *other)
{
return (typeid(other) == typeid(this)) ? true : false;
}
virtual void Dump() = 0;
};
typedef std::list<State*> StateList;
namespace
{
struct State
{
virtual ~State()
{
}
virtual bool IsEqual(State *other)
{
return (typeid(other) == typeid(this)) ? true : false;
}
virtual void Dump() = 0;
};
typedef std::list<State*> StateList;
void DumpStates(StateList *sl)
{
for (StateList::iterator iter = sl->begin(); iter != sl->end(); ++iter)

View File

@ -7,7 +7,7 @@
// TEST LIST
// Tests sh_list, sh_tinyhash, sh_vector
// :TODO: vector test
// :TODO: vector test, list insert test
namespace
{

View File

@ -33,17 +33,23 @@ namespace
ADD_STATE(State_Func2(a));
return 1000;
}
// Overloaded version
virtual int Func2(int a, int b)
{
return 0xDEADFC;
}
};
void Handler1_Func1(int a)
{
ADD_STATE(State_H1_Func1(a));
RETURN_META_NEWPARAMS(MRES_IGNORED, Test, Func1, (5));
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));
RETURN_META_NEWPARAMS(MRES_IGNORED, &Test::Func1, (a - 5));
}
void HandlerPost_Func1(int a)
{
@ -54,7 +60,9 @@ namespace
int Handler1_Func2(int a)
{
ADD_STATE(State_H1_Func2(a));
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, 500, Test, Func2, (a - 10));
// Pfeeehhh, ugly, I know, but I had to test it :)
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, 500,
static_cast<int (Test::*)(int)>(&Test::Func2), (a - 10));
}
int HandlerPost_Func2(int a)