1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-29 11:24:19 +01:00
sh_memory.h: Added ModuleInMemory; first checks /proc/self/maps OR /proc/curproc/map; if not available tries DS's sigsegv trapping method
sh_tinyhash: Added simple erase function(s)
test/Makefile: New makefile
Changed internal interface: sourcehook.hxx now doesn't need to know about implementation details like vectors etc.

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40118
This commit is contained in:
Pavol Marko 2005-10-03 17:20:22 +00:00
parent 71d74c6722
commit 2790931701
12 changed files with 2173 additions and 921 deletions

View File

@ -1,11 +1,11 @@
// FastDelegate.h // FastDelegate.h
// Efficient delegates in C++ that generate only two lines of asm code! // Efficient delegates in C++ that generate only two lines of asm code!
// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp
// //
// - Don Clugston, Mar 2004. // - Don Clugston, Mar 2004.
// Major contributions were made by Jody Hagins. // Major contributions were made by Jody Hagins.
// History: // History:
// 24-Apr-04 1.0 Submitted to CodeProject. // 24-Apr-04 1.0 Submitted to CodeProject.
// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. // 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack.
// * Improved syntax for horrible_cast (thanks Paul Bludov). // * Improved syntax for horrible_cast (thanks Paul Bludov).
// * Tested on Metrowerks MWCC and Intel ICL (IA32) // * Tested on Metrowerks MWCC and Intel ICL (IA32)
@ -13,7 +13,7 @@
// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 // 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5
// * Now works on /clr "managed C++" code on VC7, VC7.1 // * Now works on /clr "managed C++" code on VC7, VC7.1
// * Comeau C++ now compiles without warnings. // * Comeau C++ now compiles without warnings.
// * Prevent the virtual inheritance case from being used on // * Prevent the virtual inheritance case from being used on
// VC6 and earlier, which generate incorrect code. // VC6 and earlier, which generate incorrect code.
// * Improved warning and error messages. Non-standard hacks // * Improved warning and error messages. Non-standard hacks
// now have compile-time checks to make them safer. // now have compile-time checks to make them safer.
@ -37,7 +37,7 @@
// * Standardised all the compiler-specific workarounds. // * Standardised all the compiler-specific workarounds.
// * MFP conversion now works for CodePlay (but not yet supported in the full code). // * MFP conversion now works for CodePlay (but not yet supported in the full code).
// * Now compiles without warnings on _any_ compiler, including BCC 5.5.1 // * Now compiles without warnings on _any_ compiler, including BCC 5.5.1
// * New syntax: FastDelegate< int (char *, double) >. // * New syntax: FastDelegate< int (char *, double) >.
#ifndef FASTDELEGATE_H #ifndef FASTDELEGATE_H
#define FASTDELEGATE_H #define FASTDELEGATE_H
@ -58,7 +58,7 @@
// Uncomment the following #define for optimally-sized delegates. // Uncomment the following #define for optimally-sized delegates.
// In this case, the generated asm code is almost identical to the code you'd get // In this case, the generated asm code is almost identical to the code you'd get
// if the compiler had native support for delegates. // if the compiler had native support for delegates.
// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). // It will not work on systems where sizeof(dataptr) < sizeof(codeptr).
// Thus, it will not work for DOS compilers using the medium model. // Thus, it will not work for DOS compilers using the medium model.
// It will also probably fail on some DSP systems. // It will also probably fail on some DSP systems.
#define FASTDELEGATE_USESTATICFUNCTIONHACK #define FASTDELEGATE_USESTATICFUNCTIONHACK
@ -86,7 +86,7 @@
// Does the compiler uses Microsoft's member function pointer structure? // Does the compiler uses Microsoft's member function pointer structure?
// If so, it needs special treatment. // If so, it needs special treatment.
// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's // Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's
// identifier, _MSC_VER. We need to filter Metrowerks out. // identifier, _MSC_VER. We need to filter Metrowerks out.
#if defined(_MSC_VER) && !defined(__MWERKS__) #if defined(_MSC_VER) && !defined(__MWERKS__)
#define FASTDLGT_MICROSOFT_MFP #define FASTDLGT_MICROSOFT_MFP
@ -112,7 +112,7 @@
#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX
#endif #endif
#ifdef __GNUC__ // Workaround GCC bug #8271 #ifdef __GNUC__ // Workaround GCC bug #8271
// At present, GCC doesn't recognize constness of MFPs in templates // At present, GCC doesn't recognize constness of MFPs in templates
#define FASTDELEGATE_GCC_BUG_8271 #define FASTDELEGATE_GCC_BUG_8271
#endif #endif
@ -140,10 +140,10 @@ namespace fastdelegate {
namespace detail { // we'll hide the implementation details in a nested namespace. namespace detail { // we'll hide the implementation details in a nested namespace.
// implicit_cast< > // implicit_cast< >
// I believe this was originally going to be in the C++ standard but // I believe this was originally going to be in the C++ standard but
// was left out by accident. It's even milder than static_cast. // was left out by accident. It's even milder than static_cast.
// I use it instead of static_cast<> to emphasize that I'm not doing // I use it instead of static_cast<> to emphasize that I'm not doing
// anything nasty. // anything nasty.
// Usage is identical to static_cast<> // Usage is identical to static_cast<>
template <class OutputClass, class InputClass> template <class OutputClass, class InputClass>
inline OutputClass implicit_cast(InputClass input){ inline OutputClass implicit_cast(InputClass input){
@ -151,11 +151,11 @@ inline OutputClass implicit_cast(InputClass input){
} }
// horrible_cast< > // horrible_cast< >
// This is truly evil. It completely subverts C++'s type system, allowing you // This is truly evil. It completely subverts C++'s type system, allowing you
// to cast from any class to any other class. Technically, using a union // to cast from any class to any other class. Technically, using a union
// to perform the cast is undefined behaviour (even in C). But we can see if // to perform the cast is undefined behaviour (even in C). But we can see if
// it is OK by checking that the union is the same size as each of its members. // it is OK by checking that the union is the same size as each of its members.
// horrible_cast<> should only be used for compiler-specific workarounds. // horrible_cast<> should only be used for compiler-specific workarounds.
// Usage is identical to reinterpret_cast<>. // Usage is identical to reinterpret_cast<>.
// This union is declared outside the horrible_cast because BCC 5.5.1 // This union is declared outside the horrible_cast because BCC 5.5.1
@ -172,7 +172,7 @@ inline OutputClass horrible_cast(const InputClass input){
// Cause a compile-time error if in, out and u are not the same size. // Cause a compile-time error if in, out and u are not the same size.
// If the compile fails here, it means the compiler has peculiar // If the compile fails here, it means the compiler has peculiar
// unions which would prevent the cast from working. // unions which would prevent the cast from working.
typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u) typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u)
&& sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1]; && sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1];
u.in = input; u.in = input;
return u.out; return u.out;
@ -203,9 +203,9 @@ inline OutputClass horrible_cast(const InputClass input){
// Workaround for (2): On VC6, the code for calling a void function is // Workaround for (2): On VC6, the code for calling a void function is
// identical to the code for calling a non-void function in which the // identical to the code for calling a non-void function in which the
// return value is never used, provided the return value is returned // return value is never used, provided the return value is returned
// in the EAX register, rather than on the stack. // in the EAX register, rather than on the stack.
// This is true for most fundamental types such as int, enum, void *. // This is true for most fundamental types such as int, enum, void *.
// Const void * is the safest option since it doesn't participate // Const void * is the safest option since it doesn't participate
// in any automatic conversions. But on a 16-bit compiler it might // in any automatic conversions. But on a 16-bit compiler it might
// cause extra code to be generated, so we disable it for all compilers // cause extra code to be generated, so we disable it for all compilers
// except for VC6 (and VC5). // except for VC6 (and VC5).
@ -251,15 +251,15 @@ struct VoidToDefaultVoid<void> { typedef DefaultVoid type; };
#ifdef FASTDLGT_MICROSOFT_MFP #ifdef FASTDLGT_MICROSOFT_MFP
#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS #ifdef FASTDLGT_HASINHERITANCE_KEYWORDS
// For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP
// (4 bytes), even when the /vmg option is used. Declaring an empty class // (4 bytes), even when the /vmg option is used. Declaring an empty class
// would give 16 byte pointers in this case.... // would give 16 byte pointers in this case....
class __single_inheritance GenericClass; class __single_inheritance GenericClass;
#endif #endif
// ...but for Codeplay, an empty class *always* gives 4 byte pointers. // ...but for Codeplay, an empty class *always* gives 4 byte pointers.
// If compiled with the /clr option ("managed C++"), the JIT compiler thinks // If compiled with the /clr option ("managed C++"), the JIT compiler thinks
// it needs to load GenericClass before it can call any of its functions, // it needs to load GenericClass before it can call any of its functions,
// (compiles OK but crashes at runtime!), so we need to declare an // (compiles OK but crashes at runtime!), so we need to declare an
// empty class to make it happy. // empty class to make it happy.
// Codeplay and VC4 can't cope with the unknown_inheritance case either. // Codeplay and VC4 can't cope with the unknown_inheritance case either.
class GenericClass {}; class GenericClass {};
@ -272,41 +272,41 @@ const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)());
// SimplifyMemFunc< >::Convert() // SimplifyMemFunc< >::Convert()
// //
// A template function that converts an arbitrary member function pointer into the // A template function that converts an arbitrary member function pointer into the
// simplest possible form of member function pointer, using a supplied 'this' pointer. // simplest possible form of member function pointer, using a supplied 'this' pointer.
// According to the standard, this can be done legally with reinterpret_cast<>. // According to the standard, this can be done legally with reinterpret_cast<>.
// For (non-standard) compilers which use member function pointers which vary in size // For (non-standard) compilers which use member function pointers which vary in size
// depending on the class, we need to use knowledge of the internal structure of a // depending on the class, we need to use knowledge of the internal structure of a
// member function pointer, as used by the compiler. Template specialization is used // member function pointer, as used by the compiler. Template specialization is used
// to distinguish between the sizes. Because some compilers don't support partial // to distinguish between the sizes. Because some compilers don't support partial
// template specialisation, I use full specialisation of a wrapper struct. // template specialisation, I use full specialisation of a wrapper struct.
// general case -- don't know how to convert it. Force a compile failure // general case -- don't know how to convert it. Force a compile failure
template <int N> template <int N>
struct SimplifyMemFunc { struct SimplifyMemFunc {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
// Unsupported member function type -- force a compile failure. // Unsupported member function type -- force a compile failure.
// (it's illegal to have a array with negative size). // (it's illegal to have a array with negative size).
typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100]; typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100];
return 0; return 0;
} }
}; };
// For compilers where all member func ptrs are the same size, everything goes here. // For compilers where all member func ptrs are the same size, everything goes here.
// For non-standard compilers, only single_inheritance classes go here. // For non-standard compilers, only single_inheritance classes go here.
template <> template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> { struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
#if defined __DMC__ #if defined __DMC__
// Digital Mars doesn't allow you to cast between abitrary PMF's, // Digital Mars doesn't allow you to cast between abitrary PMF's,
// even though the standard says you can. The 32-bit compiler lets you // even though the standard says you can. The 32-bit compiler lets you
// static_cast through an int, but the DOS compiler doesn't. // static_cast through an int, but the DOS compiler doesn't.
bound_func = horrible_cast<GenericMemFuncType>(function_to_bind); bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);
#else #else
bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind); bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);
#endif #endif
return reinterpret_cast<GenericClass *>(pthis); return reinterpret_cast<GenericClass *>(pthis);
@ -334,13 +334,13 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> {
template<> template<>
struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > { struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
// We need to use a horrible_cast to do this conversion. // We need to use a horrible_cast to do this conversion.
// In MSVC, a multiple inheritance member pointer is internally defined as: // In MSVC, a multiple inheritance member pointer is internally defined as:
union { union {
XFuncType func; XFuncType func;
struct { struct {
GenericMemFuncType funcaddress; // points to the actual member function GenericMemFuncType funcaddress; // points to the actual member function
int delta; // #BYTES to be added to the 'this' pointer int delta; // #BYTES to be added to the 'this' pointer
}s; }s;
@ -349,7 +349,7 @@ struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > {
typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1]; typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1];
u.func = function_to_bind; u.func = function_to_bind;
bound_func = u.s.funcaddress; bound_func = u.s.funcaddress;
return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta); return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta);
} }
}; };
@ -358,10 +358,10 @@ struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > {
// enable conversion to a closure pointer. Earlier versions of this code didn't // enable conversion to a closure pointer. Earlier versions of this code didn't
// work for all cases, and generated a compile-time error instead. // work for all cases, and generated a compile-time error instead.
// But a very clever hack invented by John M. Dlugosz solves this problem. // But a very clever hack invented by John M. Dlugosz solves this problem.
// My code is somewhat different to his: I have no asm code, and I make no // My code is somewhat different to his: I have no asm code, and I make no
// assumptions about the calling convention that is used. // assumptions about the calling convention that is used.
// In VC++ and ICL, a virtual_inheritance member pointer // In VC++ and ICL, a virtual_inheritance member pointer
// is internally defined as: // is internally defined as:
struct MicrosoftVirtualMFP { struct MicrosoftVirtualMFP {
void (GenericClass::*codeptr)(); // points to the actual member function void (GenericClass::*codeptr)(); // points to the actual member function
@ -389,7 +389,7 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
{ {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
union { union {
XFuncType func; XFuncType func;
@ -406,7 +406,7 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >
typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s) typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)
&& sizeof(function_to_bind)==sizeof(u.ProbeFunc) && sizeof(function_to_bind)==sizeof(u.ProbeFunc)
&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1]; && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
// Unfortunately, taking the address of a MF prevents it from being inlined, so // Unfortunately, taking the address of a MF prevents it from being inlined, so
// this next line can't be completely optimised away by the compiler. // this next line can't be completely optimised away by the compiler.
u2.virtfunc = &GenericVirtualClass::GetThis; u2.virtfunc = &GenericVirtualClass::GetThis;
u.s.codeptr = u2.s.codeptr; u.s.codeptr = u2.s.codeptr;
@ -423,55 +423,55 @@ template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) > struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
{ {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
// There is an apalling but obscure compiler bug in MSVC6 and earlier: // There is an apalling but obscure compiler bug in MSVC6 and earlier:
// vtable_index and 'vtordisp' are always set to 0 in the // vtable_index and 'vtordisp' are always set to 0 in the
// unknown_inheritance case! // unknown_inheritance case!
// This means that an incorrect function could be called!!! // This means that an incorrect function could be called!!!
// Compiling with the /vmg option leads to potentially incorrect code. // Compiling with the /vmg option leads to potentially incorrect code.
// This is probably the reason that the IDE has a user interface for specifying // This is probably the reason that the IDE has a user interface for specifying
// the /vmg option, but it is disabled - you can only specify /vmg on // the /vmg option, but it is disabled - you can only specify /vmg on
// the command line. In VC1.5 and earlier, the compiler would ICE if it ever // the command line. In VC1.5 and earlier, the compiler would ICE if it ever
// encountered this situation. // encountered this situation.
// It is OK to use the /vmg option if /vmm or /vms is specified. // It is OK to use the /vmg option if /vmm or /vms is specified.
// Fortunately, the wrong function is only called in very obscure cases. // Fortunately, the wrong function is only called in very obscure cases.
// It only occurs when a derived class overrides a virtual function declared // It only occurs when a derived class overrides a virtual function declared
// in a virtual base class, and the member function // in a virtual base class, and the member function
// points to the *Derived* version of that function. The problem can be // points to the *Derived* version of that function. The problem can be
// completely averted in 100% of cases by using the *Base class* for the // completely averted in 100% of cases by using the *Base class* for the
// member fpointer. Ie, if you use the base class as an interface, you'll // member fpointer. Ie, if you use the base class as an interface, you'll
// stay out of trouble. // stay out of trouble.
// Occasionally, you might want to point directly to a derived class function // Occasionally, you might want to point directly to a derived class function
// that isn't an override of a base class. In this case, both vtable_index // that isn't an override of a base class. In this case, both vtable_index
// and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated. // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated.
// We can generate correct code in this case. To prevent an incorrect call from // We can generate correct code in this case. To prevent an incorrect call from
// ever being made, on MSVC6 we generate a warning, and call a function to // ever being made, on MSVC6 we generate a warning, and call a function to
// make the program crash instantly. // make the program crash instantly.
typedef char ERROR_VC6CompilerBug[-100]; typedef char ERROR_VC6CompilerBug[-100];
return 0; return 0;
} }
}; };
#else #else
// Nasty hack for Microsoft and Intel (IA32 and Itanium) // Nasty hack for Microsoft and Intel (IA32 and Itanium)
// unknown_inheritance classes go here // unknown_inheritance classes go here
// This is probably the ugliest bit of code I've ever written. Look at the casts! // This is probably the ugliest bit of code I've ever written. Look at the casts!
// There is a compiler bug in MSVC6 which prevents it from using this code. // There is a compiler bug in MSVC6 which prevents it from using this code.
template <> template <>
struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) > struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
{ {
template <class X, class XFuncType, class GenericMemFuncType> template <class X, class XFuncType, class GenericMemFuncType>
inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,
GenericMemFuncType &bound_func) { GenericMemFuncType &bound_func) {
// The member function pointer is 16 bytes long. We can't use a normal cast, but // The member function pointer is 16 bytes long. We can't use a normal cast, but
// we can use a union to do the conversion. // we can use a union to do the conversion.
union { union {
XFuncType func; XFuncType func;
// In VC++ and ICL, an unknown_inheritance member pointer // In VC++ and ICL, an unknown_inheritance member pointer
// is internally defined as: // is internally defined as:
struct { struct {
GenericMemFuncType m_funcaddress; // points to the actual member function GenericMemFuncType m_funcaddress; // points to the actual member function
@ -486,13 +486,13 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
bound_func = u.s.funcaddress; bound_func = u.s.funcaddress;
int virtual_delta = 0; int virtual_delta = 0;
if (u.s.vtable_index) { // Virtual inheritance is used if (u.s.vtable_index) { // Virtual inheritance is used
// First, get to the vtable. // First, get to the vtable.
// It is 'vtordisp' bytes from the start of the class. // It is 'vtordisp' bytes from the start of the class.
const int * vtable = *reinterpret_cast<const int *const*>( const int * vtable = *reinterpret_cast<const int *const*>(
reinterpret_cast<const char *>(pthis) + u.s.vtordisp ); reinterpret_cast<const char *>(pthis) + u.s.vtordisp );
// 'vtable_index' tells us where in the table we should be looking. // 'vtable_index' tells us where in the table we should be looking.
virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>( virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>(
reinterpret_cast<const char *>(vtable) + u.s.vtable_index); reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
} }
// The int at 'virtual_delta' gives us the amount to add to 'this'. // The int at 'virtual_delta' gives us the amount to add to 'this'.
@ -518,7 +518,7 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
// It knows nothing about the calling convention or number of arguments used by // It knows nothing about the calling convention or number of arguments used by
// the function pointed to. // the function pointed to.
// It supplies comparison operators so that it can be stored in STL collections. // It supplies comparison operators so that it can be stored in STL collections.
// It cannot be set to anything other than null, nor invoked directly: // It cannot be set to anything other than null, nor invoked directly:
// it must be converted to a specific delegate. // it must be converted to a specific delegate.
// Implementation: // Implementation:
@ -526,7 +526,7 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
// DelegateMemento - Safe version // DelegateMemento - Safe version
// //
// This implementation is standard-compliant, but a bit tricky. // This implementation is standard-compliant, but a bit tricky.
// A static function pointer is stored inside the class. // A static function pointer is stored inside the class.
// Here are the valid values: // Here are the valid values:
// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ // +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+
// | 0 | 0 | 0 | Empty | // | 0 | 0 | 0 | Empty |
@ -539,18 +539,18 @@ struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >
// DelegateMemento - Evil version // DelegateMemento - Evil version
// //
// For compilers where data pointers are at least as big as code pointers, it is // For compilers where data pointers are at least as big as code pointers, it is
// possible to store the function pointer in the this pointer, using another // possible to store the function pointer in the this pointer, using another
// horrible_cast. In this case the DelegateMemento implementation is simple: // horrible_cast. In this case the DelegateMemento implementation is simple:
// +--pThis --+-- pMemFunc-+-- Meaning---------------------+ // +--pThis --+-- pMemFunc-+-- Meaning---------------------+
// | 0 | 0 | Empty | // | 0 | 0 | Empty |
// | !=0 | !=0 | Static function or method call| // | !=0 | !=0 | Static function or method call|
// +----------+------------+-------------------------------+ // +----------+------------+-------------------------------+
// Note that the Sun C++ and MSVC documentation explicitly state that they // Note that the Sun C++ and MSVC documentation explicitly state that they
// support static_cast between void * and function pointers. // support static_cast between void * and function pointers.
class DelegateMemento { class DelegateMemento {
protected: protected:
// the data is protected, not private, because many // the data is protected, not private, because many
// compilers have problems with template friends. // compilers have problems with template friends.
typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.
@ -593,11 +593,11 @@ public:
inline bool IsLess(const DelegateMemento &right) const { inline bool IsLess(const DelegateMemento &right) const {
// deal with static function pointers first // deal with static function pointers first
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0)
return m_pStaticFunction < right.m_pStaticFunction; return m_pStaticFunction < right.m_pStaticFunction;
#endif #endif
if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis; if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis;
// There are no ordering operators for member function pointers, // There are no ordering operators for member function pointers,
// but we can fake one by comparing each byte. The resulting ordering is // but we can fake one by comparing each byte. The resulting ordering is
// arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers.
return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;
@ -607,7 +607,7 @@ public:
{ return m_pFunction==0; } { return m_pFunction==0; }
public: public:
DelegateMemento & operator = (const DelegateMemento &right) { DelegateMemento & operator = (const DelegateMemento &right) {
SetMementoFrom(right); SetMementoFrom(right);
return *this; return *this;
} }
inline bool operator <(const DelegateMemento &right) { inline bool operator <(const DelegateMemento &right) {
@ -616,8 +616,8 @@ public:
inline bool operator >(const DelegateMemento &right) { inline bool operator >(const DelegateMemento &right) {
return right.IsLess(*this); return right.IsLess(*this);
} }
DelegateMemento (const DelegateMemento &right) : DelegateMemento (const DelegateMemento &right) :
m_pthis(right.m_pthis), m_pFunction(right.m_pFunction) m_pthis(right.m_pthis), m_pFunction(right.m_pFunction)
#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)
, m_pStaticFunction (right.m_pStaticFunction) , m_pStaticFunction (right.m_pStaticFunction)
#endif #endif
@ -638,8 +638,8 @@ protected:
// A private wrapper class that adds function signatures to DelegateMemento. // A private wrapper class that adds function signatures to DelegateMemento.
// It's the class that does most of the actual work. // It's the class that does most of the actual work.
// The signatures are specified by: // The signatures are specified by:
// GenericMemFunc: must be a type of GenericClass member function pointer. // GenericMemFunc: must be a type of GenericClass member function pointer.
// StaticFuncPtr: must be a type of function pointer with the same signature // StaticFuncPtr: must be a type of function pointer with the same signature
// as GenericMemFunc. // as GenericMemFunc.
// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 // UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6
// where it never returns void (returns DefaultVoid instead). // where it never returns void (returns DefaultVoid instead).
@ -655,8 +655,8 @@ class ClosurePtr : public DelegateMemento {
public: public:
// These functions are for setting the delegate to a member function. // These functions are for setting the delegate to a member function.
// Here's the clever bit: we convert an arbitrary member function into a // Here's the clever bit: we convert an arbitrary member function into a
// standard form. XMemFunc should be a member function of class X, but I can't // standard form. XMemFunc should be a member function of class X, but I can't
// enforce that here. It needs to be enforced by the wrapper class. // enforce that here. It needs to be enforced by the wrapper class.
template < class X, class XMemFunc > template < class X, class XMemFunc >
inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) { inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) {
@ -667,7 +667,7 @@ public:
#endif #endif
} }
// For const member functions, we only need a const class pointer. // For const member functions, we only need a const class pointer.
// Since we know that the member function is const, it's safe to // Since we know that the member function is const, it's safe to
// remove the const qualifier from the 'this' pointer with a const_cast. // remove the const qualifier from the 'this' pointer with a const_cast.
// VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name.
template < class X, class XMemFunc> template < class X, class XMemFunc>
@ -717,47 +717,47 @@ public:
m_pthis=reinterpret_cast<GenericClass *>(pParent); m_pthis=reinterpret_cast<GenericClass *>(pParent);
} }
} }
// For static functions, the 'static_function_invoker' class in the parent // For static functions, the 'static_function_invoker' class in the parent
// will be called. The parent then needs to call GetStaticFunction() to find out // will be called. The parent then needs to call GetStaticFunction() to find out
// the actual function to invoke. // the actual function to invoke.
template < class DerivedClass, class ParentInvokerSig > template < class DerivedClass, class ParentInvokerSig >
inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
StaticFuncPtr function_to_bind ) { StaticFuncPtr function_to_bind ) {
bindmemfunc(pParent, static_function_invoker); bindmemfunc(pParent, static_function_invoker);
m_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind); m_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind);
} }
inline UnvoidStaticFuncPtr GetStaticFunction() const { inline UnvoidStaticFuncPtr GetStaticFunction() const {
return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction); return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction);
} }
#else #else
// ClosurePtr<> - Evil version // ClosurePtr<> - Evil version
// //
// For compilers where data pointers are at least as big as code pointers, it is // For compilers where data pointers are at least as big as code pointers, it is
// possible to store the function pointer in the this pointer, using another // possible to store the function pointer in the this pointer, using another
// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and // horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and
// speeds up comparison and assignment. If C++ provided direct language support // speeds up comparison and assignment. If C++ provided direct language support
// for delegates, they would produce asm code that was almost identical to this. // for delegates, they would produce asm code that was almost identical to this.
// Note that the Sun C++ and MSVC documentation explicitly state that they // Note that the Sun C++ and MSVC documentation explicitly state that they
// support static_cast between void * and function pointers. // support static_cast between void * and function pointers.
template< class DerivedClass > template< class DerivedClass >
inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &right) { inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &right) {
SetMementoFrom(right); SetMementoFrom(right);
} }
// For static functions, the 'static_function_invoker' class in the parent // For static functions, the 'static_function_invoker' class in the parent
// will be called. The parent then needs to call GetStaticFunction() to find out // will be called. The parent then needs to call GetStaticFunction() to find out
// the actual function to invoke. // the actual function to invoke.
// ******** EVIL, EVIL CODE! ******* // ******** EVIL, EVIL CODE! *******
template < class DerivedClass, class ParentInvokerSig> template < class DerivedClass, class ParentInvokerSig>
inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker,
StaticFuncPtr function_to_bind) { StaticFuncPtr function_to_bind) {
// We'll be ignoring the 'this' pointer, but we need to make sure we pass // We'll be ignoring the 'this' pointer, but we need to make sure we pass
// a valid value to bindmemfunc(). // a valid value to bindmemfunc().
bindmemfunc(pParent, static_function_invoker); bindmemfunc(pParent, static_function_invoker);
// WARNING! Evil hack. We store the function in the 'this' pointer! // WARNING! Evil hack. We store the function in the 'this' pointer!
// Ensure that there's a compilation failure if function pointers // Ensure that there's a compilation failure if function pointers
// and data pointers have different sizes. // and data pointers have different sizes.
// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1]; typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1];
@ -772,7 +772,7 @@ public:
// We're just returning the 'this' pointer, converted into // We're just returning the 'this' pointer, converted into
// a function pointer! // a function pointer!
inline UnvoidStaticFuncPtr GetStaticFunction() const { inline UnvoidStaticFuncPtr GetStaticFunction() const {
// Ensure that there's a compilation failure if function pointers // Ensure that there's a compilation failure if function pointers
// and data pointers have different sizes. // and data pointers have different sizes.
// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.
typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1]; typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1];
@ -794,7 +794,7 @@ public:
// Once we have the member function conversion templates, it's easy to make the // Once we have the member function conversion templates, it's easy to make the
// wrapper classes. So that they will work with as many compilers as possible, // wrapper classes. So that they will work with as many compilers as possible,
// the classes are of the form // the classes are of the form
// FastDelegate3<int, char *, double> // FastDelegate3<int, char *, double>
// They can cope with any combination of parameters. The max number of parameters // They can cope with any combination of parameters. The max number of parameters
@ -805,7 +805,7 @@ public:
// Because of the weird rule about the class of derived member function pointers, // Because of the weird rule about the class of derived member function pointers,
// you sometimes need to apply a downcast to the 'this' pointer. // you sometimes need to apply a downcast to the 'this' pointer.
// This is the reason for the use of "implicit_cast<X*>(pthis)" in the code below. // This is the reason for the use of "implicit_cast<X*>(pthis)" in the code below.
// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, // If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction,
// without this trick you'd need to write: // without this trick you'd need to write:
// MyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction); // MyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction);
@ -862,7 +862,7 @@ public:
FastDelegate@NUM(DesiredRetType (*function_to_bind)(@FUNCARGS) ) { FastDelegate@NUM(DesiredRetType (*function_to_bind)(@FUNCARGS) ) {
bind(function_to_bind); } bind(function_to_bind); }
inline void bind(DesiredRetType (*function_to_bind)(@FUNCARGS)) { inline void bind(DesiredRetType (*function_to_bind)(@FUNCARGS)) {
m_Closure.bindstaticfunc(this, &FastDelegate@NUM::InvokeStaticFunction, m_Closure.bindstaticfunc(this, &FastDelegate@NUM::InvokeStaticFunction,
function_to_bind); } function_to_bind); }
RetType operator() (@FUNCARGS) const { // Invoke the delegate RetType operator() (@FUNCARGS) const { // Invoke the delegate
// this next line is the only one that violates the standard // this next line is the only one that violates the standard
@ -885,7 +885,7 @@ private: // Invoker for static functions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Fast Delegates, part 4: // Fast Delegates, part 4:
// //
// FastDelegate<> class (Original author: Jody Hagins) // FastDelegate<> class (Original author: Jody Hagins)
// Allows boost::function style syntax like: // Allows boost::function style syntax like:
// FastDelegate< double (int, long) > // FastDelegate< double (int, long) >
@ -923,7 +923,7 @@ public:
FastDelegate() : BaseType() { } FastDelegate() : BaseType() { }
template < class X, class Y > template < class X, class Y >
FastDelegate(Y * pthis, FastDelegate(Y * pthis,
R (X::* function_to_bind)( @FUNCARGS )) R (X::* function_to_bind)( @FUNCARGS ))
: BaseType(pthis, function_to_bind) { } : BaseType(pthis, function_to_bind) { }
@ -935,7 +935,7 @@ public:
FastDelegate(R (*function_to_bind)( @FUNCARGS )) FastDelegate(R (*function_to_bind)( @FUNCARGS ))
: BaseType(function_to_bind) { } : BaseType(function_to_bind) { }
void operator = (const BaseType &x) { void operator = (const BaseType &x) {
*static_cast<BaseType*>(this) = x; } *static_cast<BaseType*>(this) = x; }
}; };
@ -954,7 +954,7 @@ public:
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Also declare overloads of a MakeDelegate() global function to // Also declare overloads of a MakeDelegate() global function to
// reduce the need for typedefs. // reduce the need for typedefs.
// We need seperate overloads for const and non-const member functions. // We need seperate overloads for const and non-const member functions.
// Also, because of the weird rule about the class of derived member function pointers, // Also, because of the weird rule about the class of derived member function pointers,
@ -969,23 +969,23 @@ public:
#ifdef FASTDLGT_VC6 #ifdef FASTDLGT_VC6
#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type #define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type
#else #else
#define FASTDLGT_RETTYPE RetType #define FASTDLGT_RETTYPE RetType
#endif #endif
@VARARGS @VARARGS
template <class X, class Y, @CLASSARGS, class RetType> template <class X, class Y, @CLASSARGS, class RetType>
FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(@FUNCARGS)) { FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(@FUNCARGS)) {
return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(x, func); return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(x, func);
} }
template <class X, class Y, @CLASSARGS, class RetType> template <class X, class Y, @CLASSARGS, class RetType>
FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(@FUNCARGS) const) { FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(@FUNCARGS) const) {
return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(x, func); return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(x, func);
} }
template <@CLASSARGS, class RetType> template <@CLASSARGS, class RetType>
FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(RetType (*func)(@FUNCARGS)) { FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE> MakeDelegate(RetType (*func)(@FUNCARGS)) {
return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(func); return FastDelegate@NUM<@SELARGS, FASTDLGT_RETTYPE>(func);
} }

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__ #ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__ #define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1 #define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 1 #define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR #ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr #define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID #define SH_GLOB_PLUGPTR g_PLID
#endif #endif
#ifdef SH_DEBUG #ifdef SH_DEBUG
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0) # define SH_ASSERT(x, info) \
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__) do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else #else
# define SH_ASSERT(x, info) # define SH_ASSERT(x, info)
#endif #endif
@ -67,13 +75,9 @@
#endif #endif
#define SH_PTRSIZE sizeof(void*) #define SH_PTRSIZE sizeof(void*)
#include "FastDelegate.h" #include "FastDelegate.h"
#include "sh_memfuncinfo.h" #include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod! // Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook namespace SourceHook
{ {
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/** /**
* @brief An empty class. No inheritance used. Used for original-function-call hacks * @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/ */
class EmptyClass class EmptyClass
{ {
@ -111,29 +118,33 @@ namespace SourceHook
/** /**
* @brief A plugin typedef * @brief A plugin typedef
* *
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it * SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* and every plugin has a unique identifier, everything is ok. * plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/ */
typedef int Plugin; typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction enum HookManagerAction
{ {
HA_GetInfo = 0, // -> Only store info HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, // -> Save the pointer for future reference HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister // -> Clear the saved pointer HA_Unregister //!< Clear the saved pointer
}; };
struct HookManagerInfo; class IHookManagerInfo;
/** /**
* @brief Pointer to hook manager type * @brief Pointer to hook manager interface function
* *
* A "hook manager" 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 HookManagerInfo structure. The hook manager should fill it and store it for * @param ha What the hook manager should do
* future reference (mainly if something should get hooked to its hookfunc) * @param hi A pointer to IHookManagerInfo
*/ */
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi); typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate class ISHDelegate
{ {
@ -161,7 +172,7 @@ namespace SourceHook
bool IsEqual(ISHDelegate *other) bool IsEqual(ISHDelegate *other)
{ {
return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg(); return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg();
} }
T &GetDeleg() T &GetDeleg()
@ -170,65 +181,83 @@ namespace SourceHook
} }
}; };
/** struct IHookList
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
{ {
struct VfnPtr struct IIter
{ {
struct Iface virtual bool End() = 0;
{ virtual void Next() = 0;
struct Hook virtual ISHDelegate *Handler() = 0;
{ virtual int ThisPtrOffs() = 0;
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
}; };
virtual IIter *GetIter() = 0;
Plugin plug; //!< The owner plugin virtual void ReleaseIter(IIter *pIter) = 0;
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
}; };
typedef SourceHook::CVector<void*> OrigFuncs; struct IIface
typedef SourceHook::THash<int, OrigFuncs> OrigVTables; {
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass template<class B> struct CallClass
{ {
B *ptr; //!< Pointer to the actual object virtual B *GetThisPtr() = 0;
size_t objsize; //!< Size of the instance virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
OrigVTables vt; //!< Info about vtables & functions
}; };
typedef CallClass<void> GenericCallClass; typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook class ISourceHook
{ {
public: public:
virtual ~ISourceHook()
{ }
/** /**
* @brief Return interface version * @brief Return interface version
*/ */
@ -263,7 +290,8 @@ namespace SourceHook
* @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 thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Removes a hook. * @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @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, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Checks whether a plugin has (a) hook manager(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
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0; virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined virtual const void *GetOrigRet() = 0; //!< Gets the original result.
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL //!< If not in post function, undefined
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 hook managers // For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC #elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \ reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0; reinterpret_cast<void**>(&mfp)[1] = 0;
#else #else
# error Not supported yet. # error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov #define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \ #define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \ SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \ /* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \ if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \ return 1; \
\ \
if (action == ::SourceHook::HA_GetInfo) \ if (action == ::SourceHook::HA_GetInfo) \
{ \ { \
param->proto = ms_Proto; \ param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
\ \
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \ GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \ param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \ reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \ return 0; \
} \ } \
else if (action == ::SourceHook::HA_Register) \ else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
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 ::SourceHook::HookManagerInfo *ms_HI; \ static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \ static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \ #define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \ }; \
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; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \ ::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \ bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \ rettype orig_ret; \
rettype override_ret; \ rettype override_ret; \
rettype plugin_ret; \ rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \ #define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \ } \
else \ else \
orig_ret = override_ret; orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \ #define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \ return; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \ void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \ #define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} }
#define SH_RETURN_void() #define SH_RETURN_void()
@ -1490,6 +1514,210 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \ SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc))) (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 17 arguments *********
#define SH_DECL_HOOK17(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 18 arguments *********
#define SH_DECL_HOOK18(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 19 arguments *********
#define SH_DECL_HOOK19(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 20 arguments *********
#define SH_DECL_HOOK20(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1497,14 +1725,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \ # define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -1512,9 +1742,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \ RetType(EmptyClass::*mfpnew)prms; \
void *addr; \ void *addr; \
} u; \ } u; \
u.addr = iter->val[mfi.vtblindex]; \ u.addr = origfunc; \
\ \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \ void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
} }
@ -1524,10 +1754,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -1539,10 +1769,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \ intptr_t adjustor; \
} s; \ } s; \
} u; \ } u; \
u.s.addr = iter->val[mfi.vtblindex]; \ u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \ u.s.adjustor = mfi.thisptroffs; \
\ \
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
} }
#endif #endif
@ -1559,73 +1789,89 @@ namespace SourceHook
} }
// Support for 0 arguments // Support for 0 arguments
RetType operator()() const RetType operator()() const
SH_MAKE_EXECUTABLECLASS_OB((), ()) SH_MAKE_EXECUTABLECLASS_OB((), ())
// Support for 1 arguments // Support for 1 arguments
template<class Param1> RetType operator()(Param1 p1) const template<class Param1> RetType operator()(Param1 p1) const
SH_MAKE_EXECUTABLECLASS_OB((p1), (Param1)) SH_MAKE_EXECUTABLECLASS_OB((p1), (Param1))
// Support for 2 arguments // Support for 2 arguments
template<class Param1, class Param2> RetType operator()(Param1 p1, Param2 p2) const template<class Param1, class Param2> RetType operator()(Param1 p1, Param2 p2) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2), (Param1, Param2)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2), (Param1, Param2))
// Support for 3 arguments // Support for 3 arguments
template<class Param1, class Param2, class Param3> RetType operator()(Param1 p1, Param2 p2, Param3 p3) const template<class Param1, class Param2, class Param3> RetType operator()(Param1 p1, Param2 p2, Param3 p3) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3), (Param1, Param2, Param3)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3), (Param1, Param2, Param3))
// Support for 4 arguments // Support for 4 arguments
template<class Param1, class Param2, class Param3, class Param4> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const template<class Param1, class Param2, class Param3, class Param4> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4), (Param1, Param2, Param3, Param4)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4), (Param1, Param2, Param3, Param4))
// Support for 5 arguments // Support for 5 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const template<class Param1, class Param2, class Param3, class Param4, class Param5> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5), (Param1, Param2, Param3, Param4, Param5)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5), (Param1, Param2, Param3, Param4, Param5))
// Support for 6 arguments // Support for 6 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6), (Param1, Param2, Param3, Param4, Param5, Param6)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6), (Param1, Param2, Param3, Param4, Param5, Param6))
// Support for 7 arguments // Support for 7 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7), (Param1, Param2, Param3, Param4, Param5, Param6, Param7)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7), (Param1, Param2, Param3, Param4, Param5, Param6, Param7))
// Support for 8 arguments // Support for 8 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
// Support for 9 arguments // Support for 9 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
// Support for 10 arguments // Support for 10 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
// Support for 11 arguments // Support for 11 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
// Support for 12 arguments // Support for 12 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
// Support for 13 arguments // Support for 13 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
// Support for 14 arguments // Support for 14 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
// Support for 15 arguments // Support for 15 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
// Support for 16 arguments // Support for 16 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
// Support for 17 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
// Support for 18 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
// Support for 19 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
// Support for 20 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19, Param20 p20) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
}; };
} }
@ -1888,6 +2134,66 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp); return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
} }
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300 #if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300
// GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it // GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it
@ -2147,12 +2453,72 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp); return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
} }
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#endif #endif
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp)) #define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY #undef SH_MAKE_EXECUTABLECLASS_OB
#endif #endif
// The pope is dead. -> :( // The pope is dead. -> :(

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__ #ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__ #define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1 #define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 1 #define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR #ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr #define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID #define SH_GLOB_PLUGPTR g_PLID
#endif #endif
#ifdef SH_DEBUG #ifdef SH_DEBUG
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0) # define SH_ASSERT(x, info) \
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__) do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else #else
# define SH_ASSERT(x, info) # define SH_ASSERT(x, info)
#endif #endif
@ -67,13 +75,9 @@
#endif #endif
#define SH_PTRSIZE sizeof(void*) #define SH_PTRSIZE sizeof(void*)
#include "FastDelegate.h" #include "FastDelegate.h"
#include "sh_memfuncinfo.h" #include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod! // Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook namespace SourceHook
{ {
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/** /**
* @brief An empty class. No inheritance used. Used for original-function-call hacks * @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/ */
class EmptyClass class EmptyClass
{ {
@ -111,29 +118,33 @@ namespace SourceHook
/** /**
* @brief A plugin typedef * @brief A plugin typedef
* *
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it * SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* and every plugin has a unique identifier, everything is ok. * plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/ */
typedef int Plugin; typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction enum HookManagerAction
{ {
HA_GetInfo = 0, // -> Only store info HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, // -> Save the pointer for future reference HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister // -> Clear the saved pointer HA_Unregister //!< Clear the saved pointer
}; };
struct HookManagerInfo; class IHookManagerInfo;
/** /**
* @brief Pointer to hook manager type * @brief Pointer to hook manager interface function
* *
* A "hook manager" 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 HookManagerInfo structure. The hook manager should fill it and store it for * @param ha What the hook manager should do
* future reference (mainly if something should get hooked to its hookfunc) * @param hi A pointer to IHookManagerInfo
*/ */
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi); typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate class ISHDelegate
{ {
@ -161,7 +172,7 @@ namespace SourceHook
bool IsEqual(ISHDelegate *other) bool IsEqual(ISHDelegate *other)
{ {
return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg(); return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg();
} }
T &GetDeleg() T &GetDeleg()
@ -170,65 +181,83 @@ namespace SourceHook
} }
}; };
/** struct IHookList
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
{ {
struct VfnPtr struct IIter
{ {
struct Iface virtual bool End() = 0;
{ virtual void Next() = 0;
struct Hook virtual ISHDelegate *Handler() = 0;
{ virtual int ThisPtrOffs() = 0;
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
}; };
virtual IIter *GetIter() = 0;
Plugin plug; //!< The owner plugin virtual void ReleaseIter(IIter *pIter) = 0;
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
}; };
typedef SourceHook::CVector<void*> OrigFuncs; struct IIface
typedef SourceHook::THash<int, OrigFuncs> OrigVTables; {
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass template<class B> struct CallClass
{ {
B *ptr; //!< Pointer to the actual object virtual B *GetThisPtr() = 0;
size_t objsize; //!< Size of the instance virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
OrigVTables vt; //!< Info about vtables & functions
}; };
typedef CallClass<void> GenericCallClass; typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook class ISourceHook
{ {
public: public:
virtual ~ISourceHook()
{ }
/** /**
* @brief Return interface version * @brief Return interface version
*/ */
@ -263,7 +290,8 @@ namespace SourceHook
* @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 thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Removes a hook. * @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @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, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Checks whether a plugin has (a) hook manager(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
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0; virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined virtual const void *GetOrigRet() = 0; //!< Gets the original result.
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL //!< If not in post function, undefined
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 hook managers // For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC #elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \ reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0; reinterpret_cast<void**>(&mfp)[1] = 0;
#else #else
# error Not supported yet. # error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov #define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \ #define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \ SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \ /* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \ if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \ return 1; \
\ \
if (action == ::SourceHook::HA_GetInfo) \ if (action == ::SourceHook::HA_GetInfo) \
{ \ { \
param->proto = ms_Proto; \ param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
\ \
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \ GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \ param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \ reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \ return 0; \
} \ } \
else if (action == ::SourceHook::HA_Register) \ else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
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 ::SourceHook::HookManagerInfo *ms_HI; \ static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \ static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \ #define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \ }; \
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; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \ ::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \ bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \ rettype orig_ret; \
rettype override_ret; \ rettype override_ret; \
rettype plugin_ret; \ rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \ #define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \ } \
else \ else \
orig_ret = override_ret; orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \ #define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \ return; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \ void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \ #define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} }
#define SH_RETURN_void() #define SH_RETURN_void()
@ -683,14 +707,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \ # define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -698,9 +724,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \ RetType(EmptyClass::*mfpnew)prms; \
void *addr; \ void *addr; \
} u; \ } u; \
u.addr = iter->val[mfi.vtblindex]; \ u.addr = origfunc; \
\ \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \ void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
} }
@ -710,10 +736,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -725,10 +751,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \ intptr_t adjustor; \
} s; \ } s; \
} u; \ } u; \
u.s.addr = iter->val[mfi.vtblindex]; \ u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \ u.s.adjustor = mfi.thisptroffs; \
\ \
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
} }
#endif #endif
@ -746,7 +772,7 @@ namespace SourceHook
@VARARGS@ @VARARGS@
// Support for @$@ arguments // Support for @$@ arguments
@template<@@class Param%%|, @@> @RetType operator()(@Param%% p%%|, @) const @template<@@class Param%%|, @@> @RetType operator()(@Param%% p%%|, @) const
SH_MAKE_EXECUTABLECLASS_OB((@p%%|, @), (@Param%%|, @)) SH_MAKE_EXECUTABLECLASS_OB((@p%%|, @), (@Param%%|, @))
@ENDARGS@ @ENDARGS@
@ -800,7 +826,7 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@Param%%|, @@
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp)) #define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY #undef SH_MAKE_EXECUTABLECLASS_OB
#endif #endif
// The pope is dead. -> :( // The pope is dead. -> :(

