包装任何API函数

Wrapping any API Function

本文关键字:函数 API 任何 包装      更新时间:2023-10-16

我正在包装Windows API,我希望让错误检查变得容易使用,而且很有帮助。目前,我有一个全局错误对象,其函数set用于处理新错误。set函数有四个参数:bool Error::set (const int code, const char * file, const char * const function, const int line);该函数使用文件、函数和行参数将它们显示在格式良好的消息中。

为了简化错误设置,有一个宏#define setError() error.set (GetLastError(), __FILE__, __FUNCTION__, __LINE__);。通过这种方式,我可以随时使用setError()来响应API函数设置的错误,方法是在调用API函数后添加它。

不幸的是,这导致代码看起来像这样:

SomeAPIFunction();
setError();
AnotherAPIFunction();
setError();

构造函数也有一个问题:

MyClass:MyClass()
    : a (SomeAPIFunction), b (AnotherAPIFunction)
{
    setError(); //what if both functions set an error?
}

正如您所看到的,通过使用成员初始值设定项语法,我实际上限制了自己。

解决这个问题的一种方法是包装每个API函数:

int someAPIFunction()
{
    int ret = SomeAPIFunction();
    setError();
    return ret;
}

错误消息的function部分会告诉我是哪个函数引发了错误。当然,这是最糟糕的处理方式。

解决方案似乎是使用可变模板。问题是,我不知道我应该做什么来让他们为此工作。我想最终的代码看起来像以下代码之一:

wrap<int, SomeAPIFunction (5)>();
wrap<int, SomeAPIFunction, 5>();
wrap<int, SomeAPIFunction> (5);

我读过一些关于开始可变模板的东西,但它们都让我不知道如何设置这样的模板。有人能给我指正确的方向吗?

我在一个类似的问题上发现了以下内容:

#include <iostream>
template<void f(void)>
struct Wrap {
   void operator()() const {
      std::cout << "Pre call hook" << std::endl;
      f();
   }
};
namespace {
   void test_func() {
      std::cout << "Real function" << std::endl;
   }
}
const Wrap<&test_func> wrapped_test_func = {};
int main() {
   wrapped_test_func();
   return 0;
}

答辩人指出,为了使这一点足够通用,有必要使用各种各样的模板。这是一个开始,但我很失落,也很感激在这件事上得到的任何帮助。

我认为您将能够使用以下语法:

wrap(&SomeAPIFunction, arg1, arg2);

关键是让编译器使用类型推导来确定模板类型参数,因为它们在匆忙中会变得非常混乱。

代码应该看起来像:

template<typename TRet, typename... TArgs>
TRet wrap( TRet(WINAPI *api)(TArgs...), TArgs... args )
{
    return api(args...);
}

当然,您会希望使用宏来隐藏函数运算符的地址,使用字符串化来存储函数名称,还存储文件名和行号,并将所有这些传递给实际的变元函数。为此,您需要可变宏。事实上,你能只使用可变宏而不使用模板来完成所有这些吗?