107 lines
3.4 KiB
C++
107 lines
3.4 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
#include <string_view>
|
|
|
|
#include <fxn/context.hpp>
|
|
|
|
namespace fxn
|
|
{
|
|
struct invoker_base
|
|
{
|
|
typedef void*(*get_native_handler_t)(std::uint64_t hash);
|
|
static get_native_handler_t _get_native_handler;
|
|
|
|
typedef void(*schedule_native_t)(fxn::NativeContext* context, bool wait);
|
|
static schedule_native_t _schedule_native;
|
|
|
|
typedef bool(*native_hook_t)(fxn::NativeContext* context, bool& call_original);
|
|
typedef void(*register_native_hook_t)(std::uint64_t hash, native_hook_t hook);
|
|
static register_native_hook_t _register_native_hook;
|
|
|
|
static void initialize(std::string_view module_name);
|
|
static void get_native_handler(std::uint64_t hash);
|
|
static void schedule_native(fxn::NativeContext* context, bool wait);
|
|
static void register_native_hook(std::uint64_t hash, native_hook_t hook);
|
|
};
|
|
|
|
template <std::uint64_t Hash, typename Ret, typename... Args>
|
|
struct invoker
|
|
{
|
|
using return_type = Ret;
|
|
using native_hash = std::integral_constant<std::uint64_t, Hash>;
|
|
|
|
return_type operator()(Args... args);
|
|
};
|
|
}
|
|
|
|
#ifdef FXN_IMPORTS
|
|
#include <Windows.h>
|
|
|
|
namespace fxn
|
|
{
|
|
inline invoker_base::get_native_handler_t invoker_base::_get_native_handler = nullptr;
|
|
inline invoker_base::schedule_native_t invoker_base::_schedule_native = nullptr;
|
|
inline invoker_base::register_native_hook_t invoker_base::_register_native_hook = nullptr;
|
|
|
|
inline void invoker_base::initialize(std::string_view module_name)
|
|
{
|
|
HMODULE mod = GetModuleHandleA(module_name.data());
|
|
if (!mod)
|
|
{
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
invoker_base::_get_native_handler = reinterpret_cast<get_native_handler_t>(
|
|
GetProcAddress(mod, "fxn_native_invoker_get_handler")
|
|
);
|
|
|
|
invoker_base::_schedule_native = reinterpret_cast<schedule_native_t>(
|
|
GetProcAddress(mod, "fxn_schedule_native")
|
|
);
|
|
|
|
invoker_base::_register_native_hook = reinterpret_cast<register_native_hook_t>(
|
|
GetProcAddress(mod, "fxn_register_native_hook")
|
|
);
|
|
|
|
if (!invoker_base::_get_native_handler ||
|
|
!invoker_base::_schedule_native ||
|
|
!invoker_base::_register_native_hook)
|
|
{
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
inline void invoker_base::get_native_handler(std::uint64_t hash)
|
|
{
|
|
invoker_base::_get_native_handler(hash);
|
|
}
|
|
|
|
inline void invoker_base::schedule_native(fxn::NativeContext* context, bool wait)
|
|
{
|
|
invoker_base::_schedule_native(context, wait);
|
|
}
|
|
|
|
inline void invoker_base::register_native_hook(std::uint64_t hash, native_hook_t hook)
|
|
{
|
|
invoker_base::_register_native_hook(hash, hook);
|
|
}
|
|
|
|
template <std::uint64_t Hash, typename Ret, typename... Args>
|
|
inline typename invoker<Hash, Ret, Args...>::return_type invoker<Hash, Ret, Args...>::operator()(Args... args)
|
|
{
|
|
fxn::NativeContext context(Hash);
|
|
|
|
// Push arguments
|
|
(context.PushArgument<Args>(args), ...);
|
|
|
|
// Schedule native call
|
|
invoker_base::schedule_native(&context, true);
|
|
|
|
if constexpr (!std::is_same_v<Ret, void>)
|
|
{
|
|
return context.GetResult<Ret>();
|
|
}
|
|
}
|
|
}
|
|
#endif
|