diff --git a/Vutils.vcxproj b/Vutils.vcxproj
index e40d454..930b032 100644
--- a/Vutils.vcxproj
+++ b/Vutils.vcxproj
@@ -43,52 +43,52 @@
StaticLibrary
true
- v110
+ v142
Unicode
StaticLibrary
true
- v110
+ v142
Unicode
StaticLibrary
false
- v110
+ v142
true
Unicode
StaticLibrary
false
- v110
+ v142
true
Unicode
StaticLibrary
true
- v110
+ v142
Unicode
StaticLibrary
true
- v110
+ v142
Unicode
StaticLibrary
false
- v110
+ v142
true
Unicode
StaticLibrary
false
- v110
+ v142
true
Unicode
@@ -329,6 +329,11 @@
+
+
+
+
+
@@ -401,6 +406,7 @@
+
diff --git a/Vutils.vcxproj.filters b/Vutils.vcxproj.filters
index 25fa723..16f51fc 100644
--- a/Vutils.vcxproj.filters
+++ b/Vutils.vcxproj.filters
@@ -64,6 +64,9 @@
{0e80967e-0e61-4762-98d0-e9774dcee22f}
+
+ {09804e65-3ba8-4b2d-ac74-8f7e22ab2be0}
+
@@ -156,6 +159,21 @@
Header Files\Third Files\EP
+
+ Header Files\Third Files\CH
+
+
+ Header Files\Third Files\CH
+
+
+ Header Files\Third Files\CH
+
+
+ Header Files\Third Files\CH
+
+
+ Header Files\Third Files\CH
+
@@ -358,5 +376,8 @@
Header Files\Template Files
+
+ Header Files\Template Files
+
\ No newline at end of file
diff --git a/include/3rdparty/CH/cpp-hooking/common.h b/include/3rdparty/CH/cpp-hooking/common.h
new file mode 100644
index 0000000..02d9593
--- /dev/null
+++ b/include/3rdparty/CH/cpp-hooking/common.h
@@ -0,0 +1,73 @@
+/**
+ * @file common.h
+ * @author Vic P.
+ * @brief Header for common use.
+ */
+
+#pragma once
+
+#include "invokable.h"
+
+#include
+#include
+
+/**
+ * @brief The structure that holds the hooking information of a function.
+ */
+struct Hooked
+{
+ void* m_function;
+ void* m_trampoline;
+ std::shared_ptr m_invoker;
+
+ Hooked() : m_function(nullptr), m_trampoline(nullptr) {}
+
+ Hooked(const Hooked& right)
+ {
+ *this = right;
+ }
+
+ const Hooked& operator=(const Hooked& right)
+ {
+ if (this != &right)
+ {
+ m_function = right.m_function;
+ m_trampoline = right.m_trampoline;
+ m_invoker = right.m_invoker;
+ }
+
+ return *this;
+ }
+};
+
+template
+struct LibraryT;
+
+template <>
+struct LibraryT
+{
+ typedef vu::LibraryA self;
+};
+
+template <>
+struct LibraryT
+{
+ typedef vu::LibraryW self;
+};
+
+/**
+ * @brief Get the address of an exported function from the given dynamic-link module.
+ * @param module The module name.
+ * @param function The function name.
+ * @returns The address of the function or null.
+ */
+template
+inline void* get_proc_address(const StdString& module, const StdString& function)
+{
+ if (module.empty() || function.empty())
+ {
+ return nullptr;
+ }
+
+ return LibraryT::self::quick_get_proc_address(module, function);
+}
diff --git a/include/3rdparty/CH/cpp-hooking/hooking.h b/include/3rdparty/CH/cpp-hooking/hooking.h
new file mode 100644
index 0000000..eea2b87
--- /dev/null
+++ b/include/3rdparty/CH/cpp-hooking/hooking.h
@@ -0,0 +1,10 @@
+/**
+ * @file hooking.h
+ * @author Vic P.
+ * @brief Header for Inline Hooking Manager & IAT Hooking Manager.
+ */
+
+#pragma once
+
+#include "inl_hooking.h"
+#include "iat_hooking.h"
diff --git a/include/3rdparty/CH/cpp-hooking/iat_hooking.h b/include/3rdparty/CH/cpp-hooking/iat_hooking.h
new file mode 100644
index 0000000..7a6d507
--- /dev/null
+++ b/include/3rdparty/CH/cpp-hooking/iat_hooking.h
@@ -0,0 +1,134 @@
+/**
+ * @file iat_hooking.h
+ * @author Vic P.
+ * @brief Header/Implementation for IAT Hooking Manager.
+ */
+
+#pragma once
+
+#include "common.h"
+
+#include
+
+/**
+ * @brief IAT Hooking Manager.
+ */
+class IATHookingManager : public vu::SingletonT
+{
+ struct IAT_Hooked : public Hooked {};
+
+ std::unordered_map m_list;
+
+ using Entry = vu::IATHookingA::Entry;
+
+ vu::IATHookingA& hooker()
+ {
+ return vu::IATHookingA::instance();
+ }
+
+ void* get_proc_address(const Entry& entry)
+ {
+ Entry temp;
+
+ if (!this->hooker().exist(entry.target, entry.module, entry.function, &temp))
+ {
+ return nullptr;
+ }
+
+ return temp.original;
+ }
+
+public:
+ /**
+ * @brief Hook a given function.
+ * @param[in] entry The entry of function that want to hook ({ tartget name, module name, function name }).
+ * @param[in] hk_function The hooking function.
+ * @return true if succeeds otherwise return false.
+ */
+ template
+ bool hook(const Entry& entry, Function&& hk_function)
+ {
+ IAT_Hooked hooked;
+
+ auto ret = this->hooker().install(entry.target, entry.module, entry.function,
+ (void*)hk_function, &hooked.m_trampoline);
+ if (ret != vu::VU_OK)
+ {
+ return false;
+ }
+
+ auto function = this->get_proc_address(entry);
+ if (function == nullptr)
+ {
+ return false;
+ }
+
+ using FunctionPtr = decltype(&hk_function);
+
+ hooked.m_function = function;
+ hooked.m_invoker.reset(new Invokable(FunctionPtr(hooked.m_trampoline)));
+
+ void* key = hooked.m_function;
+ m_list[key] = std::move(hooked);
+
+ return true;
+ }
+
+ /**
+ * @brief Unhook a given function that was hooked.
+ * @param[in] entry The entry of function that want to un-hook ({ tartget name, module name, function name }).
+ * @return true if succeeds otherwise return false.
+ */
+ bool unhook(const Entry& entry)
+ {
+ auto function = this->get_proc_address(entry);
+ if (function == nullptr)
+ {
+ return false;
+ }
+
+ auto it = m_list.find(function);
+ if (it == m_list.cend())
+ {
+ return false;
+ }
+
+ auto ret = this->hooker().uninstall(entry.target, entry.module, entry.function);
+ if (ret != vu::VU_OK)
+ {
+ return false;
+ }
+
+ m_list.erase(it);
+
+ return true;
+ }
+
+ /**
+ * @brief Invoke the original function.
+ * @param[in] entry The entry of function that want to invoke ({ tartget name, module name, function name }).
+ * @param[in] args The arguments that pass to the original function.
+ * @return Based on the result of the original function.
+ */
+ template
+ Return invoke(const Entry& entry, Args ... args)
+ {
+ auto function = this->get_proc_address(entry);
+ auto it = m_list.find(function);
+ if (it == m_list.cend())
+ {
+ throw "invoke the function that did not hook";
+ }
+
+ auto& hooked = it->second;
+
+ if (std::is_void::value)
+ {
+ hooked.m_invoker->invoke(std::forward(args)...);
+ }
+ else
+ {
+ return hooked.m_invoker->invoke(std::forward(args)...);
+ }
+ }
+};
diff --git a/include/3rdparty/CH/cpp-hooking/inl_hooking.h b/include/3rdparty/CH/cpp-hooking/inl_hooking.h
new file mode 100644
index 0000000..5d3fb65
--- /dev/null
+++ b/include/3rdparty/CH/cpp-hooking/inl_hooking.h
@@ -0,0 +1,154 @@
+/**
+ * @file inl_hooking.h
+ * @author Vic P.
+ * @brief Header/Implementation for Inline Hooking Manager.
+ */
+
+#pragma once
+
+#include "common.h"
+
+#include
+
+/**
+ * @brief Inline Hooking Manager.
+ */
+class INLHookingManager : public vu::SingletonT
+{
+ struct INL_Hooked: public Hooked
+ {
+ vu::INLHooking m_hooker;
+
+ INL_Hooked() : Hooked() {}
+
+ INL_Hooked(const INL_Hooked& right)
+ {
+ *this = right;
+ }
+
+ const INL_Hooked& operator=(const INL_Hooked& right)
+ {
+ if (this != &right)
+ {
+ Hooked::operator=(right);
+ m_hooker = right.m_hooker;
+ }
+
+ return *this;
+ }
+ };
+
+ std::unordered_map m_list;
+
+public:
+ /**
+ * @brief Hook a given function.
+ * @param[in] function The function that want to hook.
+ * @param[in] hk_function The hooking function.
+ * @return true if succeeds otherwise return false.
+ */
+ template
+ bool hook(void* function, Function&& hk_function)
+ {
+ auto it = m_list.find(function);
+ if (it != m_list.cend())
+ {
+ return false;
+ }
+
+ INL_Hooked hooked;
+ if (!hooked.m_hooker.attach(function, (void*)hk_function, &hooked.m_trampoline))
+ {
+ return false;
+ }
+
+ using FunctionPtr = decltype(&hk_function);
+
+ hooked.m_function = function;
+ hooked.m_invoker.reset(new Invokable(FunctionPtr(hooked.m_trampoline)));
+
+ void* key = hooked.m_function;
+ m_list[key] = std::move(hooked);
+
+ return true;
+ }
+
+ /**
+ * @brief Unhook a given function that was hooked.
+ * @param[in] entry The function that want to un-hook.
+ * @return true if succeeds otherwise return false.
+ */
+ bool unhook(void* function)
+ {
+ auto it = m_list.find(function);
+ if (it == m_list.cend())
+ {
+ return false;
+ }
+
+ auto& hooked = it->second;
+ auto result = hooked.m_hooker.detach(function, &hooked.m_trampoline);
+ if (result)
+ {
+ m_list.erase(it);
+ }
+
+ return result;
+ }
+
+ /**
+ * @brief Hook a given function.
+ * @param[in] module The module name.
+ * @param[in] function The function name.
+ * @param[in] hk_function The hooking function.
+ * @return true if succeeds otherwise return false.
+ */
+ template
+ bool hook(const StdString& module, const StdString& function, Function&& hk_function)
+ {
+ auto ptr = get_proc_address(module, function);
+ return ptr != nullptr ? this->hook(ptr, hk_function) : false;
+ }
+
+ /**
+ * @brief Unhook a given function that was hooked.
+ * @param[in] module The module name.
+ * @param[in] function The function name.
+ * @return true if succeeds otherwise return false.
+ */
+ template
+ bool unhook(const StdString& module, const StdString& function)
+ {
+ auto ptr = get_proc_address(module, function);
+ return ptr != nullptr ? this->unhook(ptr) : false;
+ }
+
+ /**
+ * @brief Invoke the original function.
+ * @param[in] entry The function that want to invoke.
+ * @param[in] args The arguments that pass to the original function.
+ * @return Based on the result of the original function.
+ */
+ template
+ Return invoke(void* function, Args ... args)
+ {
+ auto it = m_list.find(function);
+ if (it == m_list.cend())
+ {
+ throw "invoke the function that did not hook";
+ }
+
+ auto& hooked = it->second;
+
+ if (std::is_void::value)
+ {
+ hooked.m_invoker->invoke(std::forward(args)...);
+ }
+ else
+ {
+ return hooked.m_invoker->invoke(std::forward(args)...);
+ }
+
+ return 0;
+ }
+};
diff --git a/include/3rdparty/CH/cpp-hooking/invokable.h b/include/3rdparty/CH/cpp-hooking/invokable.h
new file mode 100644
index 0000000..b7a1056
--- /dev/null
+++ b/include/3rdparty/CH/cpp-hooking/invokable.h
@@ -0,0 +1,46 @@
+/**
+ * @file invokable.h
+ * @author Vic P.
+ * @brief Header/Implementation for the function-container that can hold any function prototype.
+ */
+
+#pragma once
+
+#ifndef _ANY_
+#include
+#include
+#endif // _ANY_
+
+/**
+ * @brief The function-container that can hold any function prototype.
+ */
+struct Invokable
+{
+ Invokable() {}
+
+ template
+ Invokable(Function&& function) : Invokable(std::function(std::forward(function))) {}
+
+ template
+ Invokable(std::function function) : m_function(function)
+ {
+ m_function = function;
+ }
+
+ template
+ Return invoke(Args ... args)
+ {
+ auto function = std::any_cast>(m_function);
+
+ if (std::is_void::value)
+ {
+ std::invoke(function, std::forward(args)...);
+ }
+ else
+ {
+ return std::invoke(function, std::forward(args)...);
+ }
+ }
+
+ std::any m_function;
+};
diff --git a/include/Vutils.h b/include/Vutils.h
index f127e8f..4614412 100644
--- a/include/Vutils.h
+++ b/include/Vutils.h
@@ -38,6 +38,15 @@
#error Vutils required C++11 or newer
#endif
+// C++14 (MSVC 2015+ or MinGW 5.1+)
+#if (defined(_MSC_VER) && _MSVC_LANG >= 201402L) || (defined(__MINGW32__) && __cplusplus >= 201402L)
+#define VU_HAS_CXX14
+#endif // C++17 (MSVC 2017+ or MinGW 7.1+)
+
+#if (defined(_MSC_VER) && _MSVC_LANG >= 201703L) || (defined(__MINGW32__) && __cplusplus >= 201703L)
+#define VU_HAS_CXX17
+#endif // C++17 (MSVC 2017+ or MinGW 7.1+)
+
/* Vutils Configurations */
// VU_NO_EX - To disable all extended utilities
@@ -105,6 +114,9 @@
#include
#include
#include
+#if defined(VU_HAS_CXX17)
+#include
+#endif // VU_HAS_CXX17
#ifdef _MSC_VER
#pragma warning(push)
@@ -3695,6 +3707,10 @@ class Debouncer : public SingletonT
#define RESTClient RESTClientA
#endif // _UNICODE
+// C++ Hooking
+
+#include "template/fnhooking.tpl"
+
} // namespace vu
#ifdef _MSC_VER
diff --git a/include/template/fnhooking.tpl b/include/template/fnhooking.tpl
new file mode 100644
index 0000000..cf1b8fa
--- /dev/null
+++ b/include/template/fnhooking.tpl
@@ -0,0 +1,20 @@
+/**
+ * @file easyprint.tpl
+ * @author Vic P.
+ * @brief Template for Easy Print
+ */
+
+ /**
+ * Easy Print
+ */
+
+#pragma once
+
+// C++17 (MSVC 2017+ or MinGW 7.1+)
+#if (defined(_MSC_VER) && _MSVC_LANG >= 201703L) || (defined(__MINGW32__) && __cplusplus >= 201703L)
+
+#include "3rdparty/CH/cpp-hooking/hooking.h"
+
+#define VU_HAS_CPP_HOOKING
+
+#endif // C++17 (MSVC 2017+ or MinGW 7.1+)
\ No newline at end of file