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__ #ifndef __SOURCEHOOK_H__
#define __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 } #define SH_ASSERT(x) if (!(x)) __asm { int 3 }
// System // System
@ -73,26 +81,24 @@ namespace SourceHook
*/ */
typedef void* Plugin; typedef void* Plugin;
enum HookerAction enum HookManagerAction
{ {
HA_GetInfo = 0, // -> Only store info HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference HA_Register, // -> Save the pointer for future reference
HA_Unregister, // -> Clear the saved pointer HA_Unregister // -> Clear the saved pointer
HA_IfaceAdded, // -> Request call class
HA_IfaceRemoved // -> Release call class
}; };
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) * 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 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 struct Iface
{ {
@ -148,11 +154,11 @@ namespace SourceHook
} }
}; };
Plugin plug; //!< The owner plugin 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_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset int vtbl_offs; //!< The vtable offset
int thisptr_offs; //!< The this-pointer-adjuster 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_idx; //!< the vtable index of the hookfunc
int hookfunc_vtbl_offs; //!< the vtable offset 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 plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @param iface The interface pointer
* @param ifacesize The size of the class iface points to * @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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. * @brief Removes a hook.
@ -216,14 +222,14 @@ namespace SourceHook
* *
* @param plug The unique identifier of the plugin that calls this function * @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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 * @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 const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer 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 &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 &GetPrevResRef() = 0; //!< Gets the pointer to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable
@ -263,15 +269,15 @@ namespace SourceHook
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Macro interface // Macro interface
#define SET_META_RESULT(result) g_SHPtr->SetRes(result) #define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { g_SHPtr->SetRes(result); return; } while(0) #define RETURN_META(result) do { SH_GLOB_SHPTR->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { g_SHPtr->SetRes(result); return (value); } 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_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS g_SHPtr->GetPrevRes() #define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)g_SHPtr->GetOrigRet() #define META_RESULT_ORIG_RET(type) *(const type *)SH_GLOB_SHPTR->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)g_SHPtr->GetOverrideRet() #define META_RESULT_OVERRIDE_RET(type) *(const type *)SH_GLOB_SHPTR->GetOverrideRet()
#define META_IFACEPTR g_SHPtr->GetIfacePtr() #define META_IFACEPTR SH_GLOB_SHPTR->GetIfacePtr()
/** /**
@ -280,8 +286,8 @@ namespace SourceHook
* @param ifacetype The type of the interface * @param ifacetype The type of the interface
* @param ifaceptr The interface pointer * @param ifaceptr The interface pointer
*/ */
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(g_SHPtr->GetCallClass(ifaceptr, sizeof(ifacetype))) #define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(SH_GLOB_SHPTR->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) g_SHPtr->ReleaseCallClass(reinterpret_cast<void*>(ptr)) #define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \ #define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler) 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 SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \ #define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int Hooker(HookerAction action, HookerInfo *param) \ static int HookManPubFunc(HookManagerAction action, HookManagerInfo *param) \
{ \ { \
if (action == HA_GetInfo) \ if (action == HA_GetInfo) \
{ \ { \
@ -314,7 +320,7 @@ namespace SourceHook
param->vtbl_idx = mfi.vtblindex; \ param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \ param->vtbl_offs = mfi.vtbloffs; \
param->thisptr_offs = mfi.thisptroffs; \ param->thisptr_offs = mfi.thisptroffs; \
if (param->thisptr_offs) \ if (param->thisptr_offs < 0) \
return 2; /*No virtual inheritance supported*/ \ return 2; /*No virtual inheritance supported*/ \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \ GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vtbl_idx = mfi.vtblindex; \ param->hookfunc_vtbl_idx = mfi.vtblindex; \
@ -342,28 +348,28 @@ namespace SourceHook
struct SH_FHCls(ifacetype,ifacefunc,overload) \ struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \ { \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \ static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static HookerInfo *ms_HI; \ static HookManagerInfo *ms_HI; \
static const char *ms_Proto; \ 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) \ #define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
}; \ }; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \ const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \ 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, \ bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
return g_SHPtr->AddHook(g_Plug, iface, sizeof(ifacetype), \ return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, \ SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \ new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \ } \
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \ bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \ CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
return g_SHPtr->RemoveHook(g_Plug, iface, \ return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, &tmp, post); \ SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
} \ } \
} }
@ -371,25 +377,25 @@ namespace SourceHook
/* 1) Find the iface ptr */ \ /* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \ /* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \ 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); \ ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \ SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \ HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \ std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \ std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
rettype orig_ret, override_ret, plugin_ret; \ rettype orig_ret, override_ret, plugin_ret; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \ SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \ SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
g_SHPtr->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS(post, params) \ #define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \ 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; \ cur_res = MRES_IGNORED; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
@ -399,7 +405,7 @@ namespace SourceHook
if (cur_res >= MRES_OVERRIDE) \ if (cur_res >= MRES_OVERRIDE) \
{ \ { \
override_ret = plugin_ret; \ 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) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \ /* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \ 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); \ ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \ SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \ HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \ std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \ std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \ SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \ #define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \ 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; \ cur_res = MRES_IGNORED; \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \

View File

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

View File

@ -12,6 +12,14 @@
#ifndef __SOURCEHOOK_H__ #ifndef __SOURCEHOOK_H__
#define __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 } #define SH_ASSERT(x) if (!(x)) __asm { int 3 }
// System // System
@ -73,26 +81,24 @@ namespace SourceHook
*/ */
typedef void* Plugin; typedef void* Plugin;
enum HookerAction enum HookManagerAction
{ {
HA_GetInfo = 0, // -> Only store info HA_GetInfo = 0, // -> Only store info
HA_Register, // -> Save the pointer for future reference HA_Register, // -> Save the pointer for future reference
HA_Unregister, // -> Clear the saved pointer HA_Unregister // -> Clear the saved pointer
HA_IfaceAdded, // -> Request call class
HA_IfaceRemoved // -> Release call class
}; };
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) * 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 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 struct Iface
{ {
@ -148,11 +154,11 @@ namespace SourceHook
} }
}; };
Plugin plug; //!< The owner plugin 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_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset int vtbl_offs; //!< The vtable offset
int thisptr_offs; //!< The this-pointer-adjuster 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_idx; //!< the vtable index of the hookfunc
int hookfunc_vtbl_offs; //!< the vtable offset 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 plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @param iface The interface pointer
* @param ifacesize The size of the class iface points to * @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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. * @brief Removes a hook.
@ -216,14 +222,14 @@ namespace SourceHook
* *
* @param plug The unique identifier of the plugin that calls this function * @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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 * @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 const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer 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 &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 &GetPrevResRef() = 0; //!< Gets the pointer to the previous meta result
virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable
@ -263,15 +269,15 @@ namespace SourceHook
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Macro interface // Macro interface
#define SET_META_RESULT(result) g_SHPtr->SetRes(result) #define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result)
#define RETURN_META(result) do { g_SHPtr->SetRes(result); return; } while(0) #define RETURN_META(result) do { SH_GLOB_SHPTR->SetRes(result); return; } while(0)
#define RETURN_META_VALUE(result, value) do { g_SHPtr->SetRes(result); return (value); } 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_STATUS SH_GLOB_SHPTR->GetStatus()
#define META_RESULT_PREVIOUS g_SHPtr->GetPrevRes() #define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes()
#define META_RESULT_ORIG_RET(type) *(const type *)g_SHPtr->GetOrigRet() #define META_RESULT_ORIG_RET(type) *(const type *)SH_GLOB_SHPTR->GetOrigRet()
#define META_RESULT_OVERRIDE_RET(type) *(const type *)g_SHPtr->GetOverrideRet() #define META_RESULT_OVERRIDE_RET(type) *(const type *)SH_GLOB_SHPTR->GetOverrideRet()
#define META_IFACEPTR g_SHPtr->GetIfacePtr() #define META_IFACEPTR SH_GLOB_SHPTR->GetIfacePtr()
/** /**
@ -280,8 +286,8 @@ namespace SourceHook
* @param ifacetype The type of the interface * @param ifacetype The type of the interface
* @param ifaceptr The interface pointer * @param ifaceptr The interface pointer
*/ */
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(g_SHPtr->GetCallClass(ifaceptr, sizeof(ifacetype))) #define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(SH_GLOB_SHPTR->GetCallClass(ifaceptr, sizeof(ifacetype)))
#define SH_RELEASE_CALLCLASS(ptr) g_SHPtr->ReleaseCallClass(reinterpret_cast<void*>(ptr)) #define SH_RELEASE_CALLCLASS(ptr) SH_GLOB_SHPTR->ReleaseCallClass(reinterpret_cast<void*>(ptr))
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \ #define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler) 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 SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \ #define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int Hooker(HookerAction action, HookerInfo *param) \ static int HookManPubFunc(HookManagerAction action, HookManagerInfo *param) \
{ \ { \
if (action == HA_GetInfo) \ if (action == HA_GetInfo) \
{ \ { \
@ -342,28 +348,28 @@ namespace SourceHook
struct SH_FHCls(ifacetype,ifacefunc,overload) \ struct SH_FHCls(ifacetype,ifacefunc,overload) \
{ \ { \
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \ static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
static HookerInfo *ms_HI; \ static HookManagerInfo *ms_HI; \
static const char *ms_Proto; \ 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) \ #define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
}; \ }; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \ const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \ 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, \ bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
return g_SHPtr->AddHook(g_Plug, iface, sizeof(ifacetype), \ return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, sizeof(ifacetype), \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, \ SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \ new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \ } \
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \ bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \ CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
return g_SHPtr->RemoveHook(g_Plug, iface, \ return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, \
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, &tmp, post); \ SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, &tmp, post); \
} \ } \
} }
@ -371,25 +377,25 @@ namespace SourceHook
/* 1) Find the iface ptr */ \ /* 1) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \ /* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \ 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); \ ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \ SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \ HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \ std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \ std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
rettype orig_ret, override_ret, plugin_ret; \ rettype orig_ret, override_ret, plugin_ret; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \ SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \ SH_GLOB_SHPTR->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
g_SHPtr->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS(post, params) \ #define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \ 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; \ cur_res = MRES_IGNORED; \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
@ -399,7 +405,7 @@ namespace SourceHook
if (cur_res >= MRES_OVERRIDE) \ if (cur_res >= MRES_OVERRIDE) \
{ \ { \
override_ret = plugin_ret; \ 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) Find the iface ptr */ \
/* 1.1) Adjust to original this pointer */ \ /* 1.1) Adjust to original this pointer */ \
void *origthis = this - ms_HI->thisptr_offs; \ 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); \ ms_HI->ifaces.end(), origthis); \
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \ SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
HookerInfo::Iface &ci = *ifaceiter; \ HookManagerInfo::Iface &ci = *ifaceiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \ std::list<HookManagerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \ std::list<HookManagerInfo::Iface::Hook> &postlist = ci.hooks_post; \
META_RES &cur_res = g_SHPtr->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = g_SHPtr->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
g_SHPtr->SetIfacePtr(ci.ptr); \ SH_GLOB_SHPTR->SetIfacePtr(ci.ptr); \
g_SHPtr->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \ #define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \ 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; \ cur_res = MRES_IGNORED; \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \

View File

@ -22,9 +22,26 @@ namespace SourceHook
class CSourceHookImpl : public ISourceHook 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; typedef std::list<CallClass> Impl_CallClassList;
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses 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 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); const char *proto, int vtblofs, int vtblidx, int thisptrofs);
void FreeCallClass(CallClass &cc); void FreeCallClass(CallClass &cc);
@ -57,12 +74,12 @@ namespace SourceHook
~CSourceHookImpl(); ~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); 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(); void CompleteShutdown();
@ -73,11 +90,12 @@ namespace SourceHook
* *
* @param plug The unique identifier of the plugin that calls this function * @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @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 handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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. * @brief Removes a hook.
@ -86,16 +104,14 @@ namespace SourceHook
* *
* @param plug The unique identifier of the plugin that calls this function * @param plug The unique identifier of the plugin that calls this function
* @param iface The interface pointer * @param iface The interface pointer
* @param vtableoffset Offset to the vtable, in bytes * @param myHookMan A hook manager function that should be capable of handling the function
* @param vtableidx Pointer to the vtable index of the function
* @param proto A text version of the function prototype; generated by the macros
* @param handler A pointer to a FastDelegate containing the hook handler * @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post 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 * @param plug The unique identifier of the plugin in question
*/ */
@ -123,7 +139,7 @@ namespace SourceHook
virtual void *GetIfacePtr(); //!< Gets the interface pointer 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 &GetCurResRef(); //!< Gets the pointer to the current meta result
virtual META_RES &GetPrevResRef(); //!< Gets the pointer to the previous 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 virtual META_RES &GetStatusRef(); //!< Gets the pointer to the status variable