Last active
August 23, 2020 05:53
-
-
Save stevemk14ebr/5cac9e678f10f71f5d477ecf6637ed75 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Thanks @_can1357 for help with this. | |
#include <type_traits> | |
#include <tuple> | |
#include <utility> | |
template<typename T, typename = void> | |
struct callback_type { using type = T; }; | |
template<typename T> | |
using callback_type_t = typename callback_type<T>::type; | |
template<auto V> | |
using callback_type_v = typename callback_type<decltype(V)>::type; | |
#define MAKE_CALLBACK_IMPL(CCFROM, CCTO) template<typename F, typename Ret, typename... Args> \ | |
auto make_callback(Ret(CCFROM*)(Args...), F&& f) \ | |
{ \ | |
Ret(CCTO * fn)(Args...) = f; \ | |
return fn; \ | |
} \ | |
template<typename Ret, typename... Args> \ | |
struct callback_type<Ret(CCFROM*)(Args...), void> \ | |
{ \ | |
using type = Ret(CCTO*)(Args...); \ | |
}; | |
// switch to __VA_OPT__ when C++ 2a release. MSVC removes comma before empty __VA_ARGS__ as is. | |
// https://devblogs.microsoft.com/cppblog/msvc-preprocessor-progress-towards-conformance/ | |
#define MAKE_CALLBACK_CLASS_IMPL(CCFROM, CCTO, ...) template<typename F, typename Ret, typename Class, typename... Args> \ | |
auto make_callback(Ret(CCFROM Class::*)(Args...), F&& f) \ | |
{ \ | |
Ret(CCTO * fn)(Class*, ## __VA_ARGS__, Args...) = f; \ | |
return fn; \ | |
} \ | |
template<typename Ret, typename Class, typename... Args> \ | |
struct callback_type<Ret(CCFROM Class::*)(Args...), void> \ | |
{ \ | |
using type = Ret(CCTO*)(Class*, ## __VA_ARGS__, Args...); \ | |
}; | |
#ifndef _WIN64 | |
MAKE_CALLBACK_IMPL(__stdcall, __stdcall) | |
MAKE_CALLBACK_CLASS_IMPL(__stdcall, __stdcall) | |
MAKE_CALLBACK_IMPL(__cdecl, __cdecl) | |
MAKE_CALLBACK_CLASS_IMPL(__cdecl, __cdecl) | |
MAKE_CALLBACK_IMPL(__thiscall, __thiscall) | |
MAKE_CALLBACK_CLASS_IMPL(__thiscall, __fastcall, char*) | |
#endif | |
MAKE_CALLBACK_IMPL(__fastcall, __fastcall) | |
MAKE_CALLBACK_CLASS_IMPL(_fastcall, __fastcall) | |
#define HOOK_CALLBACK(pType, name, body) typedef callback_type_v<pType> ##name##_t; \ | |
callback_type_v<pType> name = make_callback(pType, [](auto... _args) body ) | |
template <int I, class... Ts> | |
decltype(auto) get_pack_idx(Ts&&... ts) { | |
return std::get<I>(std::forward_as_tuple(ts...)); | |
} | |
// for member functions this is essentially 1's indexed because first param is this* | |
#define GET_ARG(idx) get_pack_idx<idx>(_args...); | |
// Usage: | |
HOOK_CALLBACK(&IWbemServices::ExecQuery, hkExecQuery, { | |
auto orig = HkIWbemServices.GetOrig((hkExecQuery_t)&hkExecQuery); | |
BSTR strQuery = GET_ARG(2); | |
Log(L"ComIWbemService!ExecQuery {:#x} {}\n", RetAddr, PU_BS(strQuery)); | |
return orig(_args...); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment