mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2024-12-04 16:24:16 +01:00
20cf4639e5
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%403
545 lines
19 KiB
C++
Executable File
545 lines
19 KiB
C++
Executable File
/* ======== SourceHook ========
|
|
* By PM
|
|
* No warranties of any kind
|
|
* ============================
|
|
*/
|
|
|
|
/**
|
|
* @file sourcehook.h
|
|
* @brief Contains the public SourceHook API
|
|
*/
|
|
|
|
#ifndef __SOURCEHOOK_H__
|
|
#define __SOURCEHOOK_H__
|
|
|
|
#define SH_ASSERT(x) if (!(x)) __asm { int 3 }
|
|
|
|
// System
|
|
#define SH_SYS_WIN32 1
|
|
#define SH_SYS_LINUX 2
|
|
|
|
#ifdef _WIN32
|
|
# define SH_SYS SH_SYS_WIN32
|
|
#elif defined __linux__
|
|
# define SH_SYS SH_SYS_LINUX
|
|
#else
|
|
# error Unsupported system
|
|
#endif
|
|
|
|
// Compiler
|
|
#define SH_COMP_GCC 1
|
|
#define SH_COMP_MSVC 2
|
|
|
|
#ifdef _MSC_VER
|
|
# define SH_COMP SH_COMP_MSVC
|
|
#elif defined __GNUC__
|
|
# define SH_COMP SH_COMP_GCC
|
|
#else
|
|
# error Unsupported compiler
|
|
#endif
|
|
|
|
#if SH_COMP==SH_COMP_MSVC
|
|
# define vsnprintf _vsnprintf
|
|
#endif
|
|
|
|
#include "FastDelegate.h"
|
|
#include "sh_memfuncinfo.h"
|
|
#include "sh_memory.h"
|
|
#include <list>
|
|
#include <algorithm>
|
|
|
|
// Good old metamod!
|
|
|
|
// Flags returned by a plugin's api function.
|
|
// NOTE: order is crucial, as greater/less comparisons are made.
|
|
enum META_RES
|
|
{
|
|
MRES_IGNORED=0, // plugin didn't take any action
|
|
MRES_HANDLED, // plugin did something, but real function should still be called
|
|
MRES_OVERRIDE, // call real function, but use my return value
|
|
MRES_SUPERCEDE, // skip real function; use my return value
|
|
};
|
|
|
|
|
|
namespace SourceHook
|
|
{
|
|
const int STRBUF_LEN=8192; // In bytes, for "vafmt" functions
|
|
|
|
/**
|
|
* @brief A plugin typedef
|
|
*
|
|
* SourceHook doesn't really care what this is. As long as the ==, != and = operators work on it
|
|
* and every plugin has a unique identifier, everything is ok.
|
|
*/
|
|
typedef void* Plugin;
|
|
|
|
enum HookerAction
|
|
{
|
|
HA_GetInfo = 0, // -> Only store info
|
|
HA_Register, // -> Save the pointer for future reference
|
|
HA_Unregister, // -> Clear the saved pointer
|
|
HA_IfaceAdded, // -> Request call class
|
|
HA_IfaceRemoved // -> Release call class
|
|
};
|
|
|
|
struct HookerInfo;
|
|
|
|
/**
|
|
* @brief Pointer to hooker type
|
|
*
|
|
* A "hooker" is a the only thing that knows the actual protoype of the function at compile time.
|
|
*
|
|
* @param hi A pointer to a HookerInfo structure. The hooker should fill it and store it for
|
|
* future reference (mainly if something should get hooked to its hookfunc)
|
|
*/
|
|
typedef int (*Hooker)(HookerAction ha, HookerInfo *hi);
|
|
|
|
class ISHDelegate
|
|
{
|
|
public:
|
|
virtual void DeleteThis() = 0; // Ugly, I know
|
|
virtual bool IsEqual(ISHDelegate *other) = 0;
|
|
};
|
|
|
|
template <class T> class CSHDelegate : public ISHDelegate
|
|
{
|
|
T m_Deleg;
|
|
public:
|
|
CSHDelegate(T deleg) : m_Deleg(deleg)
|
|
{
|
|
}
|
|
|
|
void DeleteThis()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
bool IsEqual(ISHDelegate *other)
|
|
{
|
|
return static_cast<CSHDelegate<T>* >(other)->GetDeleg() == GetDeleg();
|
|
}
|
|
|
|
T &GetDeleg()
|
|
{
|
|
return m_Deleg;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief This structure contains information about a hooker (hook manager)
|
|
*/
|
|
struct HookerInfo
|
|
{
|
|
struct Iface
|
|
{
|
|
struct Hook
|
|
{
|
|
ISHDelegate *handler; //!< Pointer to the handler
|
|
Plugin plug; //!< The owner plugin
|
|
};
|
|
void *callclass; //!< Stores a call class for this interface
|
|
void *ptr; //!< Pointer to the interface instance
|
|
void *orig_entry; //!< The original vtable entry
|
|
std::list<Hook> hooks_pre; //!< A list of pre-hooks
|
|
std::list<Hook> hooks_post; //!< A list of post-hooks
|
|
bool operator ==(void *other) const
|
|
{
|
|
return ptr == other;
|
|
}
|
|
};
|
|
Plugin plug; //!< The owner plugin
|
|
const char *proto; //!< The prototype of the function the hooker is responsible for
|
|
int vtbl_idx; //!< The vtable index
|
|
int vtbl_offs; //!< The vtable offset
|
|
int thisptr_offs; //!< The this-pointer-adjuster
|
|
Hooker func; //!< The interface to the hooker
|
|
|
|
int hookfunc_vtbl_idx; //!< the vtable index of the hookfunc
|
|
int hookfunc_vtbl_offs; //!< the vtable offset of the hookfunc
|
|
void *hookfunc_inst; //!< Instance of the class the hookfunc is in
|
|
|
|
std::list<Iface> ifaces; //!< List of hooked interfaces
|
|
};
|
|
|
|
/**
|
|
* @brief Structure describing a callclass
|
|
*/
|
|
struct CallClass
|
|
{
|
|
struct VTable
|
|
{
|
|
void *ptr;
|
|
int actsize;
|
|
std::list<int> patches; //!< Already patched entries
|
|
bool operator ==(void *other) const
|
|
{
|
|
return ptr == other;
|
|
}
|
|
};
|
|
void *iface; //!< The iface pointer this callclass belongs to
|
|
size_t size; //!< The size of the callclass
|
|
void *ptr; //!< The actual "object"
|
|
typedef std::list<VTable> VTableList;
|
|
VTableList vtables; //!< Already known vtables
|
|
int refcounter; //!< How many times it was requested
|
|
|
|
bool operator ==(void *other) const
|
|
{
|
|
return ptr == other;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief The main SourceHook interface
|
|
*/
|
|
class ISourceHook
|
|
{
|
|
public:
|
|
/**
|
|
* @brief Add a hook.
|
|
*
|
|
* @return True if the function succeeded, false otherwise
|
|
*
|
|
* @param plug The unique identifier of the plugin that calls this function
|
|
* @param iface The interface pointer
|
|
* @param ifacesize The size of the class iface points to
|
|
* @param myHooker A hooker function that should be capable of handling the function
|
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
|
* @param post Set to true if you want a post handler
|
|
*/
|
|
virtual bool AddHook(Plugin plug, void *iface, int ifacesize, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
|
|
|
|
/**
|
|
* @brief Removes a hook.
|
|
*
|
|
* @return True if the function succeeded, false otherwise
|
|
*
|
|
* @param plug The unique identifier of the plugin that calls this function
|
|
* @param iface The interface pointer
|
|
* @param myHooker A hooker function that should be capable of handling the function
|
|
* @param handler A pointer to a FastDelegate containing the hook handler
|
|
* @param post Set to true if you want a post handler
|
|
*/
|
|
virtual bool RemoveHook(Plugin plug, void *iface, Hooker myHooker, ISHDelegate *handler, bool post) = 0;
|
|
|
|
/**
|
|
* @brief Checks whether a plugin has (a) hooker(s) that is/are currently used by other plugins
|
|
*
|
|
* @param plug The unique identifier of the plugin in question
|
|
*/
|
|
virtual bool IsPluginInUse(Plugin plug) = 0;
|
|
|
|
/**
|
|
* @brief Return a pointer to a callclass. Generate a new one if required.
|
|
*
|
|
* @param iface The interface pointer
|
|
* @param size Size of the class
|
|
*/
|
|
virtual void *GetCallClass(void *iface, size_t size) = 0;
|
|
|
|
/**
|
|
* @brief Release a callclass
|
|
*
|
|
* @param ptr Pointer to the callclass
|
|
*/
|
|
virtual void ReleaseCallClass(void *ptr) = 0;
|
|
|
|
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 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 *GetOverrideRet() = 0; //!< Gets the override result. If none is specified, NULL
|
|
virtual void *GetIfacePtr() = 0; //!< Gets the interface pointer
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// For hookers
|
|
virtual META_RES &GetCurResRef() = 0; //!< Gets the pointer to the current meta result
|
|
virtual META_RES &GetPrevResRef() = 0; //!< Gets the pointer to the previous meta result
|
|
virtual META_RES &GetStatusRef() = 0; //!< Gets the pointer to the status variable
|
|
virtual void SetOrigRet(const void *ptr) = 0; //!< Sets the original return pointer
|
|
virtual void SetOverrideRet(const void *ptr) = 0; //!< Sets the override result pointer
|
|
virtual void SetIfacePtr(void *ptr) = 0; //!< Sets the interface this pointer
|
|
};
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Macro interface
|
|
#define SET_META_RESULT(result) g_SHPtr->SetRes(result)
|
|
#define RETURN_META(result) do { g_SHPtr->SetRes(result); return; } while(0)
|
|
#define RETURN_META_VALUE(result, value) do { g_SHPtr->SetRes(result); return (value); } while(0)
|
|
|
|
#define META_RESULT_STATUS g_SHPtr->GetStatus()
|
|
#define META_RESULT_PREVIOUS g_SHPtr->GetPrevRes()
|
|
#define META_RESULT_ORIG_RET(type) *(const type *)g_SHPtr->GetOrigRet()
|
|
#define META_RESULT_OVERRIDE_RET(type) *(const type *)g_SHPtr->GetOverrideRet()
|
|
#define META_IFACEPTR g_SHPtr->GetIfacePtr()
|
|
|
|
|
|
/**
|
|
* @brief Get/generate callclass for an interface pointer
|
|
*
|
|
* @param ifacetype The type of the interface
|
|
* @param ifaceptr The interface pointer
|
|
*/
|
|
#define SH_GET_CALLCLASS(ifacetype, ifaceptr) reinterpret_cast<ifacetype*>(g_SHPtr->GetCallClass(ifaceptr, sizeof(ifacetype)))
|
|
#define SH_RELEASE_CALLCLASS(ptr) g_SHPtr->ReleaseCallClass(reinterpret_cast<void*>(ptr))
|
|
|
|
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
|
SourceHook::SH_FHAdd##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
|
|
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
|
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post)
|
|
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
|
|
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
|
|
|
|
#define SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
|
SourceHook::SH_FHRemove##ifacetype##ifacefunc((void*)ifaceptr, post, handler)
|
|
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
|
|
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post)
|
|
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
|
|
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
|
|
|
|
#define SH_NOATTRIB
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
#define SH_FHCls(ift, iff, ov) FHCls_##ift##iff##ov
|
|
|
|
#define SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr) \
|
|
static int Hooker(HookerAction action, HookerInfo *param) \
|
|
{ \
|
|
if (action == HA_GetInfo) \
|
|
{ \
|
|
param->proto = ms_Proto; \
|
|
MemFuncInfo mfi; \
|
|
GetFuncInfo(funcptr, mfi); \
|
|
param->vtbl_idx = mfi.vtblindex; \
|
|
param->vtbl_offs = mfi.vtbloffs; \
|
|
param->thisptr_offs = mfi.thisptroffs; \
|
|
if (param->thisptr_offs) \
|
|
return 2; /*No virtual inheritance supported*/ \
|
|
GetFuncInfo(&SH_FHCls(ifacetype,ifacefunc,overload)::Func, mfi); \
|
|
param->hookfunc_vtbl_idx = mfi.vtblindex; \
|
|
param->hookfunc_vtbl_offs = mfi.vtbloffs; \
|
|
param->hookfunc_inst = (void*)&ms_Inst; \
|
|
return 0; \
|
|
} \
|
|
else if (action == HA_Register) \
|
|
{ \
|
|
ms_HI = param; \
|
|
return 0; \
|
|
} \
|
|
else if (action == HA_Unregister) \
|
|
{ \
|
|
ms_HI = NULL; \
|
|
return 0; \
|
|
} \
|
|
else \
|
|
return 1; \
|
|
}
|
|
|
|
#define SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, funcptr) \
|
|
namespace SourceHook \
|
|
{ \
|
|
struct SH_FHCls(ifacetype,ifacefunc,overload) \
|
|
{ \
|
|
static SH_FHCls(ifacetype,ifacefunc,overload) ms_Inst; \
|
|
static HookerInfo *ms_HI; \
|
|
static const char *ms_Proto; \
|
|
SHINT_MAKE_HOOKERPUBFUNC(ifacetype, ifacefunc, overload, funcptr)
|
|
|
|
#define SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, proto) \
|
|
}; \
|
|
const char *SH_FHCls(ifacetype,ifacefunc,overload)::ms_Proto = proto; \
|
|
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
|
|
HookerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
|
|
bool SH_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
|
|
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
|
{ \
|
|
return g_SHPtr->AddHook(g_Plug, iface, sizeof(ifacetype), \
|
|
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, \
|
|
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
|
|
} \
|
|
bool SH_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
|
|
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
|
|
{ \
|
|
CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD> tmp(handler); \
|
|
return g_SHPtr->RemoveHook(g_Plug, iface, \
|
|
SH_FHCls(ifacetype,ifacefunc,overload)::Hooker, &tmp, post); \
|
|
} \
|
|
}
|
|
|
|
#define SH_SETUPCALLS(rettype) \
|
|
/* 1) Find the iface ptr */ \
|
|
/* 1.1) Adjust to original this pointer */ \
|
|
void *origthis = this - ms_HI->thisptr_offs; \
|
|
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
|
|
ms_HI->ifaces.end(), origthis); \
|
|
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
|
|
HookerInfo::Iface &ci = *ifaceiter; \
|
|
/* 2) Declare some vars and set it up */ \
|
|
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
|
|
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
|
|
rettype orig_ret, override_ret, plugin_ret; \
|
|
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
|
|
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
|
|
META_RES &status = g_SHPtr->GetStatusRef(); \
|
|
status = MRES_IGNORED; \
|
|
g_SHPtr->SetIfacePtr(ci.ptr); \
|
|
g_SHPtr->SetOrigRet(reinterpret_cast<void*>(&orig_ret)); \
|
|
g_SHPtr->SetOverrideRet(NULL);
|
|
|
|
#define SH_CALL_HOOKS(post, params) \
|
|
prev_res = MRES_IGNORED; \
|
|
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
|
{ \
|
|
cur_res = MRES_IGNORED; \
|
|
plugin_ret = reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
|
|
prev_res = cur_res; \
|
|
if (cur_res > status) \
|
|
status = cur_res; \
|
|
if (cur_res >= MRES_OVERRIDE) \
|
|
{ \
|
|
override_ret = plugin_ret; \
|
|
g_SHPtr->SetOverrideRet(&override_ret); \
|
|
} \
|
|
}
|
|
|
|
#define SH_CALL_ORIG(ifacetype, ifacefunc, params) \
|
|
if (status != MRES_SUPERCEDE) \
|
|
orig_ret = reinterpret_cast<ifacetype*>(ci.callclass)->ifacefunc params; \
|
|
else \
|
|
orig_ret = override_ret;
|
|
|
|
#define SH_RETURN() \
|
|
return status >= MRES_OVERRIDE ? override_ret : orig_ret;
|
|
|
|
#define SH_HANDLEFUNC(ifacetype, ifacefunc, params, rettype) \
|
|
SH_SETUPCALLS(rettype) \
|
|
SH_CALL_HOOKS(pre, params) \
|
|
SH_CALL_ORIG(ifacetype, ifacefunc, params) \
|
|
SH_CALL_HOOKS(post, params) \
|
|
SH_RETURN()
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
#define SH_SETUPCALLS_void() \
|
|
/* 1) Find the iface ptr */ \
|
|
/* 1.1) Adjust to original this pointer */ \
|
|
void *origthis = this - ms_HI->thisptr_offs; \
|
|
std::list<HookerInfo::Iface>::iterator ifaceiter = std::find(ms_HI->ifaces.begin(), \
|
|
ms_HI->ifaces.end(), origthis); \
|
|
SH_ASSERT(ifaceiter != ms_HI->ifaces.end()); \
|
|
HookerInfo::Iface &ci = *ifaceiter; \
|
|
/* 2) Declare some vars and set it up */ \
|
|
std::list<HookerInfo::Iface::Hook> &prelist = ci.hooks_pre; \
|
|
std::list<HookerInfo::Iface::Hook> &postlist = ci.hooks_post; \
|
|
META_RES &cur_res = g_SHPtr->GetCurResRef(); \
|
|
META_RES &prev_res = g_SHPtr->GetPrevResRef(); \
|
|
META_RES &status = g_SHPtr->GetStatusRef(); \
|
|
status = MRES_IGNORED; \
|
|
g_SHPtr->SetIfacePtr(ci.ptr); \
|
|
g_SHPtr->SetOverrideRet(NULL);
|
|
|
|
#define SH_CALL_HOOKS_void(post, params) \
|
|
prev_res = MRES_IGNORED; \
|
|
for (std::list<HookerInfo::Iface::Hook>::iterator hiter = post##list.begin(); hiter != post##list.end(); ++hiter) \
|
|
{ \
|
|
cur_res = MRES_IGNORED; \
|
|
reinterpret_cast<CSHDelegate<FD>*>(hiter->handler)->GetDeleg() params; \
|
|
prev_res = cur_res; \
|
|
if (cur_res > status) \
|
|
status = cur_res; \
|
|
}
|
|
|
|
#define SH_CALL_ORIG_void(ifacetype, ifacefunc, params) \
|
|
if (status != MRES_SUPERCEDE) \
|
|
reinterpret_cast<ifacetype*>(ci.callclass)->ifacefunc params;
|
|
|
|
#define SH_RETURN_void()
|
|
|
|
#define SH_HANDLEFUNC_void(ifacetype, ifacefunc, params) \
|
|
SH_SETUPCALLS_void() \
|
|
SH_CALL_HOOKS_void(pre, params) \
|
|
SH_CALL_ORIG_void(ifacetype, ifacefunc, params) \
|
|
SH_CALL_HOOKS_void(post, params) \
|
|
SH_RETURN_void()
|
|
|
|
|
|
// Special vafmt handlers
|
|
#define SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, params_orig, params_plug, rettype) \
|
|
SH_SETUPCALLS(rettype) \
|
|
SH_CALL_HOOKS(pre, params_plug) \
|
|
SH_CALL_ORIG(ifacetype, ifacefunc, params_orig) \
|
|
SH_CALL_HOOKS(post, params_plug) \
|
|
SH_RETURN()
|
|
|
|
#define SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, params_orig, params_plug) \
|
|
SH_SETUPCALLS_void() \
|
|
SH_CALL_HOOKS_void(pre, params_plug) \
|
|
SH_CALL_ORIG_void(ifacetype, ifacefunc, params_orig) \
|
|
SH_CALL_HOOKS_void(post, params_plug) \
|
|
SH_RETURN_void()
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
@VARARGS@
|
|
// *********
|
|
#define SH_DECL_HOOK@$@(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @)> \
|
|
(&ifacetype::ifacefunc))) \
|
|
typedef fastdelegate::FastDelegate@$@<@param%%|, @@, @rettype> FD; \
|
|
virtual rettype Func(@param%% p%%|, @) attr \
|
|
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (@p%%|, @), rettype); } \
|
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @)
|
|
|
|
#define SH_DECL_HOOK@$@_void(ifacetype, ifacefunc, attr, overload@, param%%@) \
|
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @)> \
|
|
(&ifacetype::ifacefunc))) \
|
|
typedef fastdelegate::FastDelegate@$@<@param%%|, @> FD; \
|
|
virtual void Func(@param%% p%%|, @) attr \
|
|
{ SH_HANDLEFUNC_void(ifacetype, ifacefunc, (@p%%|, @)); } \
|
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @)
|
|
|
|
#define SH_DECL_HOOK@$@_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<rettype (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
|
(&ifacetype::ifacefunc))) \
|
|
typedef fastdelegate::FastDelegate@$+1@<@param%%|, @@, @const char *, rettype> FD; \
|
|
virtual rettype Func(@param%% p%%|, @@, @const char *fmt, ...) attr \
|
|
{ \
|
|
char buf[STRBUF_LEN]; \
|
|
va_list ap; \
|
|
va_start(ap, fmt); \
|
|
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
|
va_end(ap); \
|
|
SH_HANDLEFUNC_vafmt(ifacetype, ifacefunc, (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf), rettype); \
|
|
} \
|
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype @"|" #param%%| @ "|const char*|...")
|
|
|
|
#define SH_DECL_HOOK@$@_void_vafmt(ifacetype, ifacefunc, attr, overload, rettype@, param%%@) \
|
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload, (static_cast<void (ifacetype::*)(@param%%|, @@, @const char *, ...)> \
|
|
(&ifacetype::ifacefunc))) \
|
|
typedef fastdelegate::FastDelegate@$+1@<@param%%|, @@, @const char *> FD; \
|
|
virtual void Func(@param%% p%%|, @@, @const char *, ...) attr \
|
|
{ \
|
|
char buf[STRBUF_LEN]; \
|
|
va_list ap; \
|
|
va_start(ap, fmt); \
|
|
vsnprintf(buf, sizeof(buf), fmt, ap); \
|
|
va_end(ap); \
|
|
SH_HANDLEFUNC_void_vafmt(ifacetype, ifacefunc, (@p%%|, @@, @"%s", buf), (@p%%|, @@, @buf)); \
|
|
} \
|
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr @"|" #param%%| @ "|const char*|...")
|
|
|
|
@ENDARGS@
|
|
|
|
/*
|
|
#define SH_DECL_HOOK1(ifacetype, ifacefunc, attr, overload, rettype, param1) \
|
|
SHINT_MAKE_GENERICSTUFF_BEGIN(ifacetype, ifacefunc, overload) \
|
|
typedef fastdelegate::FastDelegate1<param1, rettype> FD; \
|
|
virtual rettype Func(param1 p1) \
|
|
{ SH_HANDLEFUNC(ifacetype, ifacefunc, (p1), rettype); } \
|
|
SHINT_MAKE_GENERICSTUFF_END(ifacetype, ifacefunc, overload, #attr "|" #rettype "|" #param1)
|
|
|
|
|
|
*/
|
|
|
|
#endif
|
|
// The pope is dead. -> :(
|