removed old providers location

replaced sourcehook with v4.5

--HG--
branch : sourcemm-1.6.0
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/sourcemm-1.6.0%40436
This commit is contained in:
David Anderson 2007-09-28 21:40:58 +00:00
parent c9b52f2cf0
commit 98aeb7b419
28 changed files with 5621 additions and 5454 deletions

View File

@ -1,70 +0,0 @@
#(C)2004-2007 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../../hl2sdk
SMM_ROOT = ..
SRCDS = ~/srcds
### EDIT BELOW FOR OTHER PROJECTS ###
OPT_FLAGS = -O2 -funroll-loops -s -pipe
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
DEBUG_FLAGS = -g -ggdb3
CPP = gcc-4.1
BINARY = provider_ep1_i486.so
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
OBJECTS = provider_util.cpp episode1/provider_ep1.cpp episode1/console.cpp
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook \
-I$(SMM_ROOT)/sourcemm
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
CFLAGS = $(DEBUG_FLAGS)
else
BIN_DIR = Release
CFLAGS = $(OPT_FLAGS)
endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS)
endif
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)
mkdir -p $(BIN_DIR)/episode1
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
$(MAKE) -f Makefile.ep1 provider
rm -rf $(BINARY)
provider: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) -f Makefile.ep1 all DEBUG=true
default: all
clean:
rm -rf Release/episode1/*.o
rm -rf Release/*.o
rm -rf Release/$(BINARY)
rm -rf Debug/episode1/*.o
rm -rf Debug/*.o
rm -rf Debug/$(BINARY)

View File

@ -1,111 +0,0 @@
#include "console.h"
#include "provider_ep1.h"
using namespace SourceHook;
SMConVarAccessor g_SMConVarAccessor;
class CAlwaysRegisterableCommand : public ConCommandBase
{
public:
CAlwaysRegisterableCommand()
{
Create("metamod_eternal", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
}
bool IsRegistered( void ) const
{
return false;
}
void BringToFront()
{
// First, let's try to find us!
ConCommandBase *pPtr = icvar->GetCommands();
if (pPtr == this)
{
// We are already at the beginning; Nothing to do
return;
}
while (pPtr)
{
if (pPtr == this)
{
break;
}
ConCommandBase *pPrev = NULL;
while (pPtr)
{
if (pPtr == this)
{
break;
}
pPrev = pPtr;
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
}
if (pPrev && pPtr == this)
{
pPrev->SetNext(m_pNext); // Remove us from the list
}
// Now, register us
SetNext(NULL);
icvar->RegisterConCommandBase(this);
}
}
} s_EternalCommand;
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
{
m_RegisteredCommands.push_back(pCommand);
pCommand->SetNext(NULL);
icvar->RegisterConCommandBase(pCommand);
return true;
}
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
{
pCommand->SetNext(NULL);
icvar->RegisterConCommandBase(pCommand);
return true;
}
void SMConVarAccessor::MarkCommandsAsGameDLL()
{
for (List<ConCommandBase*>::iterator iter = m_RegisteredCommands.begin();
iter != m_RegisteredCommands.end(); ++iter)
{
(*iter)->AddFlags(FCVAR_GAMEDLL);
}
}
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
{
ConCommandBase *ptr = icvar->GetCommands();
if (ptr == pCommand)
{
s_EternalCommand.BringToFront();
s_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
}
else
{
/* Find us and unregister us */
ConCommandBase *pPrev = NULL;
while (ptr)
{
if (ptr == pCommand)
{
break;
}
pPrev = ptr;
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
}
if (pPrev && ptr == pCommand)
{
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
}
}
}

View File

@ -1,24 +0,0 @@
#ifndef _INCLUDE_CONSOLE_MMS_H_
#define _INCLUDE_CONSOLE_MMS_H_
#include "convar_smm.h"
#include <interface.h>
#include <eiface.h>
#include <sh_list.h>
class SMConVarAccessor : public IConCommandBaseAccessor
{
public:
bool RegisterConCommandBase(ConCommandBase *pCommand);
bool Register(ConCommandBase *pCommand);
void MarkCommandsAsGameDLL();
void Unregister(ConCommandBase *pCommand);
void UnregisterGameDLLCommands();
private:
SourceHook::List<ConCommandBase*> m_RegisteredCommands;
};
extern SMConVarAccessor g_SMConVarAccessor;
#endif //_INCLUDE_CONSOLE_MMS_H_

View File

@ -1,523 +0,0 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: 2007-02-08 04:19:19 -0500 (Thu, 08 Feb 2007) $
//
//-----------------------------------------------------------------------------
// $NoKeywords: $
//=============================================================================//
#ifndef CONVAR_H
#define CONVAR_H
#if _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#ifdef _WIN32
#define FORCEINLINE_CVAR FORCEINLINE
#elif _LINUX
#define FORCEINLINE_CVAR __inline__ FORCEINLINE
#else
#error "implement me"
#endif
// The default, no flags at all
#define FCVAR_NONE 0
// Command to ConVars and ConCommands
// ConVar Systems
#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
#define FCVAR_LAUNCHER (1<<1) // defined by launcher
#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system.
#define FCVAR_DATACACHE (1<<19) // Defined by the datacache system.
#define FCVAR_STUDIORENDER (1<<15) // Defined by the studiorender system.
#define FCVAR_FILESYSTEM (1<<21) // Defined by the file system.
#define FCVAR_PLUGIN (1<<18) // Defined by a 3rd party plugin.
#define FCVAR_TOOLSYSTEM (1<<20) // Defined by an IToolSystem library
#define FCVAR_SOUNDSYSTEM (1<<23) // Defined by the soundsystem library
#define FCVAR_INPUTSYSTEM (1<<25) // Defined by the inputsystem dll
#define FCVAR_NETWORKSYSTEM (1<<26) // Defined by the network system
// NOTE!! if you add a cvar system, add it here too!!!!
// the engine lacks a cvar flag, but needs it for xbox
// an engine cvar is thus a cvar not marked with any other system
#define FCVAR_NON_ENGINE ((FCVAR_LAUNCHER|FCVAR_GAMEDLL|FCVAR_CLIENTDLL|FCVAR_MATERIAL_SYSTEM|FCVAR_DATACACHE|FCVAR_STUDIORENDER|FCVAR_FILESYSTEM|FCVAR_PLUGIN|FCVAR_TOOLSYSTEM|FCVAR_SOUNDSYSTEM|FCVAR_INPUTSYSTEM|FCVAR_NETWORKSYSTEM))
// ConVar only
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
#define FCVAR_NOTIFY (1<<8) // notifies players when changed
#define FCVAR_USERINFO (1<<9) // changes the client's info string
#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
// It's a ConVar that's shared between the client and the server.
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
// client, of course )
// If a change is requested it must come from the console (i.e., no remote client changes)
// If a value is changed while a server is active, it's replicated to all connected clients
#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox
// #define FCVAR_AVAILABLE (1<<27)
// #define FCVAR_AVAILABLE (1<<28)
// #define FCVAR_AVAILABLE (1<<29)
// #define FCVAR_AVAILABLE (1<<30)
// #define FCVAR_AVAILABLE (1<<31)
class ConVar;
class ConCommand;
class ConCommandBase;
// Any executable that wants to use ConVars need to implement one of
// these to hook up access to console variables.
class IConCommandBaseAccessor
{
public:
// Flags is a combination of FCVAR flags in cvar.h.
// hOut is filled in with a handle to the variable.
virtual bool RegisterConCommandBase( ConCommandBase *pVar )=0;
};
// You don't have to instantiate one of these, just call its
// OneTimeInit function when your executable is initializing.
class ConCommandBaseMgr
{
public:
// Call this ONCE when the executable starts up.
static void OneTimeInit( IConCommandBaseAccessor *pAccessor );
#ifdef _XBOX
static bool Fixup( ConCommandBase* pConCommandBase );
#ifndef _RETAIL
static void PublishCommands( bool bForce );
#endif
#endif
};
// Called when a ConVar changes value
typedef void ( *FnChangeCallback )( ConVar *var, char const *pOldString );
// Called when a ConCommand needs to execute
typedef void ( *FnCommandCallback )( void );
#define COMMAND_COMPLETION_MAXITEMS 64
#define COMMAND_COMPLETION_ITEM_LENGTH 64
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
typedef int ( *FnCommandCompletionCallback )( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
//-----------------------------------------------------------------------------
// Purpose: The base console invoked command/cvar interface
//-----------------------------------------------------------------------------
class ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class ConVar;
friend class ConCommand;
public:
ConCommandBase( void );
ConCommandBase( char const *pName, char const *pHelpString = 0,
int flags = 0 );
virtual ~ConCommandBase( void );
virtual bool IsCommand( void ) const;
// Check flag
virtual bool IsBitSet( int flag ) const;
// Set flag
virtual void AddFlags( int flags );
// Return name of cvar
virtual char const *GetName( void ) const;
// Return help text for cvar
virtual char const *GetHelpText( void ) const;
// Deal with next pointer
const ConCommandBase *GetNext( void ) const;
void SetNext( ConCommandBase *next );
virtual bool IsRegistered( void ) const;
// Global methods
static ConCommandBase const *GetCommands( void );
static void AddToList( ConCommandBase *var );
static void RemoveFlaggedCommands( int flag );
static void RevertFlaggedCvars( int flag );
static ConCommandBase const *FindCommand( char const *name );
protected:
virtual void Create( char const *pName, char const *pHelpString = 0,
int flags = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
// Internal copy routine ( uses new operator from correct module )
char *CopyString( char const *from );
// Next ConVar in chain
ConCommandBase *m_pNext;
private:
// Has the cvar been added to the global list?
bool m_bRegistered;
// Static data
char const *m_pszName;
char const *m_pszHelpString;
// ConVar flags
int m_nFlags;
protected:
// ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through
// all the console variables and registers them.
static ConCommandBase *s_pConCommandBases;
// ConVars in this executable use this 'global' to access values.
static IConCommandBaseAccessor *s_pAccessor;
};
//-----------------------------------------------------------------------------
// Purpose: The console invoked command
//-----------------------------------------------------------------------------
class ConCommand : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
#ifdef _STATIC_LINKED
friend class G_ConCommand;
friend class C_ConCommand;
friend class M_ConCommand;
friend class S_ConCommand;
friend class D_ConCommand;
#endif
public:
typedef ConCommandBase BaseClass;
ConCommand( void );
ConCommand( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
virtual ~ConCommand( void );
virtual bool IsCommand( void ) const;
virtual int AutoCompleteSuggest( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
virtual bool CanAutoComplete( void );
// Invoke the function
virtual void Dispatch( void );
private:
virtual void Create( char const *pName, FnCommandCallback callback,
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
// Call this function when executing the command
FnCommandCallback m_fnCommandCallback;
FnCommandCompletionCallback m_fnCompletionCallback;
bool m_bHasCompletionCallback;
public:
FnCommandCallback GetCallback() { return m_fnCommandCallback; }
};
//-----------------------------------------------------------------------------
// Purpose: A console variable
//-----------------------------------------------------------------------------
class ConVar : public ConCommandBase
{
friend class ConCommandBaseMgr;
friend class CCvar;
friend class CDefaultCvar;
#ifdef _STATIC_LINKED
friend class G_ConVar;
friend class C_ConVar;
friend class M_ConVar;
friend class S_ConVar;
friend class D_ConVar;
#endif
public:
typedef ConCommandBase BaseClass;
ConVar( char const *pName, char const *pDefaultValue, int flags = 0);
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, FnChangeCallback callback );
ConVar( char const *pName, char const *pDefaultValue, int flags,
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
FnChangeCallback callback );
virtual ~ConVar( void );
virtual bool IsBitSet( int flag ) const;
virtual char const* GetHelpText( void ) const;
virtual bool IsRegistered( void ) const;
virtual char const *GetName( void ) const;
virtual void AddFlags( int flags );
virtual bool IsCommand( void ) const;
// Install a change callback (there shouldn't already be one....)
void InstallChangeCallback( FnChangeCallback callback );
// Retrieve value
FORCEINLINE_CVAR float GetFloat( void ) const;
FORCEINLINE_CVAR int GetInt( void ) const;
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
FORCEINLINE_CVAR char const *GetString( void ) const;
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
// from alloc/free across dll/exe boundaries.
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
virtual void SetValue( char const *value );
virtual void SetValue( float value );
virtual void SetValue( int value );
// Reset to default value
void Revert( void );
// True if it has a min/max setting
bool GetMin( float& minVal ) const;
bool GetMax( float& maxVal ) const;
char const *GetDefault( void ) const;
static void RevertAll( void );
private:
// Called by CCvar when the value of a var is changing.
virtual void InternalSetValue(char const *value);
// For CVARs marked FCVAR_NEVER_AS_STRING
virtual void InternalSetFloatValue( float fNewValue );
virtual void InternalSetIntValue( int nValue );
virtual bool ClampValue( float& value );
virtual void ChangeStringValue( char const *tempVal );
virtual void Create( char const *pName, char const *pDefaultValue, int flags = 0,
char const *pHelpString = 0, bool bMin = false, float fMin = 0.0,
bool bMax = false, float fMax = false, FnChangeCallback callback = 0 );
// Used internally by OneTimeInit to initialize.
virtual void Init();
private:
// This either points to "this" or it points to the original declaration of a ConVar.
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
ConVar *m_pParent;
// Static data
char const *m_pszDefaultValue;
// Value
// Dynamically allocated
char *m_pszString;
int m_StringLength;
// Values
float m_fValue;
int m_nValue;
// Min/Max values
bool m_bHasMin;
float m_fMinVal;
bool m_bHasMax;
float m_fMaxVal;
// Call this function when ConVar changes
FnChangeCallback m_fnChangeCallback;
};
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a float
// Output : float
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
{
return m_pParent->m_fValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as an int
// Output : int
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
{
return m_pParent->m_nValue;
}
//-----------------------------------------------------------------------------
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
// Output : char const *
//-----------------------------------------------------------------------------
FORCEINLINE_CVAR char const *ConVar::GetString( void ) const
{
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
{
return "FCVAR_NEVER_AS_STRING";
}
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
}
#ifdef _STATIC_LINKED
// identifies subsystem via piggybacking constructors with flags
class G_ConCommand : public ConCommand
{
public:
G_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_GAMEDLL, completionFunc) {}
};
class C_ConCommand : public ConCommand
{
public:
C_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_CLIENTDLL, completionFunc) {}
};
class M_ConCommand : public ConCommand
{
public:
M_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_MATERIAL_SYSTEM, completionFunc) {}
};
class S_ConCommand : public ConCommand
{
public:
S_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_STUDIORENDER, completionFunc) {}
};
class D_ConCommand : public ConCommand
{
public:
D_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_DATACACHE, completionFunc) {}
};
typedef void ( *G_FnChangeCallback )( G_ConVar *var, char const *pOldString );
typedef void ( *C_FnChangeCallback )( C_ConVar *var, char const *pOldString );
typedef void ( *M_FnChangeCallback )( M_ConVar *var, char const *pOldString );
typedef void ( *S_FnChangeCallback )( S_ConVar *var, char const *pOldString );
typedef void ( *D_FnChangeCallback )( D_ConVar *var, char const *pOldString );
class G_ConVar : public ConVar
{
public:
G_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, (FnChangeCallback)callback ) {}
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class C_ConVar : public ConVar
{
public:
C_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, (FnChangeCallback)callback ) {}
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class M_ConVar : public ConVar
{
public:
M_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, (FnChangeCallback)callback ) {}
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class S_ConVar : public ConVar
{
public:
S_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, (FnChangeCallback)callback ) {}
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, S_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
class D_ConVar : public ConVar
{
public:
D_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, (FnChangeCallback)callback ) {}
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, D_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
};
// redirect these declarations to their specific subsystem
#ifdef GAME_DLL
#define ConCommand G_ConCommand
#define ConVar G_ConVar
#endif
#ifdef CLIENT_DLL
#define ConCommand C_ConCommand
#define ConVar C_ConVar
#endif
#ifdef MATERIALSYSTEM_DLL
#define ConCommand M_ConCommand
#define ConVar M_ConVar
#endif
#ifdef STUDIORENDER_DLL
#define ConCommand S_ConCommand
#define ConVar S_ConVar
#endif
#ifdef DATACACHE_DLL
#define ConCommand D_ConCommand
#define ConVar D_ConVar
#endif
#endif // _STATIC_LINKED
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND( name, description ) \
static void name(); \
static ConCommand name##_command( #name, name, description ); \
static void name()
//-----------------------------------------------------------------------------
// Purpose: Utility to quicky generate a simple console command
//-----------------------------------------------------------------------------
#define CON_COMMAND_F( name, description, flags ) \
static void name(); \
static ConCommand name##_command( #name, name, description, flags ); \
static void name()
#endif // CONVAR_H