View File

@ -23,6 +23,9 @@
# define SH_MEM_EXEC 4 # define SH_MEM_EXEC 4
# elif /******/ defined __linux__ # elif /******/ defined __linux__
# include <sys/mman.h> # include <sys/mman.h>
# include <stdio.h>
# include <signal.h>
# include <setjmp.h>
// http://www.die.net/doc/linux/man/man2/mprotect.2.html // http://www.die.net/doc/linux/man/man2/mprotect.2.html
# include <limits.h> # include <limits.h>
# ifndef PAGESIZE # ifndef PAGESIZE
@ -66,6 +69,118 @@ namespace SourceHook
# endif # endif
} }
#ifdef __linux__
namespace
{
bool g_BadReadCalled;
jmp_buf g_BadReadJmpBuf;
static void BadReadHandler(int sig)
{
if (g_BadReadCalled)
longjmp(g_BadReadJmpBuf, 1);
}
}
#endif
/**
* @brief Checks whether the specified memory region is (still) accessible
*
* @param addr The lower boundary
* @param len Length of the region to be checked
*/
namespace
{
bool ModuleInMemory(char *addr, size_t len)
{
#ifdef __linux__
// On linux, first check /proc/self/maps
long lower = reinterpret_cast<long>(addr);
long upper = lower + len;
FILE *pF = fopen("/proc/self/maps", "r");
if (pF)
{
// Linux /proc/self/maps -> parse
// Format:
// lower upper prot stuff path
// 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat
long rlower, rupper;
while (fscanf(pF, "%lx-%lx", &rlower, &rupper) != EOF)
{
// Check whether we're IN THERE!
if (lower >= rlower && upper <= rupper)
{
fclose(pF);
return true;
}
// Read to end of line
int c;
while ((c = fgetc(pF)) != '\n')
{
if (c == EOF)
break;
}
if (c == EOF)
break;
}
fclose(pF);
return false;
}
pF = fopen("/proc/curproc/map", "r");
if (pF)
{
// FreeBSD /proc/curproc/map -> parse
// 0x804800 0x805500 13 15 0xc6e18960 r-x 21 0x0 COW NC vnode
long rlower, rupper;
while (fscanf(pF, "0x%lx 0x%lx", &rlower, &rupper) != EOF)
{
// Check whether we're IN THERE!
if (lower >= rlower && upper <= rupper)
{
fclose(pF);
return true;
}
// Read to end of line
int c;
while ((c = fgetc(pF)) != '\n')
{
if (c == EOF)
break;
}
if (c == EOF)
break;
}
fclose(pF);
return false;
}
// Both of the above failed, try to actually read and trap sigsegv (implemented by Damaged Soul)
void(*prevHandler)(int sig);
g_BadReadCalled = true;
if (setjmp(g_BadReadJmpBuf))
return true;
prevHandler = signal(SIGSEGV, BadReadHandler);
volatile const char *p = reinterpret_cast<const char*>(addr);
char dummy;
for (size_t i = 0; i < len; i++)
dummy = p[i];
g_BadReadCalled = false;
signal(SIGSEGV, prevHandler);
return false;
#else
// On Win32, simply use IsBadReadPtr
return !IsBadReadPtr(addr, len);
#endif
}
}
} }
#endif #endif

