1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-01-19 08:52:34 +01:00

Fixed hooking vtables with unaligned thunk entries, and returning references in manual hooks. (bug 4655, r=dvander)

This commit is contained in:
Pavol Marko 2010-10-16 23:21:58 -07:00
parent 749bdd044a
commit 31be74561d
41 changed files with 2253 additions and 679 deletions

View File

@ -23,6 +23,10 @@ for i in MMS.sdkInfo:
'provider/provider_ep2.cpp',
'sourcehook/sourcehook.cpp',
'sourcehook/sourcehook_hookmangen.cpp',
'sourcehook/sourcehook_impl_chookidman.cpp',
'sourcehook/sourcehook_impl_chookmaninfo.cpp',
'sourcehook/sourcehook_impl_cproto.cpp',
'sourcehook/sourcehook_impl_cvfnptr.cpp',
'gamedll_bridge.cpp',
'vsp_bridge.cpp'
]

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shworker", "shworker.vcproj", "{7CD76E64-A9DF-47DB-8A68-36297C67E557}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Debug|Win32.ActiveCfg = Debug|Win32
{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Debug|Win32.Build.0 = Debug|Win32
{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Release|Win32.ActiveCfg = Release|Win32
{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="shworker"
ProjectGUID="{7CD76E64-A9DF-47DB-8A68-36297C67E557}"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;stricmp=_stricmp"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
DisableSpecificWarnings="4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/shworker.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/shworker.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;stricmp=_stricmp"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
DisableSpecificWarnings="4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/shworker.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath="..\fd_hopter.cpp"
>
</File>
<File
RelativePath="..\shworker.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -743,7 +743,7 @@ int main(int argc, const char **argv)
const char *action = argv[1];
if (strcasecmp(action, "hopter") == 0)
if (stricmp(action, "hopter") == 0)
{
const char *filenamein = argv[2];
const char *filenameout = argv[3];
@ -751,7 +751,7 @@ int main(int argc, const char **argv)
return action_hopter(argsnum, filenamein, filenameout);
}
else if (strcasecmp(action, "iter") == 0)
else if (stricmp(action, "iter") == 0)
{
const char *filenamein = argv[2];
const char *filenameout = argv[3];

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -307,6 +307,20 @@ namespace SourceHook
};
};
template <class T> struct ReferenceUtil
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
template <class T> struct ReferenceUtil<T&>
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
struct IHookContext
{
virtual ISHDelegate *GetNext() = 0;
@ -480,7 +494,7 @@ namespace SourceHook
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
const void *origRetPtr, void *overrideRetPtr) = 0;
@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
// only call these from the hook handlers directly!
#define MAKE_NOREF_VALUE(rettype) \
*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
// If a hook on a function which returns a reference does not want to specify a return value,
// it can use this macro.
// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
#define RETURN_META_NOREF(result, rettype) \
RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN0(hookname, rettype) \
@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN0_vafmt(hookname, rettype) \
@ -1368,7 +1386,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN1(hookname, rettype, param1) \
@ -1401,7 +1419,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN1_vafmt(hookname, rettype, param1) \
@ -1573,7 +1591,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN2(hookname, rettype, param1, param2) \
@ -1606,7 +1624,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN2_vafmt(hookname, rettype, param1, param2) \
@ -1778,7 +1796,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN3(hookname, rettype, param1, param2, param3) \
@ -1811,7 +1829,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN3_vafmt(hookname, rettype, param1, param2, param3) \
@ -1983,7 +2001,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN4(hookname, rettype, param1, param2, param3, param4) \
@ -2016,7 +2034,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN4_vafmt(hookname, rettype, param1, param2, param3, param4) \
@ -2188,7 +2206,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN5(hookname, rettype, param1, param2, param3, param4, param5) \
@ -2221,7 +2239,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN5_vafmt(hookname, rettype, param1, param2, param3, param4, param5) \
@ -2393,7 +2411,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN6(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@ -2426,7 +2444,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN6_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@ -2598,7 +2616,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN7(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@ -2631,7 +2649,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN7_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@ -2803,7 +2821,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN8(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@ -2836,7 +2854,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN8_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@ -3008,7 +3026,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN9(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@ -3041,7 +3059,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN9_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@ -3213,7 +3231,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN10(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@ -3246,7 +3264,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN10_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@ -3418,7 +3436,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN11(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@ -3451,7 +3469,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN11_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@ -3623,7 +3641,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN12(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@ -3656,7 +3674,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN12_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@ -3828,7 +3846,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN13(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@ -3861,7 +3879,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN13_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@ -4033,7 +4051,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN14(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@ -4066,7 +4084,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN14_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@ -4238,7 +4256,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN15(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@ -4271,7 +4289,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN15_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@ -4443,7 +4461,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN16(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@ -4476,7 +4494,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN16_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@ -6737,12 +6755,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Para
namespace SourceHook
{
template <class RetType>
void SetOverrideResult(ISourceHook *shptr, const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
// SetOverrideResult used to be implemented like this:
// SetOverrideResult(shptr, memfuncptr, return);
// normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@ -6767,6 +6779,14 @@ namespace SourceHook
}
};
// For manual hooks:
// The rettype is passed in manually
template <class RetType>
OverrideFunctor<RetType> SetOverrideResult()
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)())
{

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -307,6 +307,20 @@ namespace SourceHook
};
};
template <class T> struct ReferenceUtil
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
template <class T> struct ReferenceUtil<T&>
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
struct IHookContext
{
virtual ISHDelegate *GetNext() = 0;
@ -480,7 +494,7 @@ namespace SourceHook
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
const void *origRetPtr, void *overrideRetPtr) = 0;
@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
// only call these from the hook handlers directly!
#define MAKE_NOREF_VALUE(rettype) \
*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
// If a hook on a function which returns a reference does not want to specify a return value,
// it can use this macro.
// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
#define RETURN_META_NOREF(result, rettype) \
RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN$1(hookname, rettype@[$2,1,$1:, param$2@]) \
@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN$1_vafmt(hookname, rettype@[$2,1,$1:, param$2@]) \
@ -1415,12 +1433,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]..
namespace SourceHook
{
template <class RetType>
void SetOverrideResult(ISourceHook *shptr, const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
// SetOverrideResult used to be implemented like this:
// SetOverrideResult(shptr, memfuncptr, return);
// normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@ -1444,6 +1456,14 @@ namespace SourceHook
*reinterpret_cast<typename ReferenceCarrier<T&>::type *>(shptr->GetOverrideRetPtr()) = res;
}
};
// For manual hooks:
// The rettype is passed in manually
template <class RetType>
OverrideFunctor<RetType> SetOverrideResult()
{
return OverrideFunctor<RetType>();
}
@[$1,0,$a:
template <class Iface, class RetType@[$2,1,$1:, class Param$2@]>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(@[$2,1,$1|, :Param$2@]))

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,6 +1,9 @@
#ifndef __SH_PAGEALLOC_H__
#define __SH_PAGEALLOC_H__
#include "sh_list.h"
#include "sh_memory.h"
# if SH_XP == SH_XP_WINAPI
# include <windows.h>
# elif SH_XP == SH_XP_POSIX
@ -53,6 +56,7 @@ namespace SourceHook
bool isolated; // may contain only one AU
size_t minAlignment;
AUList allocUnits;
bool isRE; // true: RE, otherwise: RW
void CheckGap(size_t gap_begin, size_t gap_end, size_t reqsize,
size_t &smallestgap_pos, size_t &smallestgap_size, size_t &outAlignBytes)
@ -122,9 +126,11 @@ namespace SourceHook
void *alignedAUBegin = reinterpret_cast<void*>(
AUBegin + ((minAlignment - AUBegin % minAlignment) % minAlignment)
);
if (addr == alignedAUBegin)
{
DebugCleanMemory(reinterpret_cast<unsigned char*>(startPtr) + iter->begin_offset,
iter->size);
allocUnits.erase(iter);
return true;
}
@ -133,6 +139,26 @@ namespace SourceHook
return false;
}
void DebugCleanMemory(unsigned char* start, size_t size)
{
bool wasRE = isRE;
if (isRE)
{
SetRW();
}
unsigned char* end = start + size;
for (unsigned char* p = start; p != end; ++p)
{
*p = 0xCC;
}
if (wasRE)
{
SetRE();
}
}
bool Contains(void *addr)
{
return addr >= startPtr && addr < reinterpret_cast<void*>(reinterpret_cast<char*>(startPtr) + size);
@ -146,6 +172,18 @@ namespace SourceHook
VirtualFree(startPtr, 0, MEM_RELEASE);
#endif
}
void SetRE()
{
SetMemAccess(startPtr, size, SH_MEM_READ | SH_MEM_EXEC);
isRE = true;
}
void SetRW()
{
SetMemAccess(startPtr, size, SH_MEM_READ | SH_MEM_WRITE);
isRE = false;
}
};
typedef List<AllocatedRegion> ARList;
@ -178,6 +216,7 @@ namespace SourceHook
if (newRegion.startPtr)
{
newRegion.SetRW();
m_Regions.push_back(newRegion);
return true;
}
@ -210,7 +249,7 @@ namespace SourceHook
}
public:
CPageAlloc(size_t minAlignment = 1 /* power of 2 */ ) : m_MinAlignment(minAlignment)
CPageAlloc(size_t minAlignment = 4 /* power of 2 */ ) : m_MinAlignment(minAlignment)
{
#if SH_XP == SH_XP_POSIX
m_PageSize = sysconf(_SC_PAGESIZE);
@ -262,7 +301,7 @@ namespace SourceHook
{
if (iter->Contains(ptr))
{
SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_EXEC);
iter->SetRE();
break;
}
}
@ -274,7 +313,7 @@ namespace SourceHook
{
if (iter->Contains(ptr))
{
SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_WRITE);
iter->SetRW();
break;
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -41,373 +41,33 @@ namespace SourceHook
namespace Impl
{
//////////////////////////////////////////////////////////////////////////
// CProto
//////////////////////////////////////////////////////////////////////////
void CProto::Fill(const ProtoInfo *pProto)
{
if (pProto == NULL)
m_Version = -1;
m_ParamsPassInfo.clear();
if (pProto->paramsPassInfo[0].size == 0)
{
// Version 1
m_Version = 0;
m_Convention = pProto->convention;
m_NumOfParams = pProto->numOfParams;
m_RetPassInfo.size = pProto->retPassInfo.size;
m_RetPassInfo.type = pProto->retPassInfo.type;
m_RetPassInfo.flags = GetRealFlags(pProto->retPassInfo);
m_RetPassInfo.pNormalCtor = NULL;
m_RetPassInfo.pCopyCtor = NULL;
m_RetPassInfo.pDtor = NULL;
m_RetPassInfo.pAssignOperator = NULL;
m_ParamsPassInfo.resize(pProto->numOfParams);
for (int i = 1; i <= pProto->numOfParams; ++i)
{
m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
m_ParamsPassInfo[i-1].flags = GetRealFlags(pProto->paramsPassInfo[i]);
m_ParamsPassInfo[i-1].pNormalCtor = NULL;
m_ParamsPassInfo[i-1].pCopyCtor = NULL;
m_ParamsPassInfo[i-1].pDtor = NULL;
m_ParamsPassInfo[i-1].pAssignOperator = NULL;
}
}
else if (pProto->paramsPassInfo[0].size == 1)
{
// Version 2
m_Version = 1;
m_Convention = pProto->convention;
m_NumOfParams = pProto->numOfParams;
m_RetPassInfo.size = pProto->retPassInfo.size;
m_RetPassInfo.type = pProto->retPassInfo.type;
m_RetPassInfo.flags = pProto->retPassInfo.flags;
m_RetPassInfo.pNormalCtor = pProto->retPassInfo2.pNormalCtor;
m_RetPassInfo.pCopyCtor = pProto->retPassInfo2.pCopyCtor;
m_RetPassInfo.pDtor = pProto->retPassInfo2.pDtor;
m_RetPassInfo.pAssignOperator = pProto->retPassInfo2.pAssignOperator;
m_ParamsPassInfo.resize(pProto->numOfParams);
for (int i = 1; i <= pProto->numOfParams; ++i)
{
m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
m_ParamsPassInfo[i-1].flags = pProto->paramsPassInfo[i].flags;
m_ParamsPassInfo[i-1].pNormalCtor = pProto->paramsPassInfo2[i].pNormalCtor;
m_ParamsPassInfo[i-1].pCopyCtor = pProto->paramsPassInfo2[i].pCopyCtor;
m_ParamsPassInfo[i-1].pDtor = pProto->paramsPassInfo2[i].pDtor;
m_ParamsPassInfo[i-1].pAssignOperator = pProto->paramsPassInfo2[i].pAssignOperator;
}
}
else
{
// Unknown
m_Version = -1;
}
}
// Basic compat test
// Other than this, we assume that the plugins know what they're doing
bool CProto::operator == (const CProto &other) const
{
if (m_Version < 0 || other.GetVersion() < 0)
return false;
if (m_NumOfParams != other.GetNumOfParams())
return false;
if (m_Convention != ProtoInfo::CallConv_Unknown && other.GetConvention() != ProtoInfo::CallConv_Unknown &&
m_Convention != other.GetConvention())
return false;
if (GetRealSize(GetRet()) != GetRealSize(other.GetRet()))
return false;
for (int i = 0; i < m_NumOfParams; ++i)
{
if (GetRealSize(GetParam(i)) != GetRealSize(other.GetParam(i)))
return false;
if (GetParam(i).type != PassInfo::PassType_Unknown && other.GetParam(i).type != PassInfo::PassType_Unknown)
{
if (GetParam(i).type != other.GetParam(i).type)
return false;
if (GetParam(i).flags != other.GetParam(i).flags)
return false;
}
}
return true;
}
bool CProto::ExactlyEqual(const CProto &other) const
{
if (m_Version != other.m_Version ||
m_NumOfParams != other.m_NumOfParams ||
m_Convention != other.m_Convention ||
GetRet() != other.GetRet())
{
return false;
}
for (int i = 0; i < m_NumOfParams; ++i)
{
if(GetParam(i) != other.GetParam(i))
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// CHookManager
//////////////////////////////////////////////////////////////////////////
void CHookManager::SetInfo(int hookman_version, int vtbloffs, int vtblidx,
ProtoInfo *proto, void *hookfunc_vfnptr)
{
m_Version = hookman_version;
m_VtblOffs = vtbloffs;
m_VtblIdx = vtblidx;
m_Proto = proto;
m_HookfuncVfnptr = hookfunc_vfnptr;
}
//////////////////////////////////////////////////////////////////////////
// CVfnPtrList
//////////////////////////////////////////////////////////////////////////
CVfnPtr &CVfnPtrList::GetVfnPtr(void *vfnptr)
CVfnPtr *CVfnPtrList::GetVfnPtr(void *vfnptr)
{
iterator iter = find(vfnptr);
if (iter == end())
{
// No vfnptr info object found
// --> create a new one
CVfnPtr newVfnPtr(vfnptr);
push_back(newVfnPtr);
return back();
}
else
{
return *iter;
}
}
//////////////////////////////////////////////////////////////////////////
// CVfnPtr
//////////////////////////////////////////////////////////////////////////
void CVfnPtr::AddHookMan(CHookManager *pHookMan)
{
List<CHookManager*>::iterator iter;
// Don't accept invalid hook managers
if (!*pHookMan)
return;
// Check whether this hook manager already exists; if yes, ignore.
iter = m_HookMans.find(pHookMan);
if (iter != m_HookMans.end())
return;
// It doesn't -> add it. Add it to the end of its version group.
for (iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
{
if ((*iter)->GetVersion() < pHookMan->GetVersion())
break;
}
bool isBeginning = iter == m_HookMans.begin();
m_HookMans.insert(iter, pHookMan);
if (isBeginning)
{
pHookMan->IncrRef(this);
if (m_HookMans.size() > 1)
if (newVfnPtr.Init())
{
// If another hookman was used until now but this one is better
// (which it is because it's the first -> it has a higher version)
// -> switch!
push_back(newVfnPtr);
List<CHookManager*>::iterator second = m_HookMans.begin();
++second;
(*second)->DecrRef(this);
}
// Make sure that this vfnptr points at it
Patch(pHookMan->GetHookFunc());
}
}
bool CVfnPtr::HookManRemoved(CHookManager *pHookMan)
{
// Don't accept invalid hook managers
if (!*pHookMan)
return true;
List<CHookManager*>::iterator iter = m_HookMans.find(pHookMan);
if (iter == m_HookMans.end())
return true; // Didn't exist here anyway
if (iter == m_HookMans.begin())
{
// It is the first one!
pHookMan->DecrRef(this);
m_HookMans.erase(iter);
if (m_HookMans.empty())
return false; // No more hookmans -> let SH delete us
// Activate second -> now first hookman
m_HookMans.front()->IncrRef(this);
Patch(m_HookMans.front()->GetHookFunc());
}
else
{
m_HookMans.erase(iter);
}
return true;
}
bool CVfnPtr::Patch(void *newValue)
{
if (!SetMemAccess(m_Ptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE))
{
return false;
}
*reinterpret_cast<void**>(m_Ptr) = newValue;
return true;
}
CIface &CVfnPtr::GetIface(void *iface)
{
List<CIface>::iterator iter = m_IfaceList.find(iface);
if (iter == m_IfaceList.end())
{
CIface newIface(iface);
if (iface == NULL)
{
m_IfaceList.push_front(newIface);
return m_IfaceList.front();
return &(back());
}
else
{
m_IfaceList.push_back(newIface);
return m_IfaceList.back();
// Initialization failed.
return NULL;
}
}
else
{
return *iter;
}
}
//////////////////////////////////////////////////////////////////////////
// CHookIdManager
//////////////////////////////////////////////////////////////////////////
CHookIDManager::CHookIDManager()
{
}
int 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 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 CHookIDManager::Entry * 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 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);
}
}
}
void CHookIDManager::FindAllHooks(CVector<int> &output)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree)
output.push_back(static_cast<int>(i) + 1);
}
}
void CHookIDManager::FindAllHooks(CVector<int> &output, Plugin plug)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].plug == plug)
output.push_back(static_cast<int>(i) + 1);
}
}
void CHookIDManager::RemoveAll(void *vfnptr)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].vfnptr == vfnptr)
m_Entries[i].isfree = true;
return &(*iter);
}
}
@ -480,9 +140,18 @@ namespace SourceHook
break;
}
CVfnPtr &vfnPtr = m_VfnPtrs.GetVfnPtr(cur_vfnptr);
vfnPtr.AddHookMan(m_HookManList.GetHookMan(hookManager));
CIface &ifaceinst = vfnPtr.GetIface(adjustediface);
CVfnPtr *vfnPtr = m_VfnPtrs.GetVfnPtr(cur_vfnptr);
if (!vfnPtr)
{
// Could not create the vfnptr info object.
// This could be because a thunk generation on GCC
// has failed. See sourcehook_impl_cvfnptr.cpp
// for details.
return false;
}
vfnPtr->AddHookMan(m_HookManList.GetHookMan(hookManager));
CIface &ifaceinst = vfnPtr->GetIface(adjustediface);
// Add the hook
CHook hook(plug, thisptr_offs, handler,
@ -588,9 +257,7 @@ namespace SourceHook
ctx_iter->VfnPtrRemoved(&(*vfnptr_iter));
}
vfnptr_iter->Revert();
m_VfnPtrs.erase(vfnptr_iter);
RevertAndRemoveVfnPtr(vfnptr_iter);
}
}
@ -598,6 +265,52 @@ namespace SourceHook
return true;
}
List<CVfnPtr>::iterator CSourceHookImpl::RevertAndRemoveVfnPtr(List<CVfnPtr>::iterator vfnptr_iter)
{
ICleanupTask *cleanupTask = vfnptr_iter->GetCleanupTask();
// Some vfnptrs require cleanup.
// Concrete case: on GCC, when the original vtable entry is not even
// we generate an even-aligned thunk to call the original function.
// If the vfnptr is being removed from a pre hook on the vfnptr
// we have to delay the cleanup of this thunk until the hook loop is done
// (because the orig function call mechanism is going to use the thunk).
if (cleanupTask != NULL)
{
// If this vfnptr is in use in one of the hook loops running at the moment
// Schedule it for removal on the DEEPEST hook loop.
size_t numOfContexts = m_ContextStack.size();
// m_ContextStack.at(0) is the deepest hook context
// m_ContextStack.at(size-1) = m_ContextStack.front is the uppermost
bool cleanupImmedieately = true;
CVfnPtr *vfnPtrObjAddr = &(*vfnptr_iter);
for (size_t i = 0; i < numOfContexts; ++i)
{
CHookContext &context = m_ContextStack.at(i);
if (context.pVfnPtr == vfnPtrObjAddr)
{
// Found a hook context using this vfnptr at the moment.
context.m_CleanupTask = cleanupTask;
cleanupImmedieately = false; // Delay the cleanup
break;
}
}
if (cleanupImmedieately)
{
cleanupTask->CleanupAndDeleteThis();
}
}
// Do the work
vfnptr_iter->Revert();
return m_VfnPtrs.erase(vfnptr_iter);
}
void CSourceHookImpl::SetRes(META_RES res)
{
*m_ContextStack.front().pCurRes = res;
@ -675,10 +388,9 @@ namespace SourceHook
// This vfnptr has no more hook managers
// and asks to be removed.
vfnptr_iter->Revert();
m_HookIDMan.RemoveAll(vfnptr_iter->GetPtr());
vfnptr_iter = m_VfnPtrs.erase(vfnptr_iter);
vfnptr_iter = RevertAndRemoveVfnPtr(vfnptr_iter);
}
else
{
@ -710,7 +422,12 @@ namespace SourceHook
void CSourceHookImpl::ResetIgnoreHooks(void *vfnptr)
{
if (!m_ContextStack.empty() && m_ContextStack.front().m_State == CHookContext::State_Ignore)
m_ContextStack.pop();
{
// Actually use EndContext
// instead of m_ContextStack.pop directly
// because it runs the cleanup task if neccesary
EndContext(&(m_ContextStack.front()));
}
}
void *CSourceHookImpl::GetOrigVfnPtrEntry(void *vfnptr)
@ -753,7 +470,7 @@ namespace SourceHook
curCtx.m_State = CHookContext::State_Dead;
}
IHookContext *CSourceHookImpl::SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry, META_RES *statusPtr,
IHookContext *CSourceHookImpl::SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr, META_RES *statusPtr,
META_RES *prevResPtr, META_RES *curResPtr, const void *origRetPtr, void *overrideRetPtr)
{
CHookContext *pCtx = NULL;
@ -781,7 +498,8 @@ namespace SourceHook
}
else
{
*origentry = (*vfnptr_iter)->GetOrigEntry();
*origCallAddr = (*vfnptr_iter)->GetOrigCallAddr();
oldctx->pVfnPtr = *vfnptr_iter;
}
oldctx->pOrigRet = origRetPtr;
@ -839,7 +557,7 @@ namespace SourceHook
else
{
pCtx->pVfnPtr = *vfnptr_iter;
*origentry = pCtx->pVfnPtr->GetOrigEntry();
*origCallAddr = pCtx->pVfnPtr->GetOrigCallAddr();
pCtx->pIface = pCtx->pVfnPtr->FindIface(thisptr);
}
@ -855,6 +573,9 @@ namespace SourceHook
void CSourceHookImpl::EndContext(IHookContext *pCtx)
{
// Do clean up task, if any is associated with this context
m_ContextStack.front().DoCleanupTaskAndDeleteIt();
// Then remove it
m_ContextStack.pop();
}
@ -1085,9 +806,22 @@ namespace SourceHook
{
if (pVfnPtr == vfnptr)
{
pVfnPtr = NULL;
// Don't set pVfnPtr = NULL here!
// It may be used still.
// RevertAndRemoveVfnPtr uses it to find the hook context
// to which to attach the cleanup task of the vfnptr.
//pVfnPtr = NULL;
m_State = State_Dead;
}
}
void CHookContext::DoCleanupTaskAndDeleteIt()
{
if (m_CleanupTask != NULL)
{
m_CleanupTask->CleanupAndDeleteThis();
}
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -307,6 +307,20 @@ namespace SourceHook
};
};
template <class T> struct ReferenceUtil
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
template <class T> struct ReferenceUtil<T&>
{
typedef T plain_type;
typedef T* pointer_type;
typedef T& reference_type;
};
struct IHookContext
{
virtual ISHDelegate *GetNext() = 0;
@ -480,7 +494,7 @@ namespace SourceHook
* @return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
* when the hook func is being called as part of a recall
*/
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
const void *origRetPtr, void *overrideRetPtr) = 0;
@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
// only call these from the hook handlers directly!
#define MAKE_NOREF_VALUE(rettype) \
*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
// If a hook on a function which returns a reference does not want to specify a return value,
// it can use this macro.
// ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
#define RETURN_META_NOREF(result, rettype) do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
#define RETURN_META_NOREF(result, rettype) \
RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
// Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
// Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN0(hookname, rettype) \
@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN0_vafmt(hookname, rettype) \
@ -1368,7 +1386,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN1(hookname, rettype, param1) \
@ -1401,7 +1419,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN1_vafmt(hookname, rettype, param1) \
@ -1573,7 +1591,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN2(hookname, rettype, param1, param2) \
@ -1606,7 +1624,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN2_vafmt(hookname, rettype, param1, param2) \
@ -1778,7 +1796,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN3(hookname, rettype, param1, param2, param3) \
@ -1811,7 +1829,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN3_vafmt(hookname, rettype, param1, param2, param3) \
@ -1983,7 +2001,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN4(hookname, rettype, param1, param2, param3, param4) \
@ -2016,7 +2034,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN4_vafmt(hookname, rettype, param1, param2, param3, param4) \
@ -2188,7 +2206,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN5(hookname, rettype, param1, param2, param3, param4, param5) \
@ -2221,7 +2239,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN5_vafmt(hookname, rettype, param1, param2, param3, param4, param5) \
@ -2393,7 +2411,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN6(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@ -2426,7 +2444,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN6_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@ -2598,7 +2616,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN7(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@ -2631,7 +2649,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN7_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@ -2803,7 +2821,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN8(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@ -2836,7 +2854,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN8_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@ -3008,7 +3026,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN9(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@ -3041,7 +3059,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN9_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@ -3213,7 +3231,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN10(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@ -3246,7 +3264,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN10_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@ -3418,7 +3436,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN11(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@ -3451,7 +3469,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN11_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@ -3623,7 +3641,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN12(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@ -3656,7 +3674,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN12_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@ -3828,7 +3846,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN13(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@ -3861,7 +3879,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN13_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@ -4033,7 +4051,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN14(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@ -4066,7 +4084,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN14_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@ -4238,7 +4256,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN15(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@ -4271,7 +4289,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN15_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@ -4443,7 +4461,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN16(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@ -4476,7 +4494,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
{ \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
}
#define SH_DECL_MANUALEXTERN16_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@ -6737,12 +6755,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Para
namespace SourceHook
{
template <class RetType>
void SetOverrideResult(ISourceHook *shptr, const RetType res)
{
*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
}
// SetOverrideResult used to be implemented like this:
// SetOverrideResult(shptr, memfuncptr, return);
// normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@ -6767,6 +6779,14 @@ namespace SourceHook
}
};
// For manual hooks:
// The rettype is passed in manually
template <class RetType>
OverrideFunctor<RetType> SetOverrideResult()
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)())
{

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2009 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,6 +1,6 @@
/* ======== SourceHook ========
* vim: set ts=4 :
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -189,6 +189,10 @@ namespace SourceHook
{
struct CHookContext : IHookContext
{
CHookContext() : m_CleanupTask(NULL)
{
}
enum State
{
State_Born,
@ -224,6 +228,8 @@ namespace SourceHook
bool m_CallOrig;
ICleanupTask *m_CleanupTask;
void SkipPaused(List<CHook>::iterator &iter, List<CHook> &list)
{
while (iter != list.end() && iter->IsPaused())
@ -238,12 +244,13 @@ namespace SourceHook
void *GetOverrideRetPtr();
const void *GetOrigRetPtr();
bool ShouldCallOrig();
void DoCleanupTaskAndDeleteIt();
};
class CVfnPtrList : public List<CVfnPtr>
{
public:
CVfnPtr &GetVfnPtr(void *p);
CVfnPtr *GetVfnPtr(void *p);
};
typedef CStack<CHookContext> HookContextStack;
@ -259,6 +266,7 @@ namespace SourceHook
bool SetHookPaused(int hookid, bool paused);
CHookManList::iterator RemoveHookManager(CHookManList::iterator iter);
List<CVfnPtr>::iterator RevertAndRemoveVfnPtr(List<CVfnPtr>::iterator vfnptr_iter);
public:
CSourceHookImpl();
virtual ~CSourceHookImpl();
@ -308,7 +316,7 @@ namespace SourceHook
void DoRecall();
IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry, META_RES *statusPtr,
IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr, META_RES *statusPtr,
META_RES *prevResPtr, META_RES *curResPtr, const void *origRetPtr, void *overrideRetPtr);
void EndContext(IHookContext *pCtx);

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -0,0 +1,111 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* Contributors: Scott "Damaged Soul" Ehlert
* ============================
*/
#include "sourcehook_impl.h"
namespace SourceHook
{
namespace Impl
{
CHookIDManager::CHookIDManager()
{
}
int 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 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 CHookIDManager::Entry * 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 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);
}
}
}
void CHookIDManager::FindAllHooks(CVector<int> &output)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree)
output.push_back(static_cast<int>(i) + 1);
}
}
void CHookIDManager::FindAllHooks(CVector<int> &output, Plugin plug)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].plug == plug)
output.push_back(static_cast<int>(i) + 1);
}
}
void CHookIDManager::RemoveAll(void *vfnptr)
{
size_t cursize = m_Entries.size();
for (size_t i = 0; i < cursize; ++i)
{
if (!m_Entries[i].isfree && m_Entries[i].vfnptr == vfnptr)
m_Entries[i].isfree = true;
}
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -0,0 +1,84 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* Contributors: Scott "Damaged Soul" Ehlert
* ============================
*/
#include "sourcehook_impl.h"
namespace SourceHook
{
namespace Impl
{
CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc)
: m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1)
{
// Query pubfunc
// -> Should call SetInfo and set all the other variables!
if (m_PubFunc(false, this) != 0)
{
// Error!
m_Version = -1;
}
}
void CHookManager::SetInfo(int hookman_version, int vtbloffs, int vtblidx,
ProtoInfo *proto, void *hookfunc_vfnptr)
{
m_Version = hookman_version;
m_VtblOffs = vtbloffs;
m_VtblIdx = vtblidx;
m_Proto = proto;
m_HookfuncVfnptr = hookfunc_vfnptr;
}
void CHookManager::Register()
{
m_PubFunc(true, this);
}
void CHookManager::Unregister()
{
m_PubFunc(true, NULL);
}
void CHookManager::IncrRef(CVfnPtr *pVfnPtr)
{
m_VfnPtrs.push_back(pVfnPtr);
if (m_VfnPtrs.size() == 1)
Register();
}
void CHookManager::DecrRef(CVfnPtr *pVfnPtr)
{
m_VfnPtrs.remove(pVfnPtr);
if (m_VfnPtrs.empty())
Unregister();
}
CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc)
{
CHookManager hm(plug, pubFunc);
return GetHookMan(hm);
}
CHookManager *CHookManList::GetHookMan(CHookManager &hm)
{
iterator iter = find(hm);
if (iter == end())
{
push_back(hm);
return &(back());
}
else
{
return &(*iter);
}
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -46,7 +46,7 @@ namespace SourceHook
};
// *** Interface ***
inline CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc);
CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc);
inline bool operator==(const Descriptor &other) const;
inline bool operator==(const CHookManager &other) const;
@ -60,11 +60,11 @@ namespace SourceHook
inline void *GetHookFunc() const;
inline HookManagerPubFunc GetPubFunc() const;
inline void Register();
inline void Unregister();
void Register();
void Unregister();
inline void IncrRef(CVfnPtr *pVfnPtr);
inline void DecrRef(CVfnPtr *pVfnPtr);
void IncrRef(CVfnPtr *pVfnPtr);
void DecrRef(CVfnPtr *pVfnPtr);
List<CVfnPtr*> &GetVfnPtrList()
{
@ -79,22 +79,11 @@ namespace SourceHook
class CHookManList : public List<CHookManager>
{
public:
inline CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc);
inline CHookManager *GetHookMan(CHookManager &hm);
CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc);
CHookManager *GetHookMan(CHookManager &hm);
};
// *** Implementation ***
inline CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc)
: m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1)
{
// Query pubfunc
// -> Should call SetInfo and set all the other variables!
if (m_PubFunc(false, this) != 0)
{
// Error!
m_Version = -1;
}
}
// *** Implementation **/
inline CHookManager::operator bool() const
{
@ -147,50 +136,6 @@ namespace SourceHook
{
return m_PubFunc;
}
inline void CHookManager::Register()
{
m_PubFunc(true, this);
}
inline void CHookManager::Unregister()
{
m_PubFunc(true, NULL);
}
inline void CHookManager::IncrRef(CVfnPtr *pVfnPtr)
{
m_VfnPtrs.push_back(pVfnPtr);
if (m_VfnPtrs.size() == 1)
Register();
}
inline void CHookManager::DecrRef(CVfnPtr *pVfnPtr)
{
m_VfnPtrs.remove(pVfnPtr);
if (m_VfnPtrs.empty())
Unregister();
}
inline CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc)
{
CHookManager hm(plug, pubFunc);
return GetHookMan(hm);
}
inline CHookManager *CHookManList::GetHookMan(CHookManager &hm)
{
iterator iter = find(hm);
if (iter == end())
{
push_back(hm);
return &(back());
}
else
{
return &(*iter);
}
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -0,0 +1,29 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_IMPL_CLEANUPTASK_H__
#define __SOURCEHOOK_IMPL_CLEANUPTASK_H__
namespace SourceHook
{
namespace Impl
{
class ICleanupTask
{
public:
virtual void CleanupAndDeleteThis() = 0;
};
}
}
// __SOURCEHOOK_IMPL_CLEANUPTASK_H__
#endif

View File

@ -0,0 +1,145 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#include "sourcehook_impl.h"
namespace SourceHook
{
namespace Impl
{
void CProto::Fill(const ProtoInfo *pProto)
{
if (pProto == NULL)
m_Version = -1;
m_ParamsPassInfo.clear();
if (pProto->paramsPassInfo[0].size == 0)
{
// Version 1
m_Version = 0;
m_Convention = pProto->convention;
m_NumOfParams = pProto->numOfParams;
m_RetPassInfo.size = pProto->retPassInfo.size;
m_RetPassInfo.type = pProto->retPassInfo.type;
m_RetPassInfo.flags = GetRealFlags(pProto->retPassInfo);
m_RetPassInfo.pNormalCtor = NULL;
m_RetPassInfo.pCopyCtor = NULL;
m_RetPassInfo.pDtor = NULL;
m_RetPassInfo.pAssignOperator = NULL;
m_ParamsPassInfo.resize(pProto->numOfParams);
for (int i = 1; i <= pProto->numOfParams; ++i)
{
m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
m_ParamsPassInfo[i-1].flags = GetRealFlags(pProto->paramsPassInfo[i]);
m_ParamsPassInfo[i-1].pNormalCtor = NULL;
m_ParamsPassInfo[i-1].pCopyCtor = NULL;
m_ParamsPassInfo[i-1].pDtor = NULL;
m_ParamsPassInfo[i-1].pAssignOperator = NULL;
}
}
else if (pProto->paramsPassInfo[0].size == 1)
{
// Version 2
m_Version = 1;
m_Convention = pProto->convention;
m_NumOfParams = pProto->numOfParams;
m_RetPassInfo.size = pProto->retPassInfo.size;
m_RetPassInfo.type = pProto->retPassInfo.type;
m_RetPassInfo.flags = pProto->retPassInfo.flags;
m_RetPassInfo.pNormalCtor = pProto->retPassInfo2.pNormalCtor;
m_RetPassInfo.pCopyCtor = pProto->retPassInfo2.pCopyCtor;
m_RetPassInfo.pDtor = pProto->retPassInfo2.pDtor;
m_RetPassInfo.pAssignOperator = pProto->retPassInfo2.pAssignOperator;
m_ParamsPassInfo.resize(pProto->numOfParams);
for (int i = 1; i <= pProto->numOfParams; ++i)
{
m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
m_ParamsPassInfo[i-1].flags = pProto->paramsPassInfo[i].flags;
m_ParamsPassInfo[i-1].pNormalCtor = pProto->paramsPassInfo2[i].pNormalCtor;
m_ParamsPassInfo[i-1].pCopyCtor = pProto->paramsPassInfo2[i].pCopyCtor;
m_ParamsPassInfo[i-1].pDtor = pProto->paramsPassInfo2[i].pDtor;
m_ParamsPassInfo[i-1].pAssignOperator = pProto->paramsPassInfo2[i].pAssignOperator;
}
}
else
{
// Unknown
m_Version = -1;
}
}
// Basic compat test
// Other than this, we assume that the plugins know what they're doing
bool CProto::operator == (const CProto &other) const
{
if (m_Version < 0 || other.GetVersion() < 0)
return false;
if (m_NumOfParams != other.GetNumOfParams())
return false;
if (m_Convention != ProtoInfo::CallConv_Unknown && other.GetConvention() != ProtoInfo::CallConv_Unknown &&
m_Convention != other.GetConvention())
return false;
if (GetRealSize(GetRet()) != GetRealSize(other.GetRet()))
return false;
for (int i = 0; i < m_NumOfParams; ++i)
{
if (GetRealSize(GetParam(i)) != GetRealSize(other.GetParam(i)))
return false;
if (GetParam(i).type != PassInfo::PassType_Unknown && other.GetParam(i).type != PassInfo::PassType_Unknown)
{
if (GetParam(i).type != other.GetParam(i).type)
return false;
if (GetParam(i).flags != other.GetParam(i).flags)
return false;
}
}
return true;
}
bool CProto::ExactlyEqual(const CProto &other) const
{
if (m_Version != other.m_Version ||
m_NumOfParams != other.m_NumOfParams ||
m_Convention != other.m_Convention ||
GetRet() != other.GetRet())
{
return false;
}
for (int i = 0; i < m_NumOfParams; ++i)
{
if(GetParam(i) != other.GetParam(i))
return false;
}
return true;
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -0,0 +1,253 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#include "sourcehook_impl.h"
namespace SourceHook
{
namespace Impl
{
CPageAlloc CVfnPtr::ms_AlignedPageAllocator(8);
CVfnPtr::CVfnPtr(void *ptr)
: m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(m_Ptr)),
m_OrigCallThunk(NULL)
{
}
CVfnPtr::~CVfnPtr()
{
if (!m_HookMans.empty())
m_HookMans.front()->DecrRef(this);
}
bool CVfnPtr::Init()
{
// Initalize the vfn ptr info object.
// If we're running on GCC and the original vtable entry is odd
// we have a problem.
// The hook functions use non-virtual member function pointers to
// call the original function (see sourcehook.hxx, SH_SETUP_MFP and SH_CALL_ORIG)
// GCC has the same format for virtual and non-virtual MFPs:
// virtual ones have an odd value as "funcptr" where the offset into the vtable is encoded
// non-virtual ones have the direct function pointer as "funcptr", assuming that it is even
// When m_OrigEntry is odd, GCC's runtime MFP calling code interpretes it as a virtual
// function call though we want to call the function in a non-virtual way
// (the original function call mechanism between the pre and post hook loop has to bypass
// the virtual calling mechanism in order to call the original function).
#if SH_COMP==SH_COMP_GCC
if ((((ptrdiff_t)m_OrigEntry) & 1) != 0)
{
// Odd orig entry.
if (SH_PTRSIZE != 4)
{
// We only have code for IA32 atm!
return false;
}
// Generate a new thunk
m_OrigCallThunk = ms_AlignedPageAllocator.Alloc(5);
ms_AlignedPageAllocator.SetRW(m_OrigCallThunk);
unsigned char* thunkBase = reinterpret_cast<unsigned char*>(m_OrigCallThunk);
*(thunkBase + 0) = 0xE9; // offset jump, immediate operand
ptrdiff_t *offsetAddr = reinterpret_cast<ptrdiff_t*>(thunkBase + 1);
// destination = src + offset + 5
// <=> offset = destination - src - 5
*offsetAddr =
(reinterpret_cast<unsigned char*>(m_OrigEntry) - thunkBase) - 5;
ms_AlignedPageAllocator.SetRE(m_OrigCallThunk);
}
#endif
return true;
}
class CVfnPtrOrigThunkCleanup : public ICleanupTask
{
CPageAlloc *m_Allocator;
void *m_AddrToFree;
public:
CVfnPtrOrigThunkCleanup(CPageAlloc *allocator, void *addrToFree) :
m_Allocator(allocator), m_AddrToFree(addrToFree)
{
}
virtual void CleanupAndDeleteThis()
{
m_Allocator->Free(m_AddrToFree);
delete this;
}
};
ICleanupTask* CVfnPtr::GetCleanupTask()
{
if (m_OrigCallThunk != NULL)
{
return new CVfnPtrOrigThunkCleanup(&ms_AlignedPageAllocator, m_OrigCallThunk);
}
else
{
return NULL;
}
}
void* CVfnPtr::GetOrigCallAddr() const
{
if (m_OrigCallThunk)
{
return m_OrigCallThunk;
}
else
{
return m_OrigEntry;
}
}
bool CVfnPtr::Revert()
{
// 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*>(m_Ptr), SH_PTRSIZE))
{
return Patch(m_OrigEntry);
}
else
{
return true;
}
}
CIface *CVfnPtr::FindIface(void *iface)
{
List<CIface>::iterator iter = m_IfaceList.find(iface);
if (iter == m_IfaceList.end())
return NULL;
else
return &(*iter);
}
void CVfnPtr::AddHookMan(CHookManager *pHookMan)
{
List<CHookManager*>::iterator iter;
// Don't accept invalid hook managers
if (!*pHookMan)
return;
// Check whether this hook manager already exists; if yes, ignore.
iter = m_HookMans.find(pHookMan);
if (iter != m_HookMans.end())
return;
// It doesn't -> add it. Add it to the end of its version group.
for (iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
{
if ((*iter)->GetVersion() < pHookMan->GetVersion())
break;
}
bool isBeginning = iter == m_HookMans.begin();
m_HookMans.insert(iter, pHookMan);
if (isBeginning)
{
pHookMan->IncrRef(this);
if (m_HookMans.size() > 1)
{
// If another hookman was used until now but this one is better
// (which it is because it's the first -> it has a higher version)
// -> switch!
List<CHookManager*>::iterator second = m_HookMans.begin();
++second;
(*second)->DecrRef(this);
}
// Make sure that this vfnptr points at it
Patch(pHookMan->GetHookFunc());
}
}
bool CVfnPtr::HookManRemoved(CHookManager *pHookMan)
{
// Don't accept invalid hook managers
if (!*pHookMan)
return true;
List<CHookManager*>::iterator iter = m_HookMans.find(pHookMan);
if (iter == m_HookMans.end())
return true; // Didn't exist here anyway
if (iter == m_HookMans.begin())
{
// It is the first one!
pHookMan->DecrRef(this);
m_HookMans.erase(iter);
if (m_HookMans.empty())
return false; // No more hookmans -> let SH delete us
// Activate second -> now first hookman
m_HookMans.front()->IncrRef(this);
Patch(m_HookMans.front()->GetHookFunc());
}
else
{
m_HookMans.erase(iter);
}
return true;
}
bool CVfnPtr::Patch(void *newValue)
{
if (!SetMemAccess(m_Ptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE))
{
return false;
}
*reinterpret_cast<void**>(m_Ptr) = newValue;
return true;
}
CIface &CVfnPtr::GetIface(void *iface)
{
List<CIface>::iterator iter = m_IfaceList.find(iface);
if (iter == m_IfaceList.end())
{
CIface newIface(iface);
if (iface == NULL)
{
m_IfaceList.push_front(newIface);
return m_IfaceList.front();
}
else
{
m_IfaceList.push_back(newIface);
return m_IfaceList.back();
}
}
else
{
return *iter;
}
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -13,6 +13,8 @@
#include "sh_list.h"
#include "sh_memory.h"
#include "sh_pagealloc.h"
#include "sourcehook_impl_cleanuptask.h"
namespace SourceHook
{
@ -20,9 +22,12 @@ namespace SourceHook
{
class CVfnPtr
{
static CPageAlloc ms_AlignedPageAllocator;
// *** Data ***
void *m_Ptr;
void *m_OrigEntry;
void *m_OrigCallThunk; // See Init() method
List<CHookManager*> m_HookMans;
List<CIface> m_IfaceList;
@ -31,17 +36,21 @@ namespace SourceHook
typedef void* Descriptor;
// *** Interface ***
inline CVfnPtr(void *ptr);
inline ~CVfnPtr();
CVfnPtr(void *ptr);
~CVfnPtr();
bool Init();
inline bool operator==(const Descriptor &other);
inline void *GetPtr() const;
inline void *GetOrigEntry() const;
void *GetOrigCallAddr() const;
inline List<CIface> &GetIfaceList();
inline const List<CIface> &GetIfaceList() const;
inline CIface *FindIface(void *iface);
CIface *FindIface(void *iface);
CIface &GetIface(void *iface);
bool Patch(void *newValue);
inline bool Revert();
bool Revert();
ICleanupTask *GetCleanupTask();
void AddHookMan(CHookManager *pHookMan);
// If this returns false, it means that there is no hook manager left
@ -50,16 +59,6 @@ namespace SourceHook
};
// *** Implementation ***
inline CVfnPtr::CVfnPtr(void *ptr)
: m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(m_Ptr))
{
}
inline CVfnPtr::~CVfnPtr()
{
if (!m_HookMans.empty())
m_HookMans.front()->DecrRef(this);
}
inline bool CVfnPtr::operator==(const Descriptor &other)
{
@ -85,31 +84,6 @@ namespace SourceHook
{
return m_IfaceList;
}
inline bool CVfnPtr::Revert()
{
// 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*>(m_Ptr), SH_PTRSIZE))
{
return Patch(m_OrigEntry);
}
else
{
return true;
}
}
inline CIface *CVfnPtr::FindIface(void *iface)
{
List<CIface>::iterator iter = m_IfaceList.find(iface);
if (iter == m_IfaceList.end())
return NULL;
else
return &(*iter);
}
}
}

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng

View File

@ -9,8 +9,8 @@ INCLUDE = -I. -I..
MAX_PARAMS=20
BINARY = sourcehook_test
OBJECTS = main.cpp sourcehook.cpp sourcehook_hookmangen.cpp $(shell ls -t test*.cpp)
HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h
OBJECTS = main.cpp sourcehook.cpp sourcehook_hookmangen.cpp sourcehook_impl_chookmaninfo.cpp sourcehook_impl_chookidman.cpp sourcehook_impl_cproto.cpp sourcehook_impl_cvfnptr.cpp $(shell ls -t test*.cpp)
HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h ../sh_pagealloc.h
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
@ -48,10 +48,18 @@ all:
mkdir -p $(BIN_DIR)
ln -sf ../sourcehook.cpp
ln -sf ../sourcehook_hookmangen.cpp
ln -sf ../sourcehook_impl_chookidman.cpp
ln -sf ../sourcehook_impl_chookmaninfo.cpp
ln -sf ../sourcehook_impl_cproto.cpp
ln -sf ../sourcehook_impl_cvfnptr.cpp
$(MAKE) $(BINARY)
rm -f $(BINARY)
rm -f sourcehook.cpp
rm -f sourcehook_hookmangen.cpp
rm -f sourcehook_impl_chookidman.cpp
rm -f sourcehook_impl_chookmaninfo.cpp
rm -f sourcehook_impl_cproto.cpp
rm -f sourcehook_impl_cvfnptr.cpp
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)

View File

@ -49,6 +49,7 @@ DECL_TEST(RefRet);
DECL_TEST(VPHooks);
DECL_TEST(CPageAlloc); // in testhookmangen.cpp
DECL_TEST(HookManGen);
DECL_TEST(OddThunks);
int main(int argc, char *argv[])
{
@ -73,6 +74,7 @@ int main(int argc, char *argv[])
DO_TEST(VPHooks);
DO_TEST(CPageAlloc);
DO_TEST(HookManGen);
DO_TEST(OddThunks);
cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
cout << "Total: " << passed + failed << endl;

View File

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{456BBA64-FF14-4292-8443-3BA79E4D84CC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_NoDebugRuntimeLib|Win32 = Debug_NoDebugRuntimeLib|Win32
Debug|Win32 = Debug|Win32
DebugOpt|Win32 = DebugOpt|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.ActiveCfg = Debug_NoDebugRuntimeLib|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.Build.0 = Debug_NoDebugRuntimeLib|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.ActiveCfg = Debug|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.Build.0 = Debug|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.ActiveCfg = DebugOpt|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.Build.0 = DebugOpt|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.ActiveCfg = Release|Win32
{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,619 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="test"
ProjectGUID="{456BBA64-FF14-4292-8443-3BA79E4D84CC}"
RootNamespace="test"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
FavorSizeOrSpeed="0"
AdditionalIncludeDirectories="../..;.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;SH_DEBUG;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/test.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/test.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="1"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../..;.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/test.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
GenerateMapFile="true"
MapExports="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugOpt|Win32"
OutputDirectory="DebugOpt"
IntermediateDirectory="DebugOpt"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="false"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories=".."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
MinimalRebuild="false"
BasicRuntimeChecks="0"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/test.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/test.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug_NoDebugRuntimeLib|Win32"
OutputDirectory="Debug_NoDebugRuntimeLib"
IntermediateDirectory="Debug_NoDebugRuntimeLib"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
FavorSizeOrSpeed="0"
AdditionalIncludeDirectories="../..;.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/test.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/test.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<Filter
Name="SourceHook"
>
<File
RelativePath="..\..\sourcehook.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_chookidman.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_chookmaninfo.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_cproto.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_cvfnptr.cpp"
>
</File>
</Filter>
<Filter
Name="TestTools"
>
<File
RelativePath="..\main.cpp"
>
</File>
<File
RelativePath="..\test1.cpp"
>
</File>
<File
RelativePath="..\test2.cpp"
>
</File>
<File
RelativePath="..\test3.cpp"
>
</File>
<File
RelativePath="..\test4.cpp"
>
</File>
<File
RelativePath="..\testbail.cpp"
>
</File>
<File
RelativePath="..\testbail2.cpp"
>
</File>
<File
RelativePath="..\testhookmangen.cpp"
>
</File>
<File
RelativePath="..\testlist.cpp"
>
</File>
<File
RelativePath="..\testmanual.cpp"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
GeneratePreprocessedFile="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\testmulti.cpp"
>
</File>
<File
RelativePath="..\testoddthunks.cpp"
>
</File>
<File
RelativePath="..\testrecall.cpp"
>
</File>
<File
RelativePath="..\testreentr.cpp"
>
</File>
<File
RelativePath="..\testref.cpp"
>
</File>
<File
RelativePath="..\testrefret.cpp"
>
</File>
<File
RelativePath="..\testvphooks.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<Filter
Name="TestTools"
>
<File
RelativePath="..\testbail.h"
>
</File>
<File
RelativePath="..\testevents.h"
>
</File>
<File
RelativePath="..\testhookmangen.h"
>
</File>
</Filter>
<Filter
Name="SourceHook"
>
<File
RelativePath="..\..\sh_list.h"
>
</File>
<File
RelativePath="..\..\sh_memfuncinfo.h"
>
</File>
<File
RelativePath="..\..\sh_memory.h"
>
</File>
<File
RelativePath="..\..\sh_pagealloc.h"
>
</File>
<File
RelativePath="..\..\sh_stack.h"
>
</File>
<File
RelativePath="..\..\sh_string.h"
>
</File>
<File
RelativePath="..\..\sh_tinyhash.h"
>
</File>
<File
RelativePath="..\..\sh_vector.h"
>
</File>
<File
RelativePath="..\..\sourcehook.h"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.h"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen_x86.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_chook.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_chookidman.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_chookmaninfo.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_ciface.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_cleanuptask.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_cproto.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl_cvfnptr.h"
>
</File>
<File
RelativePath="..\..\sourcehook_pibuilder.h"
>
</File>
<File
RelativePath="..\sourcehook_test.h"
>
</File>
<Filter
Name="generate"
>
<File
RelativePath="..\..\generate\FastDelegate.hxx"
>
</File>
<File
RelativePath="..\..\generate\sh_memfuncinfo.hxx"
>
</File>
<File
RelativePath="..\..\generate\sourcehook.hxx"
>
<FileConfiguration
Name="Debug_NoDebugRuntimeLib|Win32"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="echo on&#x0D;&#x0A;pushd ..\..\generate&#x0D;&#x0A;shworker.exe iter sourcehook.hxx sourcehook.h 16&#x0D;&#x0A;copy sourcehook.h ..\sourcehook.h&#x0D;&#x0A;popd&#x0D;&#x0A;"
Outputs="..\..\sourcehook.h"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\testhookmangen.hxx"
>
</File>
</Filter>
</Filter>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,163 @@
#include <string>
#include "sourcehook_test.h"
#include "sh_pagealloc.h"
#include "testevents.h"
namespace
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
MAKE_STATE(State_Func_Called);
MAKE_STATE(State_Pre1_Called);
MAKE_STATE(State_Pre2_Called);
int g_CallNumber;
class Test
{
public:
virtual void Func()
{
ADD_STATE(State_Func_Called);
}
};
Test *g_pInst;
void Handler_Func_Pre1()
{
ADD_STATE(State_Pre1_Called);
}
SH_DECL_HOOK0_void(Test, Func, SH_NOATTRIB, 0);
void Handler_Func_Pre2()
{
ADD_STATE(State_Pre2_Called);
++g_CallNumber;
if (g_CallNumber == 2)
{
// REMOVE ourselves
SH_REMOVE_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre1), false);
SH_REMOVE_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre2), false);
}
// Call again.
g_pInst->Func();
}
Test *MyInstanceFactory()
{
return new Test;
}
SourceHook::CPageAlloc g_ThunkAllocator(2);
void *g_OddThunkMemory = NULL;
void *g_OddThunk = NULL;
// Guarantees that Func()
// has a vtable entry showing to an ODD address
void PatchFuncWithOddThunk()
{
g_OddThunkMemory = g_ThunkAllocator.Alloc(10);
unsigned char* base = reinterpret_cast<unsigned char*>(g_OddThunkMemory);
if (((ptrdiff_t)base) & 1)
{
// ODD, ok.
}
else
{
// EVEN. make odd.
base += 1;
}
// Get vtable entry pointer
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
SourceHook::GetFuncInfo(g_pInst, &Test::Func, info);
void *adjustediface = NULL;
void **cur_vtptr = NULL;
void **cur_vfnptr = NULL;
adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(g_pInst) + info.thisptroffs);
cur_vtptr = *reinterpret_cast<void***>(
reinterpret_cast<char*>(adjustediface) + info.vtbloffs);
cur_vfnptr = reinterpret_cast<void**>(cur_vtptr + info.vtblindex);
// Original function
void *origEntry = *cur_vfnptr;
// Now generate the jump code
g_ThunkAllocator.SetRW(g_OddThunkMemory);
*(base + 0) = 0xE9; // offset jump, immediate operand
ptrdiff_t *offsetAddr = reinterpret_cast<ptrdiff_t*>(base + 1);
// destination = src + offset + 5
// <=> offset = destination - src - 5
*offsetAddr =
(reinterpret_cast<unsigned char*>(origEntry) - base) - 5;
g_ThunkAllocator.SetRE(g_OddThunkMemory);
g_OddThunk = reinterpret_cast<void*>(base);
// Now set the odd thunk as new vtable entry
SourceHook::SetMemAccess((void*)cur_vfnptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE);
*cur_vfnptr = g_OddThunk;
}
void FreeOddThunk()
{
g_ThunkAllocator.Free(g_OddThunkMemory);
g_OddThunk = NULL;
}
}
bool TestOddThunks(std::string &error)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
g_CallNumber = 0;
g_pInst = MyInstanceFactory();
PatchFuncWithOddThunk();
SH_ADD_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre1), false);
SH_ADD_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre2), false);
g_pInst->Func();
CHECK_STATES((&g_States,
// FIRST func() call
new State_Pre1_Called(),
new State_Pre2_Called(), // calls Func() again
// SECOND func() call
new State_Pre1_Called(),
new State_Pre2_Called(), // removes hooks and calls Func() again
// THIRD func() call
new State_Func_Called(),
// SECOND func() call
new State_Func_Called(),
// FIRST func() call
new State_Func_Called(),
NULL), "Part 1");
delete g_pInst;
FreeOddThunk();
return true;
}