View File

@ -1,502 +0,0 @@
#include "convar_smm.h"
#include <eiface.h>
#include <tier0/icommandline.h>
#include <tier1/utldict.h>
#include <sourcehook/sourcehook.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "provider_util.h"
#include "provider_ep1.h"
#include "console.h"
/* Types */
typedef void (*CONPRINTF_FUNC)(const char *, ...);
struct UsrMsgInfo
{
int size;
String name;
};
/* Imports */
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
/* Functions */
CONPRINTF_FUNC ExtractRemotePrinter();
bool CacheUserMessages();
void ClientCommand(edict_t *pEdict);
/* Variables */
bool usermsgs_extracted = false;
CVector<UsrMsgInfo> usermsgs_list;
CONPRINTF_FUNC echo_msg_func = NULL;
METAMOD_COMMAND client_cmd_handler = NULL;
ICvar *icvar = NULL;
ISourceHook *g_SHPtr = NULL;
IVEngineServer *engine = NULL;
IServerGameDLL *server = NULL;
IServerGameClients *gameclients = NULL;
unsigned int g_PLID;
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
void BaseProvider::ConsolePrint(const char *str)
{
if (echo_msg_func != NULL)
{
echo_msg_func("%s", str);
}
else
{
Msg("%s", str);
}
}
void BaseProvider::Notify_DLLInit_Pre()
{
echo_msg_func = ExtractRemotePrinter();
usermsgs_extracted = CacheUserMessages();
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false);
}
bool BaseProvider::IsRemotePrintingAvailable()
{
return (echo_msg_func != NULL);
}
void BaseProvider::ClientConsolePrint(edict_t *client, const char *message)
{
engine->ClientPrintf(client, message);
}
void BaseProvider::ServerCommand(const char *cmd)
{
engine->ServerCommand(cmd);
}
const char *BaseProvider::GetConVarString(ConVar *convar)
{
return convar->GetString();
}
bool BaseProvider::IsConCommandBaseACommand(ConCommandBase *pCommand)
{
return pCommand->IsCommand();
}
bool BaseProvider::IsSourceEngineBuildCompatible(int build)
{
return (build == SOURCE_ENGINE_ORIGINAL
|| build == SOURCE_ENGINE_EPISODEONE);
}
const char *BaseProvider::GetCommandLineValue(const char *key, const char *defval)
{
if (key[0] == '-' || key[0] == '+')
{
return CommandLine()->ParmValue(key, defval);
}
else
{
const char *val;
if ((val = icvar->GetCommandLineValue(key)) == NULL)
{
return defval;
}
return val;
}
}
int BaseProvider::TryServerGameDLL(const char *iface)
{
if (strncmp(iface, "ServerGameDLL", 13) != 0)
{
return 0;
}
return atoi(&iface[13]);
}
bool BaseProvider::LogMessage(const char *buffer)
{
if (!engine)
{
return false;
}
engine->LogPrint(buffer);
return true;
}
bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo)
{
SourceHook::MemFuncInfo mfi = {true, -1, 0, 0};
if (hook == ProvidedHook_LevelInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelInit, mfi);
}
else if (hook == ProvidedHook_LevelShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::LevelShutdown, mfi);
}
else if (hook == ProvidedHook_GameInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
}
else if (hook == ProvidedHook_DLLShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
}
else if (hook == ProvidedHook_DLLInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
}
*pInfo = mfi;
return (mfi.thisptroffs >= 0);
}
void BaseProvider::DisplayError(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Error(buffer);
}
void BaseProvider::DisplayWarning(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Warning(buffer);
}
IConCommandBaseAccessor *BaseProvider::GetConCommandBaseAccessor()
{
return &g_SMConVarAccessor;
}
bool BaseProvider::RegisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Register(pCommand);
}
void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand)
{
return g_SMConVarAccessor.Unregister(pCommand);
}
int BaseProvider::GetUserMessageCount()
{
if (!usermsgs_extracted)
{
return -1;
}
return (int)usermsgs_list.size();
}
int BaseProvider::FindUserMessage(const char *name, int *size)
{
for (size_t i = 0; i < usermsgs_list.size(); i++)
{
if (usermsgs_list[i].name.compare(name) == 0)
{
if (size)
{
*size = usermsgs_list[i].size;
}
return (int)i;
}
}
return -1;
}
const char *BaseProvider::GetUserMessage(int index, int *size)
{
if (!usermsgs_extracted || index < 0 || index >= (int)usermsgs_list.size())
{
return NULL;
}
if (size)
{
*size = usermsgs_list[index].size;
}
return usermsgs_list[index].name.c_str();
}
const char *BaseProvider::GetGameDescription()
{
return server->GetGameDescription();
}
void BaseProvider::SetClientCommandHandler(METAMOD_COMMAND callback)
{
client_cmd_handler = callback;
}
class GlobCommand : public IMetamodSourceCommandInfo
{
public:
unsigned int GetArgCount()
{
return engine->Cmd_Argc() - 1;
}
const char *GetArg(unsigned int num)
{
return engine->Cmd_Argv(num);
}
const char *GetArgString()
{
return engine->Cmd_Args();
}
};
void ClientCommand(edict_t *pEdict)
{
if (client_cmd_handler)
{
GlobCommand cmd;
bool result;
if ((result = client_cmd_handler(pEdict, &cmd)) == true)
{
RETURN_META(MRES_SUPERCEDE);
}
}
}
//////////////////////////////////////////////////////////////////////////
//THERE BE HAX HERE!!!! DON'T TELL ALFRED, BUT GABE WANTED IT THAT WAY. //
// (note: you can find the offset by looking for the text //
// "Echo text to console", you'll find the callback cmd pushed on the //
// stack.) //
//////////////////////////////////////////////////////////////////////////
#define SIGLEN 8
#define ENGINE486_SIG "\x55\x89\xE5\x53\x83\xEC\x14\xBB"
#define ENGINE486_OFFS 40
#define ENGINE686_SIG "\x53\x83\xEC\x08\xBB\x01\x00\x00"
#define ENGINE686_OFFS 50
#define ENGINEAMD_SIG "\x53\x51\xBB\x01\x00\x00\x00\x51"
#define ENGINEAMD_OFFS 47
#define ENGINEW32_SIG "\xA1\x2A\x2A\x2A\x2A\x56\xBE\x01"
#define ENGINEW32_OFFS 38
#define IA32_CALL 0xE8
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
{
unsigned char *addr1 = (unsigned char *)_addr1;
unsigned char *addr2 = (unsigned char *)_addr2;
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
{
continue;
}
if (addr1[i] != addr2[i])
{
return false;
}
}
return true;
}
//Thanks to fysh for the idea of extracting info from "echo" and for
// having the original offsets at hand!
CONPRINTF_FUNC ExtractRemotePrinter()
{
ConCommandBase *pBase = icvar->GetCommands();
unsigned char *ptr = NULL;
FnCommandCallback callback = NULL;
int offs = 0;
while (pBase)
{
if (strcmp(pBase->GetName(), "echo") == 0)
{
callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback;
#ifdef OS_LINUX
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
{
offs = ENGINE486_OFFS;
}
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
{
offs = ENGINE686_OFFS;
}
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
{
offs = ENGINEAMD_OFFS;
}
#elif defined OS_WIN32 // Only one Windows engine binary so far...
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
{
offs = ENGINEW32_OFFS;
}
#endif
if (!offs || ptr[offs - 1] != IA32_CALL)
{
return NULL;
}
//get the relative offset
void *addr = *((void **)(ptr + offs));
//add the base offset, to the ip (which is the address+offset + 4 bytes for next instruction)
return (CONPRINTF_FUNC)((unsigned long)addr + (unsigned long)(ptr + offs) + 4);
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
return NULL;
}
//////////////////////////////////////////////////////////////////////
// EVEN MORE HACKS HERE! YOU HAVE BEEN WARNED! //
// Signatures necessary in finding the pointer to the CUtlDict that //
// stores user message information. //
// IServerGameDLL::GetUserMessageInfo() normally crashes with bad //
// message indices. This is our answer to it. Yuck! <:-( //
//////////////////////////////////////////////////////////////////////
#ifdef OS_WIN32
/* General Windows sig */
#define MSGCLASS_SIGLEN 7
#define MSGCLASS_SIG "\x8B\x0D\x2A\x2A\x2A\x2A\x56"
#define MSGCLASS_OFFS 2
/* Dystopia Wimdows hack */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
#define MSGCLASS_SIG "\x53\x83\xEC\x2A\x8B\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS_OFFS 9
/* Frame pointer sig */
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x55\x89\xE5\x53\x83\xEC\x2A\x8B\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x89"
#define MSGCLASS2_OFFS 11
#endif
struct UserMessage
{
int size;
const char *name;
};
typedef CUtlDict<UserMessage *, int> UserMsgDict;
/* This is the ugliest function in all of SourceMM */
bool CacheUserMessages()
{
/* Get address of original GetUserMessageInfo() */
char *vfunc = NULL;
/* :TODO: fix this for v5 (char *)SH_GET_ORIG_VFNPTR_ENTRY(server, &IServerGameDLL::GetUserMessageInfo); */
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc += *reinterpret_cast<int *>(vfunc + 1) + 5;
}
CUtlDict<UserMessage *, int> *dict = NULL;
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
}
else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN))
{
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
/* Get the address of the CUtlRBTree */
char *rbtree = *reinterpret_cast<char **>(vfunc + MSGCLASS2_OFFS);
/* CUtlDict should be 8 bytes before the CUtlRBTree (hacktacular!) */
dict = reinterpret_cast<UserMsgDict *>(rbtree - 8);
#elif defined OS_LINUX
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS2_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
}
else if (vcmp(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)
{
int msg_count = dict->Count();
/* Ensure that count is within bounds of an unsigned byte, because that's what engine supports */
if (msg_count < 0 || msg_count > 255)
{
return false;
}
UserMessage *msg;
UsrMsgInfo u_msg;
/* Cache messages in our CUtlDict */
for (int i = 0; i < msg_count; i++)
{
msg = dict->Element(i);
u_msg.name = msg->name;
u_msg.size = msg->size;
usermsgs_list.push_back(u_msg);
}
return true;
}
return false;
}

View File

@ -1,52 +0,0 @@
#ifndef _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#define _INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_
#include <metamod_provider.h>
#include <ISmmAPI.h>
#include "oslink.h"
using namespace SourceMM;
using namespace SourceHook;
class BaseProvider : public IMetamodSourceProvider
{
public:
virtual bool IsSourceEngineBuildCompatible(int build);
virtual bool GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo);
virtual bool LogMessage(const char *buffer);
virtual const char *GetCommandLineValue(const char *key, const char *defval);
virtual void ConsolePrint(const char *msg);
virtual bool IsRemotePrintingAvailable();
virtual void ClientConsolePrint(edict_t *client, const char *msg);
virtual IServerPluginCallbacks *GetVSPCallbacks(const char *iface);
virtual void DisplayError(const char *fmt, ...);
virtual void DisplayWarning(const char *fmt, ...);
virtual int TryServerGameDLL(const char *iface);
virtual void Notify_DLLInit_Pre();
virtual void ServerCommand(const char *cmd);
virtual ConVar *CreateConVar(const char *name,
const char *defval,
const char *help,
int flags);
virtual const char *GetConVarString(ConVar *convar);
virtual void CreateCommand(const char *name,
METAMOD_COMMAND callback,
const char *help);
virtual void SetClientCommandHandler(METAMOD_COMMAND callback);
virtual const char *GetGameDescription();
virtual IConCommandBaseAccessor *GetConCommandBaseAccessor();
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
virtual void UnregisterConCommandBase(ConCommandBase *pCommand);
virtual bool IsConCommandBaseACommand(ConCommandBase *pCommand);
virtual int GetUserMessageCount();
virtual int FindUserMessage(const char *name, int *size=NULL);
virtual const char *GetUserMessage(int index, int *size=NULL);
};
extern IVEngineServer *engine;
extern IServerGameDLL *server;
extern IServerGameClients *gameclients;
extern ICvar *icvar;
#endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_

View File

@ -1,15 +0,0 @@
#include "provider_util.h"
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
{
size_t len = vsnprintf(buffer, maxlength, fmt, params);
if (len >= maxlength)
{
len = maxlength - 1;
buffer[len] = '\0';
}
return len;
}

View File

