为__stdcall函数指针提供比预期更多的参数

时间:2014-01-22 19:16:44

标签: c++ c pointers dll function-pointers

我从供应商提供的dll(所有__stdcall)导入大约1500个函数。由于繁琐的原因,dll存在于包含完整功能列表的各种子集的许多版本中(尽管所有存在的功能都具有公共接口)。所有函数都返回一个指示错误代码的UINT,但是会采用不同类型的各种参数。目前,如果GetProcAddress失败(因为有问题的函数在特定的dll版本中不存在),则函数指针为left = nullptr,每次客户端从dll调用函数时都需要检查它。我想改为指向一个函数的指针,该函数返回一个适当的错误代码的UINT。建议的解决方案是这样的:

UINT missing_func() {
   return ERR_MISSING_FUNC;
}
.....
typedef UINT(*LibFuncTy)(int a, const char *b, double c);
.....
//GetProcAddress returned nullptr... set generic function
LibFuncTy LibFunc = reinterpret_cast<LibFunctTy>(missing_func);
.....
//programme tries to call library function
errorval = LibFunc(arg1, arg2, arg3);

这种方法按写入方式工作(尽管标准明确未定义)但是一旦调用__stdcall就会失败(大概是因为我们搞乱了堆栈)。我看过使用(/滥用)绑定,但似乎没有帮助我正在尝试做什么(除非我错过了什么)。许多库函数调用最终都是在一个深度嵌套的循环中,所以我不想在GetProcAddress能够找到函数的情况下产生任何(非平凡的)开销。

是否有一个“正确”,符合标准的方法来实现这种行为,它将与__stdcall调用约定一起使用,或者我将不得不使用不同的参数列表生成1500个不同版本的missing_func(),所有这些都返回相同的价值?

2 个答案:

答案 0 :(得分:2)

每个堆栈帧大小需要一个虚函数,因为此约定的ret指令相应地调整堆栈指针。

请注意,“未实现”的标准错误代码,我认为像E_NOTIMPL这样的符号名称。看看吧。

答案 1 :(得分:1)

在调用导入函数之前创建一个检查nullptr的包装器似乎可行。

template<typename... Args>
struct get_proc_address_wrapper;

template<typename... Args>
struct get_proc_address_wrapper<unsigned(Args...)>
{
    typedef unsigned(__stdcall *func_type)(Args...);
    get_proc_address_wrapper(func_type pf)
        : pf(pf)
    {}

    unsigned operator()(Args... args)
    {
        if (not pf) return static_cast<unsigned>(-1);
        else return (*pf)(args...);
    }

    func_type pf;
};

这是你如何使用它的demo。如您所见,如果使用nullptr初始化包装器,它会优雅地返回错误代码。我在VS2013上测试了相同的代码,它返回了相同的结果。