View File

@ -27,13 +27,13 @@ namespace SourceHook
* This is a tiny, growable hash class. * This is a tiny, growable hash class.
* Meant for quick and dirty dictionaries only! * Meant for quick and dirty dictionaries only!
*/ */
template <class K, class V> template <class K, class V>
class THash class THash
{ {
public: public:
struct THashNode struct THashNode
{ {
THashNode(const K & k, const V & v) : THashNode(const K & k, const V & v) :
key(k), val(v) key(k), val(v)
{ {
}; };
@ -139,7 +139,7 @@ namespace SourceHook
typename List<THashNode *>::iterator iter; typename List<THashNode *>::iterator iter;
size_t place; size_t place;
THashNode *pHashNode; THashNode *pHashNode;
NodePtr *temp = new NodePtr[m_numBuckets]; NodePtr *temp = new NodePtr[m_numBuckets];
for (size_t i=0; i<m_numBuckets; i++) for (size_t i=0; i<m_numBuckets; i++)
temp[i] = NULL; temp[i] = NULL;
//look in old hash table //look in old hash table
@ -222,10 +222,10 @@ namespace SourceHook
{ {
if (where.hash == this->hash if (where.hash == this->hash
&& where.end == this->end && where.end == this->end
&& &&
(this->end || (this->end ||
((where.curbucket == this->curbucket) ((where.curbucket == this->curbucket)
&& (where.iter == iter)) && (where.iter == iter))
)) ))
return true; return true;
return false; return false;
@ -234,6 +234,20 @@ namespace SourceHook
{ {
return !( (*this) == where ); return !( (*this) == where );
} }
void erase()
{
if (end || !hash || curbucket < 0 || curbucket >= static_cast<int>(hash->m_numBuckets))
return;
// Remove this element and move to the next one
iterator tmp = *this;
++tmp;
hash->m_Buckets[curbucket]->erase(iter);
*this = tmp;
// :TODO: Maybe refactor to a lower size if required
}
private: private:
void _Inc() void _Inc()
{ {
@ -321,10 +335,10 @@ namespace SourceHook
{ {
if (where.hash == this->hash if (where.hash == this->hash
&& where.end == this->end && where.end == this->end
&& &&
(this->end || (this->end ||
((where.curbucket == this->curbucket) ((where.curbucket == this->curbucket)
&& (where.iter == iter)) && (where.iter == iter))
)) ))
return true; return true;
return false; return false;
@ -392,7 +406,7 @@ namespace SourceHook
iter.hash = this; iter.hash = this;
return iter; return iter;
} }
const_iterator begin() const const_iterator begin() const
{ {
return const_iterator(this); return const_iterator(this);
@ -403,7 +417,7 @@ namespace SourceHook
iter.hash = this; iter.hash = this;
return iter; return iter;
} }
template <typename U> template <typename U>
iterator find(const U & u) const iterator find(const U & u) const
{ {
@ -428,6 +442,20 @@ namespace SourceHook
} }
return end(); return end();
} }
iterator erase(iterator where)
{
where.erase();
return where;
}
template <typename U>
void erase(const U & u)
{
iterator iter = find(u);
if (iter == end())
return;
iter.erase();
}
private: private:
NodePtr *m_Buckets; NodePtr *m_Buckets;
size_t m_numBuckets; size_t m_numBuckets;

View File

@ -17,8 +17,9 @@
#if defined __GNUC__ #if defined __GNUC__
#include <stdint.h> #include <stdint.h>
#endif #endif
#include "sourcehook_impl.h" #include "sourcehook_impl.h"
#include "sh_tinyhash.h" #include "sh_memory.h"
namespace SourceHook namespace SourceHook
{ {
@ -41,7 +42,6 @@ namespace SourceHook
CSourceHookImpl::CSourceHookImpl() CSourceHookImpl::CSourceHookImpl()
{ {
} }
CSourceHookImpl::~CSourceHookImpl() CSourceHookImpl::~CSourceHookImpl()
{ {
} }
@ -63,23 +63,23 @@ namespace SourceHook
// 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
#define TMP_CHECK_LIST(name) \ #define TMP_CHECK_LIST(name) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \ for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
if (hook_iter->plug == plug) \ if (hook_iter->plug == plug) \
return true; return true;
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter) for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{ {
if (hmil_iter->plug != plug) if (hmil_iter->m_Plug != plug)
continue; continue;
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{ {
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter) iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{ {
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter; List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre); TMP_CHECK_LIST(m_PreHooks);
TMP_CHECK_LIST(hooks_post); TMP_CHECK_LIST(m_PostHooks);
} }
} }
} }
@ -94,21 +94,22 @@ namespace SourceHook
HookManInfoList::iterator hmil_iter; HookManInfoList::iterator hmil_iter;
#define TMP_CHECK_LIST(name, ispost) \ #define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \ for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
if (hook_iter->plug == plug) \ if (hook_iter->plug == plug) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \ hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->func, hook_iter->handler, ispost)) hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter) for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{ {
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{ {
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter) iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{ {
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter; List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre, false); TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(hooks_post, true); TMP_CHECK_LIST(m_PostHooks, true);
} }
} }
} }
@ -126,9 +127,9 @@ namespace SourceHook
for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); for (hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end();
erase ? hmil_iter=m_HookMans.erase(hmil_iter) : ++hmil_iter) erase ? hmil_iter=m_HookMans.erase(hmil_iter) : ++hmil_iter)
{ {
if (hmil_iter->plug == plug) if (hmil_iter->m_Plug == plug)
{ {
if (!hmil_iter->vfnptrs.empty()) if (!hmil_iter->m_VfnPtrs.empty())
{ {
// All hooks by this plugin are already removed // All hooks by this plugin are already removed
// So if there is a vfnptr, it has to be used by an other plugin // So if there is a vfnptr, it has to be used by an other plugin
@ -139,42 +140,42 @@ namespace SourceHook
else else
erase = false; erase = false;
} }
// For each hook manager: // For each hook manager that is used in an other plugin:
for (hmil_iter = tmphookmans.begin(); hmil_iter != tmphookmans.end(); ++hmil_iter) for (hmil_iter = tmphookmans.begin(); hmil_iter != tmphookmans.end(); ++hmil_iter)
{ {
// Find a suitable hook manager in an other plugin // Find a suitable hook manager in an other plugin
HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(), HookManInfoList::iterator newHookMan = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
hmil_iter->proto, hmil_iter->vtbl_offs, hmil_iter->vtbl_idx); hmil_iter->m_Proto, hmil_iter->m_VtblOffs, hmil_iter->m_VtblIdx);
// This should _never_ happen. // This should _never_ happen.
// If there is a hook from an other plugin, the plugin must have provided a hook manager as well. // If there is a hook from an other plugin, the plugin must have provided a hook manager as well.
SH_ASSERT(newHookMan != m_HookMans.end(), SH_ASSERT(newHookMan != m_HookMans.end(),
"Could not find a suitable hook manager in an other plugin!"); ("Could not find a suitable hook manager in an other plugin!"));
// AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo // AddHook should make sure that every plugin only has _one_ hook manager for _one_ proto/vi/vo
SH_ASSERT(newHookMan->plug != plug, "New hook manager from same plugin!"); SH_ASSERT(newHookMan->m_Plug != plug, ("New hook manager from same plugin!"));
// The first hook manager should be always used - so the new hook manager has to be empty // The first hook manager should be always used - so the new hook manager has to be empty
SH_ASSERT(newHookMan->vfnptrs.empty(), "New hook manager not empty!"); SH_ASSERT(newHookMan->m_VfnPtrs.empty(), ("New hook manager not empty!"));
// Move the vfnptrs from the old hook manager to the new one // Move the vfnptrs from the old hook manager to the new one
newHookMan->vfnptrs = hmil_iter->vfnptrs; newHookMan->m_VfnPtrs = hmil_iter->m_VfnPtrs;
// Unregister the old one, register the new one // Unregister the old one, register the new one
hmil_iter->func(HA_Unregister, NULL); hmil_iter->m_Func(HA_Unregister, NULL);
newHookMan->func(HA_Register, &(*newHookMan)); newHookMan->m_Func(HA_Register, &(*newHookMan));
// zOMG BAIL, here is part of what you wanted: // zOMG BAIL, here is part of what you wanted:
// Go through all vfnptrs in this hookman and patch them to point to the new manager's handler! // Go through all vfnptrs in this hookman and patch them to point to the new manager's handler!
// or whatever // or whatever
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = newHookMan->m_VfnPtrs.begin();
vfnptr_iter != newHookMan->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != newHookMan->m_VfnPtrs.end(); ++vfnptr_iter)
{ {
// And DEREFERENCE newHookMan->hookfunc_vfnptr! // And DEREFERENCE newHookMan->m_HookfuncVfnptr!
// otherwise it will be executing the vtable... had to find out the hard way // otherwise it will be executing the vtable... had to find out the hard way
*reinterpret_cast<void**>(vfnptr_iter->vfnptr) = *reinterpret_cast<void**>(newHookMan->hookfunc_vfnptr); *reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = *reinterpret_cast<void**>(newHookMan->m_HookfuncVfnptr);
} }
// That should fix it, bail! // That should fix it, bail!
@ -185,20 +186,20 @@ namespace SourceHook
{ {
List<RemoveHookInfo> hookstoremove; List<RemoveHookInfo> hookstoremove;
#define TMP_CHECK_LIST(name, ispost) \ #define TMP_CHECK_LIST(name, ispost) \
for (hook_iter = iface_iter->name.begin(); hook_iter != iface_iter->name.end(); ++hook_iter) \ for (hook_iter = iface_iter->name.m_List.begin(); hook_iter != iface_iter->name.m_List.end(); ++hook_iter) \
hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->ptr, \ hookstoremove.push_back(RemoveHookInfo(hook_iter->plug, iface_iter->m_Ptr, \
hook_iter->thisptr_offs, hmil_iter->func, hook_iter->handler, ispost)) hook_iter->thisptr_offs, hmil_iter->m_Func, hook_iter->handler, ispost))
for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter) for (HookManInfoList::iterator hmil_iter = m_HookMans.begin(); hmil_iter != m_HookMans.end(); ++hmil_iter)
{ {
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hmil_iter->m_VfnPtrs.begin();
vfnptr_iter != hmil_iter->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != hmil_iter->m_VfnPtrs.end(); ++vfnptr_iter)
{ {
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter) iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{ {
List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hook_iter; List<HookInfo>::iterator hook_iter;
TMP_CHECK_LIST(hooks_pre, false); TMP_CHECK_LIST(m_PreHooks, false);
TMP_CHECK_LIST(hooks_post, true); TMP_CHECK_LIST(m_PostHooks, true);
} }
} }
} }
@ -214,87 +215,84 @@ namespace SourceHook
{ {
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs); void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
// 1) Get info about the hook manager // 1) Get info about the hook manager
HookManagerInfo tmp; CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0) if (myHookMan(HA_GetInfo, &tmp) != 0)
return false; return false;
// 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 // Add the proposed hook manager to the _end_ of the list if the plugin doesn't have a hook manager
// with this proto/vo/vi registered
HookManInfoList::iterator hkmi_iter; HookManInfoList::iterator hkmi_iter;
for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter) for (hkmi_iter = m_HookMans.begin(); hkmi_iter != m_HookMans.end(); ++hkmi_iter)
{ {
if (hkmi_iter->plug == plug && strcmp(hkmi_iter->proto, tmp.proto) == 0 && if (hkmi_iter->m_Plug == plug && strcmp(hkmi_iter->m_Proto, tmp.m_Proto) == 0 &&
hkmi_iter->vtbl_offs == tmp.vtbl_offs && hkmi_iter->vtbl_idx == tmp.vtbl_idx) hkmi_iter->m_VtblOffs == tmp.m_VtblOffs && hkmi_iter->m_VtblIdx == tmp.m_VtblIdx)
break; break;
} }
if (hkmi_iter == m_HookMans.end()) if (hkmi_iter == m_HookMans.end())
{ {
// No such hook manager from this plugin yet, add it! // No such hook manager from this plugin yet, add it!
tmp.func = myHookMan; tmp.m_Func = myHookMan;
tmp.plug = plug; tmp.m_Plug = plug;
m_HookMans.push_back(tmp); m_HookMans.push_back(tmp);
} }
// Then, search for a suitable hook manager (from the beginning) // Then, search for a suitable hook manager (from the beginning)
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx); HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), tmp.m_Proto,
SH_ASSERT(hookman != m_HookMans.end(), "No hookman found - but if there was none, we've just added one!"); tmp.m_VtblOffs, tmp.m_VtblIdx);
SH_ASSERT(hookman != m_HookMans.end(), ("No hookman found - but if there was none, we've just added one!"));
// 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 (hookman->vfnptrs.empty()) if (hookman->m_VfnPtrs.empty())
hookman->func(HA_Register, &(*hookman)); hookman->m_Func(HA_Register, &(*hookman));
void **cur_vtptr = *reinterpret_cast<void***>( void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs); reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx); void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.find(cur_vfnptr); CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->vfnptrs.end()) if (vfnptr_iter == hookman->m_VfnPtrs.end())
{ {
// Add a new one // Add a new one
HookManagerInfo::VfnPtr vfp; CVfnPtr vfp(cur_vfnptr);
vfp.vfnptr = cur_vfnptr;
vfp.orig_entry = *reinterpret_cast<void**>(cur_vfnptr);
// Alter vtable entry // Alter vtable entry
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.vtbl_idx + 1), SH_MEM_READ | SH_MEM_WRITE)) if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
return false; return false;
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->hookfunc_vfnptr);
hookman->vfnptrs.push_back(vfp); *reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->m_HookfuncVfnptr);
hookman->m_VfnPtrs.push_back(vfp);
// Make vfnptr_iter point to the new element // Make vfnptr_iter point to the new element
vfnptr_iter = hookman->vfnptrs.end(); vfnptr_iter = hookman->m_VfnPtrs.end();
--vfnptr_iter; --vfnptr_iter;
// Now that it is done, check whether we have to update any callclasses // Now that it is done, check whether we have to update any callclasses
ApplyCallClassPatches(adjustediface, tmp.vtbl_offs, tmp.vtbl_idx, vfp.orig_entry); ApplyCallClassPatches(adjustediface, tmp.m_VtblOffs, tmp.m_VtblIdx, vfp.m_OrigEntry);
} }
HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.find(adjustediface); CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(adjustediface);
if (iface_iter == vfnptr_iter->ifaces.end()) if (iface_iter == vfnptr_iter->m_Ifaces.end())
{ {
// Add a new one // Add a new one
HookManagerInfo::VfnPtr::Iface ifs; vfnptr_iter->m_Ifaces.push_back(CIface(adjustediface));
ifs.ptr = adjustediface;
vfnptr_iter->ifaces.push_back(ifs);
// Make iface_iter point to the new element // Make iface_iter point to the new element
iface_iter = vfnptr_iter->ifaces.end(); iface_iter = vfnptr_iter->m_Ifaces.end();
--iface_iter; --iface_iter;
} }
// Add the hook // Add the hook
HookManagerInfo::VfnPtr::Iface::Hook hookinfo; HookInfo hookinfo;
hookinfo.handler = handler; hookinfo.handler = handler;
hookinfo.plug = plug; hookinfo.plug = plug;
hookinfo.paused = false; hookinfo.paused = false;
hookinfo.thisptr_offs = thisptr_offs; hookinfo.thisptr_offs = thisptr_offs;
if (post) if (post)
iface_iter->hooks_post.push_back(hookinfo); iface_iter->m_PostHooks.m_List.push_back(hookinfo);
else else
iface_iter->hooks_pre.push_back(hookinfo); iface_iter->m_PreHooks.m_List.push_back(hookinfo);
return true; return true;
} }
@ -307,40 +305,42 @@ namespace SourceHook
bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) bool CSourceHookImpl::RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{ {
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs); void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs);
HookManagerInfo tmp; CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0) if (myHookMan(HA_GetInfo, &tmp) != 0)
return false; return false;
// Find the hook manager and the hook // Find the hook manager and the hook
HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(), HookManInfoList::iterator hookman = FindHookMan(m_HookMans.begin(), m_HookMans.end(),
tmp.proto, tmp.vtbl_offs, tmp.vtbl_idx); tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman == m_HookMans.end()) if (hookman == m_HookMans.end())
return false; return false;
if (IsBadReadPtr(reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs, sizeof(char))) if (!ModuleInMemory(reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs,
sizeof(void*) * (tmp.m_VtblIdx + 1)))
{ {
hookman->vfnptrs.clear(); // The module the vtable was in is already unloaded.
hookman->func(HA_Unregister, NULL); hookman->m_VfnPtrs.clear();
hookman->m_Func(HA_Unregister, NULL);
return true; return true;
} }
void **cur_vtptr = *reinterpret_cast<void***>( void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.vtbl_offs); reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.vtbl_idx); void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.find(cur_vfnptr); CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->vfnptrs.end()) if (vfnptr_iter == hookman->m_VfnPtrs.end())
return false; return false;
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end();) iface_iter != vfnptr_iter->m_Ifaces.end();)
{ {
List<HookManagerInfo::VfnPtr::Iface::Hook> &hooks = List<HookInfo> &hooks =
post ? iface_iter->hooks_post : iface_iter->hooks_pre; post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
bool erase; bool erase;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = hooks.begin(); for (List<HookInfo>::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) &&
@ -348,25 +348,27 @@ namespace SourceHook
if (erase) if (erase)
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
} }
if (iface_iter->hooks_post.empty() && iface_iter->hooks_pre.empty()) if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{ {
iface_iter = vfnptr_iter->ifaces.erase(iface_iter); // There are no hooks on this iface anymore...
if (vfnptr_iter->ifaces.empty())
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
{ {
// Deactivate the hook // No ifaces at all -> Deactivate the hook
*reinterpret_cast<void**>(vfnptr_iter->vfnptr) = vfnptr_iter->orig_entry; *reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = vfnptr_iter->m_OrigEntry;
hookman->vfnptrs.erase(vfnptr_iter); hookman->m_VfnPtrs.erase(vfnptr_iter);
// Remove callclass patch // Remove callclass patch
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter) for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
if (cciter->cc.ptr == adjustediface) if (cciter->m_Ptr == adjustediface)
RemoveCallClassPatch(*cciter, tmp.vtbl_offs, tmp.vtbl_idx); cciter->RemoveCallClassPatch(tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman->vfnptrs.empty()) if (hookman->m_VfnPtrs.empty())
{ {
// Unregister the hook manager // Unregister the hook manager
hookman->func(HA_Unregister, NULL); hookman->m_Func(HA_Unregister, NULL);
} }
// Don't try to continue looping through ifaces // Don't try to continue looping through ifaces
@ -384,22 +386,19 @@ namespace SourceHook
{ {
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter) for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
{ {
if (cciter->cc.ptr == iface && cciter->cc.objsize == size) if (cciter->m_Ptr == iface && cciter->m_ObjSize == size)
{ {
++cciter->refcounter; ++cciter->m_RefCounter;
return &cciter->cc; return &(*cciter);
} }
} }
CallClassInfo tmp; // Make a new one
tmp.refcounter = 1;
tmp.cc.ptr = iface;
tmp.cc.objsize = size;
CCallClassImpl tmp(iface, size);
ApplyCallClassPatches(tmp); ApplyCallClassPatches(tmp);
m_CallClasses.push_back(tmp); m_CallClasses.push_back(tmp);
return &m_CallClasses.back().cc; return &m_CallClasses.back();
} }
void CSourceHookImpl::ReleaseCallClass(GenericCallClass *ptr) void CSourceHookImpl::ReleaseCallClass(GenericCallClass *ptr)
@ -407,35 +406,27 @@ namespace SourceHook
Impl_CallClassList::iterator iter = m_CallClasses.find(ptr); Impl_CallClassList::iterator iter = m_CallClasses.find(ptr);
if (iter == m_CallClasses.end()) if (iter == m_CallClasses.end())
return; return;
--iter->refcounter; --iter->m_RefCounter;
if (iter->refcounter < 1) if (iter->m_RefCounter < 1)
m_CallClasses.erase(iter); m_CallClasses.erase(iter);
} }
void CSourceHookImpl::ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry) void CSourceHookImpl::ApplyCallClassPatches(CCallClassImpl &cc)
{
OrigFuncs &tmpvec = cc.cc.vt[vtbl_offs];
if (tmpvec.size() <= (size_t)vtbl_idx)
tmpvec.resize(vtbl_idx+1);
tmpvec[vtbl_idx] = orig_entry;
}
void CSourceHookImpl::ApplyCallClassPatches(CallClassInfo &cc)
{ {
for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman) for (HookManInfoList::iterator hookman = m_HookMans.begin(); hookman != m_HookMans.end(); ++hookman)
{ {
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.begin();
vfnptr_iter != hookman->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != hookman->m_VfnPtrs.end(); ++vfnptr_iter)
{ {
for (HookManagerInfo::VfnPtr::IfaceListIter iface_iter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->ifaces.end(); ++iface_iter) iface_iter != vfnptr_iter->m_Ifaces.end(); ++iface_iter)
{ {
if (iface_iter->ptr >= cc.cc.ptr && if (iface_iter->m_Ptr >= cc.m_Ptr &&
iface_iter->ptr < (reinterpret_cast<char*>(cc.cc.ptr) + cc.cc.objsize)) iface_iter->m_Ptr < (reinterpret_cast<char*>(cc.m_Ptr) + cc.m_ObjSize))
{ {
ApplyCallClassPatch(cc, static_cast<int>(reinterpret_cast<char*>(iface_iter->ptr) - cc.ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(iface_iter->m_Ptr) -
reinterpret_cast<char*>(cc.cc.ptr)) + hookman->vtbl_offs, reinterpret_cast<char*>(cc.m_Ptr)) + hookman->m_VtblOffs,
hookman->vtbl_idx, vfnptr_iter->orig_entry); hookman->m_VtblIdx, vfnptr_iter->m_OrigEntry);
} }
} }
} }
@ -447,11 +438,11 @@ namespace SourceHook
for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end(); for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end();
++cc_iter) ++cc_iter)
{ {
if (ifaceptr >= cc_iter->cc.ptr && if (ifaceptr >= cc_iter->m_Ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->cc.ptr) + cc_iter->cc.objsize)) ifaceptr < (reinterpret_cast<char*>(cc_iter->m_Ptr) + cc_iter->m_ObjSize))
{ {
ApplyCallClassPatch(*cc_iter, static_cast<int>(reinterpret_cast<char*>(ifaceptr) - cc_iter->ApplyCallClassPatch(static_cast<int>(reinterpret_cast<char*>(ifaceptr) -
reinterpret_cast<char*>(cc_iter->cc.ptr)) + vtbl_offs, vtbl_idx, orig_entry); reinterpret_cast<char*>(cc_iter->m_Ptr)) + vtbl_offs, vtbl_idx, orig_entry);
} }
} }
} }
@ -461,34 +452,10 @@ namespace SourceHook
for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end(); for (Impl_CallClassList::iterator cc_iter = m_CallClasses.begin(); cc_iter != m_CallClasses.end();
++cc_iter) ++cc_iter)
{ {
if (ifaceptr >= cc_iter->cc.ptr && if (ifaceptr >= cc_iter->m_Ptr &&
ifaceptr < (reinterpret_cast<char*>(cc_iter->cc.ptr) + cc_iter->cc.objsize)) ifaceptr < (reinterpret_cast<char*>(cc_iter->m_Ptr) + cc_iter->m_ObjSize))
{ {
RemoveCallClassPatch(*cc_iter, vtbl_offs, vtbl_idx); cc_iter->RemoveCallClassPatch(vtbl_offs, vtbl_idx);
}
}
}
void CSourceHookImpl::RemoveCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx)
{
OrigVTables::iterator iter = cc.cc.vt.find(vtbl_offs);
if (iter != cc.cc.vt.end())
{
if (iter->val.size() > (size_t)vtbl_idx)
{
iter->val[vtbl_idx] = 0;
// Free some memory if possible
// :TODO: add this back in!
/*
OrigFuncs::reverse_iterator riter;
for (riter = iter->second.rbegin(); riter != iter->second.rend(); ++riter)
{
if (*riter != 0)
break;
}
iter->second.resize(iter->second.size() - (riter - iter->second.rbegin()));
if (!iter->second.size())
cc.cc.vt.erase(iter);*/
} }
} }
} }
@ -496,56 +463,44 @@ namespace SourceHook
CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin, CSourceHookImpl::HookManInfoList::iterator CSourceHookImpl::FindHookMan(HookManInfoList::iterator begin,
HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx) HookManInfoList::iterator end, const char *proto, int vtblofs, int vtblidx)
{ {
HookManInfoList::iterator hookmaniter; HookManInfoList::iterator hookmaniter;
for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter) for (hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
{ {
if (strcmp(hookmaniter->proto, proto) == 0 && hookmaniter->vtbl_offs == vtblofs && if (strcmp(hookmaniter->m_Proto, proto) == 0 && hookmaniter->m_VtblOffs == vtblofs &&
hookmaniter->vtbl_idx == vtblidx) hookmaniter->m_VtblIdx == vtblidx)
break; break;
} }
return hookmaniter; return hookmaniter;
} }
void CSourceHookImpl::PausePlugin(Plugin plug) void CSourceHookImpl::SetPluginPaused(Plugin plug, bool paused)
{ {
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused // Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter) for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin(); for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin();
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter) vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter)
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin(); for (CVfnPtr::IfaceListIter ifaceiter = vfnptr_iter->m_Ifaces.begin();
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter) ifaceiter != vfnptr_iter->m_Ifaces.end(); ++ifaceiter)
{ {
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin(); for (List<HookInfo>::iterator hookiter = ifaceiter->m_PreHooks.m_List.begin();
hookiter != ifaceiter->hooks_pre.end(); ++hookiter) hookiter != ifaceiter->m_PreHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug) if (plug == hookiter->plug)
hookiter->paused = true; hookiter->paused = paused;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin(); for (List<HookInfo>::iterator hookiter = ifaceiter->m_PostHooks.m_List.begin();
hookiter != ifaceiter->hooks_post.end(); ++hookiter) hookiter != ifaceiter->m_PostHooks.m_List.end(); ++hookiter)
if (plug == hookiter->plug) if (plug == hookiter->plug)
hookiter->paused = true; hookiter->paused = paused;
} }
} }
void CSourceHookImpl::PausePlugin(Plugin plug)
{
SetPluginPaused(plug, true);
}
void CSourceHookImpl::UnpausePlugin(Plugin plug) void CSourceHookImpl::UnpausePlugin(Plugin plug)
{ {
// Go through all hook managers, all interfaces, and set the status of all hooks of this plugin to paused SetPluginPaused(plug, false);
for (HookManInfoList::iterator hookmaniter = m_HookMans.begin(); hookmaniter != m_HookMans.end(); ++hookmaniter)
for (HookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->vfnptrs.begin();
vfnptr_iter != hookmaniter->vfnptrs.end(); ++vfnptr_iter)
for (HookManagerInfo::VfnPtr::IfaceListIter ifaceiter = vfnptr_iter->ifaces.begin();
ifaceiter != vfnptr_iter->ifaces.end(); ++ifaceiter)
{
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_pre.begin();
hookiter != ifaceiter->hooks_pre.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = false;
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hookiter = ifaceiter->hooks_post.begin();
hookiter != ifaceiter->hooks_post.end(); ++hookiter)
if (plug == hookiter->plug)
hookiter->paused = false;
}
} }
void CSourceHookImpl::SetRes(META_RES res) void CSourceHookImpl::SetRes(META_RES res)
@ -608,38 +563,212 @@ namespace SourceHook
return m_IfacePtr; return m_IfacePtr;
} }
#ifdef __linux__ ////////////////////////////
bool g_BadReadCalled; // CCallClassImpl
jmp_buf g_BadReadJmpBuf; ////////////////////////////
CSourceHookImpl::CCallClassImpl::CCallClassImpl(void *ptr, size_t size)
// Windows has an implementation for this already, but Linux does not :( : m_Ptr(ptr), m_ObjSize(size), m_RefCounter(1)
bool IsBadReadPtr(const void *ptr, size_t len) {
}
CSourceHookImpl::CCallClassImpl::~CCallClassImpl()
{ {
void(*prevHandler)(int sig);
g_BadReadCalled = true;
if (setjmp(g_BadReadJmpBuf))
return true;
prevHandler = signal(SIGSEGV, BadReadHandler);
volatile const char *p = reinterpret_cast<const char*>(ptr);
char dummy;
for (size_t i = 0; i < len; i++)
dummy = p[i];
g_BadReadCalled = false;
signal(SIGSEGV, prevHandler);
return false;
} }
void BadReadHandler(int sig) void *CSourceHookImpl::CCallClassImpl::GetThisPtr()
{ {
if (g_BadReadCalled) return m_Ptr;
longjmp(g_BadReadJmpBuf, 1); }
void *CSourceHookImpl::CCallClassImpl::GetOrigFunc(int vtbloffs, int vtblidx)
{
OrigVTables::iterator iter = m_VT.find(vtbloffs);
if (iter != m_VT.end() && iter->val.size() > (size_t)vtblidx)
{
return iter->val[vtblidx];
}
return NULL;
}
void CSourceHookImpl::CCallClassImpl::ApplyCallClassPatch(int vtbl_offs, int vtbl_idx, void *orig_entry)
{
OrigFuncs &tmpvec = m_VT[vtbl_offs];
if (tmpvec.size() <= (size_t)vtbl_idx)
tmpvec.resize(vtbl_idx+1);
tmpvec[vtbl_idx] = orig_entry;
}
void CSourceHookImpl::CCallClassImpl::RemoveCallClassPatch(int vtbl_offs, int vtbl_idx)
{
OrigVTables::iterator iter = m_VT.find(vtbl_offs);
if (iter != m_VT.end())
{
if (iter->val.size() > (size_t)vtbl_idx)
{
iter->val[vtbl_idx] = 0;
OrigFuncs &of = iter->val;
OrigFuncs::iterator lastused = of.end();
for (OrigFuncs::iterator viter = of.begin(); viter != of.end(); ++viter)
{
if (*viter)
lastused = viter;
}
if (lastused == of.end())
{
// No used element => Remove the whole vector
m_VT.erase(iter);
return;
}
of.resize(lastused - of.begin() + 1);
}
}
}
////////////////////////////
// CHookManagerInfo
////////////////////////////
CSourceHookImpl::CHookManagerInfo::~CHookManagerInfo()
{
}
IVfnPtr *CSourceHookImpl::CHookManagerInfo::FindVfnPtr(void *vfnptr)
{
VfnPtrListIter iter = m_VfnPtrs.find(vfnptr);
return iter == m_VfnPtrs.end() ? NULL : &(*iter);
}
void CSourceHookImpl::CHookManagerInfo::SetInfo(int vtbl_offs, int vtbl_idx, const char *proto)
{
m_VtblOffs = vtbl_offs;
m_VtblIdx = vtbl_idx;
m_Proto = proto;
}
void CSourceHookImpl::CHookManagerInfo::SetHookfuncVfnptr(void *hookfunc_vfnptr)
{
m_HookfuncVfnptr = hookfunc_vfnptr;
}
////////////////////////////
// CVfnPtr
////////////////////////////
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr) : m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(ptr))
{
}
CSourceHookImpl::CVfnPtr::~CVfnPtr()
{
}
void *CSourceHookImpl::CVfnPtr::GetVfnPtr()
{
return m_Ptr;
}
void *CSourceHookImpl::CVfnPtr::GetOrigEntry()
{
return m_OrigEntry;
}
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
{
IfaceListIter iter = m_Ifaces.find(ptr);
return iter == m_Ifaces.end() ? NULL : &(*iter);
}
////////////////////////////
// CIface
////////////////////////////
CSourceHookImpl::CIface::CIface(void *ptr) : m_Ptr(ptr)
{
}
CSourceHookImpl::CIface::~CIface()
{
}
void *CSourceHookImpl::CIface::GetPtr()
{
return m_Ptr;
}
IHookList *CSourceHookImpl::CIface::GetPreHooks()
{
return &m_PreHooks;
}
IHookList *CSourceHookImpl::CIface::GetPostHooks()
{
return &m_PostHooks;
}
////////////////////////////
// CHookList
////////////////////////////
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL)
{
}
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List), m_FreeIters(NULL)
{
}
CSourceHookImpl::CHookList::~CHookList()
{
while (m_FreeIters)
{
CIter *iter = m_FreeIters->m_pNext;
delete m_FreeIters;
m_FreeIters = iter;
}
}
IHookList::IIter *CSourceHookImpl::CHookList::GetIter()
{
if (m_FreeIters)
{
CIter *ret = m_FreeIters;
m_FreeIters = ret->m_pNext;
ret->GoToBegin();
return ret;
}
return new CIter(this);
}
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
{
CIter *pIter2 = static_cast<CIter*>(pIter);
pIter2->m_pNext = m_FreeIters;
m_FreeIters = pIter2;
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList), m_pNext(NULL)
{
GoToBegin();
}
CSourceHookImpl::CHookList::CIter::~CIter()
{
}
void CSourceHookImpl::CHookList::CIter::GoToBegin()
{
m_Iter = m_pList->m_List.begin();
SkipPaused();
}
bool CSourceHookImpl::CHookList::CIter::End()
{
return m_Iter == m_pList->m_List.end();
}
void CSourceHookImpl::CHookList::CIter::Next()
{
++m_Iter;
SkipPaused();
}
void CSourceHookImpl::CHookList::CIter::SkipPaused()
{
while (m_Iter != m_pList->m_List.end() && m_Iter->paused)
++m_Iter;
}
ISHDelegate *CSourceHookImpl::CHookList::CIter::Handler()
{
return m_Iter->handler;
}
int CSourceHookImpl::CHookList::CIter::ThisPtrOffs()
{
return m_Iter->thisptr_offs;
} }
#endif
} }