@ -1,11 +0,0 @@
#ifndef _METAMOD_SOURCE_PROVIDER_UTIL_H_
#define _METAMOD_SOURCE_PROVIDER_UTIL_H_
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params);
#endif //_METAMOD_SOURCE_PROVIDER_UTIL_H_

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,14 @@
// 3 - Added "hook loop status variable"
// 4 - Reentrant
#define SH_IFACE_VERSION 4
#define SH_IMPL_VERSION 3
// Impl versions:
// ???
// 4 - addition of hook ids and vp hooks (with them, AddHookNew and RemoveHookNew)
// This is not a SH_IFACE_VERSION change so that old plugins continue working!
// 5 - addition of direct vp hooks (new hook mode; from now on AddHookNew checks for
// invalid hookmode -> impl version won't have to change because of things like this)
#define SH_IMPL_VERSION 5
// Hookman version:
// 1 - Support for recalls, performance optimisations
@ -291,15 +298,12 @@ namespace SourceHook
}
};
template<class B> struct CallClass
template<class B> struct DeprecatedCallClass
{
virtual B *GetThisPtr() = 0;
virtual void *GetOrigFunc(int vtbloffs, int vtblidx) = 0;
};
typedef CallClass<void> GenericCallClass;
typedef CallClass<EmptyClass> ManualCallClass;
// 09.08.2008 (6 AM, I just woke up, the others are still sleeping so i finally can use this notebook !!)
// - Today is an important day.
// I'm adding support for functions which return references.
@ -401,14 +405,14 @@ namespace SourceHook
* @param iface The interface pointer
* @param size Size of the class instance
*/
virtual GenericCallClass *GetCallClass(void *iface, size_t size) = 0;
virtual DeprecatedCallClass<void> *GetCallClass(void *iface, size_t size) = 0;
/**
* @brief Release a callclass
*
* @param ptr Pointer to the callclass
*/
virtual void ReleaseCallClass(GenericCallClass *ptr) = 0;
virtual void ReleaseCallClass(DeprecatedCallClass<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
@ -479,7 +483,65 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr) = 0;
//!<
/**
* @brief Modes for the new AddHook
*/
enum AddHookMode
{
Hook_Normal,
Hook_VP,
Hook_DVP
};
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook)
* @param iface The interface pointer
* @param ifacesize The size of the class iface points to
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post) = 0;
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid) = 0;
/**
* @brief Makes sure that hooks are going to be ignored on the next call of vfnptr
*
* @param plug The unique identifier of the plugin that calls this function
* @param vfnptr The virtual function pointer of the function in question
*/
virtual void SetIgnoreHooks(Plugin plug, void *vfnptr) = 0;
/**
* @brief Reverses SetIgnoreHooks' effect
*
* @param plug The unique identifier of the plugin that calls this function
* @param vfnptr The virtual function pointer of the function in question
*/
virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr) = 0;
/**
* @brief Finds the original entry of a virtual function pointer
*
* @param vfnptr The virtual function pointer
* @return The original entry if the virtual function pointer has been patched; NULL otherwise.
*/
virtual void *GetOrigVfnPtrEntry(void *vfnptr) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
@ -510,6 +572,50 @@ namespace SourceHook
return &ref;
}
};
// For source-level compatibility
template <class T> struct CallClass
{
T *ptr;
CallClass(T *p) : ptr(p)
{
}
operator T*()
{
return ptr;
}
};
typedef CallClass<void> GenericCallClass;
typedef CallClass<EmptyClass> ManualCallClass;
template <class T>
CallClass<T> *GetCallClass(T *p)
{
return new CallClass<T>(p);
}
template <class T>
void ReleaseCallClass(CallClass<T> *p)
{
delete p;
}
template <class X, class MFP>
void *GetOrigVfnPtrEntry(X *pInstance, MFP mfp, ISourceHook *pSH)
{
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
SourceHook::GetFuncInfo(pInstance, mfp, info);
void *vfnptr = reinterpret_cast<void*>(
*reinterpret_cast<void***>(reinterpret_cast<char*>(pInstance) + info.thisptroffs + info.vtbloffs) + info.vtblindex);
void *origentry = pSH->GetOrigVfnPtrEntry(vfnptr);
return origentry ? origentry : *reinterpret_cast<void**>(vfnptr);
}
}
/************************************************************************/
@ -614,31 +720,6 @@ namespace SourceHook
RETURN_META_VALUE(MRES_SUPERCEDE, (thisptr->*(u.mfp)) newparams); \
} while (0)
/**
* @brief Get/generate callclass for an interface pointer
*
* @param ifaceptr The interface pointer
*/
template<class ifacetype>
inline SourceHook::CallClass<ifacetype> *SH_GET_CALLCLASS_R(SourceHook::ISourceHook *shptr, ifacetype *ptr)
{
return reinterpret_cast<SourceHook::CallClass<ifacetype>*>(
shptr->GetCallClass(reinterpret_cast<void*>(ptr), sizeof(ifacetype)));
}
template<class ifacetype>
inline SourceHook::CallClass<ifacetype> *SH_GET_MCALLCLASS_R(SourceHook::ISourceHook *shptr, ifacetype *ptr, int ifacesize)
{
return reinterpret_cast<SourceHook::CallClass<ifacetype>*>(
shptr->GetCallClass(reinterpret_cast<void*>(ptr), ifacesize));
}
template<class ifacetype>
inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::CallClass<ifacetype> *ptr)
{
shptr->ReleaseCallClass(reinterpret_cast<SourceHook::GenericCallClass*>(ptr));
}
#define SH_MANUALHOOK_RECONFIGURE(hookname, pvtblindex, pvtbloffs, pthisptroffs) \
do { \
SH_GLOB_SHPTR->RemoveHookManager(SH_GLOB_PLUGPTR, SH_MFHCls(hookname)::HookManPubFunc); \
@ -647,41 +728,83 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_MFHCls(hookname)::ms_MFI.vtbloffs = pvtbloffs; \
} while (0)
#define SH_GET_CALLCLASS(ptr) SH_GET_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
#define SH_GET_MCALLCLASS(ptr, size) SH_GET_MCALLCLASS_R(SH_GLOB_SHPTR, reinterpret_cast<SourceHook::EmptyClass*>(ptr), size)
#define SH_RELEASE_CALLCLASS(ptr) SH_RELEASE_CALLCLASS_R(SH_GLOB_SHPTR, ptr)
#define SH_GET_ORIG_VFNPTR_ENTRY(inst, mfp) (SourceHook::GetOrigVfnPtrEntry(inst, mfp, SH_GLOB_SHPTR))
// For source-level compatibility
#define SH_GET_CALLCLASS(ptr) SourceHook::GetCallClass(ptr)
#define SH_GET_MCALLCLASS(ptr, size) SourceHook::GetCallClass(reinterpret_cast<SourceHook::EmptyClass*>(ptr))
#define SH_RELEASE_CALLCLASS(ptr) SourceHook::ReleaseCallClass(ptr)
// New ADD / REMOVE macros.
#define SH_STATIC(func) fastdelegate::MakeDelegate(func)
#define SH_MEMBER(inst, func) fastdelegate::MakeDelegate(inst, func)
#define SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(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_FHRemove##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, fastdelegate::MakeDelegate(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)
post, handler)
#define SH_ADD_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
#define SH_REMOVE_MANUALHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, fastdelegate::MakeDelegate(handler_inst, handler_func), post)
__SourceHook_FHMRemove##hookname(reinterpret_cast<void*>(ifaceptr), post, handler)
#define SH_ADD_VPHOOK(ifacetype, ifacefunc, ifaceptr, handler, post) \
__SourceHook_FHVPAdd##ifacetype##ifacefunc((void*)SourceHook::implicit_cast<ifacetype*>(ifaceptr), \
post, handler, false)
#define SH_ADD_DVPHOOK(ifacetype, ifacefunc, vtableptr, handler, post) \
__SourceHook_FHVPAdd##ifacetype##ifacefunc(reinterpret_cast<void*>(vtableptr), \
post, handler, true)
#define SH_ADD_MANUALVPHOOK(hookname, ifaceptr, handler, post) \
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(ifaceptr), post, handler, false)
#define SH_ADD_MANUALDVPHOOK(hookname, vtableptr, handler, post) \
__SourceHook_FHMVPAdd##hookname(reinterpret_cast<void*>(vtableptr), post, handler, true)
#define SH_REMOVE_HOOK_ID(hookid) \
(SH_GLOB_SHPTR->RemoveHookByID(SH_GLOB_PLUGPTR, hookid))
// Old macros
// !! These are now deprecated. Instead, use one of these:
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_HOOK_STATICFUNC(ifacetype, ifacefunc, ifaceptr, handler, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_HOOK_MEMFUNC(ifacetype, ifacefunc, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_HOOK(ifacetype, ifacefunc, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_ADD_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_ADD_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_ADD_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
// SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(inst, func), post)
#define SH_REMOVE_MANUALHOOK_STATICFUNC(hookname, ifaceptr, handler, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_STATIC(handler), post)
#define SH_REMOVE_MANUALHOOK_MEMFUNC(hookname, ifaceptr, handler_inst, handler_func, post) \
SH_REMOVE_MANUALHOOK(hookname, ifaceptr, SH_MEMBER(handler_inst, handler_func), post)
#define SH_NOATTRIB
@ -716,6 +839,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -760,7 +885,7 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_FHCls(ifacetype,ifacefunc,overload) SH_FHCls(ifacetype,ifacefunc,overload)::ms_Inst; \
::SourceHook::MemFuncInfo SH_FHCls(ifacetype,ifacefunc,overload)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_FHCls(ifacetype,ifacefunc,overload)::ms_HI; \
bool __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
int __SourceHook_FHAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
using namespace ::SourceHook; \
@ -769,10 +894,24 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, mfi.thisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, mfi.thisptroffs, \
SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
int __SourceHook_FHVPAdd##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler, bool direct) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(funcptr, mfi); \
if (mfi.thisptroffs < 0 || !mfi.isVirtual) \
return false; /* No non-virtual functions / virtual inheritance supported */ \
\
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, \
direct ? ::SourceHook::ISourceHook::Hook_DVP : ::SourceHook::ISourceHook::Hook_VP, \
iface, mfi.thisptroffs, SH_FHCls(ifacetype,ifacefunc,overload)::HookManPubFunc, \
new CSHDelegate<SH_FHCls(ifacetype,ifacefunc,overload)::FD>(handler), post); \
} \
bool __SourceHook_FHRemove##ifacetype##ifacefunc(void *iface, bool post, \
SH_FHCls(ifacetype,ifacefunc,overload)::FD handler) \
{ \
@ -811,6 +950,8 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
/* Verify interface version */ \
if (SH_GLOB_SHPTR->GetIfaceVersion() != SH_IFACE_VERSION) \
return 1; \
if (SH_GLOB_SHPTR->GetImplVersion() < SH_IMPL_VERSION) \
return 1; \
\
if (action == HA_GetInfo) \
{ \
@ -843,13 +984,21 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
SH_MFHCls(hookname) SH_MFHCls(hookname)::ms_Inst; \
::SourceHook::MemFuncInfo SH_MFHCls(hookname)::ms_MFI; \
::SourceHook::IHookManagerInfo *SH_MFHCls(hookname)::ms_HI; \
bool __SourceHook_FHMAdd##hookname(void *iface, bool post, \
int __SourceHook_FHMAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
return SH_GLOB_SHPTR->AddHook(SH_GLOB_PLUGPTR, iface, pthisptroffs, \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, ::SourceHook::ISourceHook::Hook_Normal, iface, pthisptroffs, \
SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \
int __SourceHook_FHMVPAdd##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler, bool direct) \
{ \
return SH_GLOB_SHPTR->AddHookNew(SH_GLOB_PLUGPTR, \
direct ? ::SourceHook::ISourceHook::Hook_DVP : ::SourceHook::ISourceHook::Hook_VP, \
iface, pthisptroffs, SH_MFHCls(hookname)::HookManPubFunc, \
new ::SourceHook::CSHDelegate<SH_MFHCls(hookname)::FD>(handler), post); \
} \
bool __SourceHook_FHMRemove##hookname(void *iface, bool post, \
SH_MFHCls(hookname)::FD handler) \
{ \
@ -1127,136 +1276,109 @@ inline void SH_RELEASE_CALLCLASS_R(SourceHook::ISourceHook *shptr, SourceHook::C
//////////////////////////////////////////////////////////////////////////
// SH_CALL
#if SH_COMP == SH_COMP_MSVC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
#define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
{ \
RetType(EmptyClass::*mfpnew)prms; \
void *addr; \
} u; \
u.addr = origfunc; \
\
void *adjustedthisptr = reinterpret_cast<void*>(reinterpret_cast<char*>(m_CC->GetThisPtr()) + mfi.thisptroffs); \
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
m_pSH->SetIgnoreHooks(m_Plug, m_VfnPtr); \
RetType tmpret = (m_ThisPtr->*m_MFP)call; \
m_pSH->ResetIgnoreHooks(m_Plug, m_VfnPtr); \
return tmpret; \
}
# define SH_MAKE_MEXECUTABLECLASS_OB(call, prms) \
#define SH_MAKE_EXECUTABLECLASS_OB_void(call, prms) \
{ \
using namespace ::SourceHook; \
char *adjustedthisptr = reinterpret_cast<char*>(m_CC->GetThisPtr()) + m_ThisPtrOffs; \
union \
{ \
RetType(EmptyClass::*mfpnew)prms; \
void *addr; \
} u; \
u.addr = m_CC->GetOrigFunc(m_ThisPtrOffs + m_VtblOffs, m_VtblIdx); \
if (!u.addr) \
u.addr = (*reinterpret_cast<void***>(adjustedthisptr + m_VtblOffs))[m_VtblIdx]; \
\
return (reinterpret_cast<EmptyClass*>(adjustedthisptr)->*u.mfpnew)call; \
m_pSH->SetIgnoreHooks(m_Plug, m_VfnPtr); \
(m_ThisPtr->*m_MFP)call; \
m_pSH->ResetIgnoreHooks(m_Plug, m_VfnPtr); \
}
#elif SH_COMP == SH_COMP_GCC
# define SH_MAKE_EXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(m_CC->GetThisPtr(), m_MFP, mfi); \
void *origfunc = m_CC->GetOrigFunc(mfi.thisptroffs + mfi.vtbloffs, mfi.vtblindex); \
if (!origfunc) \
return (m_CC->GetThisPtr()->*m_MFP)call; \
\
/* It's hooked. Call the original function. */ \
union \
{ \
RetType(EmptyClass::*mfpnew)prms; \
struct \
{ \
void *addr; \
intptr_t adjustor; \
} s; \
} u; \
u.s.addr = origfunc; \
u.s.adjustor = mfi.thisptroffs; \
\
return (reinterpret_cast<EmptyClass*>(m_CC->GetThisPtr())->*u.mfpnew)call; \
}
# define SH_MAKE_MEXECUTABLECLASS_OB(call, prms) \
{ \
using namespace ::SourceHook; \
char *thisptr = reinterpret_cast<char*>(m_CC->GetThisPtr()); \
union \
{ \
RetType(EmptyClass::*mfpnew)prms; \
struct { \
void *addr; \
intptr_t adjustor; \
} s; \
} u; \
u.s.addr = m_CC->GetOrigFunc(m_ThisPtrOffs + m_VtblOffs, m_VtblIdx); \
if (!u.s.addr) \
u.s.addr = (*reinterpret_cast<void***>(thisptr + m_ThisPtrOffs + m_VtblOffs))[m_VtblIdx]; \
\
u.s.adjustor = m_ThisPtrOffs; \
return (reinterpret_cast<EmptyClass*>(thisptr)->*u.mfpnew)call; \
}
#endif
namespace SourceHook
{
@[$1,0,$a:
// Support for $1 arguments
template<class CCType, class MFPType, class RetType@[$2,1,$1:, class Param$2@]> class ExecutableClass$1
// Call Class Wrapper!
template <class T> struct CCW
{
CCType *m_CC;
MFPType m_MFP;
public:
ExecutableClass$1(CCType *cc, MFPType mfp) : m_CC(cc), m_MFP(mfp) { }
RetType operator()(@[$2,1,$1|, :Param$2 p$2@]) const
SH_MAKE_EXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
@[$2,$1+1,$a:
template <@[$3,$1+1,$2|, :class Param$3@]> RetType operator()(@[$3,1,$2|, :Param$3 p$3@]) const
SH_MAKE_EXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
@]
typedef T type;
// Get Real Pointer!
static inline T *GRP(T *p)
{
return p;
}
};
template <class RetType@[$2,1,$1:, class Param$2@]> class MExecutableClass$1
template <class T> struct CCW< CallClass<T> >
{
ManualCallClass *m_CC;
int m_ThisPtrOffs;
int m_VtblIdx;
int m_VtblOffs;
typedef T type;
// Get Real Pointer!
static inline T *GRP(CallClass<T> *p)
{
return p->ptr;
}
};
@[$1,0,$a:
// Support for $1 arguments
template<class ObjType, class MFP, class RetType@[$2,1,$1:, class Param$2@]> class ExecutableClass$1
{
ObjType *m_ThisPtr;
void *m_VfnPtr;
MFP m_MFP;
ISourceHook *m_pSH;
Plugin m_Plug;
public:
MExecutableClass$1(ManualCallClass *cc, int vtbloffs, int vtblidx, int thisptroffs) : m_CC(cc),
m_ThisPtrOffs(thisptroffs), m_VtblIdx(vtblidx), m_VtblOffs(vtbloffs) { }
ExecutableClass$1(ObjType *tp, MFP mfp, void *vp, ISourceHook *pSH, Plugin plug) : m_ThisPtr(tp),
m_VfnPtr(vp), m_MFP(mfp), m_pSH(pSH), m_Plug(plug) { }
RetType operator()(@[$2,1,$1|, :Param$2 p$2@]) const
SH_MAKE_MEXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
SH_MAKE_EXECUTABLECLASS_OB((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
@[$2,$1+1,$a:
template <@[$3,$1+1,$2|, :class Param$3@]> RetType operator()(@[$3,1,$2|, :Param$3 p$3@]) const
SH_MAKE_MEXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
SH_MAKE_EXECUTABLECLASS_OB((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
@]
};
template<class ObjType, class MFP@[$2,1,$1:, class Param$2@]> class ExecutableClass$1<ObjType, MFP, void@[$2,1,$1:, Param$2@]>
{
ObjType *m_ThisPtr;
void *m_VfnPtr;
MFP m_MFP;
ISourceHook *m_pSH;
Plugin m_Plug;
public:
ExecutableClass$1(ObjType *tp, MFP mfp, void *vp, ISourceHook *pSH, Plugin plug) : m_ThisPtr(tp),
m_VfnPtr(vp), m_MFP(mfp), m_pSH(pSH), m_Plug(plug) { }
void operator()(@[$2,1,$1|, :Param$2 p$2@]) const
SH_MAKE_EXECUTABLECLASS_OB_void((@[$2,1,$1|, :p$2@]), (@[$2,1,$1|, :Param$2@]))
@[$2,$1+1,$a:
template <@[$3,$1+1,$2|, :class Param$3@]> void operator()(@[$3,1,$2|, :Param$3 p$3@]) const
SH_MAKE_EXECUTABLECLASS_OB_void((@[$3,1,$2|, :p$3@]), (@[$3,1,$2|, :Param$3@]))
@]
};
@]
}
#define SH__CALL_GET_VFNPTR_NORMAL \
using namespace ::SourceHook; \
MemFuncInfo mfi = {true, -1, 0, 0}; \
GetFuncInfo(CCW<Y>::GRP(ptr), mfp, mfi); \
void *vfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>(reinterpret_cast<char*>(ptr) + mfi.thisptroffs + mfi.vtbloffs) + mfi.vtblindex);
#define SH__CALL_GET_VFNPTR_MANUAL \
using namespace ::SourceHook; \
void *vfnptr = reinterpret_cast<void*>( \
*reinterpret_cast<void***>( (reinterpret_cast<char*>(CCW<Y>::GRP(ptr)) + thisptroffs + vtbloffs) ) + vtblidx); \
/* patch mfp */ \
*reinterpret_cast<void**>(&mfp) = *reinterpret_cast<void**>(vfnptr);
// SH_CALL needs to deduce the return type -> it uses templates and function overloading
// That's why SH_CALL takes two parameters: "mfp2" of type RetType(X::*mfp)(params), and "mfp" of type MFP
// The only purpose of the mfp2 parameter is to extract the return type
@ -1264,24 +1386,30 @@ namespace SourceHook
@[$1,0,$a:
// Support for $1 arguments
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]))
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]), SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
SH__CALL_GET_VFNPTR_NORMAL
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr),
mfp, vfnptr, shptr, plug);
}
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@])const)
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@])const, SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
SH__CALL_GET_VFNPTR_NORMAL
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr),
mfp, vfnptr, shptr, plug);
}
template <class X, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::MExecutableClass$1<RetType@[$2,1,$1:, Param$2@]>
SH_MCALL2(SourceHook::ManualCallClass *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]), int vtblidx, int vtbloffs, int thisptroffs)
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::ExecutableClass$1<SourceHook::EmptyClass, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_MCALL3(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]), int vtblidx, int vtbloffs, int thisptroffs, SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return SourceHook::MExecutableClass$1<RetType@[$2,1,$1:, Param$2@]>(ptr, vtbloffs, vtblidx, thisptroffs);
SH__CALL_GET_VFNPTR_MANUAL
return SourceHook::ExecutableClass$1<EmptyClass, MFP, RetType@[$2,1,$1:, Param$2@]>(
reinterpret_cast<SourceHook::EmptyClass*>(CCW<Y>::GRP(ptr)), mfp, vfnptr, shptr, plug);
}
@]
@ -1291,24 +1419,29 @@ SH_MCALL2(SourceHook::ManualCallClass *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$
@[$1,0,$a:
// Support for $1 arguments
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...))
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...), SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
SH__CALL_GET_VFNPTR_NORMAL
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr),
mfp, vfnptr, shptr, plug);
}
template <class X, class Y, class MFP, class RetType@[$2,1,$1:, class Param$2@]>
SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(SourceHook::CallClass<Y> *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...)const)
SourceHook::ExecutableClass$1<typename SourceHook::CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>
SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...)const, SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
return SourceHook::ExecutableClass$1<SourceHook::CallClass<Y>, MFP, RetType@[$2,1,$1:, Param$2@]>(ptr, mfp);
SH__CALL_GET_VFNPTR_NORMAL
return SourceHook::ExecutableClass$1<typename CCW<Y>::type, MFP, RetType@[$2,1,$1:, Param$2@]>(CCW<Y>::GRP(ptr),
mfp, vfnptr, shptr, plug);
}
@]
#endif
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp))
#define SH_CALL(ptr, mfp) SH_CALL2((ptr), (mfp), (mfp), SH_GLOB_SHPTR, SH_GLOB_PLUGPTR)
#define SH_MCALL2(ptr, mfp, vtblidx, vtbloffs, thisptroffs) SH_MCALL3((ptr), (mfp), (mfp), (vtblidx), (vtbloffs), (thisptroffs), SH_GLOB_SHPTR, SH_GLOB_PLUGPTR)
#define SH_MCALL(ptr, mhookname) SH_MCALL2((ptr), SH_MFHCls(mhookname)::ECMFP(), SH_MFHCls(mhookname)::ms_MFI.vtblindex, \
SH_MFHCls(mhookname)::ms_MFI.vtbloffs, SH_MFHCls(mhookname)::ms_MFI.thisptroffs)

