我正在编写一个基本上挂钩Windows API并记录参数和结果的应用程序分析库。我试图想出一种使用C ++模板生成这些钩子的方法,这种模板只需要很少的工作就可以添加新的钩子。基本上,我的每个钩子都如下所示:
BOOL HookCloseHandle(HANDLE h)
{
BOOL result = RealCloseHandle(h);
if(g_profiling) record(result, h);
return result;
}
我想通过模板来概括,以便可以通过decltype
为任意Windows API函数生成这些函数,例如: decltype(CreateFileW)
。这甚至可能吗?我一直在看Boost中的function_traits
,似乎我能够想出一些接近的东西:
decltype(&CloseHandle) RealCloseHandle = &::CloseHandle;
template <typename R, typename P1, R(*F)(P1)>
R perform_1(P1 value)
{
R result = F(value);
if (profiling) record(result, value);
return result;
}
template <typename T>
T* call(const T& original)
{
typedef boost::function_traits<T> traits;
switch (traits::arity)
{
case 1:
return &perform_1<traits::result_type, traits::arg1_type, RealCloseHandle>;
// ...
}
return nullptr;
};
// setup code
Hook(RealCloseHandle, call<decltype(CloseHandle)>());
挂钩库提供Hook
取代&#34;真实&#34;功能与我的钩子版本。
唯一的问题是,我不确定如何删除当前CloseHandle
函数中的call
模板参数。有什么想法吗?
答案 0 :(得分:0)
嗯,基础知识看起来像这样:
//declare the Wrap type
template<class signature, signature func> struct Wrap;
//template parameters are return type, parameter list, then the actual function
template<class R, class...Ps, R(&func)(Ps...)>
struct Wrap<R(Ps...), func>
{
static R MSVCSTDCALL call(Ps...Vs) GCCSTDCALL
{
auto result = func(Vs...);
if (g_profiling) record_w_ret(Wrap(), result, Vs...);
return result;
}
};
//pass the call function of the Wrap object
Hook(CloseHandle, Wrap<void(HANDLE),CloseHandle>::call);
但是,这不会处理void
返回,因此我们需要专门化:
//Wrappers without returns
template<class...Ps, void(&func)(Ps...)>
struct Wrap<void(Ps...), func>
{
static void MSVCSTDCALL call(Ps...Vs) GCCSTDCALL
{
func(Vs...);
if (g_profiling) record_no_ret(Wrap(), Vs...);
}
};
并修复丑陋的使用语法:
//easymode wrapper
#define WRAP(X) Wrap<decltype(X),X>::call
Hook(CloseHandle, WRAP(CloseHandle));
但是,有人指出,使用函数指针作为非类型模板参数是非法的,G ++不会接受它。我会继续努力的。 Clang和MSVC接受他们的罚款。