1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-28 10:24:20 +01:00

Added possibility to specify your own g_SHPtr / g_Plug, removed all occurencies of The Word, fixed UnloadPlugin and CompleteShutdown

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%407
This commit is contained in:
Pavol Marko 2005-04-16 16:55:53 +00:00
parent 2d1d2f7abf
commit b666b9acde
4 changed files with 285 additions and 269 deletions

View File

@ -12,6 +12,14 @@
#ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
#endif
#ifndef SH_GLOB_PLUGPTR
#define SH_GLOB_PLUGPTR g_Plug
#endif
#define SH_ASSERT(x) if (!(x)) __asm { int 3 }
// System
@ -73,26 +81,24 @@ namespace SourceHook
*/
typedef void* Plugin;
enum HookerAction
enum HookManagerAction
{
HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference
HA_Unregister, // -> Clear the saved pointer
HA_IfaceAdded, // -> Request call class
HA_IfaceRemoved // -> Release call class
HA_Unregister // -> Clear the saved pointer
};
struct HookerInfo;
struct HookManagerInfo;
/**
* @brief Pointer to hooker type
* @brief Pointer to hook manager type
*
* A "hooker" is a the only thing that knows the actual protoype of the function at compile time.
* A "hook manager" is a the only thing that knows the actual protoype of the function at compile time.
*
* @param hi A pointer to a HookerInfo structure. The hooker should fill it and store it for
* @param hi A pointer to a HookManagerInfo structure. The hook manager should fill it and store it for
* future reference (mainly if something should get hooked to its hookfunc)
*/
typedef int (*Hooker)(HookerAction ha, HookerInfo *hi);
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi);
class ISHDelegate
{
@ -126,9 +132,9 @@ namespace SourceHook
};
/**
* @brief This structure contains information about a hooker (hook manager)
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookerInfo
struct HookManagerInfo
{
struct Iface
{
@ -148,11 +154,11 @@ namespace SourceHook
}
};
Plugin plug; //!< The owner plugin
const char *proto; //!< The prototype of the function the hooker is responsible for
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
int thisptr_offs; //!< The this-pointer-adjuster
Hooker func; //!< The interface to the hooker
HookManagerPubFunc func; //!< The interface to the hook manager
int hookfunc_vtbl_idx; //!< the vtable index of the hookfunc
int hookfunc_vtbl_offs; //!< the vtable offset of the hookfunc
@ -203,11 +209,11 @@ namespace SourceHook
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param ifacesize The size of the class iface points to
* @param myHooker A hooker function that should be capable of handling the function
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
/**
* @brief Removes a hook.
@ -216,14 +222,14 @@ namespace SourceHook
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param myHooker A hooker function that should be capable of handling the function
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool RemoveHook(Plugin plug, void *iface, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
virtual bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
/**
* @brief Checks whether a plugin has (a) hooker(s) that is/are currently used by other plugins
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
*
* @param plug The unique identifier of the plugin in question
*/
@ -251,7 +257,7 @@ namespace SourceHook
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hookers
// For hook managers
virtual META_RES &GetCurResRef() = 0; //!< Gets the pointer to the current meta result
virtual META_RES &GetPrevResRef() = 0; //!< Gets the pointer to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable
@ -263,15 +269,15 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
// Macro interface
#define SET_META_RESULT(result) g_SHPtr->SetRes(result)
#define RETURN_META(result) do { g_SHPtr->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { g_SHPtr->SetRes(result); return (value); } while(0)
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SH_GLOB_SHPTR->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SH_GLOB_SHPTR->SetRes(result); return (value); } while(0)
#define META_RESULT_STATUS g_SHPtr->GetStatus()
#define META_RESULT_PREVIOUS g_SHPtr->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)g_SHPtr->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)g_SHPtr->GetOverrideRet()
#define META_IFACEPTR g_SHPtr->GetIfacePtr()
#define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)SH_GLOB_SHPTR->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)SH_GLOB_SHPTR->GetOverrideRet()
#define META_IFACEPTR SH_GLOB_SHPTR->GetIfacePtr()
/**
@ -280,8 +286,8 @@ namespace SourceHook
* @param ifacetype The type of the interface
* @param ifaceptr The interface pointer
*/
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(g_SHPtr->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) g_SHPtr->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(SH_GLOB_SHPTR->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
@ -303,8 +309,8 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
#define SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int Hooker(HookerAction action, HookerInfo *param) \
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(HookManagerAction action, HookManagerInfo *param) \
{ \
if (action == HA_GetInfo) \
{ \
@ -314,7 +320,7 @@ namespace SourceHook
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
param->thisptr_offs = mfi.thisptroffs; \
if (param->thisptr_offs) \
if (param->thisptr_offs < 0) \
return 2; /*No virtual inheritance supported*/ \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vtbl_idx = mfi.vtblindex; \
@ -342,28 +348,28 @@ namespace SourceHook
struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static HookerInfo *ms_HI; \
static HookManagerInfo *ms_HI; \
static const char *ms_Proto; \
SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
}; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
HookerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
return g_SHPtr->AddHook(g_Plug, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
return g_SHPtr->RemoveHook(g_Plug, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, &tmp, post); \
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
} \
}
@ -371,25 +377,25 @@ namespace SourceHook
/* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \
HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
rettype orig_ret, override_ret, plugin_ret; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
g_SHPtr->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
{ \
cur_res = MRES_IGNORED; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
@ -399,7 +405,7 @@ namespace SourceHook
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
g_SHPtr->SetOverrideRet(&override_ret); \
SH_GLOB_SHPTR->SetOverrideRet(&override_ret); \
} \
}
@ -424,23 +430,23 @@ namespace SourceHook
/* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \
HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
{ \
cur_res = MRES_IGNORED; \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \

View File

@ -83,18 +83,18 @@ namespace SourceHook
bool CSourceHookImpl::IsPluginInUse(Plugin plug)
{
// Iterate through all hookers which are in this plugin
// Iterate through all hook managers which are in this plugin
// Iterate through their hooks
// If a hook from an other plugin is found, return true
// Return false otherwise
for (HookerInfoList::iterator iter = m_Hookers.begin(); iter != m_Hookers.end(); ++iter)
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
{
if (iter->plug == plug && !iter->ifaces.empty())
{
for (std::list<HookerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end(); ++iter2)
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end(); ++iter2)
{
std::list<HookerInfo::Iface::Hook>::iterator iter3;
std::list<HookManagerInfo::Iface::Hook>::iterator iter3;
for (iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
if (iter3->plug == plug)
return true;
@ -109,41 +109,43 @@ namespace SourceHook
void CSourceHookImpl::UnloadPlugin(Plugin plug)
{
// Get a list of hookers that are in this plugin and are used by other plugins
// 1) Manually remove all hooks by this plugin
std::list<RemoveHookInfo> hookstoremove;
HookerInfoList tmphookers;
bool erase = false;
for (HookerInfoList::iterator iter = m_Hookers.begin(); iter != m_Hookers.end();
erase ? iter=m_Hookers.erase(iter) : ++iter)
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
{
if (iter->plug == plug && !iter->ifaces.empty())
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
++iter2)
{
bool found = false;
for (std::list<HookerInfo::Iface>::iterator iter2 = iter->ifaces.begin();
iter2 != iter->ifaces.end(); ++iter2)
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
if (iter3->plug == plug)
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, false));
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
if (iter3->plug == plug)
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, true));
}
}
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
RemoveHook(rmiter->plug, rmiter->iface, rmiter->hpf, rmiter->handler, rmiter->post);
// 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 (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end();
erase ? iter=m_HookMans.erase(iter) : ++iter)
{
if (iter->plug == plug)
{
if (!iter->ifaces.empty())
{
for (std::list<HookerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin();
iter3 != iter2->hooks_pre.end(); ++iter3)
{
if (iter3->plug != plug)
{
found = true;
break;
}
}
for (iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
{
if (iter3->plug != plug)
{
found = true;
break;
}
}
if (found)
{
tmphookers.push_back(*iter);
break;
}
// All hooks by this plugin are already removed
// So if there is an iface, it has to be used by an other plugin
tmphookmans.push_back(*iter);
}
erase = true;
}
@ -151,120 +153,106 @@ namespace SourceHook
erase = false;
}
// For each hooker:
for (HookerInfoList::iterator iter = tmphookers.begin(); iter != tmphookers.end(); ++iter)
// For each hook manager:
for (HookManInfoList::iterator iter = tmphookmans.begin(); iter != tmphookmans.end(); ++iter)
{
// Shutdown all ifaces and remove the hooks from this plugin from their lists
for (std::list<HookerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
erase ? iter2 = iter->ifaces.erase(iter2) : ++iter2)
{
*(reinterpret_cast<void**>(reinterpret_cast<char*>(iter2->ptr) + iter->vtbl_offs)
+ iter->vtbl_idx) = iter2->orig_entry;
for (std::list<HookerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end();
iter3->plug == plug ? iter3=iter2->hooks_pre.erase(iter3) : ++iter3) {}
for (std::list<HookerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end();
iter3->plug == plug ? iter3=iter2->hooks_post.erase(iter3) : ++iter3) {}
erase = iter2->hooks_pre.empty() && iter2->hooks_post.empty();
}
if (iter->ifaces.empty())
{
// Nothing more to do; no more ifaces to re-register
continue;
}
// 2) Find a suitable hooker in an other plugin
HookerInfoList::iterator newHooker = FindHooker(m_Hookers.begin(), m_Hookers.end(),
// Find a suitable hook manager in an other plugin
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
iter->proto, iter->vtbl_offs, iter->vtbl_idx, iter->thisptr_offs);
if (newHooker == m_Hookers.end())
if (newHookMan == m_HookMans.end())
{
// This should _never_ happen.
// If there is a hook from an other plugin, the plugin must have provided a hooker as well.
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
SH_ASSERT(0);
}
// AddHook should make sure that every plugin only has _one_ hooker for _one_ proto/vi/vo
SH_ASSERT(newHooker->plug != plug);
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo/thisptroffs
SH_ASSERT(newHookMan->plug != plug);
// 3) Register it!
newHooker->func(HA_Register, &(*iter));
for (std::list<HookerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
++iter2)
{
reinterpret_cast<void**>(reinterpret_cast<char*>(iter2->ptr) + iter->vtbl_offs)[iter->vtbl_idx] =
reinterpret_cast<void**>(reinterpret_cast<char*>(iter->hookfunc_inst) + iter->hookfunc_vtbl_offs)[iter->hookfunc_vtbl_idx];
}
// The first hooker should be always used - so the new hook manager has to be empty
SH_ASSERT(newHookMan->ifaces.empty());
// Move the ifaces from the old hook manager to the new one
newHookMan->ifaces = iter->ifaces;
// Unregister the old one, register the new one
iter->func(HA_Unregister, NULL);
newHookMan->func(HA_Register, &(*newHookMan));
}
}
void CSourceHookImpl::CompleteShutdown()
{
// Go through all hookers and shut down all interfaces
for (HookerInfoList::iterator iter = m_Hookers.begin(); iter != m_Hookers.end(); ++iter)
std::list<RemoveHookInfo> hookstoremove;
for (HookManInfoList::iterator iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
{
for (std::list<HookerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end(); ++iter2)
for (std::list<HookManagerInfo::Iface>::iterator iter2 = iter->ifaces.begin(); iter2 != iter->ifaces.end();
++iter2)
{
// Note that we can pass iter->func as "myHooker" because it is only used
// to retreive data
for (std::list<HookerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
RemoveHook(iter3->plug, iter2->ptr, iter->func, iter3->handler, false);
for (std::list<HookerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
RemoveHook(iter3->plug, iter2->ptr, iter->func, iter3->handler, true);
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_pre.begin(); iter3 != iter2->hooks_pre.end(); ++iter3)
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, false));
for (std::list<HookManagerInfo::Iface::Hook>::iterator iter3 = iter2->hooks_post.begin(); iter3 != iter2->hooks_post.end(); ++iter3)
hookstoremove.push_back(RemoveHookInfo(iter3->plug, iter2->ptr, iter->func, iter3->handler, true));
}
}
for (std::list<RemoveHookInfo>::iterator rmiter = hookstoremove.begin(); rmiter != hookstoremove.end(); ++rmiter)
RemoveHook(rmiter->plug, rmiter->iface, rmiter->hpf, rmiter->handler, rmiter->post);
m_HookMans.clear();
}
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int ifacesize, Hooker myHooker, ISHDelegate *handler, bool post)
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{
// 1) Get info about the hooker
HookerInfo tmp;
if (myHooker(HA_GetInfo, &tmp) != 0)
// 1) Get info about the hook manager
HookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Add the proposed hooker to the _end_ of the list if the plugin doesn't have a hooker with this proto/vo/vi registered
HookerInfoList::iterator hookeriter;
for (hookeriter = m_Hookers.begin(); hookeriter != m_Hookers.end(); ++hookeriter)
// 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 hookmaniter;
for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
{
if (hookeriter->plug == plug && strcmp(hookeriter->proto, tmp.proto) == 0 &&
hookeriter->vtbl_offs == tmp.vtbl_offs && hookeriter->vtbl_idx == tmp.vtbl_idx &&
hookeriter->thisptr_offs == tmp.thisptr_offs)
if (hookmaniter->plug == plug && strcmp(hookmaniter->proto, tmp.proto) == 0 &&
hookmaniter->vtbl_offs == tmp.vtbl_offs && hookmaniter->vtbl_idx == tmp.vtbl_idx &&
hookmaniter->thisptr_offs == tmp.thisptr_offs)
break;
}
if (hookeriter == m_Hookers.end())
if (hookmaniter == m_HookMans.end())
{
// No such hooker from this plugin yet, add it!
tmp.func = myHooker;
// No such hook manager from this plugin yet, add it!
tmp.func = myHookMan;
tmp.plug = plug;
m_Hookers.push_back(tmp);
m_HookMans.push_back(tmp);
}
// Then, search for a suitable hooker (from the beginning)
HookerInfoList::iterator hooker = FindHooker(m_Hookers.begin(), m_Hookers.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx, tmp.thisptr_offs);
SH_ASSERT(hooker != m_Hookers.end());
// Then, search for a suitable hook manager (from the beginning)
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx, tmp.thisptr_offs);
SH_ASSERT(hookman != m_HookMans.end());
// Tell it to store the pointer if it's not already active
if (hooker->ifaces.empty())
hooker->func(HA_Register, &(*hooker));
if (hookman->ifaces.empty())
hookman->func(HA_Register, &(*hookman));
std::list<HookerInfo::Iface>::iterator ifsiter = std::find(hooker->ifaces.begin(), hooker->ifaces.end(), iface);
std::list<HookManagerInfo::Iface>::iterator ifsiter = std::find(hookman->ifaces.begin(), hookman->ifaces.end(), iface);
if (ifsiter == hooker->ifaces.end())
if (ifsiter == hookman->ifaces.end())
{
HookerInfo::Iface ifs;
HookManagerInfo::Iface ifs;
ifs.ptr = iface;
ifs.callclass = GetCallClass(iface, ifacesize);
void *vtableptr = *reinterpret_cast<void**>(reinterpret_cast<char*>(iface) + hooker->vtbl_offs);
SetMemAccess(vtableptr, sizeof(void*) * hooker->vtbl_idx, SH_MEM_READ | SH_MEM_WRITE);
ifs.orig_entry = (*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hooker->vtbl_offs))[hooker->vtbl_idx];
(*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hooker->vtbl_offs))[hooker->vtbl_idx] =
(*reinterpret_cast<void***>(reinterpret_cast<char*>(hooker->hookfunc_inst) + hooker->hookfunc_vtbl_offs))[hooker->hookfunc_vtbl_idx];
hooker->ifaces.push_back(ifs);
ifsiter = hooker->ifaces.end();
void *vtableptr = *reinterpret_cast<void**>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs);
SetMemAccess(vtableptr, sizeof(void*) * hookman->vtbl_idx, SH_MEM_READ | SH_MEM_WRITE);
ifs.orig_entry = (*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs))[hookman->vtbl_idx];
(*reinterpret_cast<void***>(reinterpret_cast<char*>(iface) + hookman->vtbl_offs))[hookman->vtbl_idx] =
(*reinterpret_cast<void***>(reinterpret_cast<char*>(hookman->hookfunc_inst) + hookman->hookfunc_vtbl_offs))[hookman->hookfunc_vtbl_idx];
hookman->ifaces.push_back(ifs);
ifsiter = hookman->ifaces.end();
--ifsiter;
}
HookerInfo::Iface::Hook hookinfo;
HookManagerInfo::Iface::Hook hookinfo;
hookinfo.handler = handler;
hookinfo.plug = plug;
if (post)
@ -288,25 +276,25 @@ namespace SourceHook
return true;
}
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, Hooker myHooker, ISHDelegate *handler, bool post)
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{
HookerInfo tmp;
if (myHooker(HA_GetInfo, &tmp) != 0)
HookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Find the hooker and the hook
HookerInfoList::iterator hooker = FindHooker(m_Hookers.begin(), m_Hookers.end(),
// Find the hook manager and the hook
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx, tmp.thisptr_offs);
if (hooker == m_Hookers.end())
if (hookman == m_HookMans.end())
return false;
for (std::list<HookerInfo::Iface>::iterator ifaceiter = hooker->ifaces.begin(); ifaceiter != hooker->ifaces.end(); ++ifaceiter)
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookman->ifaces.begin(); ifaceiter != hookman->ifaces.end(); ++ifaceiter)
{
if (ifaceiter->ptr == iface)
{
std::list<HookerInfo::Iface::Hook> &hooks = post ? ifaceiter->hooks_post : ifaceiter->hooks_pre;
std::list<HookManagerInfo::Iface::Hook> &hooks = post ? ifaceiter->hooks_post : ifaceiter->hooks_pre;
bool erase;
for (std::list<HookerInfo::Iface::Hook>::iterator hookiter = hooks.begin();
for (std::list<HookManagerInfo::Iface::Hook>::iterator hookiter = hooks.begin();
hookiter != hooks.end(); erase ? hookiter = hooks.erase(hookiter) : ++hookiter)
{
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler);
@ -317,16 +305,16 @@ namespace SourceHook
{
// Deactivate the hook
(*reinterpret_cast<void***>(reinterpret_cast<char*>(ifaceiter->ptr) +
hooker->vtbl_offs))[hooker->vtbl_idx]= ifaceiter->orig_entry;
hookman->vtbl_offs))[hookman->vtbl_idx]= ifaceiter->orig_entry;
// Release the callclass
ReleaseCallClass(ifaceiter->callclass);
// Remove the iface info
hooker->ifaces.erase(ifaceiter);
hookman->ifaces.erase(ifaceiter);
if (hooker->ifaces.empty())
hooker->func(HA_Unregister, NULL);
if (hookman->ifaces.empty())
hookman->func(HA_Unregister, NULL);
}
// :TODO: Better return value? Or none?
return true;
@ -361,13 +349,13 @@ namespace SourceHook
tmp.refcounter = 1;
// Go through _all_ hooks and apply any needed patches
for (HookerInfoList::iterator hooker = m_Hookers.begin(); hooker != m_Hookers.end(); ++hooker)
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
{
for (std::list<HookerInfo::Iface>::iterator ifaceiter = hooker->ifaces.begin(); ifaceiter != hooker->ifaces.end(); ++ifaceiter)
for (std::list<HookManagerInfo::Iface>::iterator ifaceiter = hookman->ifaces.begin(); ifaceiter != hookman->ifaces.end(); ++ifaceiter)
{
if (ifaceiter->ptr == iface)
{
if (!ApplyCallClassPatch(tmp, hooker->vtbl_offs, hooker->vtbl_idx, ifaceiter->orig_entry))
if (!ApplyCallClassPatch(tmp, hookman->vtbl_offs, hookman->vtbl_idx, ifaceiter->orig_entry))
{
FreeCallClass(tmp);
return NULL;
@ -479,16 +467,16 @@ namespace SourceHook
}
CSourceHookImpl::HookerInfoList::iterator CSourceHookImpl::FindHooker(HookerInfoList::iterator begin,
HookerInfoList::iterator end, const char *proto, int vtblofs, int vtblidx, int thisptrofs)
CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin,
HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx, int thisptrofs)
{
for (HookerInfoList::iterator hookeriter = m_Hookers.begin(); hookeriter != m_Hookers.end(); ++hookeriter)
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
{
if (strcmp(hookeriter->proto, proto) == 0 && hookeriter->vtbl_offs == vtblofs && hookeriter->vtbl_idx == vtblidx &&
hookeriter->thisptr_offs == thisptrofs)
if (strcmp(hookmaniter->proto, proto) == 0 && hookmaniter->vtbl_offs == vtblofs && hookmaniter->vtbl_idx == vtblidx &&
hookmaniter->thisptr_offs == thisptrofs)
break;
}
return hookeriter;
return hookmaniter;
}

View File

@ -12,6 +12,14 @@
#ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__
#ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr
#endif
#ifndef SH_GLOB_PLUGPTR
#define SH_GLOB_PLUGPTR g_Plug
#endif
#define SH_ASSERT(x) if (!(x)) __asm { int 3 }
// System
@ -73,26 +81,24 @@ namespace SourceHook
*/
typedef void* Plugin;
enum HookerAction
enum HookManagerAction
{
HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference
HA_Unregister, // -> Clear the saved pointer
HA_IfaceAdded, // -> Request call class
HA_IfaceRemoved // -> Release call class
HA_Unregister // -> Clear the saved pointer
};
struct HookerInfo;
struct HookManagerInfo;
/**
* @brief Pointer to hooker type
* @brief Pointer to hook manager type
*
* A "hooker" is a the only thing that knows the actual protoype of the function at compile time.
* A "hook manager" is a the only thing that knows the actual protoype of the function at compile time.
*
* @param hi A pointer to a HookerInfo structure. The hooker should fill it and store it for
* @param hi A pointer to a HookManagerInfo structure. The hook manager should fill it and store it for
* future reference (mainly if something should get hooked to its hookfunc)
*/
typedef int (*Hooker)(HookerAction ha, HookerInfo *hi);
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi);
class ISHDelegate
{
@ -126,9 +132,9 @@ namespace SourceHook
};
/**
* @brief This structure contains information about a hooker (hook manager)
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookerInfo
struct HookManagerInfo
{
struct Iface
{
@ -148,11 +154,11 @@ namespace SourceHook
}
};
Plugin plug; //!< The owner plugin
const char *proto; //!< The prototype of the function the hooker is responsible for
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
int thisptr_offs; //!< The this-pointer-adjuster
Hooker func; //!< The interface to the hooker
HookManagerPubFunc func; //!< The interface to the hook manager
int hookfunc_vtbl_idx; //!< the vtable index of the hookfunc
int hookfunc_vtbl_offs; //!< the vtable offset of the hookfunc
@ -203,11 +209,11 @@ namespace SourceHook
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param ifacesize The size of the class iface points to
* @param myHooker A hooker function that should be capable of handling the function
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
/**
* @brief Removes a hook.
@ -216,14 +222,14 @@ namespace SourceHook
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param myHooker A hooker function that should be capable of handling the function
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual bool RemoveHook(Plugin plug, void *iface, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
virtual bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0;
/**
* @brief Checks whether a plugin has (a) hooker(s) that is/are currently used by other plugins
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
*
* @param plug The unique identifier of the plugin in question
*/
@ -251,7 +257,7 @@ namespace SourceHook
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hookers
// For hook managers
virtual META_RES &GetCurResRef() = 0; //!< Gets the pointer to the current meta result
virtual META_RES &GetPrevResRef() = 0; //!< Gets the pointer to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable
@ -263,15 +269,15 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
// Macro interface
#define SET_META_RESULT(result) g_SHPtr->SetRes(result)
#define RETURN_META(result) do { g_SHPtr->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { g_SHPtr->SetRes(result); return (value); } while(0)
#define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { SH_GLOB_SHPTR->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { SH_GLOB_SHPTR->SetRes(result); return (value); } while(0)
#define META_RESULT_STATUS g_SHPtr->GetStatus()
#define META_RESULT_PREVIOUS g_SHPtr->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)g_SHPtr->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)g_SHPtr->GetOverrideRet()
#define META_IFACEPTR g_SHPtr->GetIfacePtr()
#define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)SH_GLOB_SHPTR->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)SH_GLOB_SHPTR->GetOverrideRet()
#define META_IFACEPTR SH_GLOB_SHPTR->GetIfacePtr()
/**
@ -280,8 +286,8 @@ namespace SourceHook
* @param ifacetype The type of the interface
* @param ifaceptr The interface pointer
*/
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(g_SHPtr->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) g_SHPtr->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(SH_GLOB_SHPTR->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
@ -303,8 +309,8 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
#define SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int Hooker(HookerAction action, HookerInfo *param) \
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(HookManagerAction action, HookManagerInfo *param) \
{ \
if (action == HA_GetInfo) \
{ \
@ -342,28 +348,28 @@ namespace SourceHook
struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static HookerInfo *ms_HI; \
static HookManagerInfo *ms_HI; \
static const char *ms_Proto; \
SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
}; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
HookerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
return g_SHPtr->AddHook(g_Plug, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
return g_SHPtr->RemoveHook(g_Plug, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, &tmp, post); \
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
} \
}
@ -371,25 +377,25 @@ namespace SourceHook
/* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \
HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
rettype orig_ret, override_ret, plugin_ret; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
g_SHPtr->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
{ \
cur_res = MRES_IGNORED; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
@ -399,7 +405,7 @@ namespace SourceHook
if (cur_res >= MRES_OVERRIDE) \
{ \
override_ret = plugin_ret; \
g_SHPtr->SetOverrideRet(&override_ret); \
SH_GLOB_SHPTR->SetOverrideRet(&override_ret); \
} \
}
@ -424,23 +430,23 @@ namespace SourceHook
/* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
std::list<HookManagerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \
HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \
std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOverrideRet(NULL);
SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
for (std::list<HookManagerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
{ \
cur_res = MRES_IGNORED; \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \

View File

@ -22,9 +22,26 @@ namespace SourceHook
class CSourceHookImpl : public ISourceHook
{
/**
* @brief A list of HookerInfo structures
* @brief A hook can be removed if you have this information
*/
typedef std::list<HookerInfo> HookerInfoList;
struct RemoveHookInfo
{
RemoveHookInfo(Plugin p, void *i, HookManagerPubFunc h, ISHDelegate *hd, bool ps)
: plug(p), iface(i), hpf(h), handler(hd), post(ps)
{
}
Plugin plug;
void *iface;
HookManagerPubFunc hpf;
ISHDelegate *handler;
bool post;
};
/**
* @brief A list of HookManagerInfo structures
*/
typedef std::list<HookManagerInfo> HookManInfoList;
/**
@ -33,14 +50,14 @@ namespace SourceHook
typedef std::list<CallClass> Impl_CallClassList;
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
HookerInfoList m_Hookers; //!< A list of hookers
HookManInfoList m_HookMans; //!< A list of hook managers
int m_PageSize; //!< Stores the system's page size
/**
* @brief Finds a hooker for a function based on a text-prototype, a vtable offset and a vtable index
* @brief Finds a hook manager for a function based on a text-prototype, a vtable offset and a vtable index
*/
HookerInfoList::iterator FindHooker(HookerInfoList::iterator begin, HookerInfoList::iterator end,
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
const char *proto, int vtblofs, int vtblidx, int thisptrofs);
void FreeCallClass(CallClass &cc);
@ -57,12 +74,12 @@ namespace SourceHook
~CSourceHookImpl();
/**
* @brief Make sure that a plugin is not used by any other plugins anymore, and unregister all its hookers
* @brief Make sure that a plugin is not used by any other plugins anymore, and unregister all its hook managers
*/
void UnloadPlugin(Plugin plug);
/**
* @brief Shut down the whole system, unregister all hookers
* @brief Shut down the whole system, unregister all hook managers
*/
void CompleteShutdown();
@ -73,11 +90,12 @@ namespace SourceHook
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param myHooker A hooker (hook manager) function that should be capable of handling the corresponding function
* @param ifacesize The size of the class iface points to
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
bool AddHook(Plugin plug, void *iface, int ifacesize, Hooker myHooker, ISHDelegate *handler, bool post);
bool AddHook(Plugin plug, void *iface, int ifacesize, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
/**
* @brief Removes a hook.
@ -86,16 +104,14 @@ namespace SourceHook
*
* @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer
* @param vtableoffset Offset to the vtable, in bytes
* @param vtableidx Pointer to the vtable index of the function
* @param proto A text version of the function prototype; generated by the macros
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
bool RemoveHook(Plugin plug, void *iface, Hooker myHooker, ISHDelegate *handler, bool post);
bool RemoveHook(Plugin plug, void *iface, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post);
/**
* @brief Checks whether a plugin has (a) hooker(s) that is/are currently used by other plugins
* @brief Checks whether a plugin has (a) hook manager(s) that is/are currently used by other plugins
*
* @param plug The unique identifier of the plugin in question
*/
@ -123,7 +139,7 @@ namespace SourceHook
virtual void *GetIfacePtr(); //!< Gets the interface pointer
//////////////////////////////////////////////////////////////////////////
// For hookers
// For hook managers
virtual META_RES &GetCurResRef(); //!< Gets the pointer to the current meta result
virtual META_RES &GetPrevResRef(); //!< Gets the pointer to the previous meta result
virtual META_RES &GetStatusRef(); //!< Gets the pointer to the status variable