View File

@ -39,7 +39,7 @@ namespace SourceHook
return -1;
return 0;
}
CSourceHookImpl::CSourceHookImpl()
CSourceHookImpl::CSourceHookImpl() : m_OneIgnore(NULL), m_IgnoreActive(false)
{
}
CSourceHookImpl::~CSourceHookImpl()
@ -277,24 +277,32 @@ namespace SourceHook
m_HookMans.clear();
}
bool CSourceHookImpl::AddHook(Plugin plug, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan, ISHDelegate *handler, bool post)
{
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
return AddHookNew(plug, Hook_Normal, iface, thisptr_offs, myHookMan, handler, post) != 0 ? true : false;
}
int CSourceHookImpl::AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post)
{
void *adjustediface = NULL;
void **cur_vtptr = NULL;
void *cur_vfnptr = NULL;
if (mode != Hook_Normal && mode != Hook_VP && mode != Hook_DVP)
return 0;
// 1) Get info about the hook manager
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
return 0;
tmp.m_Func = myHookMan;
tmp.m_Plug = plug;
CHookManagerContainer::HMCI hmci(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx);
void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
// Add the container if not already added
HookManContList::iterator hmcl_iter = m_HookMans.find(hmci);
if (hmcl_iter == m_HookMans.end())
@ -320,7 +328,7 @@ namespace SourceHook
hmil_iter != hmcl_iter2->end(); ++hmil_iter)
{
if (hmil_iter->m_VfnPtrs.find(cur_vfnptr) != hmil_iter->m_VfnPtrs.end())
return false;
return 0;
}
}
}
@ -329,16 +337,37 @@ namespace SourceHook
if (hookman->m_VfnPtrs.empty())
hookman->m_Func(HA_Register, &(*hookman));
// find vfnptr
if (mode == Hook_Normal || mode == Hook_VP)
{
adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface) + thisptr_offs);
cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
// For Hook_VP, adjustediface will be set to NULL later
// because we first have to patch callclasses (callclasses are deprecated but left in for backwards compat)
}
else if (mode == Hook_DVP)
{
adjustediface = NULL;
cur_vtptr = reinterpret_cast<void**>(iface);
cur_vfnptr = cur_vtptr + tmp.m_VtblIdx;
}
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->m_VfnPtrs.end())
{
// Add a new one
CVfnPtr vfp(cur_vfnptr);
CVfnPtr vfp(cur_vfnptr, &m_OneIgnore);
// Alter vtable entry
if (!SetMemAccess(cur_vtptr, sizeof(void*) * (tmp.m_VtblIdx + 1), SH_MEM_READ | SH_MEM_WRITE))
return false;
return 0;
*reinterpret_cast<void**>(cur_vfnptr) = *reinterpret_cast<void**>(hookman->m_HookfuncVfnptr);
@ -352,6 +381,10 @@ namespace SourceHook
ApplyCallClassPatches(adjustediface, tmp.m_VtblOffs, tmp.m_VtblIdx, vfp.m_OrigEntry);
}
// If it's a VP hook, set adjustediface to NULL now ( see the comments at the beginning of sourcehook_impl.h )
if (mode == Hook_VP)
adjustediface = NULL;
CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(adjustediface);
if (iface_iter == vfnptr_iter->m_Ifaces.end())
{
@ -361,6 +394,34 @@ namespace SourceHook
// Make iface_iter point to the new element
iface_iter = vfnptr_iter->m_Ifaces.end();
--iface_iter;
// If this is a VP-Hook-NULL interface, go through all other interfaces of this vfnptr and tell them!
if (adjustediface == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 != NULL)
{
iface_iter2->m_PreHooks.SetVPList(&iface_iter->m_PreHooks.m_List);
iface_iter2->m_PostHooks.SetVPList(&iface_iter->m_PostHooks.m_List);
}
}
}
else
{
// If this is a new non-VP-Hook-NULL interface, look for a non-VP-Hook-NULL interface!
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 == NULL)
{
iface_iter->m_PreHooks.SetVPList(&iface_iter2->m_PreHooks.m_List);
iface_iter->m_PostHooks.SetVPList(&iface_iter2->m_PostHooks.m_List);
break; // There can only be one!
}
}
}
}
// Add the hook
@ -369,11 +430,136 @@ namespace SourceHook
hookinfo.plug = plug;
hookinfo.paused = false;
hookinfo.thisptr_offs = thisptr_offs;
hookinfo.hookid = m_HookIDMan.New(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx, cur_vfnptr,
adjustediface, plug, thisptr_offs, handler, post);
if (post)
iface_iter->m_PostHooks.m_List.push_back(hookinfo);
else
iface_iter->m_PreHooks.m_List.push_back(hookinfo);
return hookinfo.hookid;
}
bool CSourceHookImpl::RemoveHookByID(Plugin plug, int hookid)
{
const CHookIDManager::Entry *hentry;
hentry = m_HookIDMan.QueryHook(hookid);
if (!hentry)
{
// hookid doesn't exist !
return false;
}
HookManContList::iterator hmcl_iter = m_HookMans.find(
CHookManagerContainer::HMCI(hentry->proto.GetProto(), hentry->vtbl_offs, hentry->vtbl_idx));
if (hmcl_iter == m_HookMans.end() || hmcl_iter->empty())
return false;
CHookManagerContainer::iterator hookman = hmcl_iter->begin();
// Find vfnptr
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(hentry->vfnptr);
if (vfnptr_iter == hookman->m_VfnPtrs.end())
return false;
// Find iface
CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.find(hentry->adjustediface);
if (iface_iter == vfnptr_iter->m_Ifaces.end())
return false;
// Find hook
List<HookInfo> &hooks = hentry->post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
List<HookInfo>::iterator hookiter = hooks.find(hookid);
if (hookiter == hooks.end())
return false;
hookiter->handler->DeleteThis();
// Move all iterators pointing at this
List<HookInfo>::iterator oldhookiter = hookiter;
hookiter = hooks.erase(hookiter);
List<HookInfo>::iterator newhookiter = hookiter;
--newhookiter; // The hook loop will ++ it then
CHookList::CIter *pItIter;
for (pItIter = iface_iter->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
// If this is VP-Hook-NULL interface, also check all other interfaces of this vfnptr
if (*iface_iter == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (*iface_iter2 != NULL)
{
for (pItIter = iface_iter2->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
}
}
}
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
// If this is a VP-Hook-NULL interface, go through all other interfaces of this vfnptr and tell them!
if (*iface_iter == NULL)
{
for (CVfnPtr::IfaceListIter iface_iter2 = vfnptr_iter->m_Ifaces.begin();
iface_iter2 != vfnptr_iter->m_Ifaces.end(); ++iface_iter2)
{
if (iface_iter2->m_Ptr != NULL)
{
iface_iter2->m_PreHooks.ClearVPList();
iface_iter2->m_PostHooks.ClearVPList();
}
}
}
// There are no hooks on this iface anymore...
for (HookLoopInfoStack::iterator hli_iter = m_HLIStack.begin();
hli_iter != m_HLIStack.end(); ++hli_iter)
{
if (hli_iter->pCurIface == static_cast<IIface*>(&(*iface_iter)))
hli_iter->shouldContinue = false;
}
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
{
// No ifaces at all -> Deactivate the hook
// Only patch the vfnptr back if the module is still in memory
// If it's not, do not remove stuff like we did before
// First off we did it wrong (shutdown the whole hookman, uh..) and secondly applications may be
// confused by RemoveHook returning false then (yeah, I know, I made this one up, no one checks for RemoveHook error)
if (ModuleInMemory(reinterpret_cast<char*>(vfnptr_iter->m_Ptr), SH_PTRSIZE))
{
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = vfnptr_iter->m_OrigEntry;
}
hookman->m_VfnPtrs.erase(vfnptr_iter);
// Remove callclass patch
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
if (cciter->m_Ptr == hentry->adjustediface)
cciter->RemoveCallClassPatch(hentry->vtbl_offs, hentry->vtbl_idx);
if (hookman->m_VfnPtrs.empty())
{
// Unregister the hook manager
hookman->m_Func(HA_Unregister, NULL);
}
}
}
// Don't forget to remove the hookid from m_HookIDMan
m_HookIDMan.Remove(hookid);
return true;
}
@ -384,113 +570,32 @@ namespace SourceHook
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);
// Get info about hook manager and compute adjustediface
CHookManagerInfo tmp;
if (myHookMan(HA_GetInfo, &tmp) != 0)
return false;
// Find the hook manager and the hook
void *adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(iface)+thisptr_offs);
HookManContList::iterator hmcl_iter = m_HookMans.find(
CHookManagerContainer::HMCI(tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx));
if (hmcl_iter == m_HookMans.end() || hmcl_iter->empty())
return false;
CHookManagerContainer::iterator hookman = hmcl_iter->begin();
// Loop through all hooks and remove those which match:
// hookman, vfnptr, iface, plug, adjusted iface, this ptr offs, handler, post
CVector<int> removehooks;
m_HookIDMan.FindAllHooks(removehooks, tmp.m_Proto, tmp.m_VtblOffs, tmp.m_VtblIdx, adjustediface, plug, thisptr_offs, handler, post);
if (!ModuleInMemory(reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs,
sizeof(void*) * (tmp.m_VtblIdx + 1)))
{
// The module the vtable was in is already unloaded.
hookman->m_VfnPtrs.clear();
hookman->m_Func(HA_Unregister, NULL);
return true;
}
void **cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + tmp.m_VtblOffs);
void *cur_vfnptr = reinterpret_cast<void*>(cur_vtptr + tmp.m_VtblIdx);
CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookman->m_VfnPtrs.find(cur_vfnptr);
if (vfnptr_iter == hookman->m_VfnPtrs.end())
if (removehooks.empty())
return false;
for (CVfnPtr::IfaceListIter iface_iter = vfnptr_iter->m_Ifaces.begin();
iface_iter != vfnptr_iter->m_Ifaces.end();)
bool status = false;
for (CVector<int>::iterator iter = removehooks.begin(); iter != removehooks.end(); ++iter)
{
if (iface_iter->m_Ptr != adjustediface)
{
iface_iter++;
continue;
}
List<HookInfo> &hooks =
post ? iface_iter->m_PostHooks.m_List : iface_iter->m_PreHooks.m_List;
bool erase;
for (List<HookInfo>::iterator hookiter = hooks.begin();
hookiter != hooks.end(); )
{
erase = hookiter->plug == plug && hookiter->handler->IsEqual(handler) &&
hookiter->thisptr_offs == thisptr_offs;
if (erase)
{
hookiter->handler->DeleteThis(); // Make the _plugin_ delete the handler object
// Move all iterators pointing at this
List<HookInfo>::iterator oldhookiter = hookiter;
hookiter = hooks.erase(hookiter);
List<HookInfo>::iterator newhookiter = hookiter;
--newhookiter; // The hook loop will ++ it then
CHookList::CIter *pItIter;
for (pItIter = iface_iter->m_PreHooks.m_UsedIters; pItIter; pItIter = pItIter->m_pNext)
if (pItIter->m_Iter == oldhookiter)
pItIter->m_Iter = newhookiter;
}
else
++hookiter;
}
if (iface_iter->m_PostHooks.m_List.empty() && iface_iter->m_PreHooks.m_List.empty())
{
// There are no hooks on this iface anymore...
for (HookLoopInfoStack::iterator hli_iter = m_HLIStack.begin();
hli_iter != m_HLIStack.end(); ++hli_iter)
{
if (hli_iter->pCurIface == static_cast<IIface*>(&(*iface_iter)))
hli_iter->shouldContinue = false;
}
iface_iter = vfnptr_iter->m_Ifaces.erase(iface_iter);
if (vfnptr_iter->m_Ifaces.empty())
{
// No ifaces at all -> Deactivate the hook
*reinterpret_cast<void**>(vfnptr_iter->m_Ptr) = vfnptr_iter->m_OrigEntry;
hookman->m_VfnPtrs.erase(vfnptr_iter);
// Remove callclass patch
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
if (cciter->m_Ptr == adjustediface)
cciter->RemoveCallClassPatch(tmp.m_VtblOffs, tmp.m_VtblIdx);
if (hookman->m_VfnPtrs.empty())
{
// Unregister the hook manager
hookman->m_Func(HA_Unregister, NULL);
}
// Don't try to continue looping through ifaces
// - the list is already invalid
return true;
}
}
else
++iface_iter;
if (RemoveHookByID(plug, *iter))
status = true;
}
return true;
return status;
}
GenericCallClass *CSourceHookImpl::GetCallClass(void *iface, size_t size)
DeprecatedCallClass<void> *CSourceHookImpl::GetCallClass(void *iface, size_t size)
{
for (Impl_CallClassList::iterator cciter = m_CallClasses.begin(); cciter != m_CallClasses.end(); ++cciter)
{
@ -509,7 +614,7 @@ namespace SourceHook
return &m_CallClasses.back();
}
void CSourceHookImpl::ReleaseCallClass(GenericCallClass *ptr)
void CSourceHookImpl::ReleaseCallClass(DeprecatedCallClass<void> *ptr)
{
Impl_CallClassList::iterator iter = m_CallClasses.find(ptr);
if (iter == m_CallClasses.end())
@ -614,7 +719,7 @@ namespace SourceHook
void CSourceHookImpl::HookLoopBegin(IIface *pIface)
{
HookLoopInfo hli;
HookLoopInfo hli = {0};
hli.pCurIface = pIface;
hli.shouldContinue = true;
hli.recall = HookLoopInfo::Recall_No;
@ -802,6 +907,35 @@ namespace SourceHook
}
}
void CSourceHookImpl::SetIgnoreHooks(Plugin plug, void *vfnptr)
{
m_OneIgnore = vfnptr;
}
void CSourceHookImpl::ResetIgnoreHooks(Plugin plug, void *vfnptr)
{
m_OneIgnore = NULL;
}
void *CSourceHookImpl::GetOrigVfnPtrEntry(void *vfnptr)
{
for (HookManContList::iterator hmcl_iter = m_HookMans.begin();
hmcl_iter != m_HookMans.end(); ++hmcl_iter)
{
for (CHookManagerContainer::iterator hookmaniter = hmcl_iter->begin();
hookmaniter != hmcl_iter->end(); ++hookmaniter)
{
for (CHookManagerInfo::VfnPtrListIter vfnptr_iter = hookmaniter->m_VfnPtrs.begin();
vfnptr_iter != hookmaniter->m_VfnPtrs.end(); ++vfnptr_iter)
{
if (vfnptr_iter->m_Ptr == vfnptr)
return vfnptr_iter->m_OrigEntry;
}
}
}
return NULL;
}
////////////////////////////
// CCallClassImpl
////////////////////////////
@ -897,7 +1031,8 @@ namespace SourceHook
// If you get a crash here, the ptr passed is invalid
// This usually means a SH_DECL_MANUALHOOK* with wrong thisptroffs/vtbloffs/vtblidx
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr) : m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(ptr))
CSourceHookImpl::CVfnPtr::CVfnPtr(void *ptr, void **pOneIgnore) : m_Ptr(ptr),
m_OrigEntry(*reinterpret_cast<void**>(ptr)), m_pOneIgnore(pOneIgnore)
{
}
CSourceHookImpl::CVfnPtr::~CVfnPtr()
@ -916,8 +1051,24 @@ namespace SourceHook
IIface *CSourceHookImpl::CVfnPtr::FindIface(void *ptr)
{
if (m_Ptr == *m_pOneIgnore)
{
*m_pOneIgnore = NULL; // Only once!
return NULL;
}
IfaceListIter iter = m_Ifaces.find(ptr);
return iter == m_Ifaces.end() ? NULL : &(*iter);
// If nothing is found, check for a NULL-interface (VP hooks only)
if (iter == m_Ifaces.end())
{
iter = m_Ifaces.find((void*)0);
return iter == m_Ifaces.end() ? NULL : &(*iter);
}
else
{
return &(*iter);
}
}
////////////////////////////
@ -948,11 +1099,11 @@ namespace SourceHook
// CHookList
////////////////////////////
CSourceHookImpl::CHookList::CHookList() : m_FreeIters(NULL), m_UsedIters(NULL),
CSourceHookImpl::CHookList::CHookList() : m_VPList(NULL), m_FreeIters(NULL), m_UsedIters(NULL),
m_Recall(false)
{
}
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_List(other.m_List),
CSourceHookImpl::CHookList::CHookList(const CHookList &other) : m_VPList(other.m_VPList), m_List(other.m_List),
m_FreeIters(NULL), m_UsedIters(NULL), m_Recall(false)
{
}
@ -1029,9 +1180,36 @@ namespace SourceHook
m_Recall = false;
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList), m_pNext(NULL)
void CSourceHookImpl::CHookList::SetVPList(List<HookInfo> *newList)
{
m_VPList = newList;
// Update cached CIter objects
CIter *pTmp;
pTmp = m_FreeIters;
while (pTmp)
{
pTmp->m_Iter.SetListLeft(m_VPList);
pTmp = pTmp->m_pNext;
}
pTmp = m_UsedIters;
while (pTmp)
{
pTmp->m_Iter.SetListLeft(m_VPList);
pTmp = pTmp->m_pNext;
}
}
void CSourceHookImpl::CHookList::ClearVPList()
{
SetVPList(NULL);
}
CSourceHookImpl::CHookList::CIter::CIter(CHookList *pList) : m_pList(pList),
m_Iter(pList->m_VPList, &m_pList->m_List), m_pNext(NULL)
{
GoToBegin();
}
CSourceHookImpl::CHookList::CIter::~CIter()
{
@ -1044,7 +1222,7 @@ namespace SourceHook
void CSourceHookImpl::CHookList::CIter::GoToBegin()
{
m_Iter = m_pList->m_List.begin();
m_Iter.GoToBegin();
SkipPaused();
}
@ -1052,7 +1230,7 @@ namespace SourceHook
{
if (!m_pList)
return false;
return m_Iter == m_pList->m_List.end();
return m_Iter.End();;
}
void CSourceHookImpl::CHookList::CIter::Next()
{
@ -1067,7 +1245,7 @@ namespace SourceHook
}
void CSourceHookImpl::CHookList::CIter::SkipPaused()
{
while (m_Iter != m_pList->m_List.end() && m_Iter->paused)
while (!m_Iter.End() && m_Iter->paused)
++m_Iter;
}
@ -1085,6 +1263,9 @@ namespace SourceHook
//////////////////////////////////////////////////////////////////////////
char *CSourceHookImpl::CProto::DupProto(const char *p)
{
if (!p)
return NULL;
char *newproto;
if (*p)
{
@ -1105,6 +1286,9 @@ namespace SourceHook
void CSourceHookImpl::CProto::FreeProto(char *prot)
{
if (!prot)
return;
if (*prot)
{
delete [] prot;
@ -1117,6 +1301,9 @@ namespace SourceHook
bool CSourceHookImpl::CProto::Equal(const char *p1, const char *p2)
{
if (!p1 || !p2)
return false;
if (*p1 && *p2) // Case1: Both old
{
// As in old versions
@ -1209,4 +1396,68 @@ namespace SourceHook
}
}
}
//////////////////////////////////////////////////////////////////////////
// CHookIDManager
//////////////////////////////////////////////////////////////////////////
CSourceHookImpl::CHookIDManager::CHookIDManager()
{
}
int CSourceHookImpl::CHookIDManager::New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr,
void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
{
Entry tmp(proto, vtbl_offs, vtbl_idx, vfnptr, adjustediface, plug, thisptr_offs, handler, post);
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (m_Entries[i].isfree)
{
m_Entries[i] = tmp;
return static_cast<int>(i) + 1;
}
}
m_Entries.push_back(tmp);
return static_cast<int>(m_Entries.size()); // return size() because hookid = id+1 anyway
}
bool CSourceHookImpl::CHookIDManager::Remove(int hookid)
{
int realid = hookid - 1;
if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
return false;
m_Entries[realid].isfree = true;
// :TODO: remove free ids from back sometimes ??
return true;
}
const CSourceHookImpl::CHookIDManager::Entry * CSourceHookImpl::CHookIDManager::QueryHook(int hookid)
{
int realid = hookid - 1;
if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
return NULL;
return &m_Entries[realid];
}
void CSourceHookImpl::CHookIDManager::FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs,
int vtbl_idx, void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
{
// oh my god, a lot of parameters...
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs &&
m_Entries[i].vtbl_idx == vtbl_idx && m_Entries[i].adjustediface == adjustediface && m_Entries[i].plug == plug &&
m_Entries[i].thisptr_offs == thisptr_offs && m_Entries[i].handler->IsEqual(handler) && m_Entries[i].post == post)
{
output.push_back(static_cast<int>(i) + 1);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
#include "sh_vector.h"
#include "sh_tinyhash.h"
#include "sh_stack.h"
#include "sh_listcat.h"
/*
@ -89,6 +90,9 @@ Hooks
---------------------------------------
Call classes
!! deprecated !! - see below (new SH_CALL)
Call classes are identified by a this pointer and an instance size
We use the instance size because a derived class instance and a base class instance could
@ -142,6 +146,28 @@ Return Values in Post Recalls
HookLoopEnd we make sure that status is high enough so that the override return will be returned. crazy.
All this stuff could be much less complicated if I didn't try to preserve binary compatibility :)
VP Hooks
VP hooks are hooks which are called on a vfnptr, regardless of the this pointer with which it was called. They are
implemented as a special CIface instance with m_Ptr = NULL. All Hook Lists have a new "ListCatIterator" which
virtually concatenates the NULL-interface-hook-list with their normal hook list.
I'm afraid that with the addition of Recalls and VP Hooks, SourceHook is now a pretty complex and hacked-together
binary compatible beast which is pretty hard to maintain unless you've written it :)
New SH_CALL
The addition of VP hooks messed up the Call Classes concept (see above) - call classes are bound to an
instance pointer; they only work on one of the hooked instances. But VP hooks are called on all instances.
That's why now, SH_CALL takes an instance pointer instead of a callclass pointer. It basically does this:
1) call SH_GLOB_PTR->SetIgnoreHooks(vfnptr)
2) call this->*mfp
3) call SH_GLOB_PTR->ResetIgnoreHooks(vfnptr)
SourceHook stroes the "ignored vfnptr" and makes CVfnPtr::FindIface return NULL if the CVfnPtr instance
corresponds to the ignored vfnptr. This way the hook manager thinks that the instance isn't hooked, and calls
the original function. Everything works fine. This works even for VP hooks.
*/
namespace SourceHook
@ -160,6 +186,10 @@ namespace SourceHook
char *DupProto(const char *src);
void FreeProto(char *prot);
public:
CProto() : m_Proto(NULL)
{
}
CProto(const char *szProto) : m_Proto(DupProto(szProto))
{
}
@ -192,6 +222,11 @@ namespace SourceHook
{
return Equal(other.m_Proto, m_Proto);
}
const char *GetProto() const
{
return m_Proto;
}
};
@ -226,17 +261,79 @@ namespace SourceHook
HookManagerPubFunc hookman;
};
// Associates hook ids with info about the hooks
// Also used to keep track of used hook ids
class CHookIDManager
{
public:
struct Entry
{
bool isfree;
// hookman info
CProto proto;
int vtbl_offs;
int vtbl_idx;
// vfnptr
void *vfnptr;
// iface
void* adjustediface;
// hook
Plugin plug;
int thisptr_offs;
ISHDelegate *handler;
bool post;
Entry(const CProto &pprt, int pvo, int pvi, void *pvp, void *pai, Plugin pplug, int pto,
ISHDelegate *ph, bool ppost)
: isfree(false), proto(pprt), vtbl_offs(pvo), vtbl_idx(pvi), vfnptr(pvp),
adjustediface(pai), plug(pplug), thisptr_offs(pto), handler(ph), post(ppost)
{
}
Entry()
{
}
};
private:
// Internally, hookid 1 is stored as m_Entries[0]
CVector<Entry> m_Entries;
public:
CHookIDManager();
int New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr, void *adjustediface,
Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post);
bool Remove(int hookid);
const Entry * QueryHook(int hookid);
// Finds all hooks with the given info, and fills the hookids into output.
void FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs, int vtbl_idx,
void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post);
// Removes all hooks with a specified vfnptr
bool RemoveAll(void *vfnptr);
};
struct HookInfo
{
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
int hookid; //!< Unique ID given by CHookIDManager
bool operator==(int otherid)
{
return hookid == otherid;
}
};
class CHookList : public IHookList
{
public:
List<HookInfo> *m_VPList; // left-hand list for ListCatIterator -> for VP hooks
List<HookInfo> m_List;
friend class CIter;
@ -250,7 +347,7 @@ namespace SourceHook
void SkipPaused();
public:
List<HookInfo>::iterator m_Iter;
ListCatIterator<HookInfo> m_Iter;
CIter(CHookList *pList);
@ -293,6 +390,9 @@ namespace SourceHook
IIter *GetIter();
void ReleaseIter(IIter *pIter);
void SetVPList(List<HookInfo> *newList);
void ClearVPList();
};
// I know, data hiding... But I'm a lazy bastard!
@ -315,6 +415,10 @@ namespace SourceHook
{
return m_Ptr == ptr;
}
bool operator!=(void *ptr)
{
return m_Ptr != ptr;
}
};
class CVfnPtr : public IVfnPtr
@ -328,8 +432,9 @@ namespace SourceHook
IfaceList m_Ifaces;
void **m_pOneIgnore;
public:
CVfnPtr(void *ptr);
CVfnPtr(void *ptr, void **pOneIgnore);
virtual ~CVfnPtr();
void *GetVfnPtr();
@ -446,7 +551,7 @@ namespace SourceHook
void AddHookManager(Plugin plug, const CHookManagerInfo &hookman);
};
class CCallClassImpl : public GenericCallClass
class CCallClassImpl : public DeprecatedCallClass<void>
{
public:
@ -520,6 +625,10 @@ namespace SourceHook
void SetPluginPaused(Plugin plug, bool paused);
HookLoopInfoStack m_HLIStack;
CHookIDManager m_HookIDMan;
void *m_OneIgnore; //:TODO:
bool m_IgnoreActive;
public:
CSourceHookImpl();
virtual ~CSourceHookImpl();
@ -608,14 +717,14 @@ namespace SourceHook
* @param iface The interface pointer
* @param size Size of the class instance
*/
GenericCallClass *GetCallClass(void *iface, size_t size);
DeprecatedCallClass<void> *GetCallClass(void *iface, size_t size);
/**
* @brief Release a callclass
*
* @param ptr Pointer to the callclass
*/
virtual void ReleaseCallClass(GenericCallClass *ptr);
virtual void ReleaseCallClass(DeprecatedCallClass<void> *ptr);
virtual void SetRes(META_RES res); //!< Sets the meta result
virtual META_RES GetPrevRes(); //!< Gets the meta result of the previously called handler
@ -650,6 +759,58 @@ namespace SourceHook
virtual void *SetupHookLoop(META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
void **ifacePtrPtr, const void *origRetPtr, void *overrideRetPtr);
/**
* @brief Add a (VP) hook.
*
* @return non-zero hook id on success, 0 otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param mode Can be either Hook_Normal or Hook_VP (vtable-wide hook)
* @param iface The interface pointer
* The representative interface pointer for VP hooks
* The vtable pointer for direct VP hooks !!!
* @param ifacesize The size of the class iface points to
* @param myHookMan A hook manager function that should be capable of handling the function
* @param handler A pointer to a FastDelegate containing the hook handler
* @param post Set to true if you want a post handler
*/
virtual int AddHookNew(Plugin plug, AddHookMode mode, void *iface, int thisptr_offs, HookManagerPubFunc myHookMan,
ISHDelegate *handler, bool post);
/**
* @brief Remove a VP hook by ID.
*
* @return true on success, false otherwise
*
* @param plug The unique identifier of the plugin that calls this function
* @param hookid The hook id (returned by AddHookNew)
*/
virtual bool RemoveHookByID(Plugin plug, int hookid);
/**
* @brief Makes sure that hooks are going to be ignored on the next call of vfnptr
*
* @param plug The unique identifier of the plugin that calls this function
* @param vfnptr The virtual function pointer of the function in question
*/
virtual void SetIgnoreHooks(Plugin plug, void *vfnptr);
/**
* @brief Reverses SetIgnoreHooks' effect
*
* @param plug The unique identifier of the plugin that calls this function
* @param vfnptr The virtual function pointer of the function in question
*/
virtual void ResetIgnoreHooks(Plugin plug, void *vfnptr);
/**
* @brief Finds the original entry of a virtual function pointer
*
* @param vfnptr The virtual function pointer
* @return The original entry if the virtual function pointer has been patched; NULL otherwise.
*/
virtual void *GetOrigVfnPtrEntry(void *vfnptr);
};
}

