diff --git a/sourcehook/generate/sourcehook.h b/sourcehook/generate/sourcehook.h index 68bea25..a75e271 100644 --- a/sourcehook/generate/sourcehook.h +++ b/sourcehook/generate/sourcehook.h @@ -534,6 +534,14 @@ namespace SourceHook * @param vfnptr The virtual function pointer of the function in question */ virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr) = 0; + + /** + * @brief Finds the original entry of a virtual function pointer + * + * @param vfnptr The virtual function pointer + * @return The original entry if the virtual function pointer has been patched; NULL otherwise. + */ + virtual void *GetOrigVfnPtrEntry(void *vfnptr) = 0; }; // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: @@ -595,6 +603,19 @@ namespace SourceHook delete p; } + template + void *GetOrigVfnPtrEntry(X *pInstance, MFP mfp, ISourceHook *pSH) + { + SourceHook::MemFuncInfo info = {true, -1, 0, 0}; + SourceHook::GetFuncInfo(pInstance, mfp, info); + + void *vfnptr = reinterpret_cast( + *reinterpret_cast(reinterpret_cast(pInstance) + info.thisptroffs + info.vtbloffs) + info.vtblindex); + + void *origentry = pSH->GetOrigVfnPtrEntry(vfnptr); + + return origentry ? origentry : *reinterpret_cast(vfnptr); + } } /************************************************************************/ @@ -707,6 +728,9 @@ namespace SourceHook SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \ } while (0) + +#define SH_GET_ORIG_VFNPTR_ENTRY(inst, mfp) (SourceHook::GetOrigVfnPtrEntry(inst, mfp, SH_GLOB_SHPTR)) + // For source-level compatibility #define SH_GET_CALLCLASS(ptr) SourceHook::GetCallClass(ptr) diff --git a/sourcehook/generate/sourcehook.hxx b/sourcehook/generate/sourcehook.hxx index 4ee667e..e2566e8 100755 --- a/sourcehook/generate/sourcehook.hxx +++ b/sourcehook/generate/sourcehook.hxx @@ -534,6 +534,14 @@ namespace SourceHook * @param vfnptr The virtual function pointer of the function in question */ virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr) = 0; + + /** + * @brief Finds the original entry of a virtual function pointer + * + * @param vfnptr The virtual function pointer + * @return The original entry if the virtual function pointer has been patched; NULL otherwise. + */ + virtual void *GetOrigVfnPtrEntry(void *vfnptr) = 0; }; // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: @@ -595,6 +603,19 @@ namespace SourceHook delete p; } + template + void *GetOrigVfnPtrEntry(X *pInstance, MFP mfp, ISourceHook *pSH) + { + SourceHook::MemFuncInfo info = {true, -1, 0, 0}; + SourceHook::GetFuncInfo(pInstance, mfp, info); + + void *vfnptr = reinterpret_cast( + *reinterpret_cast(reinterpret_cast(pInstance) + info.thisptroffs + info.vtbloffs) + info.vtblindex); + + void *origentry = pSH->GetOrigVfnPtrEntry(vfnptr); + + return origentry ? origentry : *reinterpret_cast(vfnptr); + } } /************************************************************************/ @@ -707,6 +728,9 @@ namespace SourceHook SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \ } while (0) + +#define SH_GET_ORIG_VFNPTR_ENTRY(inst, mfp) (SourceHook::GetOrigVfnPtrEntry(inst, mfp, SH_GLOB_SHPTR)) + // For source-level compatibility #define SH_GET_CALLCLASS(ptr) SourceHook::GetCallClass(ptr) diff --git a/sourcehook/sourcehook.cpp b/sourcehook/sourcehook.cpp index d8c49b4..e2fc8b0 100644 --- a/sourcehook/sourcehook.cpp +++ b/sourcehook/sourcehook.cpp @@ -917,6 +917,25 @@ namespace SourceHook m_OneIgnore = NULL; } + void *CSourceHookImpl::GetOrigVfnPtrEntry(void *vfnptr) + { + for (HookManContList::iterator hmcl_iter = m_HookMans.begin(); + hmcl_iter != m_HookMans.end(); ++hmcl_iter) + { + for (CHookManagerContainer::iterator hookmaniter = hmcl_iter->begin(); + hookmaniter != hmcl_iter->end(); ++hookmaniter) + { + for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin(); + vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter) + { + if (vfnptr_iter->m_Ptr == vfnptr) + return vfnptr_iter->m_OrigEntry; + } + } + } + return NULL; + } + //////////////////////////// // CCallClassImpl //////////////////////////// diff --git a/sourcehook/sourcehook.h b/sourcehook/sourcehook.h index 68bea25..a75e271 100644 --- a/sourcehook/sourcehook.h +++ b/sourcehook/sourcehook.h @@ -534,6 +534,14 @@ namespace SourceHook * @param vfnptr The virtual function pointer of the function in question */ virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr) = 0; + + /** + * @brief Finds the original entry of a virtual function pointer + * + * @param vfnptr The virtual function pointer + * @return The original entry if the virtual function pointer has been patched; NULL otherwise. + */ + virtual void *GetOrigVfnPtrEntry(void *vfnptr) = 0; }; // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: @@ -595,6 +603,19 @@ namespace SourceHook delete p; } + template + void *GetOrigVfnPtrEntry(X *pInstance, MFP mfp, ISourceHook *pSH) + { + SourceHook::MemFuncInfo info = {true, -1, 0, 0}; + SourceHook::GetFuncInfo(pInstance, mfp, info); + + void *vfnptr = reinterpret_cast( + *reinterpret_cast(reinterpret_cast(pInstance) + info.thisptroffs + info.vtbloffs) + info.vtblindex); + + void *origentry = pSH->GetOrigVfnPtrEntry(vfnptr); + + return origentry ? origentry : *reinterpret_cast(vfnptr); + } } /************************************************************************/ @@ -707,6 +728,9 @@ namespace SourceHook SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \ } while (0) + +#define SH_GET_ORIG_VFNPTR_ENTRY(inst, mfp) (SourceHook::GetOrigVfnPtrEntry(inst, mfp, SH_GLOB_SHPTR)) + // For source-level compatibility #define SH_GET_CALLCLASS(ptr) SourceHook::GetCallClass(ptr) diff --git a/sourcehook/sourcehook_impl.h b/sourcehook/sourcehook_impl.h index dc5b154..ac1c5fd 100644 --- a/sourcehook/sourcehook_impl.h +++ b/sourcehook/sourcehook_impl.h @@ -803,6 +803,14 @@ namespace SourceHook * @param vfnptr The virtual function pointer of the function in question */ virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr); + + /** + * @brief Finds the original entry of a virtual function pointer + * + * @param vfnptr The virtual function pointer + * @return The original entry if the virtual function pointer has been patched; NULL otherwise. + */ + virtual void *GetOrigVfnPtrEntry(void *vfnptr); }; } diff --git a/sourcehook/test/testvphooks.cpp b/sourcehook/test/testvphooks.cpp index d53c2b8..8d03bfd 100644 --- a/sourcehook/test/testvphooks.cpp +++ b/sourcehook/test/testvphooks.cpp @@ -322,12 +322,26 @@ bool TestVPHooks(std::string &error) // Test removing normal hooks even though the instance is deleted - p_d1i1 = new CDerived1; - SH_ADD_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); - delete p_d1i1; + IBase *pOther = new CDerived1; + SH_ADD_HOOK(IBase, Func1, pOther, SH_STATIC(Handler_Func1_Pre), false); + delete pOther; // The following line may not crash! + SH_REMOVE_HOOK(IBase, Func1, pOther, SH_STATIC(Handler_Func1_Pre), false); + + + // Now test GetOrigVfnPtrEntry + void *origfuncptr = (*reinterpret_cast(p_d1i1))[0]; + + CHECK_COND(SH_GET_ORIG_VFNPTR_ENTRY(p_d1i1, &IBase::Func1) == origfuncptr, "Part 9.1"); + + SH_ADD_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); + + CHECK_COND(SH_GET_ORIG_VFNPTR_ENTRY(p_d1i1, &IBase::Func1) == origfuncptr, "Part 9.2"); + SH_REMOVE_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); + CHECK_COND(SH_GET_ORIG_VFNPTR_ENTRY(p_d1i1, &IBase::Func1) == origfuncptr, "Part 9.3"); + return true; }