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:
parent
2d1d2f7abf
commit
b666b9acde
@ -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; \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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; \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user