F4MP/f4mp_originalcode/F4MPClient/common/include/Hook.h
Jous99 e52b7b446a subida de archivos
archivos originales del proyecto F4MP
2026-01-06 18:52:24 +01:00

257 lines
7.8 KiB
C++

#ifndef COMMON_HOOK_H
#define COMMON_HOOK_H
#include <Windows.h>
#include <cstdint>
#include "detours.h"
#include "Types.h"
#include "Exceptions.h"
namespace Hooks {
enum class CallConvention
{
stdcall_t,
cdecl_t
};
template <CallConvention cc, typename retn, typename convention, typename ...args>
struct convention;
template <typename retn, typename ...args>
struct convention<CallConvention::stdcall_t, retn, args...>
{
typedef retn (__stdcall *type)(args ...);
};
template <typename retn, typename ...args>
struct convention<CallConvention::cdecl_t, retn, args...>
{
typedef retn (__cdecl *type)(args ...);
};
template <CallConvention cc, typename retn, typename ...args>
class Hook
{
typedef typename convention<cc, retn, args...>::type type;
size_t orig_;
type detour_;
bool is_applied_;
bool has_open_transaction_;
void transaction_begin()
{
const auto result = DetourTransactionBegin();
if (result != NO_ERROR)
{
if (result == ERROR_INVALID_OPERATION)
{
throw Exceptions::Core::Exceptions::DetourException(
"A pending transaction already exists"
);
}
throw Exceptions::Core::Exceptions::DetourException("Unknown error");
}
has_open_transaction_ = true;
}
void transaction_commit()
{
const auto result = DetourTransactionCommit();
if (result != NO_ERROR)
{
switch (result)
{
case ERROR_INVALID_DATA:
throw Exceptions::Core::Exceptions::DetourException(
"Target function was changed by third party between steps of the transaction"
);
case ERROR_INVALID_OPERATION:
throw Exceptions::Core::Exceptions::DetourException(
"No pending transaction exists"
);
case ERROR_INVALID_BLOCK:
throw Exceptions::Core::Exceptions::DetourException(
"The function referenced is too small to be detoured"
);
case ERROR_INVALID_HANDLE:
throw Exceptions::Core::Exceptions::DetourException(
"The ppPointer parameter is null or points to a null pointer"
);
case ERROR_NOT_ENOUGH_MEMORY:
throw Exceptions::Core::Exceptions::DetourException(
"Not enough memory exists to complete the operation"
);
default:
throw Exceptions::Core::Exceptions::DetourException(
"Unknown error"
);
}
}
has_open_transaction_ = false;
}
static void update_thread(HANDLE hThread)
{
const auto result = DetourUpdateThread(hThread);
if (result != NO_ERROR)
{
if (result == ERROR_NOT_ENOUGH_MEMORY)
{
throw Exceptions::Core::Exceptions::DetourException(
"Not enough memory to record identity of thread"
);
}
throw Exceptions::Core::Exceptions::DetourException("Unknown error");
}
}
public:
Hook() : orig_(0), detour_(0), is_applied_(false), has_open_transaction_(false)
{
}
~Hook() noexcept(false)
{
if (has_open_transaction_)
{
const auto result = DetourTransactionAbort();
if (result != NO_ERROR)
{
if (result == ERROR_INVALID_OPERATION)
{
throw Exceptions::Core::Exceptions::DetourException(
"No pending transaction exists"
);
}
throw Exceptions::Core::Exceptions::DetourException("Unknown error");
}
}
remove();
}
template <typename T>
void apply(T pFunc, type detour)
{
detour_ = detour;
orig_ = static_cast<size_t>(pFunc);
transaction_begin();
update_thread(GetCurrentThread());
const auto result = DetourAttach(reinterpret_cast<void **>(&orig_), reinterpret_cast<void *>(detour_));
if (result != NO_ERROR)
{
switch (result)
{
case ERROR_INVALID_BLOCK:
throw Exceptions::Core::Exceptions::DetourException(
"The function referenced is too small to be detoured"
);
case ERROR_INVALID_HANDLE:
throw Exceptions::Core::Exceptions::DetourException(
"The ppPointer parameter is null or points to a null pointer"
);
case ERROR_INVALID_OPERATION:
throw Exceptions::Core::Exceptions::DetourException(
"No pending transaction exists"
);
case ERROR_NOT_ENOUGH_MEMORY:
throw Exceptions::Core::Exceptions::DetourException(
"Not enough memory exists to complete the operation"
);
default:
throw Exceptions::Core::Exceptions::DetourException("Unknown error");
}
}
transaction_commit();
is_applied_ = true;
}
void remove()
{
if (!is_applied_)
return;
is_applied_ = false;
transaction_begin();
update_thread(GetCurrentThread());
const auto result = DetourDetach(reinterpret_cast<void **>(&orig_), reinterpret_cast<void *>(detour_));
if (result != NO_ERROR)
{
switch (result)
{
case ERROR_INVALID_BLOCK:
throw Exceptions::Core::Exceptions::DetourException(
"The function to be detached was too small to be detoured"
);
case ERROR_INVALID_HANDLE:
throw Exceptions::Core::Exceptions::DetourException(
"The ppPointer parameter is null or points to a null pointer"
);
case ERROR_INVALID_OPERATION:
throw Exceptions::Core::Exceptions::DetourException(
"No pending transaction exists"
);
case ERROR_NOT_ENOUGH_MEMORY:
throw Exceptions::Core::Exceptions::DetourException(
"Not enough memory exists to complete the operation"
);
default:
throw Exceptions::Core::Exceptions::DetourException(
"Unknown error"
);
}
}
transaction_commit();
}
auto get_orig(){
return orig_;
}
retn call_orig(args ... p)
{
return type(orig_)(p...);
}
bool is_applied() const
{
return is_applied_;
}
};
}
#endif