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:
parent
749bdd044a
commit
31be74561d
@ -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'
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Binary file not shown.
20
core/sourcehook/generate/shworker/msvc9/shworker.sln
Normal file
20
core/sourcehook/generate/shworker/msvc9/shworker.sln
Normal 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
|
207
core/sourcehook/generate/shworker/msvc9/shworker.vcproj
Normal file
207
core/sourcehook/generate/shworker/msvc9/shworker.vcproj
Normal 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>
|
@ -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];
|
||||
|
@ -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)())
|
||||
{
|
||||
|
@ -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@]))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -125,6 +129,8 @@ namespace SourceHook
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
if (newVfnPtr.Init())
|
||||
{
|
||||
push_back(newVfnPtr);
|
||||
|
||||
return back();
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
// Initialization failed.
|
||||
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)
|
||||
else
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)())
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
111
core/sourcehook/sourcehook_impl_chookidman.cpp
Normal file
111
core/sourcehook/sourcehook_impl_chookidman.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
|
84
core/sourcehook/sourcehook_impl_chookmaninfo.cpp
Normal file
84
core/sourcehook/sourcehook_impl_chookmaninfo.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
29
core/sourcehook/sourcehook_impl_cleanuptask.h
Normal file
29
core/sourcehook/sourcehook_impl_cleanuptask.h
Normal 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
|
||||
|
145
core/sourcehook/sourcehook_impl_cproto.cpp
Normal file
145
core/sourcehook/sourcehook_impl_cproto.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
|
253
core/sourcehook/sourcehook_impl_cvfnptr.cpp
Normal file
253
core/sourcehook/sourcehook_impl_cvfnptr.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
26
core/sourcehook/test/test.sln
Normal file
26
core/sourcehook/test/test.sln
Normal 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
|
619
core/sourcehook/test/test.vcproj
Normal file
619
core/sourcehook/test/test.vcproj
Normal 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
pushd ..\..\generate
shworker.exe iter sourcehook.hxx sourcehook.h 16
copy sourcehook.h ..\sourcehook.h
popd
"
|
||||
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>
|
163
core/sourcehook/test/testoddthunks.cpp
Normal file
163
core/sourcehook/test/testoddthunks.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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,23 +100,30 @@ 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
|
||||
{
|
||||
public:
|
||||
Test *pTest;
|
||||
CHook hook;
|
||||
|
||||
TesterRefRet()
|
||||
{
|
||||
pTest = NULL;
|
||||
}
|
||||
|
||||
bool doTests(std::string &error)
|
||||
{
|
||||
GET_SHPTR(g_SHPtr);
|
||||
g_PLID = 1;
|
||||
|
||||
Test *pTest = MyTestFactory();
|
||||
pTest = MyTestFactory();
|
||||
CAutoPtrDestruction<Test> apd(pTest);
|
||||
CHook hook;
|
||||
|
||||
int &ret1 = pTest->Func1();
|
||||
ADD_STATE(State_Func1_Ret(&ret1));
|
||||
@ -116,7 +134,7 @@ bool TestRefRet(std::string &error)
|
||||
NULL), "Part 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);
|
||||
AddHook__Test_Func1__Func1_Pre();
|
||||
|
||||
int &ret2 = pTest->Func1();
|
||||
ADD_STATE(State_Func1_Ret(&ret2));
|
||||
@ -128,7 +146,7 @@ bool TestRefRet(std::string &error)
|
||||
NULL), "Part 2");
|
||||
|
||||
// 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);
|
||||
AddHook__Test_Func1__Func1_Post();
|
||||
|
||||
int &ret3 = pTest->Func1();
|
||||
ADD_STATE(State_Func1_Ret(&ret3));
|
||||
@ -144,8 +162,8 @@ bool TestRefRet(std::string &error)
|
||||
// Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337)
|
||||
// and add Func1_Post2, which overrides and returns hook.m_Var again.
|
||||
|
||||
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
|
||||
SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
|
||||
AddHook__Test_Func1__Func1_Pre2();
|
||||
AddHook__Test_Func1__Func1_Post2();
|
||||
|
||||
int &ret4 = pTest->Func1();
|
||||
ADD_STATE(State_Func1_Ret(&ret4));
|
||||
@ -186,8 +204,8 @@ bool TestRefRet(std::string &error)
|
||||
new State_Func2_Ret(&pTest->m_Var2),
|
||||
NULL), "Part 6");
|
||||
|
||||
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);
|
||||
AddHook__Test_Func2__Func2_Pre1();
|
||||
AddHook__Test_Func2__Func2_Post1();
|
||||
|
||||
const int &ret22 = pTest->Func2(500);
|
||||
ADD_STATE(State_Func2_Ret(&ret22));
|
||||
@ -202,4 +220,100 @@ bool TestRefRet(std::string &error)
|
||||
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;
|
||||
}
|
||||
|
29
temp/sourcehook/sourcehook_impl_cleanuptask.h
Normal file
29
temp/sourcehook/sourcehook_impl_cleanuptask.h
Normal 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user