View File

@ -49,6 +49,11 @@ namespace
}
};
SH_DECL_HOOK0(Test, Func1, SH_NOATTRIB, 0, int&);
SH_DECL_MANUALHOOK0(Manual_Test_Func1, 0, 0, 0, int&);
SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, const int&, int);
SH_DECL_MANUALHOOK1(Manual_Test_Func2, 1, 0, 0, const int&, int);
class CHook
{
public:
@ -76,12 +81,18 @@ namespace
RETURN_META_VALUE(MRES_OVERRIDE, m_Var);
}
virtual const int& Func2_Pre1(int p1)
virtual const int& Func2_PreRecall_OverrideRet_Normal(int p1)
{
ADD_STATE(State_Func2_Pre1(p1, &m_Var));
RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, m_Var, static_cast<const int& (Test::*)(int)>(&Test::Func2), (1337));
}
virtual const int& Func2_PreRecall_OverrideRet_Manual(int p1)
{
ADD_STATE(State_Func2_Pre1(p1, &m_Var));
RETURN_META_VALUE_MNEWPARAMS(MRES_OVERRIDE, m_Var, Manual_Test_Func2, (1337));
}
virtual const int& Func2_Post1(int p1)
{
ADD_STATE(State_Func2_Post1(p1, &META_RESULT_ORIG_RET(int&), &META_RESULT_OVERRIDE_RET(int&)));
@ -89,117 +100,220 @@ namespace
}
};
SH_DECL_HOOK0(Test, Func1, SH_NOATTRIB, 0, int&);
SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, const int&, int);
Test *MyTestFactory()
{
return new Test;
}
}
bool TestRefRet(std::string &error)
class TesterRefRet
{
GET_SHPTR(g_SHPtr);
g_PLID = 1;
Test *pTest = MyTestFactory();
CAutoPtrDestruction<Test> apd(pTest);
public:
Test *pTest;
CHook hook;
int &ret1 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret1));
TesterRefRet()
{
pTest = NULL;
}
CHECK_STATES((&g_States,
new State_Func1(&pTest->m_Var1),
new State_Func1_Ret(&pTest->m_Var1),
NULL), "Part 1");
bool doTests(std::string &error)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1;
// Now add Func1_Pre1, which supercedes and returns hook.m_Var
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
pTest = MyTestFactory();
CAutoPtrDestruction<Test> apd(pTest);
int &ret2 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret2));
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1(&pTest->m_Var1), // Function says that it's going to return pTest->m_Var1
new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned
NULL), "Part 2");
int &ret1 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret1));
// Now add Func1_Post1, which only reports orig ret and override ret
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
CHECK_STATES((&g_States,
new State_Func1(&pTest->m_Var1),
new State_Func1_Ret(&pTest->m_Var1),
NULL), "Part 1");
int &ret3 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret3));
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1(&pTest->m_Var1), // Function says that it's going to return pTest->m_Var1
new State_Func1_Post1(&pTest->m_Var1, &hook.m_Var), // origret(=p1) is what it wanted to
// return, overrideret(=p2) is pre1's var
new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned
NULL), "Part 3");
// Now add Func1_Pre1, which supercedes and returns hook.m_Var
AddHook__Test_Func1__Func1_Pre();
// 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.
int &ret2 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret2));
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1(&pTest->m_Var1), // Function says that it's going to return pTest->m_Var1
new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned
NULL), "Part 2");
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
// Now add Func1_Post1, which only reports orig ret and override ret
AddHook__Test_Func1__Func1_Post();
int &ret4 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret4));
int &ret3 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret3));
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1(&pTest->m_Var1), // Function says that it's going to return pTest->m_Var1
new State_Func1_Post1(&pTest->m_Var1, &hook.m_Var), // origret(=p1) is what it wanted to
// return, overrideret(=p2) is pre1's var
new State_Func1_Ret(&hook.m_Var), // hook.m_Var is returned
NULL), "Part 3");
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1_Pre2(MRES_OVERRIDE, // current status
&hook.m_Var, // override ret (which it set to 1337)
&g_Var), // what it's going to ret, AND supercede with
// 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.
new State_Func1_Post1(&g_Var, &g_Var), // origret(=p1) is what pre2 superceded with,
// so overrideret(=p2) has to be the same
new State_Func1_Post2(&hook.m_Var), // post2 is going to override with hook.m_Var again
new State_Func1_Ret(&hook.m_Var), // ==>>> hook.m_Var is returned
NULL), "Part 4");
AddHook__Test_Func1__Func1_Pre2();
AddHook__Test_Func1__Func1_Post2();
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
// Through a callclass
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
int &ret5 = SH_CALL(cc1, &Test::Func1)();
ADD_STATE(State_Func1_Ret(&ret5));
int &ret4 = pTest->Func1();
ADD_STATE(State_Func1_Ret(&ret4));
CHECK_STATES((&g_States,
new State_Func1(&pTest->m_Var1),
new State_Func1_Ret(&pTest->m_Var1),
NULL), "Part 5");
CHECK_STATES((&g_States,
new State_Func1_Pre1(&hook.m_Var), // Pre1 says that it's going to override with hook.m_Var
new State_Func1_Pre2(MRES_OVERRIDE, // current status
&hook.m_Var, // override ret (which it set to 1337)
&g_Var), // what it's going to ret, AND supercede with
SH_RELEASE_CALLCLASS(cc1);
new State_Func1_Post1(&g_Var, &g_Var), // origret(=p1) is what pre2 superceded with,
// so overrideret(=p2) has to be the same
new State_Func1_Post2(&hook.m_Var), // post2 is going to override with hook.m_Var again
new State_Func1_Ret(&hook.m_Var), // ==>>> hook.m_Var is returned
NULL), "Part 4");
////////////////////////////////////////////////////////////////////////////////////////
// Func2 tests
const int &ret21 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret21));
CHECK_COND(hook.m_Var == 1337, "Part 4.1");
// Through a callclass
SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
int &ret5 = SH_CALL(cc1, &Test::Func1)();
ADD_STATE(State_Func1_Ret(&ret5));
CHECK_STATES((&g_States,
new State_Func2(500, &pTest->m_Var2),
new State_Func2_Ret(&pTest->m_Var2),
NULL), "Part 6");
CHECK_STATES((&g_States,
new State_Func1(&pTest->m_Var1),
new State_Func1_Ret(&pTest->m_Var1),
NULL), "Part 5");
SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Pre1), false);
SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
SH_RELEASE_CALLCLASS(cc1);
const int &ret22 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret22));
////////////////////////////////////////////////////////////////////////////////////////
// Func2 tests
const int &ret21 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret21));
CHECK_STATES((&g_States,
new State_Func2_Pre1(500, &hook.m_Var), // p1 was 500; it's going to override with hook.m_Var; and also change p1 to 1337
new State_Func2(1337, &pTest->m_Var2), // p1 was 1337; it's going to ret pTest->m_Var2
new State_Func2_Post1(1337, // p1 was 1337
&pTest->m_Var2, // orig ret was pTest->m_Var2
&hook.m_Var), // override ret was hook.m_Var
new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var
NULL), "Part 7");
return true;
CHECK_STATES((&g_States,
new State_Func2(500, &pTest->m_Var2),
new State_Func2_Ret(&pTest->m_Var2),
NULL), "Part 6");
AddHook__Test_Func2__Func2_Pre1();
AddHook__Test_Func2__Func2_Post1();
const int &ret22 = pTest->Func2(500);
ADD_STATE(State_Func2_Ret(&ret22));
CHECK_STATES((&g_States,
new State_Func2_Pre1(500, &hook.m_Var), // p1 was 500; it's going to override with hook.m_Var; and also change p1 to 1337
new State_Func2(1337, &pTest->m_Var2), // p1 was 1337; it's going to ret pTest->m_Var2
new State_Func2_Post1(1337, // p1 was 1337
&pTest->m_Var2, // orig ret was pTest->m_Var2
&hook.m_Var), // override ret was hook.m_Var
new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var
NULL), "Part 7");
return true;
}
virtual void AddHook__Test_Func1__Func1_Pre() = 0;
virtual void AddHook__Test_Func1__Func1_Post() = 0;
virtual void AddHook__Test_Func1__Func1_Pre2() = 0;
virtual void AddHook__Test_Func1__Func1_Post2() = 0;
virtual void AddHook__Test_Func2__Func2_Pre1() = 0;
virtual void AddHook__Test_Func2__Func2_Post1() = 0;
};
class TesterRefRetNonManual : public TesterRefRet
{
public:
void AddHook__Test_Func1__Func1_Pre()
{
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
}
void AddHook__Test_Func1__Func1_Post()
{
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
}
void AddHook__Test_Func1__Func1_Pre2()
{
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
}
void AddHook__Test_Func1__Func1_Post2()
{
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
}
void AddHook__Test_Func2__Func2_Pre1()
{
SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_PreRecall_OverrideRet_Normal), false);
}
void AddHook__Test_Func2__Func2_Post1()
{
SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
}
};
class TesterRefRetManual : public TesterRefRet
{
public:
void AddHook__Test_Func1__Func1_Pre()
{
SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
}
void AddHook__Test_Func1__Func1_Post()
{
SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
}
void AddHook__Test_Func1__Func1_Pre2()
{
SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
}
void AddHook__Test_Func1__Func1_Post2()
{
SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
}
void AddHook__Test_Func2__Func2_Pre1()
{
SH_ADD_MANUALHOOK(Manual_Test_Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_PreRecall_OverrideRet_Manual), false);
}
void AddHook__Test_Func2__Func2_Post1()
{
SH_ADD_MANUALHOOK(Manual_Test_Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
}
};
bool TestRefRet(std::string &error)
{
TesterRefRet *testerNonManual = new TesterRefRetNonManual;
bool resNonManual = testerNonManual->doTests(error);
if (!resNonManual)
{
return false;
}
TesterRefRet *testerManual = new TesterRefRetManual;
bool resManual = testerManual->doTests(error);
if (!resManual)
{
return false;
}
return true;
}

View File

@ -0,0 +1,29 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2010 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_IMPL_CLEANUPTASK_H__
#define __SOURCEHOOK_IMPL_CLEANUPTASK_H__
namespace SourceHook
{
namespace Impl
{
class ICleanupTask
{
public:
virtual void CleanupAndDeleteThis() = 0;
};
}
}
// __SOURCEHOOK_IMPL_CLEANUPTASK_H__
#endif