0

我正在编写一个应用程序分析库,它基本上挂钩 Windows API 并记录参数和结果。我试图想出一种方法来使用 C++ 模板生成这些钩子,这种方式需要最少的努力来添加新的钩子。基本上,我的每个钩子都如下所示:

BOOL HookCloseHandle(HANDLE h)
{
    BOOL result = RealCloseHandle(h);
    if(g_profiling) record(result, h);
    return result;
}

我想通过模板来概括这一点,以便可以为任何 Windows API 函数生成这些函数decltype,例如decltype(CreateFileW). 这甚至可能吗?我一直function_traits在 Boost 中查看,似乎我能够想出一些接近的东西:

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挂钩库提供了 哪里,它用我的挂钩版本替换了“真实”功能。

唯一的事情是,我不确定如何删除CloseHandle当前在call函数内部的模板参数。有任何想法吗?

4

1 回答 1

1

好吧,基本情况如下所示:

//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 接受它们很好。

于 2014-11-12T21:53:20.327 回答