View File

@ -16,8 +16,8 @@
#ifndef __SOURCEHOOK_H__ #ifndef __SOURCEHOOK_H__
#define __SOURCEHOOK_H__ #define __SOURCEHOOK_H__
#define SH_IFACE_VERSION 1 #define SH_IFACE_VERSION 2
#define SH_IMPL_VERSION 1 #define SH_IMPL_VERSION 2
#ifndef SH_GLOB_SHPTR #ifndef SH_GLOB_SHPTR
#define SH_GLOB_SHPTR g_SHPtr #define SH_GLOB_SHPTR g_SHPtr
@ -27,13 +27,21 @@
#define SH_GLOB_PLUGPTR g_PLID #define SH_GLOB_PLUGPTR g_PLID
#endif #endif
#ifdef SH_DEBUG #ifdef SH_DEBUG
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# define SH_ASSERT__(x, info, file, line, func) \
((printf("SOURCEHOOK DEBUG ASSERTION FAILED:\n %s:%u(%s): %s\n", file, line, func, info), true) ? (abort(), 0) : 0) # define SH_ASSERT(x, info) \
# define SH_ASSERT(x, info) if (!(x)) SH_ASSERT__(x, info, __FILE__, __LINE__, __FUNCTION__) do { \
if (!(x)) \
{ \
printf("SOURCEHOOK DEBUG ASSERTION FAILED: %s:%u(%s): %s: ", __FILE__, __LINE__, __FUNCTION__, #x); \
printf info; \
putchar('\n'); \
abort(); \
} \
} while(0)
#else #else
# define SH_ASSERT(x, info) # define SH_ASSERT(x, info)
#endif #endif
@ -67,13 +75,9 @@
#endif #endif
#define SH_PTRSIZE sizeof(void*) #define SH_PTRSIZE sizeof(void*)
#include "FastDelegate.h" #include "FastDelegate.h"
#include "sh_memfuncinfo.h" #include "sh_memfuncinfo.h"
#include "sh_memory.h"
#include "sh_list.h"
#include "sh_vector.h"
#include "sh_tinyhash.h"
// Good old metamod! // Good old metamod!
@ -90,10 +94,13 @@ enum META_RES
namespace SourceHook namespace SourceHook
{ {
const int STRBUF_LEN=4096; // In bytes, for "vafmt" functions
/** /**
* @brief An empty class. No inheritance used. Used for original-function-call hacks * @brief Specifies the size (in bytes) for the internal buffer of vafmt(printf-like) function handlers
*/
const int STRBUF_LEN=4096;
/**
* @brief An empty class. No inheritance used. Used for original-function-call hacks
*/ */
class EmptyClass class EmptyClass
{ {
@ -111,29 +118,33 @@ namespace SourceHook
/** /**
* @brief A plugin typedef * @brief A plugin typedef
* *
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it * SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it and every
* and every plugin has a unique identifier, everything is ok. * plugin has a unique identifier, everything is ok.
* It should also be possible to set it to 0.
*/ */
typedef int Plugin; typedef int Plugin;
/**
* @brief Specifies the actions for hook managers
*/
enum HookManagerAction enum HookManagerAction
{ {
HA_GetInfo = 0, // -> Only store info HA_GetInfo = 0, //!< Store info about the hook manager
HA_Register, // -> Save the pointer for future reference HA_Register, //!< Save the IHookManagerInfo pointer for future reference
HA_Unregister // -> Clear the saved pointer HA_Unregister //!< Clear the saved pointer
}; };
struct HookManagerInfo; class IHookManagerInfo;
/** /**
* @brief Pointer to hook manager type * @brief Pointer to hook manager interface function
* *
* A "hook manager" 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 HookManagerInfo structure. The hook manager should fill it and store it for * @param ha What the hook manager should do
* future reference (mainly if something should get hooked to its hookfunc) * @param hi A pointer to IHookManagerInfo
*/ */
typedef int (*HookManagerPubFunc)(HookManagerAction ha, HookManagerInfo *hi); typedef int (*HookManagerPubFunc)(HookManagerAction ha, IHookManagerInfo *hi);
class ISHDelegate class ISHDelegate
{ {
@ -161,7 +172,7 @@ namespace SourceHook
bool IsEqual(ISHDelegate *other) bool IsEqual(ISHDelegate *other)
{ {
return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg(); return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg();
} }
T &GetDeleg() T &GetDeleg()
@ -170,65 +181,83 @@ namespace SourceHook
} }
}; };
/** struct IHookList
* @brief This structure contains information about a hook manager (hook manager)
*/
struct HookManagerInfo
{ {
struct VfnPtr struct IIter
{ {
struct Iface virtual bool End() = 0;
{ virtual void Next() = 0;
struct Hook virtual ISHDelegate *Handler() = 0;
{ virtual int ThisPtrOffs() = 0;
ISHDelegate *handler; //!< Pointer to the handler
bool paused; //!< If true, the hook should not be executed
Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
void *ptr; //!< Pointer to the interface instance
List<Hook> hooks_pre; //!< A list of pre-hooks
List<Hook> hooks_post; //!< A list of post-hooks
bool operator ==(void *other) const
{
return ptr == other;
}
};
void *vfnptr; //!< Pointer to the function
void *orig_entry; //!< The original vtable entry
typedef List<Iface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
IfaceList ifaces; //!< List of interface pointers
bool operator ==(void *other)
{
return vfnptr == other;
}
}; };
virtual IIter *GetIter() = 0;
Plugin plug; //!< The owner plugin virtual void ReleaseIter(IIter *pIter) = 0;
const char *proto; //!< The prototype of the function the hook manager is responsible for
int vtbl_idx; //!< The vtable index
int vtbl_offs; //!< The vtable offset
HookManagerPubFunc func; //!< The interface to the hook manager
void *hookfunc_vfnptr; //!< Pointer to the hookfunc impl
typedef List<VfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
VfnPtrList vfnptrs; //!< List of hooked interfaces
}; };
typedef SourceHook::CVector<void*> OrigFuncs; struct IIface
typedef SourceHook::THash<int, OrigFuncs> OrigVTables; {
virtual void *GetPtr() = 0;
virtual IHookList *GetPreHooks() = 0;
virtual IHookList *GetPostHooks() = 0;
};
struct IVfnPtr
{
virtual void *GetVfnPtr() = 0;
virtual void *GetOrigEntry() = 0;
virtual IIface *FindIface(void *ptr) = 0;
};
struct IHookManagerInfo
{
virtual IVfnPtr *FindVfnPtr(void *vfnptr) = 0;
virtual void SetInfo(int vtbloffs, int vtblidx, const char *proto) = 0;
virtual void SetHookfuncVfnptr(void *hookfunc_vfnptr) = 0;
};
class AutoHookIter
{
IHookList *m_pList;
IHookList::IIter *m_pIter;
public:
AutoHookIter(IHookList *pList)
: m_pList(pList), m_pIter(pList->GetIter())
{
}
~AutoHookIter()
{
m_pList->ReleaseIter(m_pIter);
}
bool End()
{
return m_pIter->End();
}
void Next()
{
m_pIter->Next();
}
ISHDelegate *Handler()
{
return m_pIter->Handler();
}
int ThisPtrOffs()
{
return m_pIter->ThisPtrOffs();
}
};
template<class B> struct CallClass template<class B> struct CallClass
{ {
B *ptr; //!< Pointer to the actual object virtual B *GetThisPtr() = 0;
size_t objsize; //!< Size of the instance virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
OrigVTables vt; //!< Info about vtables & functions
}; };
typedef CallClass<void> GenericCallClass; typedef CallClass<void> GenericCallClass;
@ -239,8 +268,6 @@ namespace SourceHook
class ISourceHook class ISourceHook
{ {
public: public:
virtual ~ISourceHook()
{ }
/** /**
* @brief Return interface version * @brief Return interface version
*/ */
@ -263,7 +290,8 @@ namespace SourceHook
* @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 thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Removes a hook. * @brief Removes a hook.
@ -276,7 +304,8 @@ namespace SourceHook
* @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, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post) = 0; virtual bool RemoveHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/** /**
* @brief Checks whether a plugin has (a) hook manager(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
@ -301,10 +330,13 @@ namespace SourceHook
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0; virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void SetRes(META_RES res) = 0; //!< Sets the meta result virtual void SetRes(META_RES res) = 0; //!< Sets the meta result
virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the previously called handler virtual META_RES GetPrevRes() = 0; //!< Gets the meta result of the
//!< previously calledhandler
virtual META_RES GetStatus() = 0; //!< Gets the highest meta result virtual META_RES GetStatus() = 0; //!< Gets the highest meta result
virtual const void *GetOrigRet() = 0; //!< Gets the original result. If not in post function, undefined virtual const void *GetOrigRet() = 0; //!< Gets the original result.
virtual const void *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL //!< If not in post function, undefined
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 hook managers // For hook managers
@ -375,10 +407,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry();
#elif SH_COMP == SH_COMP_GCC #elif SH_COMP == SH_COMP_GCC
# define SH_SETUP_MFP(mfp) \ # define SH_SETUP_MFP(mfp) \
reinterpret_cast<void**>(&mfp)[0] = vfnptr.orig_entry; \ reinterpret_cast<void**>(&mfp)[0] = vfnptr->GetOrigEntry(); \
reinterpret_cast<void**>(&mfp)[1] = 0; reinterpret_cast<void**>(&mfp)[1] = 0;
#else #else
# error Not supported yet. # error Not supported yet.
@ -388,24 +420,27 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov #define SH_FHCls(ift, iff, ov) __SourceHook_FHCls_##ift##iff##ov
#define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \ #define SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::HookManagerInfo *param) \ SH_FHCls(ifacetype,ifacefunc,overload)() \
{ \
GetFuncInfo(funcptr, ms_MFI); \
} \
\
static int HookManPubFunc(::SourceHook::HookManagerAction action, ::SourceHook::IHookManagerInfo *param) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
GetFuncInfo(funcptr, ms_MFI); \
/* Verify interface version */ \ /* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \ if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \ return 1; \
\ \
if (action == ::SourceHook::HA_GetInfo) \ if (action == ::SourceHook::HA_GetInfo) \
{ \ { \
param->proto = ms_Proto; \ param->SetInfo(ms_MFI.vtbloffs, ms_MFI.vtblindex, ms_Proto); \
MemFuncInfo mfi; \
GetFuncInfo(funcptr, mfi); \
param->vtbl_idx = mfi.vtblindex; \
param->vtbl_offs = mfi.vtbloffs; \
\ \
MemFuncInfo mfi; \
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \ GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
param->hookfunc_vfnptr = \ param->SetHookfuncVfnptr( \
reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]; \ reinterpret_cast<void**>(reinterpret_cast<char*>(&ms_Inst) + mfi.vtbloffs)[mfi.vtblindex]); \
return 0; \ return 0; \
} \ } \
else if (action == ::SourceHook::HA_Register) \ else if (action == ::SourceHook::HA_Register) \
@ -429,15 +464,17 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
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 ::SourceHook::HookManagerInfo *ms_HI; \ static ::SourceHook::MemFuncInfo ms_MFI; \
static ::SourceHook::IHookManagerInfo *ms_HI; \
static const char *ms_Proto; \ static const char *ms_Proto; \
SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr) SHINT_MAKE_HOOKMANPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \ #define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto, funcptr) \
}; \ }; \
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; \
::SourceHook::HookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \ ::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \ bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \ SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \ { \
@ -469,28 +506,22 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ return (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
rettype orig_ret; \ rettype orig_ret; \
rettype override_ret; \ rettype override_ret; \
rettype plugin_ret; \ rettype plugin_ret; \
@ -504,12 +535,11 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#define SH_CALL_HOOKS(post, params) \ #define SH_CALL_HOOKS(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -525,7 +555,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
rettype (EmptyClass::*mfp)paramtypes; \ rettype (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
orig_ret = (reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ orig_ret = (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} \ } \
else \ else \
orig_ret = override_ret; orig_ret = override_ret;
@ -542,21 +572,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define SH_SETUPCALLS_void(paramtypes, params) \ #define SH_SETUPCALLS_void(paramtypes, params) \
using namespace ::SourceHook; \
/* 1) Find the vfnptr */ \ /* 1) Find the vfnptr */ \
using namespace ::SourceHook; \
void *ourvfnptr = reinterpret_cast<void*>( \ void *ourvfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_HI->vtbl_offs) + ms_HI->vtbl_idx); \ *reinterpret_cast<void***>(reinterpret_cast<char*>(this) + ms_MFI.vtbloffs) + ms_MFI.vtblindex); \
IVfnPtr *vfnptr = ms_HI->FindVfnPtr(ourvfnptr); \
SH_ASSERT(vfnptr, ("Called with vfnptr 0x%p which couldn't be found in the list", ourvfnptr)); \
\ \
HookManagerInfo::VfnPtrListIter vfptriter = ms_HI->vfnptrs.find(ourvfnptr); \ /* ... and the iface */ \
if (vfptriter == ms_HI->vfnptrs.end()) \ IIface *ifinfo = vfnptr->FindIface(reinterpret_cast<void*>(this)); \
{ \ if (!ifinfo) \
/* Bleh? Should be impossible! */ \
SH_ASSERT(0, "Called with vfnptr 0x%p which couldn't be found in the list"); \
} \
HookManagerInfo::VfnPtr &vfnptr = *vfptriter; \
/* 2) Find the iface */ \
HookManagerInfo::VfnPtr::IfaceListIter ifiter = vfnptr.ifaces.find(this); \
if (ifiter == vfnptr.ifaces.end()) \
{ \ { \
/* The iface info was not found. Redirect the call to the original function. */ \ /* The iface info was not found. Redirect the call to the original function. */ \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
@ -564,25 +589,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
(reinterpret_cast<EmptyClass*>(this)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(this)->*mfp)params; \
return; \ return; \
} \ } \
HookManagerInfo::VfnPtr::Iface &ci = *ifiter; \
/* 2) Declare some vars and set it up */ \ /* 2) Declare some vars and set it up */ \
List<HookManagerInfo::VfnPtr::Iface::Hook> &prelist = ci.hooks_pre; \ IHookList *prelist = ifinfo->GetPreHooks(); \
List<HookManagerInfo::VfnPtr::Iface::Hook> &postlist = ci.hooks_post; \ IHookList *postlist = ifinfo->GetPostHooks(); \
META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \ META_RES &cur_res = SH_GLOB_SHPTR->GetCurResRef(); \
META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \ META_RES &prev_res = SH_GLOB_SHPTR->GetPrevResRef(); \
META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \ META_RES &status = SH_GLOB_SHPTR->GetStatusRef(); \
void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \ void* &ifptr = SH_GLOB_SHPTR->GetIfacePtrRef(); \
status = MRES_IGNORED; \ status = MRES_IGNORED; \
SH_GLOB_SHPTR->SetOverrideRet(NULL); SH_GLOB_SHPTR->SetOverrideRet(NULL); \
SH_GLOB_SHPTR->SetOrigRet(NULL);
#define SH_CALL_HOOKS_void(post, params) \ #define SH_CALL_HOOKS_void(post, params) \
prev_res = MRES_IGNORED; \ prev_res = MRES_IGNORED; \
for (List<HookManagerInfo::VfnPtr::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \ for (AutoHookIter iter(post##list); !iter.End(); iter.Next()) \
{ \ { \
if (hiter->paused) continue; \
cur_res = MRES_IGNORED; \ cur_res = MRES_IGNORED; \
ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - hiter->thisptr_offs); \ ifptr = reinterpret_cast<void*>(reinterpret_cast<char*>(this) - iter.ThisPtrOffs()); \
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \ reinterpret_cast<CSHDelegate<FD>*>(iter.Handler())->GetDeleg() params; \
prev_res = cur_res; \ prev_res = cur_res; \
if (cur_res > status) \ if (cur_res > status) \
status = cur_res; \ status = cur_res; \
@ -593,7 +617,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
void (EmptyClass::*mfp)paramtypes; \ void (EmptyClass::*mfp)paramtypes; \
SH_SETUP_MFP(mfp); \ SH_SETUP_MFP(mfp); \
(reinterpret_cast<EmptyClass*>(ci.ptr)->*mfp)params; \ (reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)params; \
} }
#define SH_RETURN_void() #define SH_RETURN_void()
@ -1490,6 +1514,210 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \ SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc))) (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 17 arguments *********
#define SH_DECL_HOOK17(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate17<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK17_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 18 arguments *********
#define SH_DECL_HOOK18(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate18<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK18_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 19 arguments *********
#define SH_DECL_HOOK19(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate19<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK19_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, const char *, ...) attr>(&ifacetype::ifacefunc)))
// ********* Support for 20 arguments *********
#define SH_DECL_HOOK20(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), rettype); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate20<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20) \
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20)); } \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20, \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_vafmt(ifacetype, ifacefunc, attr, overload, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, rettype> FD; \
virtual rettype Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf), rettype); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<rettype (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
#define SH_DECL_HOOK20_void_vafmt(ifacetype, ifacefunc, attr, overload, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) \
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr> \
(&ifacetype::ifacefunc))) \
typedef fastdelegate::FastDelegate21<param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *> FD; \
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, param7 p7, param8 p8, param9 p9, param10 p10, param11 p11, param12 p12, param13 p13, param14 p14, param15 p15, param16 p16, param17 p17, param18 p18, param19 p19, param20 p20, const char *fmt, ...) \
{ \
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
va_end(ap); \
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, ...), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, "%s", buf), (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, buf)); \
} \
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #param1 "|" #param2 "|" #param3 "|" #param4 "|" #param5 "|" #param6 "|" #param7 "|" #param8 "|" #param9 "|" #param10 "|" #param11 "|" #param12 "|" #param13 "|" #param14 "|" #param15 "|" #param16 "|" #param17 "|" #param18 "|" #param19 "|" #param20 "|const char*|...", \
(static_cast<void (ifacetype::*)(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20, const char *, ...) attr>(&ifacetype::ifacefunc)))
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1497,14 +1725,16 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
#if SH_COMP == SH_COMP_MSVC #if SH_COMP == SH_COMP_MSVC
// :TODO: TEST THIS ON MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \ # define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -1512,9 +1742,9 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
RetType(EmptyClass::*mfpnew)prms; \ RetType(EmptyClass::*mfpnew)prms; \
void *addr; \ void *addr; \
} u; \ } u; \
u.addr = iter->val[mfi.vtblindex]; \ u.addr = origfunc; \
\ \
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->ptr) + mfi.thisptroffs); \ void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
} }
@ -1524,10 +1754,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
{ \ { \
using namespace ::SourceHook; \ using namespace ::SourceHook; \
MemFuncInfo mfi; \ MemFuncInfo mfi; \
GetFuncInfo(m_CC->ptr, m_MFP, mfi); \ GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
OrigVTables::iterator iter = m_CC->vt.find(mfi.thisptroffs + mfi.vtbloffs); \ void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (iter == m_CC->vt.end() || mfi.vtblindex >= (int)iter->val.size() || iter->val[mfi.vtblindex] == NULL) \ if (!origfunc) \
return (m_CC->ptr->*m_MFP)call; \ return (m_CC->GetThisPtr()->*m_MFP)call; \
\ \
/* It's hooked. Call the original function. */ \ /* It's hooked. Call the original function. */ \
union \ union \
@ -1539,10 +1769,10 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
intptr_t adjustor; \ intptr_t adjustor; \
} s; \ } s; \
} u; \ } u; \
u.s.addr = iter->val[mfi.vtblindex]; \ u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \ u.s.adjustor = mfi.thisptroffs; \
\ \
return (reinterpret_cast<EmptyClass*>(m_CC->ptr)->*u.mfpnew)call; \ return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
} }
#endif #endif
@ -1559,73 +1789,89 @@ namespace SourceHook
} }
// Support for 0 arguments // Support for 0 arguments
RetType operator()() const RetType operator()() const
SH_MAKE_EXECUTABLECLASS_OB((), ()) SH_MAKE_EXECUTABLECLASS_OB((), ())
// Support for 1 arguments // Support for 1 arguments
template<class Param1> RetType operator()(Param1 p1) const template<class Param1> RetType operator()(Param1 p1) const
SH_MAKE_EXECUTABLECLASS_OB((p1), (Param1)) SH_MAKE_EXECUTABLECLASS_OB((p1), (Param1))
// Support for 2 arguments // Support for 2 arguments
template<class Param1, class Param2> RetType operator()(Param1 p1, Param2 p2) const template<class Param1, class Param2> RetType operator()(Param1 p1, Param2 p2) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2), (Param1, Param2)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2), (Param1, Param2))
// Support for 3 arguments // Support for 3 arguments
template<class Param1, class Param2, class Param3> RetType operator()(Param1 p1, Param2 p2, Param3 p3) const template<class Param1, class Param2, class Param3> RetType operator()(Param1 p1, Param2 p2, Param3 p3) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3), (Param1, Param2, Param3)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3), (Param1, Param2, Param3))
// Support for 4 arguments // Support for 4 arguments
template<class Param1, class Param2, class Param3, class Param4> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const template<class Param1, class Param2, class Param3, class Param4> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4), (Param1, Param2, Param3, Param4)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4), (Param1, Param2, Param3, Param4))
// Support for 5 arguments // Support for 5 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const template<class Param1, class Param2, class Param3, class Param4, class Param5> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5), (Param1, Param2, Param3, Param4, Param5)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5), (Param1, Param2, Param3, Param4, Param5))
// Support for 6 arguments // Support for 6 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6), (Param1, Param2, Param3, Param4, Param5, Param6)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6), (Param1, Param2, Param3, Param4, Param5, Param6))
// Support for 7 arguments // Support for 7 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7), (Param1, Param2, Param3, Param4, Param5, Param6, Param7)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7), (Param1, Param2, Param3, Param4, Param5, Param6, Param7))
// Support for 8 arguments // Support for 8 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
// Support for 9 arguments // Support for 9 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
// Support for 10 arguments // Support for 10 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
// Support for 11 arguments // Support for 11 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
// Support for 12 arguments // Support for 12 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
// Support for 13 arguments // Support for 13 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
// Support for 14 arguments // Support for 14 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
// Support for 15 arguments // Support for 15 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
// Support for 16 arguments // Support for 16 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16)) SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
// Support for 17 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
// Support for 18 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
// Support for 19 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
// Support for 20 arguments
template<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20> RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8, Param9 p9, Param10 p10, Param11 p11, Param12 p12, Param13 p13, Param14 p14, Param15 p15, Param16 p16, Param17 p17, Param18 p18, Param19 p19, Param20 p20) const
SH_MAKE_EXECUTABLECLASS_OB((p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20), (Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
}; };
} }
@ -1888,6 +2134,66 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp); return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
} }
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300 #if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300
// GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it // GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it
@ -2147,12 +2453,72 @@ SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp); return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
} }
// Support for 17 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 18 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 19 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
// Support for 20 arguments
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...))
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
template <class X, class Y, class MFP, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16, class Param17, class Param18, class Param19, class Param20>
SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, Param17, Param18, Param19, Param20, ...)const)
{
return SourceHook::ExecutableClass<SourceHook::CallClass<Y>, RetType, MFP>(ptr, mfp);
}
#endif #endif
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp)) #define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#undef SH_MAKE_EXECUTABLECLASS_BODY #undef SH_MAKE_EXECUTABLECLASS_OB
#endif #endif
// The pope is dead. -> :( // The pope is dead. -> :(

