我正在尝试将 WinAPI 函数的调用包装在将自动检查错误的函数中:
template<typename T = void,typename function, typename ...Args>
T winapi_wrapper(function caller, Args&&... args)
{
static_assert(not std::is_function_v<function>);
auto check_error = [](){ GetLastError() != 0 ? throw std::runtime_error{"error in a WinAPI call"} : [](){}();};
if constexpr(!std::is_void_v<T>)
{
T result = caller(std::forward<Args>(args)...);
check_error();
return result;
}
else
{
caller(std::forward<Args>(args)...);
check_error();
}
}
int main()
{
using func_zero_args = long long (__cdecl*)();
using func_one_arg = long long (__cdecl*)(int);
std::unique_ptr<HINSTANCE__, decltype(&FreeLibrary)> dll_handler{winapi_wrapper<HINSTANCE>(&LoadLibraryA,"C:/test.dll"), FreeLibrary};
func_zero_args no_arg_ptr = winapi_wrapper<func_zero_args>(&GetProcAddress, dll_handler.get(), "func_no_args");
func_one_arg one_arg_ptr = winapi_wrapper<func_one_arg>(&GetProcAddress, dll_handler.get(), "one_arg_fn");
}
第一个调用按预期工作,但第二个调用未编译,并出现以下错误:
Cannot initialize a variable of type 'long long (*)(int)' with an rvalue of type 'long long (*)()': different number of parameters (1 vs 0)
我试图改变
func_one_arg
的类型
int main()
{
using func_zero_args = long long (__cdecl*)();
using func_one_arg = void (__cdecl*)();
std::unique_ptr<HINSTANCE__, decltype(&FreeLibrary)> dll_handler{winapi_wrapper<HINSTANCE>(&LoadLibraryA,"C:/test.dll"), FreeLibrary};
func_zero_args no_arg_ptr = winapi_wrapper<func_zero_args>(&GetProcAddress, dll_handler.get(), "func_no_args");
func_one_arg one_arg_ptr = winapi_wrapper<func_one_arg>(&GetProcAddress, dll_handler.get(), "one_arg_fn");
}
所以现在的错误是:
Cannot initialize a variable of type 'void (*)()' with an rvalue of type 'long long (*)()': different return type ('void' vs 'long long')
问题在于,
GetProcAddress
返回一个指向long long的指针,当我编写这个包装器时我错过了这一点,所以解决方案是将结果转换为类型T
template<typename T = void,typename function, typename ...Args>
T winapi_wrapper(function caller, Args&&... args)
{
static_assert(not std::is_function_v<function>);
auto check_error = [](){ GetLastError() != 0 ? throw std::runtime_error{"error in a WinAPI call"} : [](){}();};
if constexpr(!std::is_void_v<T>)
{
T result = (T)caller(std::forward<Args>(args)...);
check_error();
return result;
}
else
{
caller(std::forward<Args>(args)...);
check_error();
}
}