diff --git a/include/fxn/invoker.hpp b/include/fxn/invoker.hpp new file mode 100644 index 0000000..61b8335 --- /dev/null +++ b/include/fxn/invoker.hpp @@ -0,0 +1,106 @@ +#pragma once +#include +#include + +#include + +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 + struct invoker + { + using return_type = Ret; + using native_hash = std::integral_constant; + + return_type operator()(Args... args); + }; +} + +#ifdef FXN_IMPORTS +#include + +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( + GetProcAddress(mod, "fxn_native_invoker_get_handler") + ); + + invoker_base::_schedule_native = reinterpret_cast( + GetProcAddress(mod, "fxn_schedule_native") + ); + + invoker_base::_register_native_hook = reinterpret_cast( + 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 + inline typename invoker::return_type invoker::operator()(Args... args) + { + fxn::NativeContext context(Hash); + + // Push arguments + (context.PushArgument(args), ...); + + // Schedule native call + invoker_base::schedule_native(&context, true); + + if constexpr (!std::is_same_v) + { + return context.GetResult(); + } + } +} +#endif diff --git a/src/detail/exports.hpp b/src/detail/exports.hpp new file mode 100644 index 0000000..1cedaee --- /dev/null +++ b/src/detail/exports.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +extern "C" +{ + typedef bool (*native_hook_t)(fxn::NativeContext* context, bool& call_original); + + __declspec(dllexport) void* fxn_native_invoker_get_handler(std::uint64_t hash); + __declspec(dllexport) void fxn_schedule_native(fxn::NativeContext* context, bool wait); + __declspec(dllexport) void fxn_register_native_hook(std::uint64_t hash, native_hook_t hook); +} \ No newline at end of file diff --git a/src/impl/exports.cpp b/src/impl/exports.cpp new file mode 100644 index 0000000..177118b --- /dev/null +++ b/src/impl/exports.cpp @@ -0,0 +1,29 @@ +#include +#include + +extern "C" +{ + __declspec(dllexport) void* fxn_native_invoker_get_handler(std::uint64_t hash) + { + static auto& manager = fxn::FxnManager::GetInstance(); + + return manager.GetNativeHandler(hash); + } + + __declspec(dllexport) void fxn_schedule_native(fxn::NativeContext* context, bool wait) + { + static auto& manager = fxn::FxnManager::GetInstance(); + + manager.Schedule(context, wait); + } + + __declspec(dllexport) void fxn_register_native_hook(std::uint64_t hash, native_hook_t hook) + { + static auto& manager = fxn::FxnManager::GetInstance(); + + manager.RegisterNativeHook(hash, [hook](fxn::NativeContext* context, bool& call_original) + { + return hook(context, call_original); + }); + } +} \ No newline at end of file