View File

@ -12,13 +12,12 @@
#define __SOURCEHOOK_IMPL_H__ #define __SOURCEHOOK_IMPL_H__
#include "sourcehook.h" #include "sourcehook.h"
#include "sh_list.h"
#ifdef __linux__ #include "sh_vector.h"
#include <signal.h> #include "sh_tinyhash.h"
#include <setjmp.h>
#endif
// Set this to 1 to enable runtime code generation (faster) // Set this to 1 to enable runtime code generation (faster)
// (unused at the moment, but may come back, so I'm leaving it in here!)
#define SH_RUNTIME_CODEGEN 1 #define SH_RUNTIME_CODEGEN 1
namespace SourceHook namespace SourceHook
@ -28,6 +27,7 @@ namespace SourceHook
*/ */
class CSourceHookImpl : public ISourceHook class CSourceHookImpl : public ISourceHook
{ {
private:
/** /**
* @brief A hook can be removed if you have this information * @brief A hook can be removed if you have this information
*/ */
@ -48,24 +48,165 @@ namespace SourceHook
bool post; bool post;
}; };
/** struct HookInfo
* @brief A list of HookManagerInfo structures
*/
typedef List<HookManagerInfo> HookManInfoList;
struct CallClassInfo
{ {
GenericCallClass cc; ISHDelegate *handler; //!< Pointer to the handler
int refcounter; bool paused; //!< If true, the hook should not be executed
bool operator==(void *other) Plugin plug; //!< The owner plugin
int thisptr_offs; //!< This pointer offset
};
class CHookList : public IHookList
{
public:
List<HookInfo> m_List;
friend class CIter;
class CIter : public IHookList::IIter
{ {
return cc.ptr == other; friend class CHookList;
CHookList *m_pList;
List<HookInfo>::iterator m_Iter;
void SkipPaused();
public:
CIter(CHookList *pList);
virtual ~CIter();
void GoToBegin();
bool End();
void Next();
ISHDelegate *Handler();
int ThisPtrOffs();
CIter *m_pNext; // When stored in m_FreeIters
};
CIter *m_FreeIters;
CHookList();
CHookList(const CHookList &other);
virtual ~CHookList();
void operator=(const CHookList &other);
IIter *GetIter();
void ReleaseIter(IIter *pIter);
};
// I know, data hiding... But I'm a lazy bastard!
class CIface : public IIface
{
public:
void *m_Ptr;
CHookList m_PreHooks;
CHookList m_PostHooks;
public:
CIface(void *ptr);
virtual ~CIface();
void *GetPtr();
IHookList *GetPreHooks();
IHookList *GetPostHooks();
bool operator==(void *ptr)
{
return m_Ptr == ptr;
} }
}; };
class CVfnPtr : public IVfnPtr
{
public:
typedef List<CIface> IfaceList;
typedef IfaceList::iterator IfaceListIter;
void *m_Ptr;
void *m_OrigEntry;
IfaceList m_Ifaces;
public:
CVfnPtr(void *ptr);
virtual ~CVfnPtr();
void *GetVfnPtr();
void *GetOrigEntry();
virtual IIface *FindIface(void *ptr);
bool operator==(void *ptr)
{
return m_Ptr == ptr;
}
};
class CHookManagerInfo : public IHookManagerInfo
{
public:
typedef List<CVfnPtr> VfnPtrList;
typedef VfnPtrList::iterator VfnPtrListIter;
Plugin m_Plug;
HookManagerPubFunc m_Func;
int m_VtblOffs;
int m_VtblIdx;
const char *m_Proto;
void *m_HookfuncVfnptr;
VfnPtrList m_VfnPtrs;
public:
virtual ~CHookManagerInfo();
IVfnPtr *FindVfnPtr(void *vfnptr);
void SetInfo(int vtbl_offs, int vtbl_idx, const char *proto);
void SetHookfuncVfnptr(void *hookfunc_vfnptr);
};
/**
* @brief A list of CHookManagerInfo classes
*/
typedef List<CHookManagerInfo> HookManInfoList;
class CCallClassImpl : public GenericCallClass
{
public:
typedef SourceHook::CVector<void*> OrigFuncs;
typedef SourceHook::THash<int, OrigFuncs> OrigVTables;
void *m_Ptr; //!< Pointer to the actual object
size_t m_ObjSize; //!< Size of the instance
OrigVTables m_VT; //!< Info about vtables & functions
int m_RefCounter;
CCallClassImpl(void *ptr, size_t size);
virtual ~CCallClassImpl();
bool operator==(void *other)
{
return m_Ptr == other;
}
void *GetThisPtr();
void *GetOrigFunc(int vtbloffs, int vtblidx);
void ApplyCallClassPatch(int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatch(int vtbl_offs, int vtbl_idx);
};
/** /**
* @brief A list of CallClass structures * @brief A list of CallClass structures
*/ */
typedef List<CallClassInfo> Impl_CallClassList; typedef List<CCallClassImpl> Impl_CallClassList;
Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses Impl_CallClassList m_CallClasses; //!< A list of already generated callclasses
HookManInfoList m_HookMans; //!< A list of hook managers HookManInfoList m_HookMans; //!< A list of hook managers
@ -73,22 +214,22 @@ namespace SourceHook
/** /**
* @brief Finds a hook manager 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
*/ */
HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end, HookManInfoList::iterator FindHookMan(HookManInfoList::iterator begin, HookManInfoList::iterator end,
const char *proto, int vtblofs, int vtblidx); const char *proto, int vtblofs, int vtblidx);
void ApplyCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx, void *orig_entry); void ApplyCallClassPatches(CCallClassImpl &cc);
void ApplyCallClassPatches(CallClassInfo &cc);
void ApplyCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx, void *orig_entry); void ApplyCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx, void *orig_entry);
void RemoveCallClassPatch(CallClassInfo &cc, int vtbl_offs, int vtbl_idx);
void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx); void RemoveCallClassPatches(void *ifaceptr, int vtbl_offs, int vtbl_idx);
void SetPluginPaused(Plugin plug, bool paused);
META_RES m_Status, m_PrevRes, m_CurRes; META_RES m_Status, m_PrevRes, m_CurRes;
const void *m_OrigRet; const void *m_OrigRet;
const void *m_OverrideRet; const void *m_OverrideRet;
void *m_IfacePtr; void *m_IfacePtr;
public: public:
CSourceHookImpl(); CSourceHookImpl();
~CSourceHookImpl(); virtual ~CSourceHookImpl();
/** /**
* @brief Returns the interface version * @brief Returns the interface version
@ -199,19 +340,6 @@ namespace SourceHook
virtual void SetOrigRet(const void *ptr); //!< Sets the original return pointer virtual void SetOrigRet(const void *ptr); //!< Sets the original return pointer
virtual void SetOverrideRet(const void *ptr); //!< Sets the override result pointer virtual void SetOverrideRet(const void *ptr); //!< Sets the override result pointer
}; };
#ifdef __linux__
/**
* @brief Checks to see if a memory value can be read from a given pointer.
*
* @return True if the value can be read and false if it cannot.
*
* @param ptr The pointer to the memory value.
* @param len The length of the memory value to be read from the pointer.
*/
bool IsBadReadPtr(const void *ptr, size_t len);
void BadReadHandler(int sig);
#endif
} }
#endif #endif