View File

@ -80,6 +80,7 @@ DO_TEST(Recall);
DO_TEST(Multi);
DO_TEST(Ref);
DO_TEST(RefRet);
DO_TEST(VPHooks);
int main(int argc, char *argv[])
{

View File

@ -289,6 +289,12 @@
<File
RelativePath="..\testref.cpp">
</File>
<File
RelativePath="..\testrefret.cpp">
</File>
<File
RelativePath="..\testvphooks.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
@ -296,6 +302,15 @@
<File
RelativePath="..\..\sh_list.h">
</File>
<File
RelativePath="..\..\sh_listcat.h">
</File>
<File
RelativePath="..\..\sh_memfuncinfo.h">
</File>
<File
RelativePath="..\..\sh_memory.h">
</File>
<File
RelativePath="..\..\sh_stack.h">
</File>

View File

@ -338,6 +338,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public Test
{
};
SH_DECL_HOOK1(Test, F299, SH_NOATTRIB, 0, bool, const char *);
SH_DECL_HOOK0_void(Test, F1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, F2, SH_NOATTRIB, 0);
@ -416,52 +421,46 @@ bool TestBasic(std::string &error)
g_PLID = 1337;
HandlersF1 f1_handlers;
Test test;
Whatever test;
Test *pTest = &test;
// 1) Get a call class and call the member through it and normally
SourceHook::CallClass<Test> *cc = SH_GET_CALLCLASS(pTest);
// 1) SH_CALL it and call it normally
ADD_STATE(State_F1_CallClassGenerated);
return true;
SH_CALL(pTest, &Test::F1)();
SH_CALL(cc, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
new State_F1_CallClassGenerated,
new State_F1_Called,
new State_F1_Called,
NULL), "Part 1");
// 2) Request a call class again
SourceHook::CallClass<Test> *cc2 = SH_GET_CALLCLASS(pTest);
ADD_STATE(State_F1_CallClassGenerated);
SH_CALL(cc, &Test::F1)();
SH_CALL(cc2, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
SH_RELEASE_CALLCLASS(cc2);
ADD_STATE(State_F1_CallClassReleased);
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
new State_F1_CallClassGenerated,
new State_F1_Called,
new State_F1_Called,
new State_F1_Called,
new State_F1_CallClassReleased,
new State_F1_Called,
new State_F1_Called,
NULL), "Part 2");
// 3) Add a pre hook
// (one add memfunc in old format)
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false)));
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false) ? true : false));
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -470,30 +469,26 @@ bool TestBasic(std::string &error)
new State_F1_PreHandler_Called(&f1_handlers),
NULL), "Part 3");
// 4) Rerequest the callclass
SH_RELEASE_CALLCLASS(cc);
// 4) Test source-level compat with callclasses
SourceHook::CallClass<Test> *pCC = SH_GET_CALLCLASS(pTest);
ADD_STATE(State_F1_CallClassReleased);
cc2 = SH_GET_CALLCLASS(pTest);
ADD_STATE(State_F1_CallClassGenerated);
SH_CALL(cc, &Test::F1)();
SH_CALL(pCC, &Test::F1)();
pTest->F1();
SH_RELEASE_CALLCLASS(pCC);
CHECK_STATES((&g_States,
new State_F1_CallClassReleased,
new State_F1_CallClassGenerated,
new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers),
NULL), "Part 4");
// 5) Check ignore / supercede
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
g_F1Pre_WhatToDo = MRES_IGNORED;
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -505,10 +500,11 @@ bool TestBasic(std::string &error)
NULL), "Part 5");
// 6) remove the hook again
// (one remove memfunc in old format)
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
ADD_STATE(State_F1_HookRemoved);
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -519,9 +515,9 @@ bool TestBasic(std::string &error)
// 7) add a post hook now
g_F1Post_WhatToDo = MRES_IGNORED;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Post, true)));
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true) ? true : false));
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -533,13 +529,13 @@ bool TestBasic(std::string &error)
// 8) And a pre hook again
g_F1Pre_WhatToDo = MRES_IGNORED;
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false)));
ADD_STATE(State_F1_HookAdded(SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false) ? true : false));
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
g_F1Pre_WhatToDo = MRES_SUPERCEDE;
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -554,12 +550,12 @@ bool TestBasic(std::string &error)
NULL), "Part 8");
// 9) Remove all hooks
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
ADD_STATE(State_F1_HookRemoved);
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Post, true);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
ADD_STATE(State_F1_HookRemoved);
SH_CALL(cc, &Test::F1)();
SH_CALL(pTest, &Test::F1)();
pTest->F1();
CHECK_STATES((&g_States,
@ -574,7 +570,7 @@ bool TestBasic(std::string &error)
g_F299Pre_WhatToRet = false;
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_Called("hi"),
@ -583,9 +579,10 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.1");
// (one add staticfunc in old format)
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"),
@ -595,9 +592,9 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.2");
SH_ADD_HOOK_STATICFUNC(Test, F299, pTest, F299_Post, true);
SH_ADD_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"),
@ -610,7 +607,7 @@ bool TestBasic(std::string &error)
g_F299Pre_WhatToDo = MRES_OVERRIDE;
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"),
@ -623,7 +620,7 @@ bool TestBasic(std::string &error)
g_F299Pre_WhatToDo = MRES_SUPERCEDE;
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_PreHandlerCalled("hi"),
@ -633,9 +630,10 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.5");
// (one remove staticfunc in old format)
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, F299_Pre, false);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_Called("hi"),
@ -645,9 +643,9 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.6");
SH_REMOVE_HOOK_STATICFUNC(Test, F299, pTest, F299_Post, true);
SH_REMOVE_HOOK(Test, F299, pTest, SH_STATIC(F299_Post), true);
ADD_STATE(State_F299Ret(pTest->F299("hi")));
ADD_STATE(State_F299Ret(SH_CALL(cc, &Test::F299)("hi")));
ADD_STATE(State_F299Ret(SH_CALL(pTest, &Test::F299)("hi")));
CHECK_STATES((&g_States,
new State_F299_Called("hi"),
@ -656,39 +654,59 @@ bool TestBasic(std::string &error)
new State_F299Ret(true),
NULL), "Part 10.7");
// 11) Release callclass
SH_RELEASE_CALLCLASS(cc);
ADD_STATE(State_F1_CallClassReleased);
// 11 1/2) Test removing hook by id
g_F1Pre_WhatToDo = MRES_IGNORED;
pTest->F1();
int hookPre = SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
int hookPost = SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Post), true);
pTest->F1();
SH_REMOVE_HOOK_ID(hookPost);
pTest->F1();
SH_REMOVE_HOOK_ID(hookPre);
pTest->F1();
CHECK_STATES((&g_States,
new State_F1_CallClassReleased,
NULL), "Part 11");
new State_F1_Called,
new State_F1_PreHandler_Called(&f1_handlers),
new State_F1_Called,
new State_F1_PostHandler_Called(&f1_handlers),
new State_F1_PreHandler_Called(&f1_handlers),
new State_F1_Called,
new State_F1_Called,
NULL), "Part 11 1/2");
// 12) Test? Test.
SH_ADD_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F2, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F3, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F4, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F5, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F6, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_ADD_HOOK_MEMFUNC(Test, F7, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F8, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F9, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK_MEMFUNC(Test, F10, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_ADD_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F2, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F3, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F4, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F5, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F6, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_ADD_HOOK(Test, F7, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F8, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F9, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK(Test, F10, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK_MEMFUNC(Test, F1, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F2, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F3, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F4, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F5, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F6, pTest, &f1_handlers, &HandlersF1::Pre, true);
SH_REMOVE_HOOK_MEMFUNC(Test, F7, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F8, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F9, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK_MEMFUNC(Test, F10, pTest, &f1_handlers, &HandlersF1::Pre, false);
SH_REMOVE_HOOK(Test, F1, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F2, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F3, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F4, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F5, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F6, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), true);
SH_REMOVE_HOOK(Test, F7, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F8, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F9, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_REMOVE_HOOK(Test, F10, pTest, SH_MEMBER(&f1_handlers, &HandlersF1::Pre), false);
SH_ADD_HOOK_STATICFUNC(Test, F60, pTest, F60_Pre, false);
SH_ADD_HOOK(Test, F60, pTest, SH_STATIC(F60_Pre), false);
int a = 0;
pTest->F60(a);

View File

@ -50,6 +50,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public IGaben
{
};
SH_DECL_HOOK0_void(IGaben, EatYams, SH_NOATTRIB, 0);
SH_DECL_HOOK1(IGaben, EatYams, const, 1, bool, const char *);
SH_DECL_HOOK2_void_vafmt(IGaben, Vafmt1, SH_NOATTRIB, 0, bool, int);
@ -92,14 +97,12 @@ bool TestVafmtAndOverload(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
IGaben gabgab;
Whatever gabgab;
IGaben *pGab = &gabgab;
SourceHook::CallClass<IGaben> *cc = SH_GET_CALLCLASS(pGab);
// Part 1
SH_CALL(cc, static_cast<void (IGaben::*)()>(&IGaben::EatYams))();
SH_CALL(cc, static_cast<bool (IGaben::*)(const char *) const>(&IGaben::EatYams))("Here!");
SH_CALL(pGab, static_cast<void (IGaben::*)()>(&IGaben::EatYams))();
SH_CALL(pGab, static_cast<bool (IGaben::*)(const char *) const>(&IGaben::EatYams))("Here!");
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams0_Handler, false);
SH_ADD_HOOK(IGaben, EatYams, pGab, EatYams1_Handler, false);
@ -121,9 +124,9 @@ bool TestVafmtAndOverload(std::string &error)
// Part 2
pGab->Vafmt1(true, 55, "Hello %s%d%s", "BA", 1, "L");
SH_CALL(cc, &IGaben::Vafmt1)(true, 55, "Hello %s%d%s", "BA", 1, "L");
SH_CALL(pGab, &IGaben::Vafmt1)(true, 55, "Hello %s%d%s", "BA", 1, "L");
pGab->Vafmt2("Hello %s%d%s", "BA", 1, "LOPAN");
SH_CALL(cc, &IGaben::Vafmt2)("Hello %s%d%s", "BA", 1, "LOPAN");
SH_CALL(pGab, &IGaben::Vafmt2)("Hello %s%d%s", "BA", 1, "LOPAN");
CHECK_STATES((&g_States,
new State_Vafmt_Called(1, "Hello BA1L"),
@ -165,7 +168,5 @@ bool TestVafmtAndOverload(std::string &error)
new State_Vafmt_Called(2, "Hello BA1LOPAN"),
NULL), "Part 4");
SH_RELEASE_CALLCLASS(cc);
return true;
}

View File

@ -47,6 +47,8 @@ namespace
}
};
class DerivedDerived : public Derived { };
SH_DECL_HOOK0_void(Derived, Func1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Derived, Func2, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Derived, Func3, SH_NOATTRIB, 0);
@ -72,7 +74,7 @@ bool TestThisPtrOffs(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Derived inst;
DerivedDerived inst;
Derived *pD = &inst;
Base1 *pB1 = pD;
Base2 *pB2 = pD;
@ -85,11 +87,10 @@ bool TestThisPtrOffs(std::string &error)
// Get a callclass for pD
// Verify whether the this pointers are correct
// Also call them normally to make sure that we aren't messing it up ;)
SourceHook::CallClass<Derived> *pD_CC = SH_GET_CALLCLASS(pD);
SH_CALL(pD_CC, &Derived::Func1)();
SH_CALL(pD_CC, &Derived::Func2)();
SH_CALL(pD_CC, &Derived::Func3)();
SH_CALL(pD, &Derived::Func1)();
SH_CALL(pD, &Derived::Func2)();
SH_CALL(pD, &Derived::Func3)();
pD->Func1();
pD->Func2();
pD->Func3();
@ -103,8 +104,8 @@ bool TestThisPtrOffs(std::string &error)
new State_Func3_Called(pD),
NULL), "Part 1");
SH_CALL(pD_CC, &Base1::Func1)();
SH_CALL(pD_CC, &Base2::Func2)();
SH_CALL(pD, &Base1::Func1)();
SH_CALL(pD, &Base2::Func2)();
CHECK_STATES((&g_States,
new State_Func1_Called(pB1),
@ -114,11 +115,8 @@ bool TestThisPtrOffs(std::string &error)
// 2)
// Get callclasses for the other ones and verify it as well
SourceHook::CallClass<Base1> *pB1_CC = SH_GET_CALLCLASS(pB1);
SourceHook::CallClass<Base2> *pB2_CC = SH_GET_CALLCLASS(pB2);
SH_CALL(pB1_CC, &Base1::Func1)();
SH_CALL(pB2_CC, &Base2::Func2)();
SH_CALL(pB1, &Base1::Func1)();
SH_CALL(pB2, &Base2::Func2)();
CHECK_STATES((&g_States,
new State_Func1_Called(pB1),
@ -129,9 +127,9 @@ bool TestThisPtrOffs(std::string &error)
// 3) Add hooks on them (referring to them through pD1 / Derived)
// Check whether the hooks are called with the correct this pointer
SH_ADD_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -153,17 +151,17 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 3");
SH_REMOVE_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_REMOVE_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
// 4)
// Now add the hooks on Base1 and Base2 and check again
// Note that the new implicit_cast should convert the pD to Base1*/Base2* :)
SH_ADD_HOOK_STATICFUNC(Base1, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Base2, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Base1, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Base2, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -186,18 +184,18 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 4");
SH_REMOVE_HOOK_STATICFUNC(Base1, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Base2, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_REMOVE_HOOK(Base1, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Base2, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
// 5)
// Add some hooks, and use callclasses
// 5.1) First off, add all of them on pD
SH_ADD_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_ADD_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
pD->Func1();
pD->Func2();
@ -212,11 +210,11 @@ bool TestThisPtrOffs(std::string &error)
new State_Func3_Called(pD),
NULL), "Part 5.1");
SH_CALL(pD_CC, &Derived::Func1)();
SH_CALL(pD_CC, &Derived::Func2)();
SH_CALL(pD_CC, &Derived::Func3)();
SH_CALL(pB1_CC, &Base1::Func1)();
SH_CALL(pB2_CC, &Base2::Func2)();
SH_CALL(pD, &Derived::Func1)();
SH_CALL(pD, &Derived::Func2)();
SH_CALL(pD, &Derived::Func3)();
SH_CALL(pB1, &Base1::Func1)();
SH_CALL(pB2, &Base2::Func2)();
CHECK_STATES((&g_States,
new State_Func1_Called(pB1),
@ -226,13 +224,9 @@ bool TestThisPtrOffs(std::string &error)
new State_Func2_Called(pB2),
NULL), "Part 5.2");
SH_REMOVE_HOOK_STATICFUNC(Derived, Func1, pD, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func2, pD, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Derived, Func3, pD, Handler_Func3, false);
SH_RELEASE_CALLCLASS(pB1_CC);
SH_RELEASE_CALLCLASS(pB2_CC);
SH_RELEASE_CALLCLASS(pD_CC);
SH_REMOVE_HOOK(Derived, Func1, pD, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(Derived, Func2, pD, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(Derived, Func3, pD, SH_STATIC(Handler_Func3), false);
return true;
}

View File

@ -40,6 +40,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public Test
{
};
SH_DECL_HOOK0_void(Test, Func1, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, Func2, SH_NOATTRIB, 0);
SH_DECL_HOOK0_void(Test, Func3, SH_NOATTRIB, 0);
@ -63,14 +68,14 @@ bool TestPlugSys(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test inst;
Whatever inst;
Test *pInst = &inst;
// 1)
// Add hooks, then issue a complete shutdown
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
pInst->Func1();
pInst->Func2();
@ -101,23 +106,23 @@ bool TestPlugSys(std::string &error)
// Add hooks from "different plugins", then shutdown the plugins
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
pInst->Func1();
pInst->Func2();
@ -237,23 +242,23 @@ bool TestPlugSys(std::string &error)
// Add hooks from "different plugins", then pause the plugins
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 1;
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func3, pInst, Handler_Func3, false);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func3, pInst, SH_STATIC(Handler_Func3), false);
g_PLID = 3;
SH_ADD_HOOK_STATICFUNC(Test, Func1, pInst, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, pInst, Handler_Func2, true);
SH_ADD_HOOK(Test, Func1, pInst, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(Test, Func2, pInst, SH_STATIC(Handler_Func2), true);
pInst->Func1();
pInst->Func2();

View File

@ -44,7 +44,7 @@ bool TestBail(std::string &error)
g_Gabgab = new IGaben;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
@ -75,7 +75,7 @@ bool TestBail(std::string &error)
new State_EatYams_Return(5),
NULL), "Part 3");
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_REMOVE_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));
@ -97,7 +97,7 @@ bool TestBail(std::string &error)
new State_EatYams_Called(0xBEEF),
NULL), "Part 5");
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler1), false);
ADD_STATE(State_EatYams_Return(g_Gabgab->EatYams(0xDEAD)));

