Skip to content

Instantly share code, notes, and snippets.

@stevemk14ebr
Last active August 23, 2020 05:53
Show Gist options
  • Save stevemk14ebr/5cac9e678f10f71f5d477ecf6637ed75 to your computer and use it in GitHub Desktop.
Save stevemk14ebr/5cac9e678f10f71f5d477ecf6637ed75 to your computer and use it in GitHub Desktop.
//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