View File

@ -1,16 +1,16 @@
#(C)2004-2005 SourceMM Development Team #(C)2004-2005 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson # Makefile written by David "BAILOPAN" Anderson and Pavol Marko
OPT_FLAGS = -O3 -funroll-loops -s -pipe OPT_FLAGS = -O3 -funroll-loops -s -pipe
DEBUG_FLAGS = -g -ggdb3 DEBUG_FLAGS = -g -ggdb3
CPP = gcc CPP = gcc
BINARY = sourcehook_test
OBJECTS = test1.cpp test2.cpp test3.cpp test4.cpp testbail.cpp testbail2.cpp testlist.cpp main.cpp sourcehook.cpp
LINK = -lstdc++ LINK = -lstdc++
INCLUDE = -I. -I.. INCLUDE = -I. -I..
MAX_PARAMS=20
BINARY = sourcehook_test
OBJECTS = main.cpp sourcehook.cpp $(shell ls -t test*.cpp)
HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h
ifeq "$(DEBUG)" "true" ifeq "$(DEBUG)" "true"
BIN_DIR = Debug BIN_DIR = Debug
@ -20,28 +20,42 @@ else
CFLAGS = $(OPT_FLAGS) CFLAGS = $(OPT_FLAGS)
endif endif
# CFLAGS += CFLAGS += -Wall
# Also, enable SH_ASSERT
CFLAGS += -DSH_DEBUG
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp default: all
$(BIN_DIR)/%.o: %.cpp $(HEADERS)
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
../sourcehook.h: ../generate/sourcehook.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) sourcehook.hxx sourcehook.h; cp sourcehook.h ..)
../sourcehook.hxx: ../generate/sh_memfuncinfo.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) sh_memfuncinfo.hxx sh_memfuncinfo.h; cp sh_memfuncino.h ..)
../FastDelegate.hxx: ../generate/FastDelegate.hxx
(cd ../generate; ./shworker.bin iter $(MAX_PARAMS) FastDelegate.hxx FastDelegate.h; cp FastDelegate.h ..)
debug:
$(MAKE) all DEBUG=true
all: all:
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)
ln -sf ../sourcehook.cpp sourcehook.cpp ln -sf ../sourcehook.cpp sourcehook.cpp
$(MAKE) sourcehook_test $(MAKE) $(BINARY)
rm -f $(BINARY) rm -f $(BINARY)
rm -f sourcehook.cpp
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY) ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
sourcehook_test: $(OBJ_LINUX)
$(BINARY): $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(BINARY) $(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) all DEBUG=true
default: all
clean: clean:
rm -rf Release/*.o rm -rf Release/*.o
rm -rf Release/$(BINARY) rm -rf Release/$(BINARY)

View File

@ -2,6 +2,8 @@
#include "sourcehook_impl.h" #include "sourcehook_impl.h"
#include "testevents.h" #include "testevents.h"
#include "sh_memory.h"
namespace namespace
{ {
StateList g_States; StateList g_States;
@ -12,6 +14,7 @@ namespace
// Basic tests // Basic tests
// Hooking and callclass // Hooking and callclass
MAKE_STATE_1(State_ModuleInMemory, bool);
MAKE_STATE(State_F1_Called); MAKE_STATE(State_F1_Called);
MAKE_STATE_1(State_F1_PreHandler_Called, void*); MAKE_STATE_1(State_F1_PreHandler_Called, void*);
MAKE_STATE_1(State_F1_PostHandler_Called, void*); MAKE_STATE_1(State_F1_PostHandler_Called, void*);
@ -385,6 +388,22 @@ namespace
bool TestBasic(std::string &error) bool TestBasic(std::string &error)
{ {
// Simple test for ModuleInMemory:
// 1) &error should on the stack
// 2) 0 should not be mapped
// 3) &error to -1 should not be mapped
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(reinterpret_cast<char*>(&error), sizeof(error))));
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(0, 1)));
ADD_STATE(State_ModuleInMemory(SourceHook::ModuleInMemory(reinterpret_cast<char*>(&error),
(reinterpret_cast<std::string*>(-1) - &error) - 1)));
CHECK_STATES((&g_States,
new State_ModuleInMemory(true),
new State_ModuleInMemory(false),
new State_ModuleInMemory(false),
NULL), "ModuleInMemory");
SourceHook::CSourceHookImpl g_SHImpl; SourceHook::CSourceHookImpl g_SHImpl;
g_SHPtr = &g_SHImpl; g_SHPtr = &g_SHImpl;
g_PLID = 1337; g_PLID = 1337;
@ -401,7 +420,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_CallClassGenerated, new State_F1_CallClassGenerated,
new State_F1_Called, new State_F1_Called,
new State_F1_Called, new State_F1_Called,
@ -421,7 +440,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_CallClassGenerated, new State_F1_CallClassGenerated,
new State_F1_Called, new State_F1_Called,
new State_F1_Called, new State_F1_Called,
@ -437,8 +456,8 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_HookAdded(true), new State_F1_HookAdded(true),
new State_F1_Called, new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers), new State_F1_PreHandler_Called(&f1_handlers),
@ -446,7 +465,7 @@ bool TestBasic(std::string &error)
// 4) Rerequest the callclass // 4) Rerequest the callclass
SH_RELEASE_CALLCLASS(cc); SH_RELEASE_CALLCLASS(cc);
ADD_STATE(State_F1_CallClassReleased); ADD_STATE(State_F1_CallClassReleased);
cc2 = SH_GET_CALLCLASS(pTest); cc2 = SH_GET_CALLCLASS(pTest);
ADD_STATE(State_F1_CallClassGenerated); ADD_STATE(State_F1_CallClassGenerated);
@ -454,11 +473,11 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_CallClassReleased, new State_F1_CallClassReleased,
new State_F1_CallClassGenerated, new State_F1_CallClassGenerated,
new State_F1_Called, new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers), new State_F1_PreHandler_Called(&f1_handlers),
NULL), "Part 4"); NULL), "Part 4");
// 5) Check ignore / supercede // 5) Check ignore / supercede
@ -485,7 +504,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_HookRemoved, new State_F1_HookRemoved,
new State_F1_Called, new State_F1_Called,
new State_F1_Called, new State_F1_Called,
@ -498,7 +517,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_HookAdded(true), new State_F1_HookAdded(true),
new State_F1_Called, new State_F1_Called,
new State_F1_Called, new State_F1_Called,
@ -516,7 +535,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_HookAdded(true), new State_F1_HookAdded(true),
new State_F1_Called, new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers), new State_F1_PreHandler_Called(&f1_handlers),
@ -536,7 +555,7 @@ bool TestBasic(std::string &error)
SH_CALL(cc, &Test::F1)(); SH_CALL(cc, &Test::F1)();
pTest->F1(); pTest->F1();
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_HookRemoved, new State_F1_HookRemoved,
new State_F1_HookRemoved, new State_F1_HookRemoved,
new State_F1_Called, new State_F1_Called,
@ -550,7 +569,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299Ret(true), new State_F299Ret(true),
new State_F299_Called("hi"), new State_F299_Called("hi"),
@ -561,7 +580,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"), new State_F299_PreHandlerCalled("hi"),
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299Ret(true), new State_F299Ret(true),
@ -573,7 +592,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"), new State_F299_PreHandlerCalled("hi"),
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299_PostHandlerCalled("hi"), new State_F299_PostHandlerCalled("hi"),
@ -586,7 +605,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"), new State_F299_PreHandlerCalled("hi"),
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299_PostHandlerCalled("hi"), new State_F299_PostHandlerCalled("hi"),
@ -599,7 +618,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"), new State_F299_PreHandlerCalled("hi"),
new State_F299_PostHandlerCalled("hi"), new State_F299_PostHandlerCalled("hi"),
new State_F299Ret(true), new State_F299Ret(true),
@ -611,7 +630,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299_PostHandlerCalled("hi"), new State_F299_PostHandlerCalled("hi"),
new State_F299Ret(false), new State_F299Ret(false),
@ -623,7 +642,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F299Ret(pTest->F299("hi"))); ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi"))); ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F299_Called("hi"), new State_F299_Called("hi"),
new State_F299Ret(true), new State_F299Ret(true),
new State_F299_Called("hi"), new State_F299_Called("hi"),
@ -635,7 +654,7 @@ bool TestBasic(std::string &error)
ADD_STATE(State_F1_CallClassReleased); ADD_STATE(State_F1_CallClassReleased);
CHECK_STATES((&g_States, CHECK_STATES((&g_States,
new State_F1_CallClassReleased, new State_F1_CallClassReleased,
NULL), "Part 11"); NULL), "Part 11");

View File

@ -31,6 +31,58 @@ namespace
SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0); SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0);
/*
SHINT_MAKE_GENERICSTUFF_BEGIN(IGaben, EatYams, 0, (static_cast<void (IGaben::*)() SH_NOATTRIB>
(&IGaben::EatYams)))
typedef fastdelegate::FastDelegate0<> FD;
virtual void Func()
{
// SH_HANDLEFUNC_void(IGaben, EatYams, (), ());
SH_SETUPCALLS_void((), ())
SH_CALL_HOOKS_void(pre, ())
if (status != MRES_SUPERCEDE)
{
void (EmptyClass::*mfp)();
SH_SETUP_MFP(mfp);
(reinterpret_cast<EmptyClass*>(ifinfo->GetPtr())->*mfp)();
}
SH_CALL_HOOKS_void(post, ())
SH_RETURN_void()
}
};
SH_FHCls(IGaben,EatYams,0) SH_FHCls(IGaben,EatYams,0)::ms_Inst;
::SourceHook::MemFuncInfo SH_FHCls(IGaben,EatYams,0)::ms_MFI;
::SourceHook::IHookManagerInfo *SH_FHCls(IGaben,EatYams,0)::ms_HI;
const char *SH_FHCls(IGaben,EatYams,0)::ms_Proto = "SH_NOATTRIB";
bool __SourceHook_FHAddIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc,
new CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD>(handler), post);
}
bool __SourceHook_FHRemoveIGabenEatYams(void *iface, bool post,
SH_FHCls(IGaben,EatYams,0)::FD handler)
{
using namespace ::SourceHook;
MemFuncInfo mfi;
GetFuncInfo((static_cast<void (IGaben::*)() SH_NOATTRIB>(&IGaben::EatYams)), mfi);
if (mfi.thisptroffs < 0)
return false;
CSHDelegate<SH_FHCls(IGaben,EatYams,0)::FD> tmp(handler);
return SH_GLOB_SHPTR->RemoveHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs,
SH_FHCls(IGaben,EatYams,0)::HookManPubFunc, &tmp, post);
}
*/
void EatYams0_Handler() void EatYams0_Handler()
{ {
ADD_STATE(State_EatYams_Handler_Called); ADD_STATE(State_EatYams_Handler_Called);

View File

@ -33,50 +33,50 @@ namespace
return m_Int; return m_Int;
} }
}; };
#define LIST_THIS_CHECK(lst, err) \ #define LIST_THIS_CHECK(lst, err) \
for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter) \ for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter) \
CHECK_COND(&(*iter) == iter->m_This, err); CHECK_COND(&(*iter) == iter->m_This, err);
bool DoTestList(std::string &error) bool DoTestList(std::string &error)
{ {
typedef SourceHook::List<Hmm> ListType; typedef SourceHook::List<Hmm> ListType;
ListType lst; ListType lst;
CHECK_COND(lst.empty(), "Part1"); CHECK_COND(lst.empty(), "Part1");
for (int i = 1; i <= 100; ++i) for (int i = 1; i <= 100; ++i)
lst.push_back(i); lst.push_back(i);
LIST_THIS_CHECK(lst, "PartA1"); LIST_THIS_CHECK(lst, "PartA1");
CHECK_COND(!lst.empty(), "Part2"); CHECK_COND(!lst.empty(), "Part2");
lst.clear(); lst.clear();
CHECK_COND(lst.empty(), "Part3"); CHECK_COND(lst.empty(), "Part3");
for (int i = 1; i <= 100; ++i) for (int i = 1; i <= 100; ++i)
lst.push_back(i); lst.push_back(i);
CHECK_COND(lst.back() == 100, "Part4"); CHECK_COND(lst.back() == 100, "Part4");
LIST_THIS_CHECK(lst, "PartA2"); LIST_THIS_CHECK(lst, "PartA2");
int ver = 1; int ver = 1;
for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter) for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter)
CHECK_COND(*iter == ver++, "Part5"); CHECK_COND(*iter == ver++, "Part5");
CHECK_COND(ver == 101, "Part 6"); CHECK_COND(ver == 101, "Part 6");
ListType::iterator iter50 = lst.find(50); ListType::iterator iter50 = lst.find(50);
CHECK_COND(*iter50 == 50, "Part7"); CHECK_COND(*iter50 == 50, "Part7");
iter50 = lst.erase(iter50); iter50 = lst.erase(iter50);
CHECK_COND(*iter50 == 51, "Part8"); CHECK_COND(*iter50 == 51, "Part8");
CHECK_COND(*--iter50 == 49, "Part8.2"); CHECK_COND(*--iter50 == 49, "Part8.2");
lst.remove(80); lst.remove(80);
ver = 1; ver = 1;
for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter) for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter)
{ {
@ -86,68 +86,77 @@ namespace
} }
CHECK_COND(ver == 101, "Part10"); CHECK_COND(ver == 101, "Part10");
LIST_THIS_CHECK(lst, "PartA3"); LIST_THIS_CHECK(lst, "PartA3");
ListType lst2; ListType lst2;
lst = lst2; lst = lst2;
CHECK_COND(lst.empty(), "Part11"); CHECK_COND(lst.empty(), "Part11");
for (int i = 1; i <= 100; ++i) for (int i = 1; i <= 100; ++i)
lst.push_back(i); lst.push_back(i);
lst2 = lst; lst2 = lst;
CHECK_COND(lst2.size() == 100, "Part11.2"); CHECK_COND(lst2.size() == 100, "Part11.2");
LIST_THIS_CHECK(lst, "PartA4"); LIST_THIS_CHECK(lst, "PartA4");
LIST_THIS_CHECK(lst2, "PartA5"); LIST_THIS_CHECK(lst2, "PartA5");
ver = 1; ver = 1;
for (ListType::iterator iter = lst2.begin(); iter != lst2.end(); ++iter) for (ListType::iterator iter = lst2.begin(); iter != lst2.end(); ++iter)
CHECK_COND(*iter == ver++, "Part12"); CHECK_COND(*iter == ver++, "Part12");
lst.clear(); lst.clear();
for (int i = 401; i <= 500; ++i) for (int i = 401; i <= 500; ++i)
lst.push_back(i); lst.push_back(i);
lst = lst2; lst = lst2;
CHECK_COND(lst2.size() == 100, "Part13"); CHECK_COND(lst2.size() == 100, "Part13");
ver = 1; ver = 1;
for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter) for (ListType::iterator iter = lst.begin(); iter != lst.end(); ++iter)
CHECK_COND(*iter == ver++, "Part14"); CHECK_COND(*iter == ver++, "Part14");
LIST_THIS_CHECK(lst, "PartA6"); LIST_THIS_CHECK(lst, "PartA6");
LIST_THIS_CHECK(lst2, "PartA7"); LIST_THIS_CHECK(lst2, "PartA7");
return true; return true;
} }
bool DoTestTinyHash(std::string &error) bool DoTestTinyHash(std::string &error)
{ {
const int mymax = 5000; const int mymax = 5000;
typedef SourceHook::THash<int, int> HashType; typedef SourceHook::THash<int, int> HashType;
HashType hash; HashType hash;
for (int i = 1; i <= mymax; ++i) for (int i = 1; i <= mymax; ++i)
hash[i] = i + 5000; hash[i] = i + 5000;
for (int i = 1; i <= mymax; ++i) for (int i = 1; i <= mymax; ++i)
CHECK_COND(hash[i] == i + 5000, "Part1"); CHECK_COND(hash[i] == i + 5000, "Part1");
// Find // Find
int ver = 1; int ver = 1;
for (HashType::iterator iter = hash.begin(); iter != hash.end(); ++iter) for (HashType::iterator iter = hash.begin(); iter != hash.end(); ++iter)
CHECK_COND(iter->key == ver && iter->val == (ver++) + 5000, "Part2"); CHECK_COND(iter->key == ver && iter->val == (ver++) + 5000, "Part2");
CHECK_COND(ver == mymax+1, "Part2.1"); CHECK_COND(ver == mymax+1, "Part2.1");
HashType::iterator iter = hash.find(300); HashType::iterator iter = hash.find(300);
CHECK_COND(iter != hash.end() && iter->val == 300+5000, "Part3.1"); CHECK_COND(iter != hash.end() && iter->val == 300+5000, "Part3.1");
iter = hash.find(mymax+200); iter = hash.find(mymax+200);
CHECK_COND(iter == hash.end(), "Part3.2"); CHECK_COND(iter == hash.end(), "Part3.2");
HashType hash2; HashType hash2;
for (int i = 1; i <= mymax; ++i) for (int i = 1; i <= mymax; ++i)
hash2[i] = i + 5000; hash2[i] = i + 5000;
hash2.erase(mymax - 100);
CHECK_COND(hash2.find(mymax - 101) != hash2.end(), "Part 4.1");
CHECK_COND(hash2.find(mymax - 99) != hash2.end(), "Part 4.2");
CHECK_COND(hash2.find(mymax - 100) == hash2.end(), "Part 4.3");
hash2.erase(mymax - 99);
CHECK_COND(hash2.find(mymax - 101) != hash2.end(), "Part 4.4");
CHECK_COND(hash2.find(mymax - 99) == hash2.end(), "Part 4.5");
CHECK_COND(hash2.find(mymax - 100) == hash2.end(), "Part 4.6");
return true; return true;
} }
} }
@ -156,10 +165,10 @@ bool TestList(std::string &error)
{ {
if (!DoTestList(error)) if (!DoTestList(error))
return false; return false;
if (!DoTestTinyHash(error)) if (!DoTestTinyHash(error))
return false; return false;
return true; return true;
} }