View File

@ -24,8 +24,8 @@ namespace N_TestBail
{
g_PLID = 2;
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler2, false);
SH_ADD_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler3, false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler2), false);
SH_ADD_HOOK(IGaben, EatYams, g_Gabgab, SH_STATIC(EatYams_Handler3), false);
int ret = g_Gabgab->EatYams(0xDEAD);

View File

@ -52,6 +52,11 @@ namespace
{
ADD_STATE(State_Func5_Called(reinterpret_cast<void*>(this)));
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
class Whatever : public TheWall
{
};
SH_DECL_HOOK0_void(TheWall, Func1, SH_NOATTRIB, 0);
@ -106,11 +111,9 @@ bool TestManual(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
TheWall inst;
Whatever inst;
TheWall *p = &inst;
SourceHook::ManualCallClass *cc = SH_GET_MCALLCLASS(p, sizeof(void*));
// 1)
// Call each function
p->Func1();
@ -129,14 +132,14 @@ bool TestManual(std::string &error)
// 1.1)
// Now call each function through the manual call class, using the hook decl and manually
SH_MCALL(cc, TheWall_Func1)();
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
SH_MCALL(cc, TheWall_Func2)(200);
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
SH_MCALL(p, TheWall_Func1)();
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
SH_MCALL(p, TheWall_Func2)(200);
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
CHECK_STATES((&g_States,
new State_Func1_Called(p),
@ -153,12 +156,23 @@ bool TestManual(std::string &error)
new State_Return(4),
NULL), "Part 1.1");
// Compat: really get a manual call class!
SourceHook::ManualCallClass *pCC = SH_GET_MCALLCLASS(p, sizeof(void*));
SH_MCALL(pCC, TheWall_Func1)();
SH_MCALL2(pCC, MFP_Func1(), 0, 0, 0)();
CHECK_STATES((&g_States,
new State_Func1_Called(p),
new State_Func1_Called(p),
NULL), "Part 1.2");
SH_RELEASE_CALLCLASS(pCC);
// 2)
// Hook each function normally, call them
SH_ADD_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -181,14 +195,14 @@ bool TestManual(std::string &error)
// Call them through the mcallclass
// 2.1)
// Now call each function through the manual call class, using the hook decl and manually
SH_MCALL(cc, TheWall_Func1)();
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
SH_MCALL(cc, TheWall_Func2)(200);
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
SH_MCALL(p, TheWall_Func1)();
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
SH_MCALL(p, TheWall_Func2)(200);
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
CHECK_STATES((&g_States,
new State_Func1_Called(p),
@ -206,18 +220,18 @@ bool TestManual(std::string &error)
NULL), "Part 2.1");
// Unhook them
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_REMOVE_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
// 3)
// Hook each function manually, call them
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -242,14 +256,14 @@ bool TestManual(std::string &error)
// Call them through the mcallclass
// 3.1)
// Now call each function through the manual call class, using the hook decl and manually
SH_MCALL(cc, TheWall_Func1)();
SH_MCALL2(cc, MFP_Func1(), 0, 0, 0)();
SH_MCALL(cc, TheWall_Func2)(200);
SH_MCALL2(cc, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(cc, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(cc, MFP_Func4(), 3, 0, 0)(400)));
SH_MCALL(p, TheWall_Func1)();
SH_MCALL2(p, MFP_Func1(), 0, 0, 0)();
SH_MCALL(p, TheWall_Func2)(200);
SH_MCALL2(p, MFP_Func2(), 1, 0, 0)(200);
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func3)()));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func3(), 2, 0, 0)()));
ADD_STATE(State_Return(SH_MCALL(p, TheWall_Func4)(400)));
ADD_STATE(State_Return(SH_MCALL2(p, MFP_Func4(), 3, 0, 0)(400)));
CHECK_STATES((&g_States,
new State_Func1_Called(p),
@ -267,10 +281,10 @@ bool TestManual(std::string &error)
NULL), "Part 3.1");
// Unhook them
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_REMOVE_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
// 4)
// Hook each function manually, then normally, call, unhook
@ -278,7 +292,7 @@ bool TestManual(std::string &error)
AnotherBrick handler_inst;
// Why this?
// 1) tests sh_add_manualhook_memfunc
// 1) tests sh_add_manualhook
// 2) in my tests, the proto of the manual hook was not equal to the proto of the auto hook
// (because there are no attribs for manual hooks).
// sourcehook.cpp did a !strcmp(..), so it assigned a new hook manager even though there
@ -287,15 +301,15 @@ bool TestManual(std::string &error)
// The problem with this is that returning MRES_SUPERCEDE (as AnotherBrick::Handler_Func1
// does) will supercede the second hook func from being called - thus bypassing the call
// of the auto hook here.
SH_ADD_MANUALHOOK_MEMFUNC(TheWall_Func1, p, &handler_inst, &AnotherBrick::Handler_Func1, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_MEMBER(&handler_inst, &AnotherBrick::Handler_Func1), false);
SH_ADD_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_ADD_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_ADD_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_ADD_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_ADD_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_ADD_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
p->Func1();
p->Func2(200);
@ -319,19 +333,19 @@ bool TestManual(std::string &error)
new State_Return(4),
NULL), "Part 4");
SH_REMOVE_MANUALHOOK_MEMFUNC(TheWall_Func1, p, &handler_inst, &AnotherBrick::Handler_Func1, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func2, p, Handler_Func2, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func3, p, Handler_Func3, false);
SH_REMOVE_MANUALHOOK_STATICFUNC(TheWall_Func4, p, Handler_Func4, false);
SH_REMOVE_MANUALHOOK(TheWall_Func1, p, SH_MEMBER(&handler_inst, &AnotherBrick::Handler_Func1), false);
SH_REMOVE_MANUALHOOK(TheWall_Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_MANUALHOOK(TheWall_Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_MANUALHOOK(TheWall_Func4, p, SH_STATIC(Handler_Func4), false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func1, p, Handler_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func2, p, Handler_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func3, p, Handler_Func3, false);
SH_REMOVE_HOOK_STATICFUNC(TheWall, Func4, p, Handler_Func4, false);
SH_REMOVE_HOOK(TheWall, Func1, p, SH_STATIC(Handler_Func1), false);
SH_REMOVE_HOOK(TheWall, Func2, p, SH_STATIC(Handler_Func2), false);
SH_REMOVE_HOOK(TheWall, Func3, p, SH_STATIC(Handler_Func3), false);
SH_REMOVE_HOOK(TheWall, Func4, p, SH_STATIC(Handler_Func4), false);
// 5) Reconfigure TheWall_Func1 to actually hook Func5:
SH_MANUALHOOK_RECONFIGURE(TheWall_Func1, 4, 0, 0);
SH_ADD_MANUALHOOK_STATICFUNC(TheWall_Func1, p, Handler_Func1, false);
SH_ADD_MANUALHOOK(TheWall_Func1, p, SH_STATIC(Handler_Func1), false);
p->Func5();

View File

@ -53,7 +53,7 @@ bool TestMulti(std::string &error)
for (unsigned int i=0; i<10; i++)
SH_ADD_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[i], HookFunction, false);
SH_ADD_HOOK(VMultiTest, HookTarget, pv[i], SH_STATIC(HookFunction), false);
pv[0]->HookTarget();
@ -72,7 +72,7 @@ bool TestMulti(std::string &error)
}
}
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[0], HookFunction, false);
SH_REMOVE_HOOK(VMultiTest, HookTarget, pv[0], SH_STATIC(HookFunction), false);
for (unsigned int i=1; i<10; i++)
pv[i]->HookTarget();
@ -96,7 +96,7 @@ bool TestMulti(std::string &error)
for (unsigned int i=1; i<10; i++)
{
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[1], HookFunction, false);
SH_REMOVE_HOOK(VMultiTest, HookTarget, pv[1], SH_STATIC(HookFunction), false);
delete pv[i];
}

