diff --git a/core/sourcehook/sourcehook.cpp b/core/sourcehook/sourcehook.cpp index 8b66b2c3..a4362d3c 100644 --- a/core/sourcehook/sourcehook.cpp +++ b/core/sourcehook/sourcehook.cpp @@ -97,6 +97,18 @@ namespace SourceHook int CSourceHookImpl::AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) + { + return AddHook(plug, mode, iface, thisptr_offs, HookManagerPubFuncHandler(myHookMan), handler, post); + } + + int CSourceHookImpl::AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post) + { + return AddHook(plug, mode, iface, thisptr_offs, HookManagerPubFuncHandler(myHookMan), handler, post); + } + + int CSourceHookImpl::AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + ISHDelegate *handler, bool post) { if (mode != Hook_Normal && mode != Hook_VP && mode != Hook_DVP) return 0; @@ -172,6 +184,18 @@ namespace SourceHook bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) + { + return RemoveHook(plug, iface, thisptr_offs, HookManagerPubFuncHandler(myHookMan), handler, post); + } + + bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post) + { + return RemoveHook(plug, iface, thisptr_offs, HookManagerPubFuncHandler(myHookMan), handler, post); + } + + bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + ISHDelegate *handler, bool post) { // Get info about hook manager and compute adjustediface CHookManager tmpHookMan(plug, myHookMan); @@ -417,6 +441,18 @@ namespace SourceHook } void CSourceHookImpl::RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) + { + // Find the hook manager + RemoveHookManager(plug, HookManagerPubFuncHandler(pubFunc)); + } + + void CSourceHookImpl::RemoveHookManager(Plugin plug, IHookManagerMemberFunc* pubFunc) + { + // Find the hook manager + RemoveHookManager(plug, HookManagerPubFuncHandler(pubFunc)); + } + + void CSourceHookImpl::RemoveHookManager(Plugin plug, const HookManagerPubFuncHandler &pubFunc) { // Find the hook manager CHookManList::iterator hookman_iter = m_HookManList.find(CHookManager::Descriptor(plug, pubFunc)); diff --git a/core/sourcehook/sourcehook.h b/core/sourcehook/sourcehook.h index f562bc23..985ea789 100644 --- a/core/sourcehook/sourcehook.h +++ b/core/sourcehook/sourcehook.h @@ -16,6 +16,8 @@ #ifndef __SOURCEHOOK_H__ #define __SOURCEHOOK_H__ +#include + // Interface revisions: // 1 - Initial revision // 2 - Changed to virtual functions for iterators and all queries @@ -40,6 +42,15 @@ #define SH_HOOKMANAUTOGEN_IFACE_VERSION 1 #define SH_HOOKMANAUTOGEN_IMPL_VERSION 1 +namespace SourceHook +{ +class ISourceHook; +typedef int Plugin; +} + +extern SourceHook::ISourceHook *g_SHPtr; +extern SourceHook::Plugin g_PLID; + // The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook // It's used in various macros #ifndef SH_GLOB_SHPTR @@ -247,12 +258,146 @@ namespace SourceHook * @brief Pointer to hook manager interface function * * The hook manager should store hi for later use if store==true. It should then call hi->SetInfo(...) if hi - * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. + * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. * * @param hi A pointer to IHookManagerInfo */ typedef int (*HookManagerPubFunc)(bool store, IHookManagerInfo *hi); + /** + * @brief Pointer to hook manager interface function for member and static functions + * + * The hook manager should store hi for later use if store==true. It should then call hi->SetInfo(...) if hi + * is non-null. The hook manager can return 0 for success or a non-zero value if it doesn't want to be used. + * + * @param hi A pointer to IHookManagerInfo + */ + + class IHookManagerMemberFunc + { + public: + virtual ~IHookManagerMemberFunc() = default; + virtual int Call(bool store, IHookManagerInfo *hi) const = 0; + }; + + class HookManagerPubFuncHandler + { + public: + HookManagerPubFuncHandler() + : staticFunc_(nullptr) + , memberFunc_(nullptr) + { + } + + explicit HookManagerPubFuncHandler(HookManagerPubFunc func) + : staticFunc_(func) + , memberFunc_(nullptr) + { + } + + explicit HookManagerPubFuncHandler(IHookManagerMemberFunc* funcHandler) + : staticFunc_(nullptr) + , memberFunc_(funcHandler) + { + } + + explicit HookManagerPubFuncHandler(const HookManagerPubFuncHandler& other) + : staticFunc_(other.staticFunc_) + , memberFunc_(other.memberFunc_) + { + } + + explicit HookManagerPubFuncHandler(HookManagerPubFuncHandler&& other) + : staticFunc_(other.staticFunc_) + , memberFunc_(other.memberFunc_) + { + other.staticFunc_ = nullptr; + other.memberFunc_ = nullptr; + } + + HookManagerPubFuncHandler& operator=(const HookManagerPubFuncHandler& other) + { + staticFunc_ = other.staticFunc_; + memberFunc_ = other.memberFunc_; + return *this; + } + + HookManagerPubFuncHandler& operator=(HookManagerPubFuncHandler&& other) + { + if (this == &other) + return *this; + + staticFunc_ = other.staticFunc_; + memberFunc_ = other.memberFunc_; + other.staticFunc_ = nullptr; + other.memberFunc_ = nullptr; + return *this; + } + + HookManagerPubFuncHandler& operator=(HookManagerPubFunc func) + { + staticFunc_ = func; + memberFunc_ = nullptr; + return *this; + } + + HookManagerPubFuncHandler& operator=(IHookManagerMemberFunc* funcHandler) + { + staticFunc_ = nullptr; + memberFunc_ = funcHandler; + return *this; + } + + operator bool() const + { + return (staticFunc_ != nullptr || + memberFunc_ != nullptr); + } + + operator HookManagerPubFunc() const + { + return staticFunc_; + } + + operator IHookManagerMemberFunc*() const + { + return memberFunc_; + } + + int operator()(bool store, IHookManagerInfo *hi) const + { + if(staticFunc_ != nullptr) + return staticFunc_(store, hi); + + if(memberFunc_ != nullptr) + return memberFunc_->Call(store, hi); + + return 0; + } + + bool operator==(const HookManagerPubFuncHandler &rhs) const + { + return staticFunc_ == rhs.staticFunc_ && + memberFunc_ == rhs.memberFunc_; + } + + bool operator==(HookManagerPubFunc staticFunc) const + { + return staticFunc_ == staticFunc && + memberFunc_ == nullptr; + } + + bool operator==(const IHookManagerMemberFunc *memberFunc) const + { + return staticFunc_ == nullptr && + memberFunc_ == memberFunc; + } + + private: + HookManagerPubFunc staticFunc_; + IHookManagerMemberFunc* memberFunc_; + }; + class ISHDelegate { public: @@ -353,7 +498,7 @@ namespace SourceHook Hook_Normal, Hook_VP, Hook_DVP - }; + }; /** * @brief Add a (VP) hook. @@ -424,7 +569,7 @@ namespace SourceHook * @brief Remove a hook manager. Auto-removes all hooks attached to it from plugin plug. * * @param plug The owner of the hook manager - * @param pubFunc The hook manager's info function + * @param pubFunc The hook manager's info function */ virtual void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc) = 0; @@ -499,6 +644,36 @@ namespace SourceHook const void *origRetPtr, void *overrideRetPtr) = 0; virtual void EndContext(IHookContext *pCtx) = 0; + + /** + * @brief Add a (VP) hook. + * + * @return non-zero hook id on success, 0 otherwise + * + * @param plug The unique identifier of the plugin that calls this function + * @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook) + * @param iface The interface pointer + * @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 the hook handler something + * @param post Set to true if you want a post handler + */ + + virtual int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post) = 0; + + // Source backwarts compat (only for normal hooks) + virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post) = 0; + + /** + * @brief Remove a hook manager. Auto-removes all hooks attached to it from plugin plug. + * + * @param plug The owner of the hook manager + * @param pubFunc The hook manager's info function + */ + + virtual void RemoveHookManager(Plugin plug, IHookManagerMemberFunc* pubFunc) = 0; }; @@ -4924,5 +5099,500 @@ namespace SourceHook } } + +namespace SourceHook +{ + +// Get type info for type T +template +inline void TypeInfo(PassInfo& passInfo) +{ + passInfo.size = sizeof(T); + passInfo.type = GetPassInfo::type; + passInfo.flags = GetPassInfo::flags; +} + +// Get type info for type T +template<> +inline void TypeInfo(PassInfo& passInfo) +{ + passInfo.size = 1; + passInfo.type = 0; + passInfo.flags = 0; +} + +template +class PassInfoInitializer +{ +public: + constexpr PassInfoInitializer() + { + InitializePassInfo(); + } + + const PassInfo *ParamsPassInfo() const + { + return params_; + } + + const size_t ParamsPassInfoSize() const + { + return sizeof...(ArgsType); + } + +private: + template + inline typename std::enable_if::type InitializePassInfo() + { + TypeInfo(params_[index]); + InitializePassInfo(); + } + + template + inline void InitializePassInfo() + { + TypeInfo(params_[index]); + } + + PassInfo params_[sizeof...(ArgsType)]; +}; + +template +struct ReturnTypeInfo +{ + static const size_t size() + { + return sizeof(T); + } + + static const int type() + { + return GetPassInfo::type; + } + + static const unsigned int flags() + { + return GetPassInfo::flags; + } +}; + +template <> +struct ReturnTypeInfo +{ + static const size_t size() + { + return 0; // why isn't it sizeof(void) like in TypeInfo? + } + + static const int type() + { + return 0; + } + + static const unsigned int flags() + { + return 0; + } +}; + +template +class TypedValueHandler +{ +public: + TypedValueHandler(R value) + : value_(value) + { + } + + operator R() const + { + return value_; + } + +private: + R value_; +}; + +template<> +class TypedValueHandler +{ +}; + +template +class CHookManagerMemberFuncHandler : public IHookManagerMemberFunc +{ +public: + typedef int (T::*HookManagerMemberFunc)(bool store, IHookManagerInfo *hi); + + explicit CHookManagerMemberFuncHandler(T* funcHandler, HookManagerMemberFunc func) + : funcHandler_(funcHandler) + , func_(func) + { + } + + virtual ~CHookManagerMemberFuncHandler() + { + } + +private: + virtual int Call(bool store, IHookManagerInfo *hi) const override + { + return (funcHandler_->*func_)(store, hi); + } + +private: + T* funcHandler_; + HookManagerMemberFunc func_; +}; + +template +class ManualHookHandler : public CHookManagerMemberFuncHandler> +{ +public: + typedef ManualHookHandler ThisType; + typedef fastdelegate::FastDelegate FD; + typedef ReturnType(EmptyClass::*ECMFP)(Params...); + typedef ExecutableClassN CallEC; + + template + struct HookedFuncType + { + typedef ReturnType (T::*HookFunc)(Params...); + }; + + ManualHookHandler() + : CHookManagerMemberFuncHandler(this, &ThisType::HookManPubFunc) + , thisPointerOffset_(0) + , vTableIndex_(0) + , vtableOffset_(0) + , msMFI_{false, 0, 0, 0} + , msHI_(nullptr) + , msProto_{sizeof...(Params), + {ReturnTypeInfo::size(), ReturnTypeInfo::type(), ReturnTypeInfo::flags()}, + paramInfosM_.ParamsPassInfo(), + 0, + __SH_EPI, + paramInfos2M_} + { + for(PassInfo::V2Info& paramInfo : paramInfos2M_) + { + paramInfo = __SH_EPI; + } + } + + virtual ~ManualHookHandler() + { + //TODO apply RAII, cleanup all related hooks here + } + + // TODO probably not needed for manual hooks + void Reconfigure() + { + msMFI_.isVirtual = true; + msMFI_.thisptroffs = thisPointerOffset_; + msMFI_.vtblindex = vTableIndex_; + msMFI_.vtbloffs = vtableOffset_; + } + + void Reconfigure(int vtblindex, int vtbloffs = 0, int thisptroffs = 0) + { + g_SHPtr->RemoveHookManager(g_PLID, this); + msMFI_.thisptroffs = thisptroffs; + msMFI_.vtblindex = vtblindex; + msMFI_.vtbloffs = vtbloffs; + } + + template + int Add(void *iface, T* callbackInstPtr, typename HookedFuncType::HookFunc callbackFuncPtr, bool post = true, ISourceHook::AddHookMode mode = ISourceHook::AddHookMode::Hook_Normal) + { + typename ManualHookHandler::FD handler(callbackInstPtr, callbackFuncPtr); + typename ThisType::CMyDelegateImpl* tmp = new typename ThisType::CMyDelegateImpl(handler); // TODO use unique_ptr here + + return g_SHPtr->AddHook(g_PLID, mode, iface, thisPointerOffset_, this, tmp, post); + } + + template + bool Remove(void *iface, T* callbackInstPtr, typename HookedFuncType::HookFunc callbackFuncPtr, bool post = true) + { + typename ManualHookHandler::FD handler(callbackInstPtr, callbackFuncPtr); + typename ThisType::CMyDelegateImpl tmp(handler); + + return g_SHPtr->RemoveHook(g_PLID, iface, thisPointerOffset_, this, &tmp, post); + } + + // For void return type only + template::value, void>::type* = nullptr> + void Recall(META_RES result, Params... newparams) + { + g_SHPtr->SetRes(result); + g_SHPtr->DoRecall(); + SourceHook::EmptyClass *thisptr = reinterpret_cast(g_SHPtr->GetIfacePtr()); + (thisptr->*(GetRecallMFP(thisptr)))(newparams...); + g_SHPtr->SetRes(MRES_SUPERCEDE); + } + + // For any return type but void + template::value, void>::type* = nullptr> + U Recall(META_RES result, U value, Params... newparams) + { + g_SHPtr->SetRes(result); + g_SHPtr->DoRecall(); + if ((result) >= MRES_OVERRIDE) + { + /* see RETURN_META_VALUE_NEWPARAMS */ + SetOverrideResult(g_SHPtr, value); + } + EmptyClass *thisptr = reinterpret_cast(g_SHPtr->GetIfacePtr()); + g_SHPtr->SetRes(MRES_SUPERCEDE); + return (thisptr->*(GetRecallMFP(thisptr)))(newparams...); + } + +private: + struct IMyDelegate : ISHDelegate + { + virtual ReturnType Call(Params... params) = 0; + }; + + struct CMyDelegateImpl : public IMyDelegate + { + FD m_Deleg; + CMyDelegateImpl(FD deleg) + : m_Deleg(deleg) + { + } + + virtual ReturnType Call(Params... params) override + { + return m_Deleg(params...); + } + + virtual void DeleteThis() override + { + delete this; + } + + virtual bool IsEqual(ISHDelegate *pOtherDeleg) override + { + return m_Deleg == static_cast(pOtherDeleg)->m_Deleg; + } + }; + + // Implementation for any return type but void + template::value, void>::type* = nullptr> + U Func(Params... params) + { + /* 1) Set up calls */ + void *ourvfnptr = reinterpret_cast(*reinterpret_cast(reinterpret_cast(this) + msMFI_.vtbloffs) + msMFI_.vtblindex); + void *vfnptr_origentry; + + META_RES status = MRES_IGNORED; + META_RES prev_res; + META_RES cur_res; + + typedef typename ReferenceCarrier::type my_rettype; + my_rettype orig_ret; + my_rettype override_ret; + my_rettype plugin_ret; + IMyDelegate *iter = nullptr; + + IHookContext *pContext = g_SHPtr->SetupHookLoop(msHI_, + ourvfnptr, + reinterpret_cast(this), + &vfnptr_origentry, + &status, + &prev_res, + &cur_res, + &orig_ret, + &override_ret); + + prev_res = MRES_IGNORED; + + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + plugin_ret = iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + + if (cur_res >= MRES_OVERRIDE) + *reinterpret_cast(pContext->GetOverrideRetPtr()) = plugin_ret; + } + + if (status != MRES_SUPERCEDE && pContext->ShouldCallOrig()) + { + ReturnType (EmptyClass::*mfp)(Params...); + SH_SETUP_MFP(mfp); + + orig_ret = (reinterpret_cast(this)->*mfp)(params...); + } + else + orig_ret = override_ret; /* :TODO: ??? : use pContext->GetOverrideRetPtr() or not? */ + + prev_res = MRES_IGNORED; + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + plugin_ret = iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + + if (cur_res >= MRES_OVERRIDE) + *reinterpret_cast(pContext->GetOverrideRetPtr()) = plugin_ret; + } + + const void* repPtr = (status >= MRES_OVERRIDE) ? pContext->GetOverrideRetPtr() : + pContext->GetOrigRetPtr(); + + g_SHPtr->EndContext(pContext); + + return *reinterpret_cast(repPtr); + } + + // Implementation for void return type only + template::value, void>::type* = nullptr> + void Func(Params... params) + { + /* 1) Set up calls */ + void *ourvfnptr = reinterpret_cast(*reinterpret_cast(reinterpret_cast(this) + msMFI_.vtbloffs) + msMFI_.vtblindex); + void *vfnptr_origentry; + + META_RES status = MRES_IGNORED; + META_RES prev_res; + META_RES cur_res; + + IMyDelegate *iter = nullptr; + + IHookContext *pContext = g_SHPtr->SetupHookLoop(msHI_, + ourvfnptr, + reinterpret_cast(this), + &vfnptr_origentry, + &status, + &prev_res, + &cur_res, + nullptr, + nullptr); + + prev_res = MRES_IGNORED; + while ((iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + } + + if (status != MRES_SUPERCEDE && pContext->ShouldCallOrig()) + { + void (EmptyClass::*mfp)(Params...); + + reinterpret_cast(&mfp)[0] = vfnptr_origentry; + reinterpret_cast(&mfp)[1] = 0; + + (reinterpret_cast(this)->*mfp)(params...); + } + + prev_res = MRES_IGNORED; + while ( (iter = static_cast(pContext->GetNext()))) + { + cur_res = MRES_IGNORED; + + iter->Call(params...); + prev_res = cur_res; + + if (cur_res > status) + status = cur_res; + } + + g_SHPtr->EndContext(pContext); + } + + int HookManPubFunc(bool store, IHookManagerInfo *hi) + { + /* Verify interface version */ + if (g_SHPtr->GetIfaceVersion() != SH_IFACE_VERSION) + return 1; + + if (g_SHPtr->GetImplVersion() < SH_IMPL_VERSION) + return 1; + + if (store) + msHI_ = hi; + + if (hi) + { + MemFuncInfo mfi = {true, -1, 0, 0}; + GetFuncInfo(this, &ThisType::Func, mfi); + + hi->SetInfo(SH_HOOKMAN_VERSION, + msMFI_.vtbloffs, + msMFI_.vtblindex, + &msProto_, + reinterpret_cast(reinterpret_cast(this) + mfi.vtbloffs)[mfi.vtblindex]); + } + + return 0; + } + + typename ManualHookHandler::ECMFP GetRecallMFP(EmptyClass *thisptr) + { + union + { + typename ManualHookHandler::ECMFP mfp; + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + + u.s.addr = (*reinterpret_cast(reinterpret_cast(thisptr) + msMFI_.vtbloffs))[msMFI_.vtblindex]; + u.s.adjustor = 0; + + return u.mfp; + } + + typename ManualHookHandler::CallEC Call(void *ptr) + { + typename ManualHookHandler::ECMFP mfp; + void *vfnptr = reinterpret_cast(*reinterpret_cast((reinterpret_cast(ptr) + msMFI_.thisptroffs + msMFI_.vtbloffs) ) + msMFI_.vtblindex); + + /* patch mfp */ + *reinterpret_cast(&mfp) = *reinterpret_cast(vfnptr); + + if (sizeof(mfp) == 2*sizeof(void*)) /* gcc */ + *(reinterpret_cast(&mfp) + 1) = 0; + + return ManualHookHandler::CallEC(reinterpret_cast(ptr), mfp, vfnptr, g_SHPtr); + } + + // Implementation for any return type but void + template::value, void>::type* = nullptr> + void SetOverrideResult(ISourceHook *shptr, TypedValueHandler value) + { + OverrideFunctor overrideFunc = SourceHook::SetOverrideResult(); + overrideFunc(shptr, value); + } + +private: + int thisPointerOffset_; // thisptroffs + int vTableIndex_; // vtblindex + int vtableOffset_; // vtbloffs + + MemFuncInfo msMFI_; // ms_MFI + IHookManagerInfo *msHI_; // ms_HI + + PassInfoInitializer paramInfosM_; // ParamInfosM + PassInfo::V2Info paramInfos2M_[sizeof...(Params) + 1]; // ParamInfos2M + ProtoInfo msProto_; // ms_Proto +}; + +} // SourceHook + #endif // The pope is dead. -> :( diff --git a/core/sourcehook/sourcehook_hookmangen.cpp b/core/sourcehook/sourcehook_hookmangen.cpp index 287a6432..205d8fb9 100644 --- a/core/sourcehook/sourcehook_hookmangen.cpp +++ b/core/sourcehook/sourcehook_hookmangen.cpp @@ -1959,12 +1959,12 @@ namespace SourceHook return m_GeneratedPubFunc; } - bool GenContext::Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) + bool GenContext::Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) const { return (m_OrigProto.ExactlyEqual(proto) && m_VtblOffs == vtbl_offs && m_VtblIdx == vtbl_idx); } - bool GenContext::Equal(HookManagerPubFunc other) + bool GenContext::Equal(HookManagerPubFunc other) const { return m_GeneratedPubFunc == other; } @@ -2013,11 +2013,9 @@ namespace SourceHook { return NULL; } - else - { - m_Contexts.push_back(sctx); - return sctx.m_GenContext->GetPubFunc(); - } + + m_Contexts.push_back(sctx); + return sctx.m_GenContext->GetPubFunc(); } void CHookManagerAutoGen::ReleaseHookMan(HookManagerPubFunc pubFunc) diff --git a/core/sourcehook/sourcehook_hookmangen.h b/core/sourcehook/sourcehook_hookmangen.h index 9e565f77..0193273c 100644 --- a/core/sourcehook/sourcehook_hookmangen.h +++ b/core/sourcehook/sourcehook_hookmangen.h @@ -265,8 +265,8 @@ namespace SourceHook GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr); ~GenContext(); - bool Equal(const CProto &proto, int vtbl_offs, int vtbl_idx); - bool Equal(HookManagerPubFunc other); + bool Equal(const CProto &proto, int vtbl_offs, int vtbl_idx) const; + bool Equal(HookManagerPubFunc other) const; HookManagerPubFunc GetPubFunc(); }; diff --git a/core/sourcehook/sourcehook_impl.h b/core/sourcehook/sourcehook_impl.h index f9ef068f..f929cd8d 100644 --- a/core/sourcehook/sourcehook_impl.h +++ b/core/sourcehook/sourcehook_impl.h @@ -322,9 +322,21 @@ namespace SourceHook int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post); + int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post); + + int AddHook(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + ISHDelegate *handler, bool post); + bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post); + bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, IHookManagerMemberFunc* myHookMan, + ISHDelegate *handler, bool post); + + bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, const HookManagerPubFuncHandler &myHookMan, + ISHDelegate *handler, bool post); + bool RemoveHookByID(int hookid); bool PauseHookByID(int hookid); @@ -355,6 +367,10 @@ namespace SourceHook void RemoveHookManager(Plugin plug, HookManagerPubFunc pubFunc); + void RemoveHookManager(Plugin plug, IHookManagerMemberFunc* pubFunc); + + void RemoveHookManager(Plugin plug, const HookManagerPubFuncHandler &pubFunc); + void SetIgnoreHooks(void *vfnptr); void ResetIgnoreHooks(void *vfnptr); diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.cpp b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp index 639b7a2a..21e20429 100644 --- a/core/sourcehook/sourcehook_impl_chookmaninfo.cpp +++ b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp @@ -15,7 +15,7 @@ namespace SourceHook { namespace Impl { - CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc) + CHookManager::CHookManager(Plugin ownerPlugin, const HookManagerPubFuncHandler& pubFunc) : m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1) { // Query pubfunc @@ -61,7 +61,7 @@ namespace SourceHook Unregister(); } - CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc) + CHookManager *CHookManList::GetHookMan(Plugin plug, const HookManagerPubFuncHandler &pubFunc) { CHookManager hm(plug, pubFunc); return GetHookMan(hm); diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.h b/core/sourcehook/sourcehook_impl_chookmaninfo.h index 6a805ea9..afb0bd3c 100644 --- a/core/sourcehook/sourcehook_impl_chookmaninfo.h +++ b/core/sourcehook/sourcehook_impl_chookmaninfo.h @@ -24,7 +24,7 @@ namespace SourceHook { // *** Data *** Plugin m_OwnerPlugin; - HookManagerPubFunc m_PubFunc; + HookManagerPubFuncHandler m_PubFunc; int m_VtblOffs; int m_VtblIdx; CProto m_Proto; @@ -38,15 +38,15 @@ namespace SourceHook struct Descriptor { Plugin m_OwnerPlugin; - HookManagerPubFunc m_PubFunc; - Descriptor(Plugin ownerPlugin, HookManagerPubFunc pubFunc) + HookManagerPubFuncHandler m_PubFunc; + Descriptor(Plugin ownerPlugin, const HookManagerPubFuncHandler &pubFunc) : m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc) { } }; // *** Interface *** - CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc); + CHookManager(Plugin ownerPlugin, const HookManagerPubFuncHandler &pubFunc); inline bool operator==(const Descriptor &other) const; inline bool operator==(const CHookManager &other) const; @@ -58,7 +58,7 @@ namespace SourceHook inline const CProto &GetProto() const; inline int GetVersion() const; inline void *GetHookFunc() const; - inline HookManagerPubFunc GetPubFunc() const; + inline const HookManagerPubFuncHandler &GetPubFunc() const; void Register(); void Unregister(); @@ -79,7 +79,7 @@ namespace SourceHook class CHookManList : public List { public: - CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc); + CHookManager *GetHookMan(Plugin plug, const HookManagerPubFuncHandler &pubFunc); CHookManager *GetHookMan(CHookManager &hm); }; @@ -132,7 +132,7 @@ namespace SourceHook return *reinterpret_cast(m_HookfuncVfnptr); } - inline HookManagerPubFunc CHookManager::GetPubFunc() const + inline const HookManagerPubFuncHandler &CHookManager::GetPubFunc() const { return m_PubFunc; }