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