View File

@ -48,6 +48,11 @@ namespace
}
};
// GCC's optimizer is too good. I had to add this in order to make it execute a virtual table lookup!
struct Whatever : Test
{
};
void Handler1_Func1(int a)
{
ADD_STATE(State_H1_Func1(a));
@ -119,12 +124,12 @@ bool TestRecall(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
Test inst;
Whatever inst;
Test *ptr = &inst;
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler1_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, HandlerPost_Func1, true);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler1_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(HandlerPost_Func1), true);
ptr->Func1(77);
@ -135,10 +140,10 @@ bool TestRecall(std::string &error)
new State_HP_Func1(0, ptr),
NULL), "Part 1");
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, Handler1_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_ADD_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(Handler1_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_ADD_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
ptr->Func1(77);
@ -151,8 +156,8 @@ bool TestRecall(std::string &error)
new State_HP_Func1(57, ptr),
NULL), "Part 2");
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, Handler2_Func1, false);
SH_REMOVE_HOOK_STATICFUNC(Test, Func1, ptr, HandlerPost_Func1, true);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(Handler2_Func1), false);
SH_REMOVE_HOOK(Test, Func1, ptr, SH_STATIC(HandlerPost_Func1), true);
ptr->Func1(77);
@ -162,8 +167,8 @@ bool TestRecall(std::string &error)
// Func2
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func2, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost_Func2, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func2), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost_Func2), true);
int a = ptr->Func2(77);
CHECK_STATES((&g_States,
@ -175,8 +180,8 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 500, "Part 4.1");
// Func2, with other handler
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func2, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler2_Func2, false);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func2), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler2_Func2), false);
a = ptr->Func2(77);
CHECK_STATES((&g_States,
@ -191,9 +196,9 @@ bool TestRecall(std::string &error)
// 1) WITH OVERRIDE
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func22, false);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1A_Func22, true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(Handler1_Func22), false);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1A_Func22), true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
a = ptr->Func2(10, 11);
CHECK_STATES((&g_States,
@ -206,11 +211,11 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 0, "Part 5.1");
// 2) WITH IGNORE
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1A_Func22, true);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1A_Func22), true);
SH_REMOVE_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1_Func22, true);
SH_ADD_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost1_Func22), true);
SH_ADD_HOOK(Test, Func2, ptr, SH_STATIC(HandlerPost2_Func22), true);
a = ptr->Func2(10, 11);
CHECK_STATES((&g_States,

View File

@ -82,6 +82,7 @@ namespace
return 1;
}
};
struct C2
{
virtual void F()
@ -167,6 +168,15 @@ namespace
}
};
struct C1_Derived : public C1 {};
struct C2_Derived : public C2 {};
struct C3_Derived : public C3 {};
struct C4_Derived : public C4 {};
struct C5_Derived : public C5 {};
struct C6_Derived : public C6 {};
struct C7_Derived : public C7 {};
struct C8_Derived : public C8 {};
SH_DECL_HOOK0_void(C1, F, SH_NOATTRIB, 0);
SH_DECL_HOOK0(C1, G, SH_NOATTRIB, 0, int);
SH_DECL_HOOK0_void(C2, F, SH_NOATTRIB, 0);
@ -258,9 +268,9 @@ namespace
void Handler_C7_F()
{
if (g_TestID == 1 || g_TestID == 2)
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
if (g_TestID == 2)
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
ADD_STATE(State_H_C7_F(META_IFACEPTR(C7)));
g_pC7->G();
@ -282,14 +292,14 @@ namespace
return 8;
}
C1 g_C1;
C2 g_C2;
C3 g_C3;
C4 g_C4;
C5 g_C5;
C6 g_C6;
C7 g_C7;
C8 g_C8;
C1_Derived g_C1;
C2_Derived g_C2;
C3_Derived g_C3;
C4_Derived g_C4;
C5_Derived g_C5;
C6_Derived g_C6;
C7_Derived g_C7;
C8_Derived g_C8;
}
bool TestReentr(std::string &error)
@ -306,22 +316,22 @@ bool TestReentr(std::string &error)
g_pC7 = &g_C7;
g_pC8 = &g_C8;
SH_ADD_HOOK_STATICFUNC(C1, F, g_pC1, Handler_C1_F, false);
SH_ADD_HOOK_STATICFUNC(C1, G, g_pC1, Handler_C1_G, false);
SH_ADD_HOOK_STATICFUNC(C2, F, g_pC2, Handler_C2_F, false);
SH_ADD_HOOK_STATICFUNC(C2, G, g_pC2, Handler_C2_G, false);
SH_ADD_HOOK_STATICFUNC(C3, F, g_pC3, Handler_C3_F, false);
SH_ADD_HOOK_STATICFUNC(C3, G, g_pC3, Handler_C3_G, false);
SH_ADD_HOOK_STATICFUNC(C4, F, g_pC4, Handler_C4_F, false);
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_ADD_HOOK_STATICFUNC(C5, F, g_pC5, Handler_C5_F, false);
SH_ADD_HOOK_STATICFUNC(C5, G, g_pC5, Handler_C5_G, false);
SH_ADD_HOOK_STATICFUNC(C6, F, g_pC6, Handler_C6_F, false);
SH_ADD_HOOK_STATICFUNC(C6, G, g_pC6, Handler_C6_G, false);
SH_ADD_HOOK_STATICFUNC(C7, F, g_pC7, Handler_C7_F, false);
SH_ADD_HOOK_STATICFUNC(C7, G, g_pC7, Handler_C7_G, false);
SH_ADD_HOOK_STATICFUNC(C8, F, g_pC8, Handler_C8_F, false);
SH_ADD_HOOK_STATICFUNC(C8, G, g_pC8, Handler_C8_G, false);
SH_ADD_HOOK(C1, F, g_pC1, SH_STATIC(Handler_C1_F), false);
SH_ADD_HOOK(C1, G, g_pC1, SH_STATIC(Handler_C1_G), false);
SH_ADD_HOOK(C2, F, g_pC2, SH_STATIC(Handler_C2_F), false);
SH_ADD_HOOK(C2, G, g_pC2, SH_STATIC(Handler_C2_G), false);
SH_ADD_HOOK(C3, F, g_pC3, SH_STATIC(Handler_C3_F), false);
SH_ADD_HOOK(C3, G, g_pC3, SH_STATIC(Handler_C3_G), false);
SH_ADD_HOOK(C4, F, g_pC4, SH_STATIC(Handler_C4_F), false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
SH_ADD_HOOK(C5, F, g_pC5, SH_STATIC(Handler_C5_F), false);
SH_ADD_HOOK(C5, G, g_pC5, SH_STATIC(Handler_C5_G), false);
SH_ADD_HOOK(C6, F, g_pC6, SH_STATIC(Handler_C6_F), false);
SH_ADD_HOOK(C6, G, g_pC6, SH_STATIC(Handler_C6_G), false);
SH_ADD_HOOK(C7, F, g_pC7, SH_STATIC(Handler_C7_F), false);
SH_ADD_HOOK(C7, G, g_pC7, SH_STATIC(Handler_C7_G), false);
SH_ADD_HOOK(C8, F, g_pC8, SH_STATIC(Handler_C8_F), false);
SH_ADD_HOOK(C8, G, g_pC8, SH_STATIC(Handler_C8_G), false);
g_pC1->F();
@ -361,7 +371,7 @@ bool TestReentr(std::string &error)
NULL), "1");
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
g_pC1->F();
@ -517,7 +527,7 @@ bool TestReentr(std::string &error)
SH_ADD_HOOK_STATICFUNC(C4, G, g_pC4, Handler2_C4_G, false);
SH_ADD_HOOK(C4, G, g_pC4, SH_STATIC(Handler2_C4_G), false);
g_TestID = 2;
@ -578,22 +588,22 @@ bool TestReentr(std::string &error)
new State_C1_F(g_pC1),
NULL), "7");
SH_REMOVE_HOOK_STATICFUNC(C1, F, g_pC1, Handler_C1_F, false);
SH_REMOVE_HOOK_STATICFUNC(C1, G, g_pC1, Handler_C1_G, false);
SH_REMOVE_HOOK_STATICFUNC(C2, F, g_pC2, Handler_C2_F, false);
SH_REMOVE_HOOK_STATICFUNC(C2, G, g_pC2, Handler_C2_G, false);
SH_REMOVE_HOOK_STATICFUNC(C3, F, g_pC3, Handler_C3_F, false);
SH_REMOVE_HOOK_STATICFUNC(C3, G, g_pC3, Handler_C3_G, false);
SH_REMOVE_HOOK_STATICFUNC(C4, F, g_pC4, Handler_C4_F, false);
SH_REMOVE_HOOK_STATICFUNC(C4, G, g_pC4, Handler_C4_G, false);
SH_REMOVE_HOOK_STATICFUNC(C5, F, g_pC5, Handler_C5_F, false);
SH_REMOVE_HOOK_STATICFUNC(C5, G, g_pC5, Handler_C5_G, false);
SH_REMOVE_HOOK_STATICFUNC(C6, F, g_pC6, Handler_C6_F, false);
SH_REMOVE_HOOK_STATICFUNC(C6, G, g_pC6, Handler_C6_G, false);
SH_REMOVE_HOOK_STATICFUNC(C7, F, g_pC7, Handler_C7_F, false);
SH_REMOVE_HOOK_STATICFUNC(C7, G, g_pC7, Handler_C7_G, false);
SH_REMOVE_HOOK_STATICFUNC(C8, F, g_pC8, Handler_C8_F, false);
SH_REMOVE_HOOK_STATICFUNC(C8, G, g_pC8, Handler_C8_G, false);
SH_REMOVE_HOOK(C1, F, g_pC1, SH_STATIC(Handler_C1_F), false);
SH_REMOVE_HOOK(C1, G, g_pC1, SH_STATIC(Handler_C1_G), false);
SH_REMOVE_HOOK(C2, F, g_pC2, SH_STATIC(Handler_C2_F), false);
SH_REMOVE_HOOK(C2, G, g_pC2, SH_STATIC(Handler_C2_G), false);
SH_REMOVE_HOOK(C3, F, g_pC3, SH_STATIC(Handler_C3_F), false);
SH_REMOVE_HOOK(C3, G, g_pC3, SH_STATIC(Handler_C3_G), false);
SH_REMOVE_HOOK(C4, F, g_pC4, SH_STATIC(Handler_C4_F), false);
SH_REMOVE_HOOK(C4, G, g_pC4, SH_STATIC(Handler_C4_G), false);
SH_REMOVE_HOOK(C5, F, g_pC5, SH_STATIC(Handler_C5_F), false);
SH_REMOVE_HOOK(C5, G, g_pC5, SH_STATIC(Handler_C5_G), false);
SH_REMOVE_HOOK(C6, F, g_pC6, SH_STATIC(Handler_C6_F), false);
SH_REMOVE_HOOK(C6, G, g_pC6, SH_STATIC(Handler_C6_G), false);
SH_REMOVE_HOOK(C7, F, g_pC7, SH_STATIC(Handler_C7_F), false);
SH_REMOVE_HOOK(C7, G, g_pC7, SH_STATIC(Handler_C7_G), false);
SH_REMOVE_HOOK(C8, F, g_pC8, SH_STATIC(Handler_C8_F), false);
SH_REMOVE_HOOK(C8, G, g_pC8, SH_STATIC(Handler_C8_G), false);
return true;
}

