From 6a15c59cce2760a9257ffd392840c59a393fa845 Mon Sep 17 00:00:00 2001 From: Pavol Marko Date: Wed, 9 Aug 2006 06:46:11 +0000 Subject: [PATCH] Added support for functions returning references; added TestRefRet, fixed typos in sourcehook_impl.h --HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40250 --- sourcehook/generate/sourcehook.h | 203 ++++++++++++++++++++------- sourcehook/generate/sourcehook.hxx | 123 ++++++++++++++-- sourcehook/sourcehook.h | 203 ++++++++++++++++++++------- sourcehook/sourcehook_impl.h | 4 +- sourcehook/test/main.cpp | 1 + sourcehook/test/msvc8/test.vcproj | 8 +- sourcehook/test/msvc8/testrefret.cpp | 200 ++++++++++++++++++++++++++ 7 files changed, 631 insertions(+), 111 deletions(-) create mode 100644 sourcehook/test/msvc8/testrefret.cpp diff --git a/sourcehook/generate/sourcehook.h b/sourcehook/generate/sourcehook.h index e5eca06..3ef71b0 100644 --- a/sourcehook/generate/sourcehook.h +++ b/sourcehook/generate/sourcehook.h @@ -300,6 +300,49 @@ namespace SourceHook typedef CallClass GenericCallClass; typedef CallClass ManualCallClass; + // 09.08.2008 (6 AM, I just woke up, the others are still sleeping so i finally can use this notebook !!) + // - Today is an important day. + // I'm adding support for functions which return references. + + // How it works: + // SH_SETUPCALLS doesn't use plain rettype to store the temporary return values (plugin ret, orig ret, + // override ret) anymore; instead, it uses SourceHook::ReferenceCarrier::type + // this is typedefed to the original rettype normally, but if the rettype is a reference, it's a special class + // which stores the reference as a pointer, and implements constructors, operator= and a conversion operator. + // special cases were needed for getoverrideret / getorigret; these are implemented through the + // SourceHook::MacroRefHelpers structs. + // Furthermore, SetOverrideRet had to be changed a bit; see SourceHook::OverrideFunctor somewhere down in this file. + template struct ReferenceCarrier + { + typedef T type; + }; + + template struct ReferenceCarrier + { + class type + { + T *m_StoredRef; + public: + type() : m_StoredRef(NULL) + { + } + type(T& ref) : m_StoredRef(&ref) + { + } + + T& operator= (T& ref) + { + m_StoredRef = &ref; + return ref; + } + + operator T& () const + { + return *m_StoredRef; + } + }; + }; + /** * @brief The main SourceHook interface */ @@ -438,6 +481,35 @@ namespace SourceHook //!< }; + + // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: + // These have to be able to return references. If T is a reference, the pointers returned + // from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier::type. + template struct MacroRefHelpers + { + inline static const T* GetOrigRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOrigRet()); + } + inline static const T* GetOverrideRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOverrideRet()); + } + }; + + template struct MacroRefHelpers + { + inline static T* GetOrigRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOrigRet()); + return &ref; + } + inline static T* GetOverrideRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOverrideRet()); + return &ref; + } + }; } /************************************************************************/ @@ -445,14 +517,18 @@ namespace SourceHook /************************************************************************/ #define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus() #define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes() -#define META_RESULT_ORIG_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOrigRet()) -#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOverrideRet()) +#define META_RESULT_ORIG_RET(type) *SourceHook::MacroRefHelpers::GetOrigRet(SH_GLOB_SHPTR) +#define META_RESULT_OVERRIDE_RET(type) *SourceHook::MacroRefHelpers::GetOverrideRet(SH_GLOB_SHPTR) #define META_IFACEPTR(type) reinterpret_cast(SH_GLOB_SHPTR->GetIfacePtr()) #define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result) #define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0) #define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0) +// If a hook on a function which returns a reference does not want to specify a return value, +// it can use this macro. +// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!! +#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast(*SH_GLOB_SHPTR); } while(0) // only call these from the hook handlers directly! // :TODO: enforce it ? @@ -477,7 +553,7 @@ namespace SourceHook { \ /* meh, set the override result here because we don't get a chance to return */ \ /* before continuing the hook loop through the recall */ \ - SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \ + SourceHook::SetOverrideResult(memfuncptr)(SH_GLOB_SHPTR, value); \ } \ RETURN_META_VALUE(MRES_SUPERCEDE, \ (SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \ @@ -808,11 +884,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C META_RES status = MRES_IGNORED; \ META_RES prev_res; \ META_RES cur_res; \ - rettype orig_ret; \ - rettype override_ret; \ - rettype plugin_ret; \ + typedef ReferenceCarrier::type my_rettype; \ + my_rettype orig_ret; \ + my_rettype override_ret; \ + my_rettype plugin_ret; \ void* ifptr; \ - rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ + my_rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ &status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret)); #define SH_CALL_HOOKS(post, params) \ @@ -945,6 +1022,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C ////////////////////////////////////////////////////////////////////////// +// :FIXME: +// sizeof on references returns the size of the datatype, NOT the pointer size or something +// -> one should probably flag references in __SourceHook_ParamSizes_* ! +// or simply assume that their size is sizeof(void*)=SH_PTRSIZE... could be doable through a simple template + // ********* Support for 0 arguments ********* #define SH_DECL_HOOK0(ifacetype, ifacefunc, attr, overload, rettype) \ @@ -5740,11 +5822,34 @@ namespace SourceHook *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; } + // SetOverrideResult used to be implemented like this: + // SetOverrideResult(shptr, memfuncptr, return); + // normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference + // (it thought it was ambigous - the ref and non-ref type) + // so now SetOverrideResult(memfuncptr) deduces the ret type, and returns a functor which does the work + // new syntax: SetOverrideResult(memfuncptr)(shptr, return) + // This also allows us to create a special version for references which respects ReferenceCarrier. + + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T res) + { + *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + } + }; + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T &res) + { + // overrideretptr points to ReferenceCarrier + *reinterpret_cast::type *>(shptr->GetOverrideRetPtr()) = res; + } + }; template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)()) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5754,9 +5859,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5766,9 +5871,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5778,9 +5883,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5790,9 +5895,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5802,9 +5907,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5814,9 +5919,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5826,9 +5931,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5838,9 +5943,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5850,9 +5955,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5862,9 +5967,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5874,9 +5979,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5886,9 +5991,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5898,9 +6003,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5910,9 +6015,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5922,9 +6027,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5934,9 +6039,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5946,9 +6051,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5958,9 +6063,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5970,9 +6075,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5982,9 +6087,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template diff --git a/sourcehook/generate/sourcehook.hxx b/sourcehook/generate/sourcehook.hxx index 2dfea5c..1fb2aed 100755 --- a/sourcehook/generate/sourcehook.hxx +++ b/sourcehook/generate/sourcehook.hxx @@ -300,6 +300,49 @@ namespace SourceHook typedef CallClass GenericCallClass; typedef CallClass ManualCallClass; + // 09.08.2008 (6 AM, I just woke up, the others are still sleeping so i finally can use this notebook !!) + // - Today is an important day. + // I'm adding support for functions which return references. + + // How it works: + // SH_SETUPCALLS doesn't use plain rettype to store the temporary return values (plugin ret, orig ret, + // override ret) anymore; instead, it uses SourceHook::ReferenceCarrier::type + // this is typedefed to the original rettype normally, but if the rettype is a reference, it's a special class + // which stores the reference as a pointer, and implements constructors, operator= and a conversion operator. + // special cases were needed for getoverrideret / getorigret; these are implemented through the + // SourceHook::MacroRefHelpers structs. + // Furthermore, SetOverrideRet had to be changed a bit; see SourceHook::OverrideFunctor somewhere down in this file. + template struct ReferenceCarrier + { + typedef T type; + }; + + template struct ReferenceCarrier + { + class type + { + T *m_StoredRef; + public: + type() : m_StoredRef(NULL) + { + } + type(T& ref) : m_StoredRef(&ref) + { + } + + T& operator= (T& ref) + { + m_StoredRef = &ref; + return ref; + } + + operator T& () const + { + return *m_StoredRef; + } + }; + }; + /** * @brief The main SourceHook interface */ @@ -438,6 +481,35 @@ namespace SourceHook //!< }; + + // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: + // These have to be able to return references. If T is a reference, the pointers returned + // from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier::type. + template struct MacroRefHelpers + { + inline static const T* GetOrigRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOrigRet()); + } + inline static const T* GetOverrideRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOverrideRet()); + } + }; + + template struct MacroRefHelpers + { + inline static T* GetOrigRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOrigRet()); + return &ref; + } + inline static T* GetOverrideRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOverrideRet()); + return &ref; + } + }; } /************************************************************************/ @@ -445,14 +517,18 @@ namespace SourceHook /************************************************************************/ #define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus() #define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes() -#define META_RESULT_ORIG_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOrigRet()) -#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOverrideRet()) +#define META_RESULT_ORIG_RET(type) *SourceHook::MacroRefHelpers::GetOrigRet(SH_GLOB_SHPTR) +#define META_RESULT_OVERRIDE_RET(type) *SourceHook::MacroRefHelpers::GetOverrideRet(SH_GLOB_SHPTR) #define META_IFACEPTR(type) reinterpret_cast(SH_GLOB_SHPTR->GetIfacePtr()) #define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result) #define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0) #define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0) +// If a hook on a function which returns a reference does not want to specify a return value, +// it can use this macro. +// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!! +#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast(*SH_GLOB_SHPTR); } while(0) // only call these from the hook handlers directly! // :TODO: enforce it ? @@ -477,7 +553,7 @@ namespace SourceHook { \ /* meh, set the override result here because we don't get a chance to return */ \ /* before continuing the hook loop through the recall */ \ - SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \ + SourceHook::SetOverrideResult(memfuncptr)(SH_GLOB_SHPTR, value); \ } \ RETURN_META_VALUE(MRES_SUPERCEDE, \ (SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \ @@ -808,11 +884,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C META_RES status = MRES_IGNORED; \ META_RES prev_res; \ META_RES cur_res; \ - rettype orig_ret; \ - rettype override_ret; \ - rettype plugin_ret; \ + typedef ReferenceCarrier::type my_rettype; \ + my_rettype orig_ret; \ + my_rettype override_ret; \ + my_rettype plugin_ret; \ void* ifptr; \ - rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ + my_rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ &status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret)); #define SH_CALL_HOOKS(post, params) \ @@ -945,6 +1022,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C ////////////////////////////////////////////////////////////////////////// +// :FIXME: +// sizeof on references returns the size of the datatype, NOT the pointer size or something +// -> one should probably flag references in __SourceHook_ParamSizes_* ! +// or simply assume that their size is sizeof(void*)=SH_PTRSIZE... could be doable through a simple template + @[$1,0,$a: // ********* Support for $1 arguments ********* #define SH_DECL_HOOK$1(ifacetype, ifacefunc, attr, overload, rettype@[$2,1,$1:, param$2@]) \ @@ -1246,11 +1328,34 @@ namespace SourceHook *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; } + // SetOverrideResult used to be implemented like this: + // SetOverrideResult(shptr, memfuncptr, return); + // normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference + // (it thought it was ambigous - the ref and non-ref type) + // so now SetOverrideResult(memfuncptr) deduces the ret type, and returns a functor which does the work + // new syntax: SetOverrideResult(memfuncptr)(shptr, return) + // This also allows us to create a special version for references which respects ReferenceCarrier. + + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T res) + { + *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + } + }; + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T &res) + { + // overrideretptr points to ReferenceCarrier + *reinterpret_cast::type *>(shptr->GetOverrideRetPtr()) = res; + } + }; @[$1,0,$a: template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(@[$2,1,$1|, :Param$2@]), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(@[$2,1,$1|, :Param$2@])) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template diff --git a/sourcehook/sourcehook.h b/sourcehook/sourcehook.h index e5eca06..3ef71b0 100644 --- a/sourcehook/sourcehook.h +++ b/sourcehook/sourcehook.h @@ -300,6 +300,49 @@ namespace SourceHook typedef CallClass GenericCallClass; typedef CallClass ManualCallClass; + // 09.08.2008 (6 AM, I just woke up, the others are still sleeping so i finally can use this notebook !!) + // - Today is an important day. + // I'm adding support for functions which return references. + + // How it works: + // SH_SETUPCALLS doesn't use plain rettype to store the temporary return values (plugin ret, orig ret, + // override ret) anymore; instead, it uses SourceHook::ReferenceCarrier::type + // this is typedefed to the original rettype normally, but if the rettype is a reference, it's a special class + // which stores the reference as a pointer, and implements constructors, operator= and a conversion operator. + // special cases were needed for getoverrideret / getorigret; these are implemented through the + // SourceHook::MacroRefHelpers structs. + // Furthermore, SetOverrideRet had to be changed a bit; see SourceHook::OverrideFunctor somewhere down in this file. + template struct ReferenceCarrier + { + typedef T type; + }; + + template struct ReferenceCarrier + { + class type + { + T *m_StoredRef; + public: + type() : m_StoredRef(NULL) + { + } + type(T& ref) : m_StoredRef(&ref) + { + } + + T& operator= (T& ref) + { + m_StoredRef = &ref; + return ref; + } + + operator T& () const + { + return *m_StoredRef; + } + }; + }; + /** * @brief The main SourceHook interface */ @@ -438,6 +481,35 @@ namespace SourceHook //!< }; + + // For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET: + // These have to be able to return references. If T is a reference, the pointers returned + // from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier::type. + template struct MacroRefHelpers + { + inline static const T* GetOrigRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOrigRet()); + } + inline static const T* GetOverrideRet(ISourceHook *shptr) + { + return reinterpret_cast(shptr->GetOverrideRet()); + } + }; + + template struct MacroRefHelpers + { + inline static T* GetOrigRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOrigRet()); + return &ref; + } + inline static T* GetOverrideRet(ISourceHook *shptr) + { + T &ref = *reinterpret_cast::type *>(shptr->GetOverrideRet()); + return &ref; + } + }; } /************************************************************************/ @@ -445,14 +517,18 @@ namespace SourceHook /************************************************************************/ #define META_RESULT_STATUS SH_GLOB_SHPTR->GetStatus() #define META_RESULT_PREVIOUS SH_GLOB_SHPTR->GetPrevRes() -#define META_RESULT_ORIG_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOrigRet()) -#define META_RESULT_OVERRIDE_RET(type) *reinterpret_cast(SH_GLOB_SHPTR->GetOverrideRet()) +#define META_RESULT_ORIG_RET(type) *SourceHook::MacroRefHelpers::GetOrigRet(SH_GLOB_SHPTR) +#define META_RESULT_OVERRIDE_RET(type) *SourceHook::MacroRefHelpers::GetOverrideRet(SH_GLOB_SHPTR) #define META_IFACEPTR(type) reinterpret_cast(SH_GLOB_SHPTR->GetIfacePtr()) #define SET_META_RESULT(result) SH_GLOB_SHPTR->SetRes(result) #define RETURN_META(result) do { SET_META_RESULT(result); return; } while(0) #define RETURN_META_VALUE(result, value) do { SET_META_RESULT(result); return (value); } while(0) +// If a hook on a function which returns a reference does not want to specify a return value, +// it can use this macro. +// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!! +#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast(*SH_GLOB_SHPTR); } while(0) // only call these from the hook handlers directly! // :TODO: enforce it ? @@ -477,7 +553,7 @@ namespace SourceHook { \ /* meh, set the override result here because we don't get a chance to return */ \ /* before continuing the hook loop through the recall */ \ - SourceHook::SetOverrideResult(SH_GLOB_SHPTR, memfuncptr, value); \ + SourceHook::SetOverrideResult(memfuncptr)(SH_GLOB_SHPTR, value); \ } \ RETURN_META_VALUE(MRES_SUPERCEDE, \ (SourceHook::RecallGetIface(SH_GLOB_SHPTR, memfuncptr)->*(memfuncptr)) newparams); \ @@ -808,11 +884,12 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C META_RES status = MRES_IGNORED; \ META_RES prev_res; \ META_RES cur_res; \ - rettype orig_ret; \ - rettype override_ret; \ - rettype plugin_ret; \ + typedef ReferenceCarrier::type my_rettype; \ + my_rettype orig_ret; \ + my_rettype override_ret; \ + my_rettype plugin_ret; \ void* ifptr; \ - rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ + my_rettype *pOverrideRet = reinterpret_cast(SH_GLOB_SHPTR->SetupHookLoop( \ &status, &prev_res, &cur_res, &ifptr, &orig_ret, &override_ret)); #define SH_CALL_HOOKS(post, params) \ @@ -945,6 +1022,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C ////////////////////////////////////////////////////////////////////////// +// :FIXME: +// sizeof on references returns the size of the datatype, NOT the pointer size or something +// -> one should probably flag references in __SourceHook_ParamSizes_* ! +// or simply assume that their size is sizeof(void*)=SH_PTRSIZE... could be doable through a simple template + // ********* Support for 0 arguments ********* #define SH_DECL_HOOK0(ifacetype, ifacefunc, attr, overload, rettype) \ @@ -5740,11 +5822,34 @@ namespace SourceHook *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; } + // SetOverrideResult used to be implemented like this: + // SetOverrideResult(shptr, memfuncptr, return); + // normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference + // (it thought it was ambigous - the ref and non-ref type) + // so now SetOverrideResult(memfuncptr) deduces the ret type, and returns a functor which does the work + // new syntax: SetOverrideResult(memfuncptr)(shptr, return) + // This also allows us to create a special version for references which respects ReferenceCarrier. + + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T res) + { + *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + } + }; + template struct OverrideFunctor + { + void operator()(ISourceHook *shptr, T &res) + { + // overrideretptr points to ReferenceCarrier + *reinterpret_cast::type *>(shptr->GetOverrideRetPtr()) = res; + } + }; template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)()) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5754,9 +5859,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5766,9 +5871,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5778,9 +5883,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5790,9 +5895,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5802,9 +5907,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5814,9 +5919,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5826,9 +5931,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5838,9 +5943,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5850,9 +5955,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5862,9 +5967,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5874,9 +5979,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5886,9 +5991,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5898,9 +6003,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5910,9 +6015,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5922,9 +6027,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5934,9 +6039,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5946,9 +6051,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5958,9 +6063,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5970,9 +6075,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template @@ -5982,9 +6087,9 @@ namespace SourceHook } template - void SetOverrideResult(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20), const RetType res) + OverrideFunctor SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)) { - *reinterpret_cast(shptr->GetOverrideRetPtr()) = res; + return OverrideFunctor(); } template diff --git a/sourcehook/sourcehook_impl.h b/sourcehook/sourcehook_impl.h index eef4755..7de1832 100644 --- a/sourcehook/sourcehook_impl.h +++ b/sourcehook/sourcehook_impl.h @@ -25,8 +25,8 @@ IMPLEMENTATION INFO Protos ("Prototypes") The purpose of protos is to provide the amount of type information about a function which is required to be able to execute a function call without corrupting the stack. - Our protos do not fully do this, but they provide the size of the return value, the amount of - parameters, and the size of each parameter, which is enough for most situations, + Our protos do not fully do this, but they provide the size of the return value, the number of + parameters, and the size of each parameter, which is enough for most situations. There are two version of protos: OLD: diff --git a/sourcehook/test/main.cpp b/sourcehook/test/main.cpp index e500f6f..2fc9ef0 100644 --- a/sourcehook/test/main.cpp +++ b/sourcehook/test/main.cpp @@ -79,6 +79,7 @@ DO_TEST(Manual); DO_TEST(Recall); DO_TEST(Multi); DO_TEST(Ref); +DO_TEST(RefRet); int main(int argc, char *argv[]) { diff --git a/sourcehook/test/msvc8/test.vcproj b/sourcehook/test/msvc8/test.vcproj index 4e582c0..1e1260c 100644 --- a/sourcehook/test/msvc8/test.vcproj +++ b/sourcehook/test/msvc8/test.vcproj @@ -1,7 +1,7 @@ + + diff --git a/sourcehook/test/msvc8/testrefret.cpp b/sourcehook/test/msvc8/testrefret.cpp new file mode 100644 index 0000000..6853cf8 --- /dev/null +++ b/sourcehook/test/msvc8/testrefret.cpp @@ -0,0 +1,200 @@ +#include "testevents.h" +#include "sourcehook_test.h" + +// Tests support for functions which return references + +namespace +{ + StateList g_States; + SourceHook::ISourceHook *g_SHPtr; + SourceHook::Plugin g_PLID; + + MAKE_STATE_1(State_Func1_Pre1, int*); // p1: the ref Func1_Pre1 is going to return + MAKE_STATE_3(State_Func1_Pre2, META_RES, int*, int*); // p1: current status + // p2: override ret + // p3: what this handler is going to supercede with + MAKE_STATE_1(State_Func1, int*); // p1: the ref Func1 is going to return + MAKE_STATE_2(State_Func1_Post1, int*, int*); // p1: orig_ret; p2: override_ret + MAKE_STATE_1(State_Func1_Post2, int*); // p1: what it's going to return + MAKE_STATE_1(State_Func1_Ret, int*); // p1: the ref it returned + + + MAKE_STATE_2(State_Func2_Pre1, int, const int*); // p1: func's p1; p2: what it's going to ret + MAKE_STATE_2(State_Func2, int, const int*); // p1: func's p1; p2: what it's going to ret + MAKE_STATE_3(State_Func2_Post1, int, const int*, const int*); // p1: func's p1; p2: orig ret; p3: override ret + MAKE_STATE_1(State_Func2_Ret, const int*); // p1: ret + + int g_Var; + + class Test + { + public: + int m_Var1; + int m_Var2; + + Test() : m_Var1(87) + { + } + + virtual int& Func1() + { + ADD_STATE(State_Func1(&m_Var1)); + return m_Var1; + } + virtual const int& Func2(int p1) + { + ADD_STATE(State_Func2(p1, &m_Var2)); + m_Var2 = p1; + return m_Var2; + } + }; + + class CHook + { + public: + int m_Var; + virtual int& Func1_Pre1() + { + ADD_STATE(State_Func1_Pre1(&m_Var)); + RETURN_META_VALUE(MRES_OVERRIDE, m_Var); + } + virtual int &Func1_Pre2() + { + int &overrideret = META_RESULT_OVERRIDE_RET(int&); + overrideret = 1337; + ADD_STATE(State_Func1_Pre2(META_RESULT_STATUS, &overrideret, &g_Var)); + RETURN_META_VALUE(MRES_SUPERCEDE, g_Var); + } + virtual int& Func1_Post1() + { + ADD_STATE(State_Func1_Post1(&META_RESULT_ORIG_RET(int&), &META_RESULT_OVERRIDE_RET(int&))); + RETURN_META_NOREF(MRES_IGNORED, int&); + } + virtual int& Func1_Post2() + { + ADD_STATE(State_Func1_Post2(&m_Var)); + RETURN_META_VALUE(MRES_OVERRIDE, m_Var); + } + + virtual const int& Func2_Pre1(int p1) + { + ADD_STATE(State_Func2_Pre1(p1, &m_Var)); + RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, m_Var, static_cast(&Test::Func2), (1337)); + } + + virtual const int& Func2_Post1(int p1) + { + ADD_STATE(State_Func2_Post1(p1, &META_RESULT_ORIG_RET(int&), &META_RESULT_OVERRIDE_RET(int&))); + RETURN_META_NOREF(MRES_IGNORED, const int&); + } + }; + + SH_DECL_HOOK0(Test, Func1, SH_NOATTRIB, 0, int&); + SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, const int&, int); +} + +bool TestRefRet(std::string &error) +{ + GET_SHPTR(g_SHPtr); + g_PLID = 1; + + Test test; + Test *pTest = &test; + CHook hook; + + int &ret1 = pTest->Func1(); + ADD_STATE(State_Func1_Ret(&ret1)); + + CHECK_STATES((&g_States, + new State_Func1(&test.m_Var1), + new State_Func1_Ret(&test.m_Var1), + NULL), "Part 1"); + + // Now add Func1_Pre1, which supercedes and returns hook.m_Var + SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre1, false); + + int &ret2 = pTest->Func1(); + ADD_STATE(State_Func1_Ret(&ret2)); + + CHECK_STATES((&g_States, + new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var + new State_Func1(&test.m_Var1), // Function says that it's going to return test.m_Var1 + new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned + NULL), "Part 2"); + + // Now add Func1_Post1, which only reports orig ret and override ret + SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post1, true); + + int &ret3 = pTest->Func1(); + ADD_STATE(State_Func1_Ret(&ret3)); + + CHECK_STATES((&g_States, + new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var + new State_Func1(&test.m_Var1), // Function says that it's going to return test.m_Var1 + new State_Func1_Post1(&test.m_Var1, &hook.m_Var), // origret(=p1) is what it wanted to + // return, overrideret(=p2) is pre1's var + new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned + NULL), "Part 3"); + + // Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337) + // and add Func1_Post2, which overrides and returns hook.m_Var again. + + SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre2, false); + SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post2, true); + + int &ret4 = pTest->Func1(); + ADD_STATE(State_Func1_Ret(&ret4)); + + CHECK_STATES((&g_States, + new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var + new State_Func1_Pre2(MRES_OVERRIDE, // current status + &hook.m_Var, // override ret (which it set to 1337) + &g_Var), // what it's going to ret, AND supercede with + + new State_Func1_Post1(&g_Var, &g_Var), // origret(=p1) is what pre2 superceded with, + // so overrideret(=p2) has to be the same + new State_Func1_Post2(&hook.m_Var), // post2 is going to override with hook.m_Var again + new State_Func1_Ret(&hook.m_Var), // ==>>> hook.m_Var is returned + NULL), "Part 4"); + + CHECK_COND(hook.m_Var == 1337, "Part 4.1"); + + // Through a callclass + SourceHook::CallClass *cc1 = SH_GET_CALLCLASS(&test); + int &ret5 = SH_CALL(cc1, &Test::Func1)(); + ADD_STATE(State_Func1_Ret(&ret5)); + + CHECK_STATES((&g_States, + new State_Func1(&test.m_Var1), + new State_Func1_Ret(&test.m_Var1), + NULL), "Part 5"); + + SH_RELEASE_CALLCLASS(cc1); + + //////////////////////////////////////////////////////////////////////////////////////// + // Func2 tests + const int &ret21 = pTest->Func2(500); + ADD_STATE(State_Func2_Ret(&ret21)); + + CHECK_STATES((&g_States, + new State_Func2(500, &test.m_Var2), + new State_Func2_Ret(&test.m_Var2), + NULL), "Part 6"); + + SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Pre1, false); + SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Post1, true); + + const int &ret22 = pTest->Func2(500); + ADD_STATE(State_Func2_Ret(&ret22)); + + CHECK_STATES((&g_States, + new State_Func2_Pre1(500, &hook.m_Var), // p1 was 500; it's going to override with hook.m_Var; and also change p1 to 1337 + new State_Func2(1337, &test.m_Var2), // p1 was 1337; it's going to ret test.m_Var2 + new State_Func2_Post1(1337, // p1 was 1337 + &test.m_Var2, // orig ret was test.m_Var2 + &hook.m_Var), // override ret was hook.m_Var + new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var + NULL), "Part 7"); + + return true; +}