View File

@ -76,6 +76,7 @@ namespace
return sth.Func();
}
};
class CHelloDerived : public CHello { };
class CHook
{
@ -99,12 +100,10 @@ bool TestRef(std::string &error)
CDerived der;
CDerived2 der2(11);
CDerived2 der3(12);
CHello hello;
CHelloDerived hello;
CHello *pHello = &hello;
CHook hook;
SourceHook::CallClass<CHello> *cc = SH_GET_CALLCLASS(&hello);
ADD_STATE(State_Result(pHello->Func(base)));
ADD_STATE(State_Result(pHello->Func(der)));
ADD_STATE(State_Result(pHello->Func(der2)));
@ -117,10 +116,10 @@ bool TestRef(std::string &error)
new State_Result(12),
NULL), "Part 1");
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(base)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der2)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der3)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(base)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der2)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der3)));
CHECK_STATES((&g_States,
new State_Result(0),
@ -129,7 +128,7 @@ bool TestRef(std::string &error)
new State_Result(12),
NULL), "Part 2");
SH_ADD_HOOK_MEMFUNC(CHello, Func, &hello, &hook, &CHook::Func, false);
SH_ADD_HOOK(CHello, Func, &hello, SH_MEMBER(&hook, &CHook::Func), false);
ADD_STATE(State_Result(pHello->Func(base)));
ADD_STATE(State_Result(pHello->Func(der)));
@ -147,10 +146,10 @@ bool TestRef(std::string &error)
new State_Result(20),
NULL), "Part 3");
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(base)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der2)));
ADD_STATE(State_Result(SH_CALL(cc, &CHello::Func)(der3)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(base)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der2)));
ADD_STATE(State_Result(SH_CALL(pHello, &CHello::Func)(der3)));
CHECK_STATES((&g_States,
new State_Result(0),

View File

@ -48,6 +48,10 @@ namespace
return m_Var2;
}
};
class Whatever : public Test
{
};
class CHook
{
@ -98,7 +102,7 @@ bool TestRefRet(std::string &error)
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test test;
Whatever test;
Test *pTest = &test;
CHook hook;
@ -111,7 +115,7 @@ bool TestRefRet(std::string &error)
NULL), "Part 1");
// Now add Func1_Pre1, which supercedes and returns hook.m_Var
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre1, false);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
int &ret2 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret2));
@ -123,7 +127,7 @@ bool TestRefRet(std::string &error)
NULL), "Part 2");
// Now add Func1_Post1, which only reports orig ret and override ret
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post1, true);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
int &ret3 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret3));
@ -139,8 +143,8 @@ bool TestRefRet(std::string &error)
// Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337)
// and add Func1_Post2, which overrides and returns hook.m_Var again.
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre2, false);
SH_ADD_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post2, true);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
SH_ADD_HOOK(Test, Func1, &test, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
int &ret4 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret4));
@ -160,8 +164,7 @@ bool TestRefRet(std::string &error)
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
// Through a callclass
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(&test);
int &ret5 = SH_CALL(cc1, &Test::Func1)();
int &ret5 = SH_CALL(pTest, &Test::Func1)();
ADD_STATE(State_Func1_Ret(&ret5));
CHECK_STATES((&g_States,
@ -169,7 +172,6 @@ bool TestRefRet(std::string &error)
new State_Func1_Ret(&test.m_Var1),
NULL), "Part 5");
SH_RELEASE_CALLCLASS(cc1);
////////////////////////////////////////////////////////////////////////////////////////
// Func2 tests
@ -181,8 +183,8 @@ bool TestRefRet(std::string &error)
new State_Func2_Ret(&test.m_Var2),
NULL), "Part 6");
SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Pre1, false);
SH_ADD_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Post1, true);
SH_ADD_HOOK(Test, Func2, &test, SH_MEMBER(&hook, &CHook::Func2_Pre1), false);
SH_ADD_HOOK(Test, Func2, &test, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
const int &ret22 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret22));